Merge branch 'master' into postgres-query-builder

This commit is contained in:
Sven Klemm
2018-08-31 19:02:46 +02:00
183 changed files with 1048 additions and 2225 deletions

View File

@ -7,7 +7,7 @@ export class PostgresConfigCtrl {
datasourceSrv: any;
showTimescaleDBHelp: boolean;
/** @ngInject **/
/** @ngInject */
constructor($scope, datasourceSrv) {
this.datasourceSrv = datasourceSrv;
this.current.jsonData.sslmode = this.current.jsonData.sslmode || 'verify-full';
@ -34,8 +34,8 @@ export class PostgresConfigCtrl {
});
}
let major = Math.trunc(version / 100);
let minor = version % 100;
const major = Math.trunc(version / 100);
const minor = version % 100;
let name = String(major);
if (version < 1000) {
name = String(major) + '.' + String(minor);

View File

@ -9,7 +9,7 @@ export class PostgresDatasource {
responseParser: ResponseParser;
queryModel: PostgresQuery;
/** @ngInject **/
/** @ngInject */
constructor(instanceSettings, private backendSrv, private $q, private templateSrv, private timeSrv) {
this.name = instanceSettings.name;
this.id = instanceSettings.id;
@ -41,7 +41,7 @@ export class PostgresDatasource {
const queries = _.filter(options.targets, target => {
return target.hide !== true;
}).map(target => {
let queryModel = new PostgresQuery(target, this.templateSrv, options.scopedVars);
const queryModel = new PostgresQuery(target, this.templateSrv, options.scopedVars);
return {
refId: target.refId,
@ -110,7 +110,7 @@ export class PostgresDatasource {
format: 'table',
};
let range = this.timeSrv.timeRange();
const range = this.timeSrv.timeRange();
const data = {
queries: [interpolatedQuery],
from: range.from.valueOf().toString(),

View File

@ -25,7 +25,7 @@ export class PostgresMetaQuery {
findMetricTable() {
// query that returns first table found that has a timestamp(tz) column and a float column
let query = `
const query = `
SELECT
quote_ident(table_name) as table_name,
( SELECT
@ -74,7 +74,7 @@ LIMIT 1
}
buildSchemaConstraint() {
let query = `
const query = `
table_schema IN (
SELECT CASE WHEN trim(unnest) = \'"$user"\' THEN user ELSE trim(unnest) END
FROM unnest(string_to_array(current_setting(\'search_path\'),\',\'))
@ -87,7 +87,7 @@ table_schema IN (
// check for schema qualified table
if (table.includes('.')) {
let parts = table.split('.');
const parts = table.split('.');
query = 'table_schema = ' + this.quoteIdentAsLiteral(parts[0]);
query += ' AND table_name = ' + this.quoteIdentAsLiteral(parts[1]);
return query;

View File

@ -17,7 +17,7 @@ class PostgresAnnotationsQueryCtrl {
annotation: any;
/** @ngInject **/
/** @ngInject */
constructor() {
this.annotation.rawQuery = this.annotation.rawQuery || defaultQuery;
}

View File

@ -73,12 +73,12 @@ export default class PostgresQuery {
return this.quoteLiteral(value);
}
let escapedValues = _.map(value, this.quoteLiteral);
const escapedValues = _.map(value, this.quoteLiteral);
return escapedValues.join(',');
}
render(interpolate?) {
let target = this.target;
const target = this.target;
// new query with no table set yet
if (!this.target.rawQuery && !('table' in this.target)) {
@ -101,7 +101,7 @@ export default class PostgresQuery {
}
buildTimeColumn(alias = true) {
let timeGroup = this.hasTimeGroup();
const timeGroup = this.hasTimeGroup();
let query;
let macro = '$__timeGroup';
@ -139,7 +139,7 @@ export default class PostgresQuery {
buildValueColumns() {
let query = '';
for (let column of this.target.select) {
for (const column of this.target.select) {
query += ',\n ' + this.buildValueColumn(column);
}
@ -149,14 +149,14 @@ export default class PostgresQuery {
buildValueColumn(column) {
let query = '';
let columnName = _.find(column, (g: any) => g.type === 'column');
const columnName = _.find(column, (g: any) => g.type === 'column');
query = columnName.params[0];
let aggregate = _.find(column, (g: any) => g.type === 'aggregate' || g.type === 'percentile');
let windows = _.find(column, (g: any) => g.type === 'window' || g.type === 'moving_window');
const aggregate = _.find(column, (g: any) => g.type === 'aggregate' || g.type === 'percentile');
const windows = _.find(column, (g: any) => g.type === 'window' || g.type === 'moving_window');
if (aggregate) {
let func = aggregate.params[0];
const func = aggregate.params[0];
switch (aggregate.type) {
case 'aggregate':
if (func === 'first' || func === 'last') {
@ -172,13 +172,13 @@ export default class PostgresQuery {
}
if (windows) {
let overParts = [];
const overParts = [];
if (this.hasMetricColumn()) {
overParts.push('PARTITION BY ' + this.target.metricColumn);
}
overParts.push('ORDER BY ' + this.buildTimeColumn(false));
let over = overParts.join(' ');
const over = overParts.join(' ');
let curr: string;
let prev: string;
switch (windows.type) {
@ -211,7 +211,7 @@ export default class PostgresQuery {
}
}
let alias = _.find(column, (g: any) => g.type === 'alias');
const alias = _.find(column, (g: any) => g.type === 'alias');
if (alias) {
query += ' AS ' + this.quoteIdentifier(alias.params[0]);
}
@ -221,7 +221,7 @@ export default class PostgresQuery {
buildWhereClause() {
let query = '';
let conditions = _.map(this.target.where, (tag, index) => {
const conditions = _.map(this.target.where, (tag, index) => {
switch (tag.type) {
case 'macro':
return tag.name + '(' + this.target.timeColumn + ')';
@ -244,7 +244,7 @@ export default class PostgresQuery {
let groupSection = '';
for (let i = 0; i < this.target.group.length; i++) {
let part = this.target.group[i];
const part = this.target.group[i];
if (i > 0) {
groupSection += ', ';
}

View File

@ -39,7 +39,7 @@ export class PostgresQueryCtrl extends QueryCtrl {
whereParts: SqlPart[];
groupAdd: any;
/** @ngInject **/
/** @ngInject */
constructor($scope, $injector, private templateSrv, private $q, private uiSegmentSrv) {
super($scope, $injector);
this.target = this.target;
@ -119,7 +119,7 @@ export class PostgresQueryCtrl extends QueryCtrl {
buildSelectMenu() {
this.selectMenu = [];
let aggregates = {
const aggregates = {
text: 'Aggregate Functions',
value: 'aggregate',
submenu: [
@ -143,7 +143,7 @@ export class PostgresQueryCtrl extends QueryCtrl {
// ordered set aggregates require postgres 9.4+
if (this.datasource.jsonData.postgresVersion >= 904) {
let aggregates2 = {
const aggregates2 = {
text: 'Ordered-Set Aggregate Functions',
value: 'percentile',
submenu: [
@ -154,7 +154,7 @@ export class PostgresQueryCtrl extends QueryCtrl {
this.selectMenu.push(aggregates2);
}
let windows = {
const windows = {
text: 'Window Functions',
value: 'window',
submenu: [
@ -187,7 +187,7 @@ export class PostgresQueryCtrl extends QueryCtrl {
}
resetPlusButton(button) {
let plusButton = this.uiSegmentSrv.newPlusButton();
const plusButton = this.uiSegmentSrv.newPlusButton();
button.html = plusButton.html;
button.value = plusButton.value;
}
@ -205,21 +205,21 @@ export class PostgresQueryCtrl extends QueryCtrl {
this.target.group = [];
this.updateProjection();
let segment = this.uiSegmentSrv.newSegment('none');
const segment = this.uiSegmentSrv.newSegment('none');
this.metricColumnSegment.html = segment.html;
this.metricColumnSegment.value = segment.value;
this.target.metricColumn = 'none';
let task1 = this.datasource.metricFindQuery(this.metaBuilder.buildColumnQuery('time')).then(result => {
const task1 = this.datasource.metricFindQuery(this.metaBuilder.buildColumnQuery('time')).then(result => {
// check if time column is still valid
if (result.length > 0 && !_.find(result, (r: any) => r.text === this.target.timeColumn)) {
let segment = this.uiSegmentSrv.newSegment(result[0].text);
const segment = this.uiSegmentSrv.newSegment(result[0].text);
this.timeColumnSegment.html = segment.html;
this.timeColumnSegment.value = segment.value;
}
return this.timeColumnChanged(false);
});
let task2 = this.datasource.metricFindQuery(this.metaBuilder.buildColumnQuery('value')).then(result => {
const task2 = this.datasource.metricFindQuery(this.metaBuilder.buildColumnQuery('value')).then(result => {
if (result.length > 0) {
this.target.select = [[{ type: 'column', params: [result[0].text] }]];
this.updateProjection();
@ -301,7 +301,7 @@ export class PostgresQueryCtrl extends QueryCtrl {
transformToSegments(config) {
return results => {
let segments = _.map(results, segment => {
const segments = _.map(results, segment => {
return this.uiSegmentSrv.newSegment({
value: segment.text,
expandable: segment.expandable,
@ -309,7 +309,7 @@ export class PostgresQueryCtrl extends QueryCtrl {
});
if (config.addTemplateVars) {
for (let variable of this.templateSrv.variables) {
for (const variable of this.templateSrv.variables) {
let value;
value = '$' + variable.name;
if (config.templateQuoter && variable.multi === false) {
@ -355,7 +355,7 @@ export class PostgresQueryCtrl extends QueryCtrl {
switch (partType) {
case 'column':
let parts = _.map(selectParts, function(part: any) {
const parts = _.map(selectParts, function(part: any) {
return sqlPart.create({ type: part.def.type, params: _.clone(part.params) });
});
this.selectParts.push(parts);
@ -366,7 +366,7 @@ export class PostgresQueryCtrl extends QueryCtrl {
if (this.target.group.length === 0) {
this.addGroup('time', '$__interval');
}
let aggIndex = this.findAggregateIndex(selectParts);
const aggIndex = this.findAggregateIndex(selectParts);
if (aggIndex !== -1) {
// replace current aggregation
selectParts[aggIndex] = partModel;
@ -379,12 +379,12 @@ export class PostgresQueryCtrl extends QueryCtrl {
break;
case 'moving_window':
case 'window':
let windowIndex = this.findWindowIndex(selectParts);
const windowIndex = this.findWindowIndex(selectParts);
if (windowIndex !== -1) {
// replace current window function
selectParts[windowIndex] = partModel;
} else {
let aggIndex = this.findAggregateIndex(selectParts);
const aggIndex = this.findAggregateIndex(selectParts);
if (aggIndex !== -1) {
selectParts.splice(aggIndex + 1, 0, partModel);
} else {
@ -418,11 +418,11 @@ export class PostgresQueryCtrl extends QueryCtrl {
if (part.def.type === 'column') {
// remove all parts of column unless its last column
if (this.selectParts.length > 1) {
let modelsIndex = _.indexOf(this.selectParts, selectParts);
const modelsIndex = _.indexOf(this.selectParts, selectParts);
this.selectParts.splice(modelsIndex, 1);
}
} else {
let partIndex = _.indexOf(selectParts, part);
const partIndex = _.indexOf(selectParts, part);
selectParts.splice(partIndex, 1);
}
@ -490,7 +490,7 @@ export class PostgresQueryCtrl extends QueryCtrl {
if (partType === 'time') {
params = ['$__interval', 'none'];
}
let partModel = sqlPart.create({ type: partType, params: params });
const partModel = sqlPart.create({ type: partType, params: params });
if (partType === 'time') {
// put timeGroup at start
@ -500,12 +500,12 @@ export class PostgresQueryCtrl extends QueryCtrl {
}
// add aggregates when adding group by
for (let selectParts of this.selectParts) {
for (const selectParts of this.selectParts) {
if (!selectParts.some(part => part.def.type === 'aggregate')) {
let aggregate = sqlPart.create({ type: 'aggregate', params: ['avg'] });
const aggregate = sqlPart.create({ type: 'aggregate', params: ['avg'] });
selectParts.splice(1, 0, aggregate);
if (!selectParts.some(part => part.def.type === 'alias')) {
let alias = sqlPart.create({ type: 'alias', params: [selectParts[0].part.params[0]] });
const alias = sqlPart.create({ type: 'alias', params: [selectParts[0].part.params[0]] });
selectParts.push(alias);
}
}
@ -587,7 +587,7 @@ export class PostgresQueryCtrl extends QueryCtrl {
}
getWhereOptions() {
var options = [];
const options = [];
if (this.queryModel.hasUnixEpochTimecolumn()) {
options.push(this.uiSegmentSrv.newSegment({ type: 'macro', value: '$__unixEpochFilter' }));
} else {
@ -600,7 +600,7 @@ export class PostgresQueryCtrl extends QueryCtrl {
addWhereAction(part, index) {
switch (this.whereAdd.type) {
case 'macro': {
let partModel = sqlPart.create({ type: 'macro', name: this.whereAdd.value, params: [] });
const partModel = sqlPart.create({ type: 'macro', name: this.whereAdd.value, params: [] });
if (this.whereParts.length >= 1 && this.whereParts[0].def.type === 'macro') {
// replace current macro
this.whereParts[0] = partModel;
@ -623,11 +623,11 @@ export class PostgresQueryCtrl extends QueryCtrl {
return this.datasource
.metricFindQuery(this.metaBuilder.buildColumnQuery('group'))
.then(tags => {
var options = [];
const options = [];
if (!this.queryModel.hasTimeGroup()) {
options.push(this.uiSegmentSrv.newSegment({ type: 'time', value: 'time($__interval,none)' }));
}
for (let tag of tags) {
for (const tag of tags) {
options.push(this.uiSegmentSrv.newSegment({ type: 'column', value: tag.text }));
}
return options;

View File

@ -1,23 +1,23 @@
import PostgresQuery from '../postgres_query';
describe('PostgresQuery', function() {
let templateSrv = {
const templateSrv = {
replace: jest.fn(text => text),
};
describe('When initializing', function() {
it('should not be in SQL mode', function() {
let query = new PostgresQuery({}, templateSrv);
const query = new PostgresQuery({}, templateSrv);
expect(query.target.rawQuery).toBe(false);
});
it('should be in SQL mode for pre query builder queries', function() {
let query = new PostgresQuery({ rawSql: 'SELECT 1' }, templateSrv);
const query = new PostgresQuery({ rawSql: 'SELECT 1' }, templateSrv);
expect(query.target.rawQuery).toBe(true);
});
});
describe('When generating time column SQL', function() {
let query = new PostgresQuery({}, templateSrv);
const query = new PostgresQuery({}, templateSrv);
query.target.timeColumn = 'time';
expect(query.buildTimeColumn()).toBe('time AS "time"');
@ -45,7 +45,7 @@ describe('PostgresQuery', function() {
});
describe('When generating metric column SQL', function() {
let query = new PostgresQuery({}, templateSrv);
const query = new PostgresQuery({}, templateSrv);
query.target.metricColumn = 'host';
expect(query.buildMetricColumn()).toBe('host AS metric');
@ -54,7 +54,7 @@ describe('PostgresQuery', function() {
});
describe('When generating value column SQL', function() {
let query = new PostgresQuery({}, templateSrv);
const query = new PostgresQuery({}, templateSrv);
let column = [{ type: 'column', params: ['value'] }];
expect(query.buildValueColumn(column)).toBe('value');
@ -77,7 +77,7 @@ describe('PostgresQuery', function() {
});
describe('When generating value column SQL with metric column', function() {
let query = new PostgresQuery({}, templateSrv);
const query = new PostgresQuery({}, templateSrv);
query.target.metricColumn = 'host';
let column = [{ type: 'column', params: ['value'] }];
@ -111,7 +111,7 @@ describe('PostgresQuery', function() {
});
describe('When generating WHERE clause', function() {
let query = new PostgresQuery({ where: [] }, templateSrv);
const query = new PostgresQuery({ where: [] }, templateSrv);
expect(query.buildWhereClause()).toBe('');
@ -127,7 +127,7 @@ describe('PostgresQuery', function() {
});
describe('When generating GROUP BY clause', function() {
let query = new PostgresQuery({ group: [], metricColumn: 'none' }, templateSrv);
const query = new PostgresQuery({ group: [], metricColumn: 'none' }, templateSrv);
expect(query.buildGroupClause()).toBe('');
query.target.group = [{ type: 'time', params: ['5m'] }];
@ -137,14 +137,14 @@ describe('PostgresQuery', function() {
});
describe('When generating complete statement', function() {
let target = {
const target = {
timeColumn: 't',
table: 'table',
select: [[{ type: 'column', params: ['value'] }]],
where: [],
};
let result = 'SELECT\n t AS "time",\n value\nFROM table\nORDER BY 1';
let query = new PostgresQuery(target, templateSrv);
const query = new PostgresQuery(target, templateSrv);
expect(query.buildQuery()).toBe(result);

View File

@ -1,9 +1,9 @@
import { SqlPartDef, SqlPart } from 'app/core/components/sql_part/sql_part';
let index = [];
const index = [];
function createPart(part): any {
let def = index[part.type];
const def = index[part.type];
if (!def) {
return null;
}