Sven Klemm 8 лет назад
Родитель
Сommit
443504517a
1 измененных файлов с 239 добавлено и 0 удалено
  1. 239 0
      public/app/plugins/datasource/postgres/postgres_query.ts

+ 239 - 0
public/app/plugins/datasource/postgres/postgres_query.ts

@@ -0,0 +1,239 @@
+import _ from 'lodash';
+import queryPart from './query_part';
+import kbn from 'app/core/utils/kbn';
+
+export default class PostgresQuery {
+  target: any;
+  selectModels: any[];
+  queryBuilder: any;
+  groupByParts: any;
+  templateSrv: any;
+  scopedVars: any;
+
+  /** @ngInject */
+  constructor(target, templateSrv?, scopedVars?) {
+    this.target = target;
+    this.templateSrv = templateSrv;
+    this.scopedVars = scopedVars;
+
+    target.schema = target.schema || 'public';
+    target.format = target.format || 'time_series';
+    target.timeColumn = target.timeColumn || 'time';
+    target.alias = '';
+
+    target.orderByTime = target.orderByTime || 'ASC';
+//    target.groupBy = target.groupBy || [{ type: 'time', params: ['$__interval'] }, { type: 'fill', params: ['null'] }];
+    target.select = target.select || [[{ type: 'field', params: ['value'] }]];
+
+    this.updateProjection();
+  }
+
+  updateProjection() {
+    this.selectModels = _.map(this.target.select, function(parts: any) {
+      return _.map(parts, queryPart.create);
+    });
+    this.groupByParts = _.map(this.target.groupBy, queryPart.create);
+  }
+
+  updatePersistedParts() {
+    this.target.select = _.map(this.selectModels, function(selectParts) {
+      return _.map(selectParts, function(part: any) {
+        return { type: part.def.type, params: part.params };
+      });
+    });
+  }
+
+  hasGroupByTime() {
+    return _.find(this.target.groupBy, (g: any) => g.type === 'time');
+  }
+
+  hasFill() {
+    return _.find(this.target.groupBy, (g: any) => g.type === 'fill');
+  }
+
+  addGroupBy(value) {
+    var stringParts = value.match(/^(\w+)\((.*)\)$/);
+    var typePart = stringParts[1];
+    var arg = stringParts[2];
+    var partModel = queryPart.create({ type: typePart, params: [arg] });
+    var partCount = this.target.groupBy.length;
+
+    if (partCount === 0) {
+      this.target.groupBy.push(partModel.part);
+    } else if (typePart === 'time') {
+      this.target.groupBy.splice(0, 0, partModel.part);
+    } else if (typePart === 'tag') {
+      if (this.target.groupBy[partCount - 1].type === 'fill') {
+        this.target.groupBy.splice(partCount - 1, 0, partModel.part);
+      } else {
+        this.target.groupBy.push(partModel.part);
+      }
+    } else {
+      this.target.groupBy.push(partModel.part);
+    }
+
+    this.updateProjection();
+  }
+
+  removeGroupByPart(part, index) {
+    var categories = queryPart.getCategories();
+
+    if (part.def.type === 'time') {
+      // remove fill
+      this.target.groupBy = _.filter(this.target.groupBy, (g: any) => g.type !== 'fill');
+      // remove aggregations
+      this.target.select = _.map(this.target.select, (s: any) => {
+        return _.filter(s, (part: any) => {
+          var partModel = queryPart.create(part);
+          if (partModel.def.category === categories.Aggregations) {
+            return false;
+          }
+          if (partModel.def.category === categories.Selectors) {
+            return false;
+          }
+          return true;
+        });
+      });
+    }
+
+    this.target.groupBy.splice(index, 1);
+    this.updateProjection();
+  }
+
+  removeSelect(index: number) {
+    this.target.select.splice(index, 1);
+    this.updateProjection();
+  }
+
+  removeSelectPart(selectParts, part) {
+    // if we remove the field remove the whole statement
+    if (part.def.type === 'field') {
+      if (this.selectModels.length > 1) {
+        var modelsIndex = _.indexOf(this.selectModels, selectParts);
+        this.selectModels.splice(modelsIndex, 1);
+      }
+    } else {
+      var partIndex = _.indexOf(selectParts, part);
+      selectParts.splice(partIndex, 1);
+    }
+
+    this.updatePersistedParts();
+  }
+
+  addSelectPart(selectParts, type) {
+    var partModel = queryPart.create({ type: type });
+    partModel.def.addStrategy(selectParts, partModel, this);
+    this.updatePersistedParts();
+  }
+
+  private renderTagCondition(tag, index, interpolate) {
+    var str = '';
+    var operator = tag.operator;
+    var value = tag.value;
+    if (index > 0) {
+      str = (tag.condition || 'AND') + ' ';
+    }
+
+    if (!operator) {
+      if (/^\/.*\/$/.test(value)) {
+        operator = '=~';
+      } else {
+        operator = '=';
+      }
+    }
+
+    // quote value unless regex
+    if (operator !== '=~' && operator !== '!~') {
+      if (interpolate) {
+        value = this.templateSrv.replace(value, this.scopedVars);
+      }
+      if (operator !== '>' && operator !== '<') {
+        value = "'" + value.replace(/\\/g, '\\\\') + "'";
+      }
+    } else if (interpolate) {
+      value = this.templateSrv.replace(value, this.scopedVars, 'regex');
+    }
+
+    return str + '"' + tag.key + '" ' + operator + ' ' + value;
+  }
+
+  interpolateQueryStr(value, variable, defaultFormatFn) {
+    // if no multi or include all do not regexEscape
+    if (!variable.multi && !variable.includeAll) {
+      return value;
+    }
+
+    if (typeof value === 'string') {
+      return kbn.regexEscape(value);
+    }
+
+    var escapedValues = _.map(value, kbn.regexEscape);
+    return '(' + escapedValues.join('|') + ')';
+  }
+
+  render(interpolate?) {
+    var target = this.target;
+
+    if (target.rawQuery) {
+      if (interpolate) {
+        return this.templateSrv.replace(target.rawSql, this.scopedVars, this.interpolateQueryStr);
+      } else {
+        return target.rawSql;
+      }
+    }
+
+    var query = 'SELECT ';
+    query += target.timeColumn + ' AS time,';
+
+    var i, y;
+    for (i = 0; i < this.selectModels.length; i++) {
+      let parts = this.selectModels[i];
+      var selectText = '';
+      for (y = 0; y < parts.length; y++) {
+        let part = parts[y];
+        selectText = part.render(selectText);
+      }
+
+      if (i > 0) {
+        query += ', ';
+      }
+      query += selectText;
+    }
+
+    query += ' FROM ' + target.schema + '.' + target.table + ' WHERE ';
+    var conditions = _.map(target.tags, (tag, index) => {
+      return this.renderTagCondition(tag, index, interpolate);
+    });
+
+    if (conditions.length > 0) {
+      query += '(' + conditions.join(' ') + ') AND ';
+    }
+
+    query += '$__timeFilter(time)';
+
+    var groupBySection = '';
+    for (i = 0; i < this.groupByParts.length; i++) {
+      var part = this.groupByParts[i];
+      if (i > 0) {
+        // for some reason fill has no seperator
+        groupBySection += part.def.type === 'fill' ? ' ' : ', ';
+      }
+      groupBySection += part.render('');
+    }
+
+    if (groupBySection.length) {
+      query += ' GROUP BY ' + groupBySection;
+    }
+
+    query += ' ORDER BY time';
+
+    return query;
+  }
+
+  renderAdhocFilters(filters) {
+    var conditions = _.map(filters, (tag, index) => {
+      return this.renderTagCondition(tag, index, false);
+    });
+    return conditions.join(' ');
+  }
+}