The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/public/app/plugins/datasource/influxdb/query_part.ts

460 lines
11 KiB

import { map, clone } from 'lodash';
import { QueryPartDef, QueryPart, functionRenderer, suffixRenderer } from 'app/features/alerting/state/query_part';
const index: any[] = [];
const categories: any = {
Aggregations: [],
Selectors: [],
Transformations: [],
Predictors: [],
Math: [],
Aliasing: [],
Fields: [],
};
function createPart(part: any): any {
const def = index[part.type];
if (!def) {
throw { message: 'Could not find query part ' + part.type };
}
return new QueryPart(part, def);
}
function register(options: any) {
index[options.type] = new QueryPartDef(options);
options.category.push(index[options.type]);
}
const groupByTimeFunctions: any[] = [];
function aliasRenderer(part: { params: string[] }, innerExpr: string) {
return innerExpr + ' AS ' + '"' + part.params[0] + '"';
}
function fieldRenderer(part: { params: string[] }, innerExpr: any) {
if (part.params[0] === '*') {
return '*';
}
return '"' + part.params[0] + '"';
}
function replaceAggregationAddStrategy(selectParts: any[], partModel: { def: { type: string } }) {
// look for existing aggregation
for (let i = 0; i < selectParts.length; i++) {
const part = selectParts[i];
if (part.def.category === categories.Aggregations) {
if (part.def.type === partModel.def.type) {
return;
}
// count distinct is allowed
if (part.def.type === 'count' && partModel.def.type === 'distinct') {
break;
}
// remove next aggregation if distinct was replaced
if (part.def.type === 'distinct') {
const morePartsAvailable = selectParts.length >= i + 2;
if (partModel.def.type !== 'count' && morePartsAvailable) {
const nextPart = selectParts[i + 1];
if (nextPart.def.category === categories.Aggregations) {
selectParts.splice(i + 1, 1);
}
} else if (partModel.def.type === 'count') {
if (!morePartsAvailable || selectParts[i + 1].def.type !== 'count') {
selectParts.splice(i + 1, 0, partModel);
}
return;
}
}
selectParts[i] = partModel;
return;
}
if (part.def.category === categories.Selectors) {
selectParts[i] = partModel;
return;
}
}
selectParts.splice(1, 0, partModel);
}
function addTransformationStrategy(selectParts: any[], partModel: any) {
let i;
// look for index to add transformation
for (i = 0; i < selectParts.length; i++) {
const part = selectParts[i];
if (part.def.category === categories.Math || part.def.category === categories.Aliasing) {
break;
}
}
selectParts.splice(i, 0, partModel);
}
function addMathStrategy(selectParts: any[], partModel: any) {
const partCount = selectParts.length;
if (partCount > 0) {
// if last is math, replace it
if (selectParts[partCount - 1].def.type === 'math') {
selectParts[partCount - 1] = partModel;
return;
}
// if next to last is math, replace it
if (partCount > 1 && selectParts[partCount - 2].def.type === 'math') {
selectParts[partCount - 2] = partModel;
return;
} else if (selectParts[partCount - 1].def.type === 'alias') {
// if last is alias add it before
selectParts.splice(partCount - 1, 0, partModel);
return;
}
}
selectParts.push(partModel);
}
function addAliasStrategy(selectParts: any[], partModel: any) {
const partCount = selectParts.length;
if (partCount > 0) {
// if last is alias, replace it
if (selectParts[partCount - 1].def.type === 'alias') {
selectParts[partCount - 1] = partModel;
return;
}
}
selectParts.push(partModel);
}
function addFieldStrategy(selectParts: any, partModel: any, query: { selectModels: any[][] }) {
// copy all parts
const parts = map(selectParts, (part: any) => {
return createPart({ type: part.def.type, params: clone(part.params) });
});
query.selectModels.push(parts);
}
register({
type: 'field',
addStrategy: addFieldStrategy,
category: categories.Fields,
params: [{ type: 'field', dynamicLookup: true }],
defaultParams: ['value'],
renderer: fieldRenderer,
});
// Aggregations
register({
type: 'count',
addStrategy: replaceAggregationAddStrategy,
category: categories.Aggregations,
params: [],
defaultParams: [],
renderer: functionRenderer,
});
register({
type: 'distinct',
addStrategy: replaceAggregationAddStrategy,
category: categories.Aggregations,
params: [],
defaultParams: [],
renderer: functionRenderer,
});
register({
type: 'integral',
addStrategy: replaceAggregationAddStrategy,
category: categories.Aggregations,
params: [],
defaultParams: [],
renderer: functionRenderer,
});
register({
type: 'mean',
addStrategy: replaceAggregationAddStrategy,
category: categories.Aggregations,
params: [],
defaultParams: [],
renderer: functionRenderer,
});
register({
type: 'median',
addStrategy: replaceAggregationAddStrategy,
category: categories.Aggregations,
params: [],
defaultParams: [],
renderer: functionRenderer,
});
register({
type: 'mode',
addStrategy: replaceAggregationAddStrategy,
category: categories.Aggregations,
params: [],
defaultParams: [],
renderer: functionRenderer,
});
register({
type: 'sum',
addStrategy: replaceAggregationAddStrategy,
category: categories.Aggregations,
params: [],
defaultParams: [],
renderer: functionRenderer,
});
// transformations
register({
type: 'derivative',
addStrategy: addTransformationStrategy,
category: categories.Transformations,
params: [
{
name: 'duration',
type: 'interval',
options: ['1s', '10s', '1m', '5m', '10m', '15m', '1h'],
},
],
defaultParams: ['10s'],
renderer: functionRenderer,
});
register({
type: 'spread',
addStrategy: addTransformationStrategy,
category: categories.Transformations,
params: [],
defaultParams: [],
renderer: functionRenderer,
});
register({
type: 'non_negative_derivative',
addStrategy: addTransformationStrategy,
category: categories.Transformations,
params: [
{
name: 'duration',
type: 'interval',
options: ['1s', '10s', '1m', '5m', '10m', '15m', '1h'],
},
],
defaultParams: ['10s'],
renderer: functionRenderer,
});
register({
type: 'difference',
addStrategy: addTransformationStrategy,
category: categories.Transformations,
params: [],
defaultParams: [],
renderer: functionRenderer,
});
register({
type: 'non_negative_difference',
addStrategy: addTransformationStrategy,
category: categories.Transformations,
params: [],
defaultParams: [],
renderer: functionRenderer,
});
register({
type: 'moving_average',
addStrategy: addTransformationStrategy,
category: categories.Transformations,
params: [{ name: 'window', type: 'int', options: [5, 10, 20, 30, 40] }],
defaultParams: [10],
renderer: functionRenderer,
});
register({
type: 'cumulative_sum',
addStrategy: addTransformationStrategy,
category: categories.Transformations,
params: [],
defaultParams: [],
renderer: functionRenderer,
});
register({
type: 'stddev',
addStrategy: addTransformationStrategy,
category: categories.Transformations,
params: [],
defaultParams: [],
renderer: functionRenderer,
});
register({
type: 'time',
category: groupByTimeFunctions,
params: [
{
name: 'interval',
type: 'time',
options: ['$__interval', '1s', '10s', '1m', '5m', '10m', '15m', '1h'],
},
],
defaultParams: ['$__interval'],
renderer: functionRenderer,
});
register({
type: 'fill',
category: groupByTimeFunctions,
params: [
{
name: 'fill',
type: 'string',
options: ['none', 'null', '0', 'previous', 'linear'],
},
],
defaultParams: ['null'],
renderer: functionRenderer,
});
register({
type: 'elapsed',
addStrategy: addTransformationStrategy,
category: categories.Transformations,
params: [
{
name: 'duration',
type: 'interval',
options: ['1s', '10s', '1m', '5m', '10m', '15m', '1h'],
},
],
defaultParams: ['10s'],
renderer: functionRenderer,
});
// predictions
register({
type: 'holt_winters',
addStrategy: addTransformationStrategy,
category: categories.Predictors,
params: [
{ name: 'number', type: 'int', options: [5, 10, 20, 30, 40] },
{ name: 'season', type: 'int', options: [0, 1, 2, 5, 10] },
],
defaultParams: [10, 2],
renderer: functionRenderer,
});
register({
type: 'holt_winters_with_fit',
addStrategy: addTransformationStrategy,
category: categories.Predictors,
params: [
{ name: 'number', type: 'int', options: [5, 10, 20, 30, 40] },
{ name: 'season', type: 'int', options: [0, 1, 2, 5, 10] },
],
defaultParams: [10, 2],
renderer: functionRenderer,
});
// Selectors
register({
type: 'bottom',
addStrategy: replaceAggregationAddStrategy,
category: categories.Selectors,
params: [{ name: 'count', type: 'int' }],
defaultParams: [3],
renderer: functionRenderer,
});
register({
type: 'first',
addStrategy: replaceAggregationAddStrategy,
category: categories.Selectors,
params: [],
defaultParams: [],
renderer: functionRenderer,
});
register({
type: 'last',
addStrategy: replaceAggregationAddStrategy,
category: categories.Selectors,
params: [],
defaultParams: [],
renderer: functionRenderer,
});
register({
type: 'max',
addStrategy: replaceAggregationAddStrategy,
category: categories.Selectors,
params: [],
defaultParams: [],
renderer: functionRenderer,
});
register({
type: 'min',
addStrategy: replaceAggregationAddStrategy,
category: categories.Selectors,
params: [],
defaultParams: [],
renderer: functionRenderer,
});
register({
type: 'percentile',
addStrategy: replaceAggregationAddStrategy,
category: categories.Selectors,
params: [{ name: 'nth', type: 'int' }],
defaultParams: [95],
renderer: functionRenderer,
});
register({
type: 'top',
addStrategy: replaceAggregationAddStrategy,
category: categories.Selectors,
params: [{ name: 'count', type: 'int' }],
defaultParams: [3],
renderer: functionRenderer,
});
register({
type: 'tag',
category: groupByTimeFunctions,
params: [{ name: 'tag', type: 'string', dynamicLookup: true }],
defaultParams: ['tag'],
renderer: fieldRenderer,
});
register({
type: 'math',
addStrategy: addMathStrategy,
category: categories.Math,
params: [{ name: 'expr', type: 'string' }],
defaultParams: [' / 100'],
renderer: suffixRenderer,
});
register({
type: 'alias',
addStrategy: addAliasStrategy,
category: categories.Aliasing,
params: [{ name: 'name', type: 'string', quote: 'double' }],
defaultParams: ['alias'],
renderMode: 'suffix',
renderer: aliasRenderer,
});
export default {
create: createPart,
getCategories: () => {
return categories;
},
replaceAggregationAdd: replaceAggregationAddStrategy,
};