query_part.ts 4.4 KB

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