mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
SQLDS: Use builtin annotation editor
Plus strict rule fixes
This commit is contained in:
parent
035862bade
commit
fee2eb3716
@ -5573,15 +5573,6 @@ exports[`better eslint`] = {
|
||||
[0, 0, 0, "Do not use any type assertions.", "1"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "2"]
|
||||
],
|
||||
"public/app/features/plugins/sql/datasource/SqlDatasource.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "2"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "4"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "5"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "6"]
|
||||
],
|
||||
"public/app/features/plugins/tests/datasource_srv.test.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
||||
@ -7765,14 +7756,6 @@ exports[`better eslint`] = {
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "2"]
|
||||
],
|
||||
"public/app/plugins/datasource/mssql/types.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "2"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "4"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "5"]
|
||||
],
|
||||
"public/app/plugins/datasource/mysql/datasource.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
||||
|
@ -9,7 +9,7 @@ export const AGGREGATE_FNS = [
|
||||
expression
|
||||
)
|
||||
[OVER (...)]
|
||||
|
||||
|
||||
Returns the average of non-NULL input values, or NaN if the input contains a NaN.`,
|
||||
},
|
||||
{
|
||||
@ -17,13 +17,13 @@ export const AGGREGATE_FNS = [
|
||||
name: 'COUNT',
|
||||
description: `COUNT(*) [OVER (...)]
|
||||
Returns the number of rows in the input.
|
||||
|
||||
|
||||
COUNT(
|
||||
[DISTINCT]
|
||||
expression
|
||||
)
|
||||
[OVER (...)]
|
||||
|
||||
|
||||
Returns the number of rows with expression evaluated to any value other than NULL.
|
||||
`,
|
||||
},
|
||||
@ -34,7 +34,7 @@ export const AGGREGATE_FNS = [
|
||||
expression
|
||||
)
|
||||
[OVER (...)]
|
||||
|
||||
|
||||
Returns the maximum value of non-NULL expressions. Returns NULL if there are zero input rows or expression evaluates to NULL for all rows. Returns NaN if the input contains a NaN.
|
||||
`,
|
||||
},
|
||||
@ -45,7 +45,7 @@ export const AGGREGATE_FNS = [
|
||||
expression
|
||||
)
|
||||
[OVER (...)]
|
||||
|
||||
|
||||
Returns the minimum value of non-NULL expressions. Returns NULL if there are zero input rows or expression evaluates to NULL for all rows. Returns NaN if the input contains a NaN.
|
||||
`,
|
||||
},
|
||||
@ -57,9 +57,9 @@ export const AGGREGATE_FNS = [
|
||||
expression
|
||||
)
|
||||
[OVER (...)]
|
||||
|
||||
|
||||
Returns the sum of non-null values.
|
||||
|
||||
|
||||
If the expression is a floating point value, the sum is non-deterministic, which means you might receive a different result each time you use this function.
|
||||
`,
|
||||
},
|
||||
@ -110,3 +110,19 @@ export const OPERATORS = [
|
||||
{ type: OperatorType.Logical, id: 'AND', operator: 'AND' },
|
||||
{ type: OperatorType.Logical, id: 'OR', operator: 'OR' },
|
||||
];
|
||||
|
||||
export const MACRO_NAMES = [
|
||||
'$__time',
|
||||
'$__timeEpoch',
|
||||
'$__timeFilter',
|
||||
'$__timeFrom',
|
||||
'$__timeTo',
|
||||
'$__timeGroup',
|
||||
'$__timeGroupAlias',
|
||||
'$__unixEpochFilter',
|
||||
'$__unixEpochNanoFilter',
|
||||
'$__unixEpochNanoFrom',
|
||||
'$__unixEpochNanoTo',
|
||||
'$__unixEpochGroup',
|
||||
'$__unixEpochGroupAlias',
|
||||
];
|
||||
|
@ -2,15 +2,14 @@ import { lastValueFrom, of } from 'rxjs';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
|
||||
import {
|
||||
AnnotationEvent,
|
||||
DataFrame,
|
||||
DataFrameView,
|
||||
DataQueryRequest,
|
||||
DataQueryResponse,
|
||||
DataQuery,
|
||||
DataSourceInstanceSettings,
|
||||
DataSourceRef,
|
||||
MetricFindValue,
|
||||
ScopedVars,
|
||||
TimeRange,
|
||||
} from '@grafana/data';
|
||||
import {
|
||||
BackendDataSourceResponse,
|
||||
@ -20,10 +19,12 @@ import {
|
||||
getTemplateSrv,
|
||||
TemplateSrv,
|
||||
} from '@grafana/runtime';
|
||||
import { toTestingStatus } from '@grafana/runtime/src/utils/queryResponse';
|
||||
import { toDataQueryResponse, toTestingStatus } from '@grafana/runtime/src/utils/queryResponse';
|
||||
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
||||
|
||||
import { VariableWithMultiSupport } from '../../../variables/types';
|
||||
import { getSearchFilterScopedVar } from '../../../variables/utils';
|
||||
import { getSearchFilterScopedVar, SearchFilterOptions } from '../../../variables/utils';
|
||||
import { MACRO_NAMES } from '../constants';
|
||||
import {
|
||||
DB,
|
||||
SQLQuery,
|
||||
@ -39,6 +40,7 @@ export abstract class SqlDatasource extends DataSourceWithBackend<SQLQuery, SQLO
|
||||
name: string;
|
||||
interval: string;
|
||||
db: DB;
|
||||
annotations = {};
|
||||
|
||||
constructor(
|
||||
instanceSettings: DataSourceInstanceSettings<SQLOptions>,
|
||||
@ -121,78 +123,56 @@ export abstract class SqlDatasource extends DataSourceWithBackend<SQLQuery, SQLO
|
||||
return value.replace(/''/g, "'");
|
||||
}
|
||||
|
||||
// eslint-ignore @typescript-eslint/no-explicit-any
|
||||
async annotationQuery(options: any): Promise<AnnotationEvent[]> {
|
||||
if (!options.annotation.rawQuery) {
|
||||
return Promise.reject({
|
||||
message: 'Query missing in annotation definition',
|
||||
});
|
||||
}
|
||||
async metricFindQuery(query: string, optionalOptions?: MetricFindQueryOptions): Promise<MetricFindValue[]> {
|
||||
const rawSql = this.templateSrv.replace(
|
||||
query,
|
||||
getSearchFilterScopedVar({ query, wildcardChar: '%', options: optionalOptions }),
|
||||
this.interpolateVariable
|
||||
);
|
||||
|
||||
const query = {
|
||||
refId: options.annotation.name,
|
||||
const interpolatedQuery: SQLQuery = {
|
||||
refId: 'tempvar',
|
||||
datasource: this.getRef(),
|
||||
rawSql: this.templateSrv.replace(options.annotation.rawQuery, options.scopedVars, this.interpolateVariable),
|
||||
format: 'table',
|
||||
rawSql,
|
||||
format: QueryFormat.Table,
|
||||
};
|
||||
|
||||
const response = await this.runMetaQuery(interpolatedQuery, optionalOptions);
|
||||
return this.getResponseParser().transformMetricFindResponse(response);
|
||||
}
|
||||
|
||||
async runSql<T>(query: string, options?: MetricFindQueryOptions) {
|
||||
const frame = await this.runMetaQuery({ rawSql: query, format: QueryFormat.Table }, options);
|
||||
return new DataFrameView<T>(frame);
|
||||
}
|
||||
|
||||
private runMetaQuery(request: Partial<SQLQuery>, options?: MetricFindQueryOptions): Promise<DataFrame> {
|
||||
const range = getTimeSrv().timeRange();
|
||||
const refId = request.refId || 'meta';
|
||||
const queries: DataQuery[] = [{ ...request, datasource: request.datasource || this.getRef(), refId }];
|
||||
|
||||
return lastValueFrom(
|
||||
getBackendSrv()
|
||||
.fetch<BackendDataSourceResponse>({
|
||||
url: '/api/ds/query',
|
||||
method: 'POST',
|
||||
data: {
|
||||
from: options.range.from.valueOf().toString(),
|
||||
to: options.range.to.valueOf().toString(),
|
||||
queries: [query],
|
||||
from: options?.range?.from.valueOf().toString() || range.from.valueOf().toString(),
|
||||
to: options?.range?.to.valueOf().toString() || range.to.valueOf().toString(),
|
||||
queries,
|
||||
},
|
||||
requestId: options.annotation.name,
|
||||
requestId: refId,
|
||||
})
|
||||
.pipe(
|
||||
map(
|
||||
async (res: FetchResponse<BackendDataSourceResponse>) =>
|
||||
await this.getResponseParser().transformAnnotationResponse(options, res.data)
|
||||
)
|
||||
map((res: FetchResponse<BackendDataSourceResponse>) => {
|
||||
const rsp = toDataQueryResponse(res, queries);
|
||||
return rsp.data[0];
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
async metricFindQuery(query: string, optionalOptions: any): Promise<MetricFindValue[]> {
|
||||
const rawSql = this.templateSrv.replace(
|
||||
query,
|
||||
getSearchFilterScopedVar({ query, wildcardChar: '%', options: optionalOptions }),
|
||||
this.interpolateVariable
|
||||
);
|
||||
|
||||
const interpolatedQuery = {
|
||||
datasourceId: this.id,
|
||||
datasource: this.getRef(),
|
||||
rawSql,
|
||||
format: QueryFormat.Table,
|
||||
};
|
||||
|
||||
const response = await this.runQuery(interpolatedQuery, optionalOptions);
|
||||
return this.getResponseParser().transformMetricFindResponse(response);
|
||||
}
|
||||
|
||||
async runSql<T = any>(query: string) {
|
||||
const frame = await this.runQuery({ rawSql: query, format: QueryFormat.Table }, {});
|
||||
return new DataFrameView<T>(frame);
|
||||
}
|
||||
|
||||
private runQuery(request: Partial<SQLQuery>, options?: any): Promise<DataFrame> {
|
||||
return new Promise((resolve) => {
|
||||
const req = {
|
||||
targets: [{ ...request, refId: String(Math.random()) }],
|
||||
range: options?.range,
|
||||
} as DataQueryRequest<SQLQuery>;
|
||||
this.query(req).subscribe((res: DataQueryResponse) => {
|
||||
resolve(res.data[0] || { fields: [] });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
testDatasource(): Promise<any> {
|
||||
testDatasource(): Promise<{ status: string; message: string }> {
|
||||
return lastValueFrom(
|
||||
getBackendSrv()
|
||||
.fetch({
|
||||
@ -223,7 +203,15 @@ export abstract class SqlDatasource extends DataSourceWithBackend<SQLQuery, SQLO
|
||||
);
|
||||
}
|
||||
|
||||
targetContainsTemplate(target: any) {
|
||||
return this.templateSrv.containsTemplate(target.rawSql);
|
||||
targetContainsTemplate(target: SQLQuery) {
|
||||
let queryWithoutMacros = target.rawSql;
|
||||
MACRO_NAMES.forEach((value) => {
|
||||
queryWithoutMacros = queryWithoutMacros?.replace(value, '') || '';
|
||||
});
|
||||
return this.templateSrv.containsTemplate(queryWithoutMacros);
|
||||
}
|
||||
}
|
||||
|
||||
interface MetricFindQueryOptions extends SearchFilterOptions {
|
||||
range?: TimeRange;
|
||||
}
|
||||
|
@ -3,20 +3,21 @@ import { EditorMode } from '@grafana/experimental';
|
||||
import { QueryFormat, SQLQuery } from './types';
|
||||
import { createFunctionField, setGroupByField } from './utils/sql.utils';
|
||||
|
||||
export function applyQueryDefaults(q: SQLQuery): SQLQuery {
|
||||
let editorMode = q.editorMode || EditorMode.Builder;
|
||||
export function applyQueryDefaults(q?: SQLQuery): SQLQuery {
|
||||
let editorMode = q?.editorMode || EditorMode.Builder;
|
||||
|
||||
// Switching to code editor if the query was created before visual query builder was introduced.
|
||||
if (q.editorMode === undefined && q.rawSql !== undefined) {
|
||||
if (q?.editorMode === undefined && q?.rawSql !== undefined) {
|
||||
editorMode = EditorMode.Code;
|
||||
}
|
||||
|
||||
const result = {
|
||||
const result: SQLQuery = {
|
||||
...q,
|
||||
format: q.format !== undefined ? q.format : QueryFormat.Table,
|
||||
rawSql: q.rawSql || '',
|
||||
refId: q?.refId || 'A',
|
||||
format: q?.format !== undefined ? q.format : QueryFormat.Table,
|
||||
rawSql: q?.rawSql || '',
|
||||
editorMode,
|
||||
sql: q.sql || {
|
||||
sql: q?.sql || {
|
||||
columns: [createFunctionField()],
|
||||
groupBy: [setGroupByField()],
|
||||
limit: 50,
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { JsonTree } from 'react-awesome-query-builder';
|
||||
|
||||
import {
|
||||
AnnotationEvent,
|
||||
DataFrame,
|
||||
DataQuery,
|
||||
DataSourceJsonData,
|
||||
@ -11,7 +10,6 @@ import {
|
||||
toOption as toOptionFromData,
|
||||
} from '@grafana/data';
|
||||
import { CompletionItemKind, EditorMode, LanguageCompletionProvider } from '@grafana/experimental';
|
||||
import { BackendDataSourceResponse } from '@grafana/runtime';
|
||||
|
||||
import { QueryWithDefaults } from './defaults';
|
||||
import {
|
||||
@ -23,7 +21,7 @@ import {
|
||||
export interface SqlQueryForInterpolation {
|
||||
dataset?: string;
|
||||
alias?: string;
|
||||
format?: ResultFormat;
|
||||
format?: QueryFormat;
|
||||
rawSql?: string;
|
||||
refId: string;
|
||||
hide?: boolean;
|
||||
@ -34,8 +32,6 @@ export interface SQLOptions extends DataSourceJsonData {
|
||||
database: string;
|
||||
}
|
||||
|
||||
export type ResultFormat = 'time_series' | 'table';
|
||||
|
||||
export enum QueryFormat {
|
||||
Timeseries = 'time_series',
|
||||
Table = 'table',
|
||||
@ -43,7 +39,7 @@ export enum QueryFormat {
|
||||
|
||||
export interface SQLQuery extends DataQuery {
|
||||
alias?: string;
|
||||
format?: ResultFormat | QueryFormat | string | undefined;
|
||||
format?: QueryFormat;
|
||||
rawSql?: string;
|
||||
dataset?: string;
|
||||
table?: string;
|
||||
@ -150,7 +146,6 @@ export interface SqlQueryModel {
|
||||
}
|
||||
|
||||
export interface ResponseParser {
|
||||
transformAnnotationResponse: (options: object, data: BackendDataSourceResponse) => Promise<AnnotationEvent[]>;
|
||||
transformMetricFindResponse: (frame: DataFrame) => MetricFindValue[];
|
||||
}
|
||||
|
||||
|
@ -33,10 +33,14 @@ export const SEARCH_FILTER_VARIABLE = '__searchFilter';
|
||||
export const containsSearchFilter = (query: string | unknown): boolean =>
|
||||
query && typeof query === 'string' ? query.indexOf(SEARCH_FILTER_VARIABLE) !== -1 : false;
|
||||
|
||||
export interface SearchFilterOptions {
|
||||
searchFilter?: string;
|
||||
}
|
||||
|
||||
export const getSearchFilterScopedVar = (args: {
|
||||
query: string;
|
||||
wildcardChar: string;
|
||||
options: { searchFilter?: string };
|
||||
options?: SearchFilterOptions;
|
||||
}): ScopedVars => {
|
||||
const { query, wildcardChar } = args;
|
||||
if (!containsSearchFilter(query)) {
|
||||
|
Loading…
Reference in New Issue
Block a user