|
|
|
|
@ -1,4 +1,6 @@ |
|
|
|
|
import angular from 'angular'; |
|
|
|
|
import _ from 'lodash'; |
|
|
|
|
import { PostgresQueryBuilder } from './query_builder'; |
|
|
|
|
import { QueryCtrl } from 'app/plugins/sdk'; |
|
|
|
|
import queryPart from './query_part'; |
|
|
|
|
import PostgresQuery from './postgres_query'; |
|
|
|
|
@ -22,22 +24,25 @@ export class PostgresQueryCtrl extends QueryCtrl { |
|
|
|
|
showLastQuerySQL: boolean; |
|
|
|
|
formats: any[]; |
|
|
|
|
queryModel: PostgresQuery; |
|
|
|
|
queryBuilder: PostgresQueryBuilder; |
|
|
|
|
lastQueryMeta: QueryMeta; |
|
|
|
|
lastQueryError: string; |
|
|
|
|
showHelp: boolean; |
|
|
|
|
schemaSegment: any; |
|
|
|
|
tableSegment: any; |
|
|
|
|
whereSegment: any; |
|
|
|
|
whereSegments: any; |
|
|
|
|
timeColumnSegment: any; |
|
|
|
|
metricColumnSegment: any; |
|
|
|
|
selectMenu: any; |
|
|
|
|
groupBySegment: any; |
|
|
|
|
removeWhereFilterSegment: any; |
|
|
|
|
|
|
|
|
|
/** @ngInject **/ |
|
|
|
|
constructor($scope, $injector, private templateSrv, private $q, private uiSegmentSrv) { |
|
|
|
|
super($scope, $injector); |
|
|
|
|
this.target = this.target; |
|
|
|
|
this.queryModel = new PostgresQuery(this.target, templateSrv, this.panel.scopedVars); |
|
|
|
|
this.queryBuilder = new PostgresQueryBuilder(this.target, this.queryModel); |
|
|
|
|
|
|
|
|
|
this.formats = [{ text: 'Time series', value: 'time_series' }, { text: 'Table', value: 'table' }]; |
|
|
|
|
|
|
|
|
|
@ -63,8 +68,32 @@ export class PostgresQueryCtrl extends QueryCtrl { |
|
|
|
|
this.metricColumnSegment = uiSegmentSrv.newSegment(this.target.metricColumn); |
|
|
|
|
|
|
|
|
|
this.buildSelectMenu(); |
|
|
|
|
this.whereSegments = []; |
|
|
|
|
for (let tag of this.target.where) { |
|
|
|
|
if (!tag.operator) { |
|
|
|
|
if (/^\/.*\/$/.test(tag.value)) { |
|
|
|
|
tag.operator = '=~'; |
|
|
|
|
} else { |
|
|
|
|
tag.operator = '='; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (tag.condition) { |
|
|
|
|
this.whereSegments.push(uiSegmentSrv.newCondition(tag.condition)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.whereSegments.push(uiSegmentSrv.newKey(tag.key)); |
|
|
|
|
this.whereSegments.push(uiSegmentSrv.newOperator(tag.operator)); |
|
|
|
|
this.whereSegments.push(uiSegmentSrv.newKeyValue(tag.value)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.fixWhereSegments(); |
|
|
|
|
this.groupBySegment = this.uiSegmentSrv.newPlusButton(); |
|
|
|
|
|
|
|
|
|
this.removeWhereFilterSegment = uiSegmentSrv.newSegment({ |
|
|
|
|
fake: true, |
|
|
|
|
value: '-- remove tag filter --', |
|
|
|
|
}); |
|
|
|
|
this.panelCtrl.events.on('data-received', this.onDataReceived.bind(this), $scope); |
|
|
|
|
this.panelCtrl.events.on('data-error', this.onDataError.bind(this), $scope); |
|
|
|
|
} |
|
|
|
|
@ -97,42 +126,29 @@ export class PostgresQueryCtrl extends QueryCtrl { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
getSchemaSegments() { |
|
|
|
|
var schemaQuery = "SELECT schema_name FROM information_schema.schemata WHERE"; |
|
|
|
|
schemaQuery += " schema_name NOT LIKE 'pg_%' AND schema_name <> 'information_schema';"; |
|
|
|
|
return this.datasource |
|
|
|
|
.metricFindQuery(schemaQuery) |
|
|
|
|
.metricFindQuery(this.queryBuilder.buildSchemaQuery()) |
|
|
|
|
.then(this.transformToSegments(true)) |
|
|
|
|
.catch(this.handleQueryError.bind(this)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
getTableSegments() { |
|
|
|
|
var tableQuery = "SELECT table_name FROM information_schema.tables WHERE table_schema = '" + this.target.schema + "';"; |
|
|
|
|
return this.datasource |
|
|
|
|
.metricFindQuery(tableQuery) |
|
|
|
|
.metricFindQuery(this.queryBuilder.buildTableQuery()) |
|
|
|
|
.then(this.transformToSegments(true)) |
|
|
|
|
.catch(this.handleQueryError.bind(this)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
getTimeColumnSegments() { |
|
|
|
|
var columnQuery = "SELECT column_name FROM information_schema.columns WHERE "; |
|
|
|
|
columnQuery += " table_schema = '" + this.target.schema + "'"; |
|
|
|
|
columnQuery += " AND table_name = '" + this.target.table + "'"; |
|
|
|
|
columnQuery += " AND data_type IN ('timestamp without time zone','timestamp with time zone','bigint','integer','double precision','real');"; |
|
|
|
|
|
|
|
|
|
return this.datasource |
|
|
|
|
.metricFindQuery(columnQuery) |
|
|
|
|
.metricFindQuery(this.queryBuilder.buildColumnQuery("time")) |
|
|
|
|
.then(this.transformToSegments(true)) |
|
|
|
|
.catch(this.handleQueryError.bind(this)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
getMetricColumnSegments() { |
|
|
|
|
var columnQuery = "SELECT column_name FROM information_schema.columns WHERE "; |
|
|
|
|
columnQuery += " table_schema = '" + this.target.schema + "'"; |
|
|
|
|
columnQuery += " AND table_name = '" + this.target.table + "'"; |
|
|
|
|
columnQuery += " AND data_type IN ('text','char','varchar');"; |
|
|
|
|
|
|
|
|
|
return this.datasource |
|
|
|
|
.metricFindQuery(columnQuery) |
|
|
|
|
.metricFindQuery(this.queryBuilder.buildColumnQuery("metric")) |
|
|
|
|
.then(this.transformToSegments(true)) |
|
|
|
|
.catch(this.handleQueryError.bind(this)); |
|
|
|
|
} |
|
|
|
|
@ -210,13 +226,8 @@ export class PostgresQueryCtrl extends QueryCtrl { |
|
|
|
|
handleSelectPartEvent(selectParts, part, evt) { |
|
|
|
|
switch (evt.name) { |
|
|
|
|
case 'get-param-options': { |
|
|
|
|
var columnQuery = "SELECT column_name FROM information_schema.columns WHERE "; |
|
|
|
|
columnQuery += " table_schema = '" + this.target.schema + "'"; |
|
|
|
|
columnQuery += " AND table_name = '" + this.target.table + "'"; |
|
|
|
|
columnQuery += " AND data_type IN ('bigint','integer','double precision','real');"; |
|
|
|
|
|
|
|
|
|
return this.datasource |
|
|
|
|
.metricFindQuery(columnQuery) |
|
|
|
|
.metricFindQuery(this.queryBuilder.buildColumnQuery("value")) |
|
|
|
|
.then(this.transformToSegments(true)) |
|
|
|
|
.catch(this.handleQueryError.bind(this)); |
|
|
|
|
} |
|
|
|
|
@ -238,12 +249,8 @@ export class PostgresQueryCtrl extends QueryCtrl { |
|
|
|
|
handleGroupByPartEvent(part, index, evt) { |
|
|
|
|
switch (evt.name) { |
|
|
|
|
case 'get-param-options': { |
|
|
|
|
var columnQuery = "SELECT column_name FROM information_schema.columns WHERE "; |
|
|
|
|
columnQuery += " table_schema = '" + this.target.schema + "'"; |
|
|
|
|
columnQuery += " AND table_name = '" + this.target.table + "'"; |
|
|
|
|
|
|
|
|
|
return this.datasource |
|
|
|
|
.metricFindQuery(columnQuery) |
|
|
|
|
.metricFindQuery(this.queryBuilder.buildColumnQuery()) |
|
|
|
|
.then(this.transformToSegments(true)) |
|
|
|
|
.catch(this.handleQueryError.bind(this)); |
|
|
|
|
} |
|
|
|
|
@ -262,14 +269,125 @@ export class PostgresQueryCtrl extends QueryCtrl { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
getGroupByOptions() { |
|
|
|
|
var columnQuery = "SELECT column_name FROM information_schema.columns WHERE "; |
|
|
|
|
columnQuery += " table_schema = '" + this.target.schema + "'"; |
|
|
|
|
columnQuery += " AND table_name = '" + this.target.table + "'"; |
|
|
|
|
fixWhereSegments() { |
|
|
|
|
var count = this.whereSegments.length; |
|
|
|
|
var lastSegment = this.whereSegments[Math.max(count - 1, 0)]; |
|
|
|
|
|
|
|
|
|
if (!lastSegment || lastSegment.type !== 'plus-button') { |
|
|
|
|
this.whereSegments.push(this.uiSegmentSrv.newPlusButton()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
getTagsOrValues(segment, index) { |
|
|
|
|
if (segment.type === 'condition') { |
|
|
|
|
return this.$q.when([this.uiSegmentSrv.newSegment('AND'), this.uiSegmentSrv.newSegment('OR')]); |
|
|
|
|
} |
|
|
|
|
if (segment.type === 'operator') { |
|
|
|
|
var nextValue = this.whereSegments[index + 1].value; |
|
|
|
|
if (/^\/.*\/$/.test(nextValue)) { |
|
|
|
|
return this.$q.when(this.uiSegmentSrv.newOperators(['=~', '!~'])); |
|
|
|
|
} else { |
|
|
|
|
return this.$q.when(this.uiSegmentSrv.newOperators(['=', '!=', '<>', '<', '>'])); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var query, addTemplateVars; |
|
|
|
|
if (segment.type === 'key' || segment.type === 'plus-button') { |
|
|
|
|
query = this.queryBuilder.buildColumnQuery(); |
|
|
|
|
|
|
|
|
|
addTemplateVars = false; |
|
|
|
|
} else if (segment.type === 'value') { |
|
|
|
|
query = this.queryBuilder.buildValueQuery(this.whereSegments[index -2].value); |
|
|
|
|
addTemplateVars = true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return this.datasource |
|
|
|
|
.metricFindQuery(columnQuery) |
|
|
|
|
.metricFindQuery(query) |
|
|
|
|
.then(this.transformToSegments(addTemplateVars)) |
|
|
|
|
.then(results => { |
|
|
|
|
if (segment.type === 'key') { |
|
|
|
|
results.splice(0, 0, angular.copy(this.removeWhereFilterSegment)); |
|
|
|
|
} |
|
|
|
|
return results; |
|
|
|
|
}) |
|
|
|
|
.catch(this.handleQueryError.bind(this)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
getTagValueOperator(tagValue, tagOperator): string { |
|
|
|
|
if (tagOperator !== '=~' && tagOperator !== '!~' && /^\/.*\/$/.test(tagValue)) { |
|
|
|
|
return '=~'; |
|
|
|
|
} else if ((tagOperator === '=~' || tagOperator === '!~') && /^(?!\/.*\/$)/.test(tagValue)) { |
|
|
|
|
return '='; |
|
|
|
|
} |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
whereSegmentUpdated(segment, index) { |
|
|
|
|
this.whereSegments[index] = segment; |
|
|
|
|
|
|
|
|
|
// handle remove where condition
|
|
|
|
|
if (segment.value === this.removeWhereFilterSegment.value) { |
|
|
|
|
this.whereSegments.splice(index, 3); |
|
|
|
|
if (this.whereSegments.length === 0) { |
|
|
|
|
this.whereSegments.push(this.uiSegmentSrv.newPlusButton()); |
|
|
|
|
} else if (this.whereSegments.length > 2) { |
|
|
|
|
this.whereSegments.splice(Math.max(index - 1, 0), 1); |
|
|
|
|
if (this.whereSegments[this.whereSegments.length - 1].type !== 'plus-button') { |
|
|
|
|
this.whereSegments.push(this.uiSegmentSrv.newPlusButton()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
if (segment.type === 'plus-button') { |
|
|
|
|
if (index > 2) { |
|
|
|
|
this.whereSegments.splice(index, 0, this.uiSegmentSrv.newCondition('AND')); |
|
|
|
|
} |
|
|
|
|
this.whereSegments.push(this.uiSegmentSrv.newOperator('=')); |
|
|
|
|
this.whereSegments.push(this.uiSegmentSrv.newFake('select value', 'value', 'query-segment-value')); |
|
|
|
|
segment.type = 'key'; |
|
|
|
|
segment.cssClass = 'query-segment-key'; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (index + 1 === this.whereSegments.length) { |
|
|
|
|
this.whereSegments.push(this.uiSegmentSrv.newPlusButton()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.rebuildTargetWhereConditions(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
rebuildTargetWhereConditions() { |
|
|
|
|
var where = []; |
|
|
|
|
var tagIndex = 0; |
|
|
|
|
var tagOperator = ''; |
|
|
|
|
|
|
|
|
|
_.each(this.whereSegments, (segment2, index) => { |
|
|
|
|
if (segment2.type === 'key') { |
|
|
|
|
if (where.length === 0) { |
|
|
|
|
where.push({}); |
|
|
|
|
} |
|
|
|
|
where[tagIndex].key = segment2.value; |
|
|
|
|
} else if (segment2.type === 'value') { |
|
|
|
|
tagOperator = this.getTagValueOperator(segment2.value, where[tagIndex].operator); |
|
|
|
|
if (tagOperator) { |
|
|
|
|
this.whereSegments[index - 1] = this.uiSegmentSrv.newOperator(tagOperator); |
|
|
|
|
where[tagIndex].operator = tagOperator; |
|
|
|
|
} |
|
|
|
|
where[tagIndex].value = segment2.value; |
|
|
|
|
} else if (segment2.type === 'condition') { |
|
|
|
|
where.push({ condition: segment2.value }); |
|
|
|
|
tagIndex += 1; |
|
|
|
|
} else if (segment2.type === 'operator') { |
|
|
|
|
where[tagIndex].operator = segment2.value; |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
this.target.where = where; |
|
|
|
|
this.panelCtrl.refresh(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
getGroupByOptions() { |
|
|
|
|
return this.datasource |
|
|
|
|
.metricFindQuery(this.queryBuilder.buildColumnQuery()) |
|
|
|
|
.then(tags => { |
|
|
|
|
var options = []; |
|
|
|
|
if (!this.queryModel.hasFill()) { |
|
|
|
|
@ -278,12 +396,6 @@ export class PostgresQueryCtrl extends QueryCtrl { |
|
|
|
|
if (!this.target.limit) { |
|
|
|
|
options.push(this.uiSegmentSrv.newSegment({ value: 'LIMIT' })); |
|
|
|
|
} |
|
|
|
|
if (!this.target.slimit) { |
|
|
|
|
options.push(this.uiSegmentSrv.newSegment({ value: 'SLIMIT' })); |
|
|
|
|
} |
|
|
|
|
if (this.target.orderByTime === 'ASC') { |
|
|
|
|
options.push(this.uiSegmentSrv.newSegment({ value: 'ORDER BY time DESC' })); |
|
|
|
|
} |
|
|
|
|
if (!this.queryModel.hasGroupByTime()) { |
|
|
|
|
options.push(this.uiSegmentSrv.newSegment({ value: 'time($interval)' })); |
|
|
|
|
} |
|
|
|
|
|