diff --git a/pkg/tsdb/influxdb/fsql/query_model.go b/pkg/tsdb/influxdb/fsql/query_model.go
index 13cc4778976..46128708102 100644
--- a/pkg/tsdb/influxdb/fsql/query_model.go
+++ b/pkg/tsdb/influxdb/fsql/query_model.go
@@ -17,10 +17,10 @@ type queryModel struct {
// to [(*FlightSQLDatasource).QueryData].
type queryRequest struct {
RefID string `json:"refId"`
- RawQuery string `json:"query"`
+ RawQuery string `json:"rawSql"`
IntervalMilliseconds int `json:"intervalMs"`
MaxDataPoints int64 `json:"maxDataPoints"`
- Format string `json:"resultFormat"`
+ Format string `json:"format"`
}
func getQueryModel(dataQuery backend.DataQuery) (*queryModel, error) {
diff --git a/pkg/tsdb/influxdb/healthcheck.go b/pkg/tsdb/influxdb/healthcheck.go
index b37500a0b27..ecf6d358a3b 100644
--- a/pkg/tsdb/influxdb/healthcheck.go
+++ b/pkg/tsdb/influxdb/healthcheck.go
@@ -124,7 +124,7 @@ func CheckSQLHealth(ctx context.Context, dsInfo *models.DatasourceInfo, req *bac
Queries: []backend.DataQuery{
{
RefID: refID,
- JSON: []byte(`{ "query": "select 1", "resultFormat": "table" }`),
+ JSON: []byte(`{ "rawSql": "select 1", "format": "table" }`),
Interval: 1 * time.Minute,
MaxDataPoints: 423,
TimeRange: backend.TimeRange{
diff --git a/public/app/features/plugins/sql/defaults.ts b/public/app/features/plugins/sql/defaults.ts
index e67a4128acb..4532bdcc3a6 100644
--- a/public/app/features/plugins/sql/defaults.ts
+++ b/public/app/features/plugins/sql/defaults.ts
@@ -17,7 +17,7 @@ export function applyQueryDefaults(q?: SQLQuery): SQLQuery {
format: q?.format !== undefined ? q.format : QueryFormat.Table,
rawSql: q?.rawSql || '',
editorMode,
- sql: q?.sql || {
+ sql: q?.sql ?? {
columns: [createFunctionField()],
groupBy: [setGroupByField()],
limit: 50,
diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/QueryEditor.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/QueryEditor.tsx
index a5a646688a9..8c639067a2c 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/query/QueryEditor.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/query/QueryEditor.tsx
@@ -24,7 +24,7 @@ export const QueryEditor = ({ query, onChange, onRunQuery, datasource }: Props)
);
case InfluxVersion.SQL:
- return ;
+ return ;
case InfluxVersion.InfluxQL:
default:
return (
diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/fsql/FSQLEditor.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/fsql/FSQLEditor.tsx
index 362101ec2d6..041e5933bd8 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/query/fsql/FSQLEditor.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/query/fsql/FSQLEditor.tsx
@@ -1,32 +1,129 @@
-import React from 'react';
+import { css, cx } from '@emotion/css';
+import React, { PureComponent } from 'react';
-import { Input } from '@grafana/ui';
+import { GrafanaTheme2 } from '@grafana/data/src';
+import { Alert, InlineFormLabel, LinkButton, Themeable2, withTheme2 } from '@grafana/ui/src';
+import { SQLQuery } from '../../../../../../../features/plugins/sql';
+import { SqlQueryEditor } from '../../../../../../../features/plugins/sql/components/QueryEditor';
+import InfluxDatasource from '../../../../datasource';
import { InfluxQuery } from '../../../../types';
-type Props = {
+import { FlightSQLDatasource } from './FlightSQLDatasource';
+
+interface Props extends Themeable2 {
onChange: (query: InfluxQuery) => void;
onRunQuery: () => void;
query: InfluxQuery;
-};
+ datasource: InfluxDatasource;
+}
-// Flight SQL Editor
-export const FSQLEditor = (props: Props) => {
- const onSQLQueryChange = (query?: string) => {
- if (query) {
- props.onChange({ ...props.query, query, resultFormat: 'table' });
- }
- props.onRunQuery();
- };
- return (
-
- onSQLQueryChange(e.currentTarget.value)}
- onChange={(e) => onSQLQueryChange(e.currentTarget.value)}
- />
-
-
-
- );
-};
+class UnthemedSQLQueryEditor extends PureComponent {
+ datasource: FlightSQLDatasource;
+
+ constructor(props: Props) {
+ super(props);
+ const { datasource: influxDatasource } = props;
+
+ this.datasource = new FlightSQLDatasource({
+ url: influxDatasource.urls[0],
+ access: influxDatasource.access,
+ id: influxDatasource.id,
+
+ jsonData: {
+ // Not applicable to flightSQL? @itsmylife
+ allowCleartextPasswords: false,
+ tlsAuth: false,
+ tlsAuthWithCACert: false,
+ tlsSkipVerify: false,
+ maxIdleConns: 1,
+ maxOpenConns: 1,
+ maxIdleConnsAuto: true,
+ connMaxLifetime: 1,
+ timezone: '',
+ user: '',
+ database: '',
+ url: influxDatasource.urls[0],
+ timeInterval: '',
+ },
+ meta: influxDatasource.meta,
+ name: influxDatasource.name,
+ readOnly: false,
+ type: influxDatasource.type,
+ uid: influxDatasource.uid,
+ });
+ }
+
+ transformQuery(query: InfluxQuery & SQLQuery): SQLQuery {
+ return {
+ ...query,
+ };
+ }
+
+ render() {
+ const { query, theme, onRunQuery, onChange } = this.props;
+ const styles = getStyles(theme);
+
+ const onRunSQLQuery = () => {
+ return onRunQuery();
+ };
+
+ const onSQLChange = (query: SQLQuery) => {
+ // query => rawSql for now
+ onChange({ ...query });
+ };
+
+ const helpTooltip = (
+
+ Type: ctrl+space to show template variable suggestions
+ Many queries can be copied from Chronograf
+
+ );
+
+ return (
+ <>
+
+ InfluxDB SQL support is currently in alpha state. It does not have all the features.
+
+
+
+
+ SQL language syntax
+
+
+
+ Help
+
+
+ >
+ );
+ }
+}
+
+const getStyles = (theme: GrafanaTheme2) => ({
+ editorContainerStyles: css`
+ height: 200px;
+ max-width: 100%;
+ resize: vertical;
+ overflow: auto;
+ background-color: ${theme.isDark ? theme.colors.background.canvas : theme.colors.background.primary};
+ padding-bottom: ${theme.spacing(1)};
+ `,
+ editorActions: css`
+ margin-top: 6px;
+ `,
+});
+
+export const FSQLEditor = withTheme2(UnthemedSQLQueryEditor);
diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/fsql/FlightSQLDatasource.ts b/public/app/plugins/datasource/influxdb/components/editor/query/fsql/FlightSQLDatasource.ts
new file mode 100644
index 00000000000..3a5217879c4
--- /dev/null
+++ b/public/app/plugins/datasource/influxdb/components/editor/query/fsql/FlightSQLDatasource.ts
@@ -0,0 +1,105 @@
+import { DataSourceInstanceSettings, TimeRange } from '@grafana/data';
+import { CompletionItemKind, LanguageDefinition, TableIdentifier } from '@grafana/experimental';
+import { SqlDatasource } from 'app/features/plugins/sql/datasource/SqlDatasource';
+import { DB, SQLQuery } from 'app/features/plugins/sql/types';
+import { formatSQL } from 'app/features/plugins/sql/utils/formatSQL';
+
+// @todo These are being imported for PoC, but should probably be reimplemented within the influx datasource?
+import { mapFieldsToTypes } from '../../../../../mysql/fields';
+import { buildColumnQuery, buildTableQuery, showDatabases } from '../../../../../mysql/mySqlMetaQuery';
+import { getSqlCompletionProvider } from '../../../../../mysql/sqlCompletionProvider';
+import { quoteIdentifierIfNecessary, quoteLiteral, toRawSql } from '../../../../../mysql/sqlUtil';
+import { MySQLOptions } from '../../../../../mysql/types';
+
+export class FlightSQLDatasource extends SqlDatasource {
+ sqlLanguageDefinition: LanguageDefinition | undefined;
+
+ constructor(private instanceSettings: DataSourceInstanceSettings) {
+ super(instanceSettings);
+ }
+
+ getQueryModel() {
+ return { quoteLiteral };
+ }
+
+ getSqlLanguageDefinition(): LanguageDefinition {
+ if (this.sqlLanguageDefinition !== undefined) {
+ return this.sqlLanguageDefinition;
+ }
+
+ const args = {
+ getMeta: (identifier?: TableIdentifier) => this.fetchMeta(identifier),
+ };
+ this.sqlLanguageDefinition = {
+ id: 'mysql',
+ completionProvider: getSqlCompletionProvider(args),
+ formatter: formatSQL,
+ };
+ return this.sqlLanguageDefinition;
+ }
+
+ async fetchDatasets(): Promise {
+ const datasets = await this.runSql(showDatabases(), { refId: 'datasets' });
+ return datasets.map((t) => quoteIdentifierIfNecessary(t[0]));
+ }
+
+ async fetchTables(dataset?: string): Promise {
+ const query = buildTableQuery(dataset);
+ const tables = await this.runSql(query, { refId: 'tables' });
+ return tables.map((t) => quoteIdentifierIfNecessary(t[0]));
+ }
+
+ async fetchFields(query: Partial) {
+ if (!query.dataset || !query.table) {
+ return [];
+ }
+ const queryString = buildColumnQuery(query.table, query.dataset);
+ const frame = await this.runSql(queryString, { refId: 'fields' });
+ const fields = frame.map((f) => ({
+ name: f[0],
+ text: f[0],
+ value: quoteIdentifierIfNecessary(f[0]),
+ type: f[1],
+ label: f[0],
+ }));
+ return mapFieldsToTypes(fields);
+ }
+
+ async fetchMeta(identifier?: TableIdentifier) {
+ const defaultDB = this.instanceSettings.jsonData.database;
+ if (!identifier?.schema && defaultDB) {
+ const tables = await this.fetchTables(defaultDB);
+ return tables.map((t) => ({ name: t, completion: `${defaultDB}.${t}`, kind: CompletionItemKind.Class }));
+ } else if (!identifier?.schema && !defaultDB) {
+ const datasets = await this.fetchDatasets();
+ return datasets.map((d) => ({ name: d, completion: `${d}.`, kind: CompletionItemKind.Module }));
+ } else {
+ if (!identifier?.table && (!defaultDB || identifier?.schema)) {
+ const tables = await this.fetchTables(identifier?.schema);
+ return tables.map((t) => ({ name: t, completion: t, kind: CompletionItemKind.Class }));
+ } else if (identifier?.table && identifier.schema) {
+ const fields = await this.fetchFields({ dataset: identifier.schema, table: identifier.table });
+ return fields.map((t) => ({ name: t.name, completion: t.value, kind: CompletionItemKind.Field }));
+ } else {
+ return [];
+ }
+ }
+ }
+
+ getDB(): DB {
+ if (this.db !== undefined) {
+ return this.db;
+ }
+ return {
+ datasets: () => this.fetchDatasets(),
+ tables: (dataset?: string) => this.fetchTables(dataset),
+ fields: (query: SQLQuery) => this.fetchFields(query),
+ validateQuery: (query: SQLQuery, range?: TimeRange) =>
+ Promise.resolve({ query, error: '', isError: false, isValid: true }),
+ dsID: () => this.id,
+ toRawSql,
+ functions: () => ['VARIANCE', 'STDDEV'],
+ getEditorLanguageDefinition: () => this.getSqlLanguageDefinition(),
+ };
+ }
+}
diff --git a/public/app/plugins/datasource/influxdb/components/editor/variable/VariableQueryEditor.tsx b/public/app/plugins/datasource/influxdb/components/editor/variable/VariableQueryEditor.tsx
index aa3536da533..1df0f2ff78b 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/variable/VariableQueryEditor.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/variable/VariableQueryEditor.tsx
@@ -19,33 +19,41 @@ export default class VariableQueryEditor extends PureComponent {
render() {
let { query, datasource, onChange } = this.props;
- if (datasource.version === InfluxVersion.Flux) {
- return (
- onChange(v.query)}
- />
- );
- }
- return (
-
- );
+ );
+ //@todo add support for SQL
+ case InfluxVersion.SQL:
+ return TODO
;
+
+ // Influx/default case
+ case InfluxVersion.InfluxQL:
+ default:
+ return (
+
+ );
+ }
}
}