diff --git a/public/app/features/plugins/sql/components/QueryEditor.tsx b/public/app/features/plugins/sql/components/QueryEditor.tsx index 3556048483d..b0145b4ee0b 100644 --- a/public/app/features/plugins/sql/components/QueryEditor.tsx +++ b/public/app/features/plugins/sql/components/QueryEditor.tsx @@ -13,9 +13,19 @@ import { QueryHeader } from './QueryHeader'; import { RawEditor } from './query-editor-raw/RawEditor'; import { VisualEditor } from './visual-query-builder/VisualEditor'; -type Props = QueryEditorProps; +type Props = QueryEditorProps< + SqlDatasource, + TSQLQuery, + TSQLOptions +>; -export function SqlQueryEditor({ datasource, query, onChange, onRunQuery, range }: Props) { +export function SqlQueryEditor({ + datasource, + query, + onChange, + onRunQuery, + range, +}: Props) { const [isQueryRunnable, setIsQueryRunnable] = useState(true); const db = datasource.getDB(); const { loading, error } = useAsync(async () => { @@ -52,7 +62,7 @@ export function SqlQueryEditor({ datasource, query, onChange, onRunQuery, range [onRunQuery] ); - const onQueryChange = (q: SQLQuery, process = true) => { + const onQueryChange = (q: TSQLQuery, process = true) => { setQueryToValidate(q); onChange(q); @@ -65,7 +75,7 @@ export function SqlQueryEditor({ datasource, query, onChange, onRunQuery, range } }; - const onQueryHeaderChange = (q: SQLQuery) => { + const onQueryHeaderChange = (q: TSQLQuery) => { setQueryToValidate(q); onChange(q); }; @@ -76,7 +86,7 @@ export function SqlQueryEditor({ datasource, query, onChange, onRunQuery, range return ( <> - db={db} onChange={onQueryHeaderChange} onRunQuery={onRunQuery} @@ -92,7 +102,7 @@ export function SqlQueryEditor({ datasource, query, onChange, onRunQuery, range onQueryChange(q, false)} + onChange={(q: TSQLQuery) => onQueryChange(q, false)} queryRowFilter={queryRowFilter} onValidate={setIsQueryRunnable} range={range} diff --git a/public/app/features/plugins/sql/components/QueryHeader.tsx b/public/app/features/plugins/sql/components/QueryHeader.tsx index d092ccc4172..cbf4fe36225 100644 --- a/public/app/features/plugins/sql/components/QueryHeader.tsx +++ b/public/app/features/plugins/sql/components/QueryHeader.tsx @@ -5,7 +5,6 @@ import { SelectableValue } from '@grafana/data'; import { EditorField, EditorHeader, EditorMode, EditorRow, FlexItem, InlineSelect, Space } from '@grafana/experimental'; import { Button, InlineField, InlineSwitch, RadioButtonGroup, Select, Tooltip } from '@grafana/ui'; -import { QueryWithDefaults } from '../defaults'; import { SQLQuery, QueryFormat, QueryRowFilter, QUERY_FORMAT_OPTIONS, DB } from '../types'; import { defaultToRawSql } from '../utils/sql.utils'; @@ -14,10 +13,10 @@ import { DatasetSelector } from './DatasetSelector'; import { ErrorBoundary } from './ErrorBoundary'; import { TableSelector } from './TableSelector'; -interface QueryHeaderProps { +interface QueryHeaderProps { db: DB; - query: QueryWithDefaults; - onChange: (query: SQLQuery) => void; + query: T; + onChange: (query: T) => void; onRunQuery: () => void; onQueryRowChange: (queryRowFilter: QueryRowFilter) => void; queryRowFilter: QueryRowFilter; @@ -29,7 +28,7 @@ const editorModes = [ { label: 'Code', value: EditorMode.Code }, ]; -export function QueryHeader({ +export function QueryHeader({ db, query, queryRowFilter, @@ -37,7 +36,7 @@ export function QueryHeader({ onRunQuery, onQueryRowChange, isQueryRunnable, -}: QueryHeaderProps) { +}: QueryHeaderProps) { const { editorMode } = query; const [_, copyToClipboard] = useCopyToClipboard(); const [showConfirm, setShowConfirm] = useState(false); @@ -80,7 +79,7 @@ export function QueryHeader({ return; } - const next: SQLQuery = { + const next = { ...query, table: e.value, sql: undefined, diff --git a/public/app/features/plugins/sql/components/TableSelector.tsx b/public/app/features/plugins/sql/components/TableSelector.tsx index 65171e2b918..bb502471373 100644 --- a/public/app/features/plugins/sql/components/TableSelector.tsx +++ b/public/app/features/plugins/sql/components/TableSelector.tsx @@ -4,13 +4,12 @@ import { useAsync } from 'react-use'; import { SelectableValue, toOption } from '@grafana/data'; import { Select } from '@grafana/ui'; -import { QueryWithDefaults } from '../defaults'; -import { DB, ResourceSelectorProps } from '../types'; +import { DB, ResourceSelectorProps, SQLQuery } from '../types'; interface TableSelectorProps extends ResourceSelectorProps { db: DB; value: string | null; - query: QueryWithDefaults; + query: SQLQuery; onChange: (v: SelectableValue) => void; } diff --git a/public/app/features/plugins/sql/components/query-editor-raw/QueryEditorRaw.tsx b/public/app/features/plugins/sql/components/query-editor-raw/QueryEditorRaw.tsx index 1d0e1ca6773..51fb50e254a 100644 --- a/public/app/features/plugins/sql/components/query-editor-raw/QueryEditorRaw.tsx +++ b/public/app/features/plugins/sql/components/query-editor-raw/QueryEditorRaw.tsx @@ -5,18 +5,25 @@ import { LanguageCompletionProvider, SQLEditor } from '@grafana/experimental'; import { SQLQuery } from '../../types'; import { formatSQL } from '../../utils/formatSQL'; -type Props = { - query: SQLQuery; - onChange: (value: SQLQuery, processQuery: boolean) => void; +type Props = { + query: T; + onChange: (value: T, processQuery: boolean) => void; children?: (props: { formatQuery: () => void }) => React.ReactNode; width?: number; height?: number; completionProvider: LanguageCompletionProvider; }; -export function QueryEditorRaw({ children, onChange, query, width, height, completionProvider }: Props) { +export function QueryEditorRaw({ + children, + onChange, + query, + width, + height, + completionProvider, +}: Props) { // We need to pass query via ref to SQLEditor as onChange is executed via monacoEditor.onDidChangeModelContent callback, not onChange property - const queryRef = useRef(query); + const queryRef = useRef(query); useEffect(() => { queryRef.current = query; }, [query]); diff --git a/public/app/features/plugins/sql/components/query-editor-raw/RawEditor.tsx b/public/app/features/plugins/sql/components/query-editor-raw/RawEditor.tsx index 994c26267e9..7161d1a6393 100644 --- a/public/app/features/plugins/sql/components/query-editor-raw/RawEditor.tsx +++ b/public/app/features/plugins/sql/components/query-editor-raw/RawEditor.tsx @@ -11,14 +11,22 @@ import { SQLQuery, QueryEditorProps } from '../../types'; import { QueryEditorRaw } from './QueryEditorRaw'; import { QueryToolbox } from './QueryToolbox'; -interface RawEditorProps extends Omit { +interface RawEditorProps extends Omit, 'onChange'> { onRunQuery: () => void; - onChange: (q: SQLQuery, processQuery: boolean) => void; + onChange: (q: T, processQuery: boolean) => void; onValidate: (isValid: boolean) => void; - queryToValidate: SQLQuery; + queryToValidate: T; } -export function RawEditor({ db, query, onChange, onRunQuery, onValidate, queryToValidate, range }: RawEditorProps) { +export function RawEditor({ + db, + query, + onChange, + onRunQuery, + onValidate, + queryToValidate, + range, +}: RawEditorProps) { const theme = useTheme2(); const styles = useStyles2(getStyles); const [isExpanded, setIsExpanded] = useState(false); diff --git a/public/app/features/plugins/sql/components/visual-query-builder/SQLGroupByRow.tsx b/public/app/features/plugins/sql/components/visual-query-builder/SQLGroupByRow.tsx index 617b8fa5632..716dd1efe92 100644 --- a/public/app/features/plugins/sql/components/visual-query-builder/SQLGroupByRow.tsx +++ b/public/app/features/plugins/sql/components/visual-query-builder/SQLGroupByRow.tsx @@ -2,21 +2,20 @@ import React from 'react'; import { SelectableValue } from '@grafana/data'; -import { QueryWithDefaults } from '../../defaults'; import { DB, SQLQuery } from '../../types'; import { useSqlChange } from '../../utils/useSqlChange'; import { GroupByRow } from './GroupByRow'; -interface SQLGroupByRowProps { +interface SQLGroupByRowProps { fields: SelectableValue[]; - query: QueryWithDefaults; - onQueryChange: (query: SQLQuery) => void; + query: T; + onQueryChange: (query: T) => void; db: DB; } -export function SQLGroupByRow({ fields, query, onQueryChange, db }: SQLGroupByRowProps) { +export function SQLGroupByRow({ fields, query, onQueryChange, db }: SQLGroupByRowProps) { const { onSqlChange } = useSqlChange({ query, onQueryChange, db }); - return ; + return ; } diff --git a/public/app/features/plugins/sql/components/visual-query-builder/SQLOrderByRow.tsx b/public/app/features/plugins/sql/components/visual-query-builder/SQLOrderByRow.tsx index 80a5d50b213..c2400063c2c 100644 --- a/public/app/features/plugins/sql/components/visual-query-builder/SQLOrderByRow.tsx +++ b/public/app/features/plugins/sql/components/visual-query-builder/SQLOrderByRow.tsx @@ -2,20 +2,19 @@ import React from 'react'; import { SelectableValue } from '@grafana/data'; -import { QueryWithDefaults } from '../../defaults'; import { DB, SQLQuery } from '../../types'; import { useSqlChange } from '../../utils/useSqlChange'; import { OrderByRow } from './OrderByRow'; -type SQLOrderByRowProps = { +type SQLOrderByRowProps = { fields: SelectableValue[]; - query: QueryWithDefaults; - onQueryChange: (query: SQLQuery) => void; + query: T; + onQueryChange: (query: T) => void; db: DB; }; -export function SQLOrderByRow({ fields, query, onQueryChange, db }: SQLOrderByRowProps) { +export function SQLOrderByRow({ fields, query, onQueryChange, db }: SQLOrderByRowProps) { const { onSqlChange } = useSqlChange({ query, onQueryChange, db }); let columnsWithIndices: SelectableValue[] = []; @@ -36,5 +35,5 @@ export function SQLOrderByRow({ fields, query, onQueryChange, db }: SQLOrderByRo ]; } - return ; + return ; } diff --git a/public/app/features/plugins/sql/components/visual-query-builder/SQLSelectRow.tsx b/public/app/features/plugins/sql/components/visual-query-builder/SQLSelectRow.tsx index 29844d0e4ce..f13a9ff56ab 100644 --- a/public/app/features/plugins/sql/components/visual-query-builder/SQLSelectRow.tsx +++ b/public/app/features/plugins/sql/components/visual-query-builder/SQLSelectRow.tsx @@ -2,21 +2,20 @@ import React from 'react'; import { SelectableValue } from '@grafana/data'; -import { QueryWithDefaults } from '../../defaults'; import { DB, SQLQuery } from '../../types'; import { useSqlChange } from '../../utils/useSqlChange'; import { SelectRow } from './SelectRow'; -interface SQLSelectRowProps { +interface SQLSelectRowProps { fields: SelectableValue[]; - query: QueryWithDefaults; - onQueryChange: (query: SQLQuery) => void; + query: T; + onQueryChange: (query: T) => void; db: DB; } -export function SQLSelectRow({ fields, query, onQueryChange, db }: SQLSelectRowProps) { +export function SQLSelectRow({ fields, query, onQueryChange, db }: SQLSelectRowProps) { const { onSqlChange } = useSqlChange({ query, onQueryChange, db }); - return ; + return ; } diff --git a/public/app/features/plugins/sql/components/visual-query-builder/SQLWhereRow.tsx b/public/app/features/plugins/sql/components/visual-query-builder/SQLWhereRow.tsx index 2602a485776..cba8e348caf 100644 --- a/public/app/features/plugins/sql/components/visual-query-builder/SQLWhereRow.tsx +++ b/public/app/features/plugins/sql/components/visual-query-builder/SQLWhereRow.tsx @@ -3,21 +3,20 @@ import useAsync from 'react-use/lib/useAsync'; import { SelectableValue } from '@grafana/data'; -import { QueryWithDefaults } from '../../defaults'; import { DB, SQLExpression, SQLQuery, SQLSelectableValue } from '../../types'; import { useSqlChange } from '../../utils/useSqlChange'; import { Config } from './AwesomeQueryBuilder'; import { WhereRow } from './WhereRow'; -interface WhereRowProps { - query: QueryWithDefaults; +interface WhereRowProps { + query: T; fields: SelectableValue[]; - onQueryChange: (query: SQLQuery) => void; + onQueryChange: (query: T) => void; db: DB; } -export function SQLWhereRow({ query, fields, onQueryChange, db }: WhereRowProps) { +export function SQLWhereRow({ query, fields, onQueryChange, db }: WhereRowProps) { const state = useAsync(async () => { return mapFieldsToTypes(fields); }, [fields]); @@ -29,7 +28,7 @@ export function SQLWhereRow({ query, fields, onQueryChange, db }: WhereRowProps) // TODO: fix key that's used to force clean render or SQLWhereRow - otherwise it doesn't render operators correctly key={JSON.stringify(state.value)} config={{ fields: state.value || {} }} - sql={query.sql!} + sql={query.sql || {}} onSqlChange={(val: SQLExpression) => { onSqlChange(val); }} diff --git a/public/app/features/plugins/sql/components/visual-query-builder/VisualEditor.tsx b/public/app/features/plugins/sql/components/visual-query-builder/VisualEditor.tsx index 81b9c1f8b58..934bdc2a5b9 100644 --- a/public/app/features/plugins/sql/components/visual-query-builder/VisualEditor.tsx +++ b/public/app/features/plugins/sql/components/visual-query-builder/VisualEditor.tsx @@ -3,7 +3,7 @@ import { useAsync } from 'react-use'; import { EditorField, EditorRow, EditorRows } from '@grafana/experimental'; -import { DB, QueryEditorProps, QueryRowFilter } from '../../types'; +import { DB, QueryEditorProps, QueryRowFilter, SQLQuery } from '../../types'; import { QueryToolbox } from '../query-editor-raw/QueryToolbox'; import { Preview } from './Preview'; @@ -12,20 +12,20 @@ import { SQLOrderByRow } from './SQLOrderByRow'; import { SQLSelectRow } from './SQLSelectRow'; import { SQLWhereRow } from './SQLWhereRow'; -interface VisualEditorProps extends QueryEditorProps { +interface VisualEditorProps extends QueryEditorProps { db: DB; queryRowFilter: QueryRowFilter; onValidate: (isValid: boolean) => void; } -export const VisualEditor: React.FC = ({ +export function VisualEditor({ query, db, queryRowFilter, onChange, onValidate, range, -}) => { +}: VisualEditorProps) { const state = useAsync(async () => { const fields = await db.fields(query); return fields; @@ -65,4 +65,4 @@ export const VisualEditor: React.FC = ({ ); -}; +} diff --git a/public/app/features/plugins/sql/datasource/SqlDatasource.ts b/public/app/features/plugins/sql/datasource/SqlDatasource.ts index 8039583dad2..36b461fef59 100644 --- a/public/app/features/plugins/sql/datasource/SqlDatasource.ts +++ b/public/app/features/plugins/sql/datasource/SqlDatasource.ts @@ -25,17 +25,12 @@ import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv'; import { VariableWithMultiSupport } from '../../../variables/types'; import { getSearchFilterScopedVar, SearchFilterOptions } from '../../../variables/utils'; import { MACRO_NAMES } from '../constants'; -import { - DB, - SQLQuery, - SQLOptions, - SqlQueryForInterpolation, - ResponseParser, - SqlQueryModel, - QueryFormat, -} from '../types'; +import { DB, SQLQuery, SQLOptions, ResponseParser, SqlQueryModel, QueryFormat } from '../types'; -export abstract class SqlDatasource extends DataSourceWithBackend { +export abstract class SqlDatasource< + TSQLQuery extends SQLQuery, + TSQLOptions extends SQLOptions +> extends DataSourceWithBackend { id: number; name: string; interval: string; @@ -43,7 +38,7 @@ export abstract class SqlDatasource extends DataSourceWithBackend, + instanceSettings: DataSourceInstanceSettings, protected readonly templateSrv: TemplateSrv = getTemplateSrv() ) { super(instanceSettings); @@ -82,10 +77,7 @@ export abstract class SqlDatasource extends DataSourceWithBackend 0) { expandedQueries = queries.map((query) => { diff --git a/public/app/features/plugins/sql/defaults.ts b/public/app/features/plugins/sql/defaults.ts index e67a4128acb..6bb329ad268 100644 --- a/public/app/features/plugins/sql/defaults.ts +++ b/public/app/features/plugins/sql/defaults.ts @@ -3,7 +3,7 @@ import { EditorMode } from '@grafana/experimental'; import { QueryFormat, SQLQuery } from './types'; import { createFunctionField, setGroupByField } from './utils/sql.utils'; -export function applyQueryDefaults(q?: SQLQuery): SQLQuery { +export function applyQueryDefaults(q: T): T { let editorMode = q?.editorMode || EditorMode.Builder; // Switching to code editor if the query was created before visual query builder was introduced. @@ -11,7 +11,7 @@ export function applyQueryDefaults(q?: SQLQuery): SQLQuery { editorMode = EditorMode.Code; } - const result: SQLQuery = { + const result: T = { ...q, refId: q?.refId || 'A', format: q?.format !== undefined ? q.format : QueryFormat.Table, @@ -26,5 +26,3 @@ export function applyQueryDefaults(q?: SQLQuery): SQLQuery { return result; } - -export type QueryWithDefaults = ReturnType; diff --git a/public/app/features/plugins/sql/types.ts b/public/app/features/plugins/sql/types.ts index b5509dbba2e..bb5541a5377 100644 --- a/public/app/features/plugins/sql/types.ts +++ b/public/app/features/plugins/sql/types.ts @@ -11,22 +11,12 @@ import { } from '@grafana/data'; import { CompletionItemKind, EditorMode, LanguageCompletionProvider } from '@grafana/experimental'; -import { QueryWithDefaults } from './defaults'; import { QueryEditorFunctionExpression, QueryEditorGroupByExpression, QueryEditorPropertyExpression, } from './expressions'; -export interface SqlQueryForInterpolation { - dataset?: string; - alias?: string; - format?: QueryFormat; - rawSql?: string; - refId: string; - hide?: boolean; -} - export interface SQLOptions extends DataSourceJsonData { timeInterval: string; database: string; @@ -122,10 +112,10 @@ export interface DB { toRawSql?: (query: SQLQuery) => string; } -export interface QueryEditorProps { +export interface QueryEditorProps { db: DB; - query: QueryWithDefaults; - onChange: (query: SQLQuery) => void; + query: T; + onChange: (query: T) => void; range?: TimeRange; } diff --git a/public/app/features/plugins/sql/utils/useSqlChange.ts b/public/app/features/plugins/sql/utils/useSqlChange.ts index b7e0cbdfd51..1473698cd1f 100644 --- a/public/app/features/plugins/sql/utils/useSqlChange.ts +++ b/public/app/features/plugins/sql/utils/useSqlChange.ts @@ -4,18 +4,18 @@ import { DB, SQLExpression, SQLQuery } from '../types'; import { defaultToRawSql } from './sql.utils'; -interface UseSqlChange { +interface UseSqlChange { db: DB; - query: SQLQuery; - onQueryChange: (query: SQLQuery) => void; + query: T; + onQueryChange: (query: T) => void; } -export function useSqlChange({ query, onQueryChange, db }: UseSqlChange) { +export function useSqlChange({ query, onQueryChange, db }: UseSqlChange) { const onSqlChange = useCallback( (sql: SQLExpression) => { const toRawSql = db.toRawSql || defaultToRawSql; const rawSql = toRawSql({ sql, dataset: query.dataset, table: query.table, refId: query.refId }); - const newQuery: SQLQuery = { ...query, sql, rawSql }; + const newQuery: T = { ...query, sql, rawSql }; onQueryChange(newQuery); }, [db, onQueryChange, query]