query_part.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. ///<reference path="../../../headers/common.d.ts" />
  2. import _ = require('lodash');
  3. var index = [];
  4. var categories = {
  5. Aggregations: [],
  6. Transformations: [],
  7. Math: [],
  8. Aliasing: [],
  9. };
  10. class QueryPartDef {
  11. name: string;
  12. params: any[];
  13. defaultParams: any[];
  14. renderer: any;
  15. constructor(options: any) {
  16. this.name = options.name;
  17. this.params = options.params;
  18. this.defaultParams = options.defaultParams;
  19. this.renderer = options.renderer;
  20. }
  21. static register(options: any) {
  22. index[options.name] = new QueryPartDef(options);
  23. options.category.push(index[options.name]);
  24. }
  25. }
  26. function functionRenderer(part, innerExpr) {
  27. var str = part.def.name + '(';
  28. var parameters = _.map(part.params, (value, index) => {
  29. var paramType = part.def.params[index];
  30. if (paramType.quote === 'single') {
  31. return "'" + value + "'";
  32. } else if (paramType.quote === 'double') {
  33. return '"' + value + '"';
  34. }
  35. return value;
  36. });
  37. if (innerExpr) {
  38. parameters.unshift(innerExpr);
  39. }
  40. return str + parameters.join(', ') + ')';
  41. }
  42. function aliasRenderer(part, innerExpr) {
  43. return innerExpr + ' AS ' + '"' + part.params[0] + '"';
  44. }
  45. function suffixRenderer(part, innerExpr) {
  46. return innerExpr + ' ' + part.params[0];
  47. }
  48. function identityRenderer(part, innerExpr) {
  49. return part.params[0];
  50. }
  51. function quotedIdentityRenderer(part, innerExpr) {
  52. return '"' + part.params[0] + '"';
  53. }
  54. QueryPartDef.register({
  55. name: 'mean',
  56. category: categories.Aggregations,
  57. params: [{type: 'field', quote: 'double'}],
  58. defaultParams: ['value'],
  59. renderer: functionRenderer,
  60. });
  61. QueryPartDef.register({
  62. name: 'sum',
  63. category: categories.Aggregations,
  64. params: [{type: 'field', quote: 'double'}],
  65. defaultParams: ['value'],
  66. renderer: functionRenderer,
  67. });
  68. QueryPartDef.register({
  69. name: 'derivative',
  70. category: categories.Transformations,
  71. params: [{ name: "duration", type: "interval", options: ['1s', '10s', '1m', '5min', '10m', '15m', '1h']}],
  72. defaultParams: ['10s'],
  73. renderer: functionRenderer,
  74. });
  75. QueryPartDef.register({
  76. name: 'time',
  77. category: categories.Transformations,
  78. params: [{ name: "rate", type: "interval", options: ['$interval', '1s', '10s', '1m', '5min', '10m', '15m', '1h'] }],
  79. defaultParams: ['$interval'],
  80. renderer: functionRenderer,
  81. });
  82. QueryPartDef.register({
  83. name: 'math',
  84. category: categories.Math,
  85. params: [{ name: "expr", type: "string"}],
  86. defaultParams: [' / 100'],
  87. renderer: suffixRenderer,
  88. });
  89. QueryPartDef.register({
  90. name: 'alias',
  91. category: categories.Aliasing,
  92. params: [{ name: "name", type: "string", quote: 'double'}],
  93. defaultParams: ['alias'],
  94. renderMode: 'suffix',
  95. renderer: aliasRenderer,
  96. });
  97. class QueryPart {
  98. part: any;
  99. def: QueryPartDef;
  100. params: any[];
  101. text: string;
  102. constructor(part: any) {
  103. this.part = part;
  104. this.def = index[part.name];
  105. if (!this.def) {
  106. throw {message: 'Could not find query part ' + part.name};
  107. }
  108. this.params = part.params || _.clone(this.def.defaultParams);
  109. this.updateText();
  110. }
  111. render(innerExpr: string) {
  112. return this.def.renderer(this, innerExpr);
  113. }
  114. hasMultipleParamsInString (strValue, index) {
  115. if (strValue.indexOf(',') === -1) {
  116. return false;
  117. }
  118. return this.def.params[index + 1] && this.def.params[index + 1].optional;
  119. }
  120. updateParam (strValue, index) {
  121. // handle optional parameters
  122. // if string contains ',' and next param is optional, split and update both
  123. if (this.hasMultipleParamsInString(strValue, index)) {
  124. _.each(strValue.split(','), function(partVal: string, idx) {
  125. this.updateParam(partVal.trim(), idx);
  126. }, this);
  127. return;
  128. }
  129. if (strValue === '' && this.def.params[index].optional) {
  130. this.params.splice(index, 1);
  131. }
  132. else {
  133. this.params[index] = strValue;
  134. }
  135. this.part.params = this.params;
  136. this.updateText();
  137. }
  138. updateText() {
  139. if (this.params.length === 0) {
  140. this.text = this.def.name + '()';
  141. return;
  142. }
  143. var text = this.def.name + '(';
  144. text += this.params.join(', ');
  145. text += ')';
  146. this.text = text;
  147. }
  148. }
  149. export = {
  150. create: function(part): any {
  151. return new QueryPart(part);
  152. },
  153. getFuncDef: function(name) {
  154. return index[name];
  155. },
  156. getCategories: function() {
  157. return categories;
  158. }
  159. };