query_part.ts 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. ///<reference path="../../../headers/common.d.ts" />
  2. import _ from 'lodash';
  3. import {
  4. QueryPartDef,
  5. QueryPart,
  6. functionRenderer,
  7. suffixRenderer,
  8. } from 'app/core/components/query_part/query_part';
  9. var index = [];
  10. var categories = {
  11. Aggregations: [],
  12. Selectors: [],
  13. Transformations: [],
  14. Predictors: [],
  15. Math: [],
  16. Aliasing: [],
  17. Fields: [],
  18. };
  19. function createPart(part): any {
  20. var def = index[part.type];
  21. if (!def) {
  22. throw { message: 'Could not find query part ' + part.type };
  23. }
  24. return new QueryPart(part, def);
  25. }
  26. function register(options: any) {
  27. index[options.type] = new QueryPartDef(options);
  28. options.category.push(index[options.type]);
  29. }
  30. var groupByTimeFunctions = [];
  31. function aliasRenderer(part, innerExpr) {
  32. return innerExpr + ' AS ' + '"' + part.params[0] + '"';
  33. }
  34. function fieldRenderer(part, innerExpr) {
  35. if (part.params[0] === '*') {
  36. return '*';
  37. }
  38. return '"' + part.params[0] + '"';
  39. }
  40. function replaceAggregationAddStrategy(selectParts, partModel) {
  41. // look for existing aggregation
  42. for (var i = 0; i < selectParts.length; i++) {
  43. var part = selectParts[i];
  44. if (part.def.category === categories.Aggregations) {
  45. selectParts[i] = partModel;
  46. return;
  47. }
  48. if (part.def.category === categories.Selectors) {
  49. selectParts[i] = partModel;
  50. return;
  51. }
  52. }
  53. selectParts.splice(1, 0, partModel);
  54. }
  55. function addTransformationStrategy(selectParts, partModel) {
  56. var i;
  57. // look for index to add transformation
  58. for (i = 0; i < selectParts.length; i++) {
  59. var part = selectParts[i];
  60. if (
  61. part.def.category === categories.Math ||
  62. part.def.category === categories.Aliasing
  63. ) {
  64. break;
  65. }
  66. }
  67. selectParts.splice(i, 0, partModel);
  68. }
  69. function addMathStrategy(selectParts, partModel) {
  70. var partCount = selectParts.length;
  71. if (partCount > 0) {
  72. // if last is math, replace it
  73. if (selectParts[partCount - 1].def.type === 'math') {
  74. selectParts[partCount - 1] = partModel;
  75. return;
  76. }
  77. // if next to last is math, replace it
  78. if (partCount > 1 && selectParts[partCount - 2].def.type === 'math') {
  79. selectParts[partCount - 2] = partModel;
  80. return;
  81. } else if (selectParts[partCount - 1].def.type === 'alias') {
  82. // if last is alias add it before
  83. selectParts.splice(partCount - 1, 0, partModel);
  84. return;
  85. }
  86. }
  87. selectParts.push(partModel);
  88. }
  89. function addAliasStrategy(selectParts, partModel) {
  90. var partCount = selectParts.length;
  91. if (partCount > 0) {
  92. // if last is alias, replace it
  93. if (selectParts[partCount - 1].def.type === 'alias') {
  94. selectParts[partCount - 1] = partModel;
  95. return;
  96. }
  97. }
  98. selectParts.push(partModel);
  99. }
  100. function addFieldStrategy(selectParts, partModel, query) {
  101. // copy all parts
  102. var parts = _.map(selectParts, function(part: any) {
  103. return createPart({ type: part.def.type, params: _.clone(part.params) });
  104. });
  105. query.selectModels.push(parts);
  106. }
  107. register({
  108. type: 'field',
  109. addStrategy: addFieldStrategy,
  110. category: categories.Fields,
  111. params: [{ type: 'field', dynamicLookup: true }],
  112. defaultParams: ['value'],
  113. renderer: fieldRenderer,
  114. });
  115. // Aggregations
  116. register({
  117. type: 'count',
  118. addStrategy: replaceAggregationAddStrategy,
  119. category: categories.Aggregations,
  120. params: [],
  121. defaultParams: [],
  122. renderer: functionRenderer,
  123. });
  124. register({
  125. type: 'distinct',
  126. addStrategy: replaceAggregationAddStrategy,
  127. category: categories.Aggregations,
  128. params: [],
  129. defaultParams: [],
  130. renderer: functionRenderer,
  131. });
  132. register({
  133. type: 'integral',
  134. addStrategy: replaceAggregationAddStrategy,
  135. category: categories.Aggregations,
  136. params: [],
  137. defaultParams: [],
  138. renderer: functionRenderer,
  139. });
  140. register({
  141. type: 'mean',
  142. addStrategy: replaceAggregationAddStrategy,
  143. category: categories.Aggregations,
  144. params: [],
  145. defaultParams: [],
  146. renderer: functionRenderer,
  147. });
  148. register({
  149. type: 'median',
  150. addStrategy: replaceAggregationAddStrategy,
  151. category: categories.Aggregations,
  152. params: [],
  153. defaultParams: [],
  154. renderer: functionRenderer,
  155. });
  156. register({
  157. type: 'mode',
  158. addStrategy: replaceAggregationAddStrategy,
  159. category: categories.Aggregations,
  160. params: [],
  161. defaultParams: [],
  162. renderer: functionRenderer,
  163. });
  164. register({
  165. type: 'sum',
  166. addStrategy: replaceAggregationAddStrategy,
  167. category: categories.Aggregations,
  168. params: [],
  169. defaultParams: [],
  170. renderer: functionRenderer,
  171. });
  172. // transformations
  173. register({
  174. type: 'derivative',
  175. addStrategy: addTransformationStrategy,
  176. category: categories.Transformations,
  177. params: [
  178. {
  179. name: 'duration',
  180. type: 'interval',
  181. options: ['1s', '10s', '1m', '5m', '10m', '15m', '1h'],
  182. },
  183. ],
  184. defaultParams: ['10s'],
  185. renderer: functionRenderer,
  186. });
  187. register({
  188. type: 'spread',
  189. addStrategy: addTransformationStrategy,
  190. category: categories.Transformations,
  191. params: [],
  192. defaultParams: [],
  193. renderer: functionRenderer,
  194. });
  195. register({
  196. type: 'non_negative_derivative',
  197. addStrategy: addTransformationStrategy,
  198. category: categories.Transformations,
  199. params: [
  200. {
  201. name: 'duration',
  202. type: 'interval',
  203. options: ['1s', '10s', '1m', '5m', '10m', '15m', '1h'],
  204. },
  205. ],
  206. defaultParams: ['10s'],
  207. renderer: functionRenderer,
  208. });
  209. register({
  210. type: 'difference',
  211. addStrategy: addTransformationStrategy,
  212. category: categories.Transformations,
  213. params: [],
  214. defaultParams: [],
  215. renderer: functionRenderer,
  216. });
  217. register({
  218. type: 'non_negative_difference',
  219. addStrategy: addTransformationStrategy,
  220. category: categories.Transformations,
  221. params: [],
  222. defaultParams: [],
  223. renderer: functionRenderer,
  224. });
  225. register({
  226. type: 'moving_average',
  227. addStrategy: addTransformationStrategy,
  228. category: categories.Transformations,
  229. params: [{ name: 'window', type: 'int', options: [5, 10, 20, 30, 40] }],
  230. defaultParams: [10],
  231. renderer: functionRenderer,
  232. });
  233. register({
  234. type: 'cumulative_sum',
  235. addStrategy: addTransformationStrategy,
  236. category: categories.Transformations,
  237. params: [],
  238. defaultParams: [],
  239. renderer: functionRenderer,
  240. });
  241. register({
  242. type: 'stddev',
  243. addStrategy: addTransformationStrategy,
  244. category: categories.Transformations,
  245. params: [],
  246. defaultParams: [],
  247. renderer: functionRenderer,
  248. });
  249. register({
  250. type: 'time',
  251. category: groupByTimeFunctions,
  252. params: [
  253. {
  254. name: 'interval',
  255. type: 'time',
  256. options: ['$__interval', '1s', '10s', '1m', '5m', '10m', '15m', '1h'],
  257. },
  258. ],
  259. defaultParams: ['$__interval'],
  260. renderer: functionRenderer,
  261. });
  262. register({
  263. type: 'fill',
  264. category: groupByTimeFunctions,
  265. params: [
  266. {
  267. name: 'fill',
  268. type: 'string',
  269. options: ['none', 'null', '0', 'previous', 'linear'],
  270. },
  271. ],
  272. defaultParams: ['null'],
  273. renderer: functionRenderer,
  274. });
  275. register({
  276. type: 'elapsed',
  277. addStrategy: addTransformationStrategy,
  278. category: categories.Transformations,
  279. params: [
  280. {
  281. name: 'duration',
  282. type: 'interval',
  283. options: ['1s', '10s', '1m', '5m', '10m', '15m', '1h'],
  284. },
  285. ],
  286. defaultParams: ['10s'],
  287. renderer: functionRenderer,
  288. });
  289. // predictions
  290. register({
  291. type: 'holt_winters',
  292. addStrategy: addTransformationStrategy,
  293. category: categories.Predictors,
  294. params: [
  295. { name: 'number', type: 'int', options: [5, 10, 20, 30, 40] },
  296. { name: 'season', type: 'int', options: [0, 1, 2, 5, 10] },
  297. ],
  298. defaultParams: [10, 2],
  299. renderer: functionRenderer,
  300. });
  301. register({
  302. type: 'holt_winters_with_fit',
  303. addStrategy: addTransformationStrategy,
  304. category: categories.Predictors,
  305. params: [
  306. { name: 'number', type: 'int', options: [5, 10, 20, 30, 40] },
  307. { name: 'season', type: 'int', options: [0, 1, 2, 5, 10] },
  308. ],
  309. defaultParams: [10, 2],
  310. renderer: functionRenderer,
  311. });
  312. // Selectors
  313. register({
  314. type: 'bottom',
  315. addStrategy: replaceAggregationAddStrategy,
  316. category: categories.Selectors,
  317. params: [{ name: 'count', type: 'int' }],
  318. defaultParams: [3],
  319. renderer: functionRenderer,
  320. });
  321. register({
  322. type: 'first',
  323. addStrategy: replaceAggregationAddStrategy,
  324. category: categories.Selectors,
  325. params: [],
  326. defaultParams: [],
  327. renderer: functionRenderer,
  328. });
  329. register({
  330. type: 'last',
  331. addStrategy: replaceAggregationAddStrategy,
  332. category: categories.Selectors,
  333. params: [],
  334. defaultParams: [],
  335. renderer: functionRenderer,
  336. });
  337. register({
  338. type: 'max',
  339. addStrategy: replaceAggregationAddStrategy,
  340. category: categories.Selectors,
  341. params: [],
  342. defaultParams: [],
  343. renderer: functionRenderer,
  344. });
  345. register({
  346. type: 'min',
  347. addStrategy: replaceAggregationAddStrategy,
  348. category: categories.Selectors,
  349. params: [],
  350. defaultParams: [],
  351. renderer: functionRenderer,
  352. });
  353. register({
  354. type: 'percentile',
  355. addStrategy: replaceAggregationAddStrategy,
  356. category: categories.Selectors,
  357. params: [{ name: 'nth', type: 'int' }],
  358. defaultParams: [95],
  359. renderer: functionRenderer,
  360. });
  361. register({
  362. type: 'top',
  363. addStrategy: replaceAggregationAddStrategy,
  364. category: categories.Selectors,
  365. params: [{ name: 'count', type: 'int' }],
  366. defaultParams: [3],
  367. renderer: functionRenderer,
  368. });
  369. register({
  370. type: 'tag',
  371. category: groupByTimeFunctions,
  372. params: [{ name: 'tag', type: 'string', dynamicLookup: true }],
  373. defaultParams: ['tag'],
  374. renderer: fieldRenderer,
  375. });
  376. register({
  377. type: 'math',
  378. addStrategy: addMathStrategy,
  379. category: categories.Math,
  380. params: [{ name: 'expr', type: 'string' }],
  381. defaultParams: [' / 100'],
  382. renderer: suffixRenderer,
  383. });
  384. register({
  385. type: 'alias',
  386. addStrategy: addAliasStrategy,
  387. category: categories.Aliasing,
  388. params: [{ name: 'name', type: 'string', quote: 'double' }],
  389. defaultParams: ['alias'],
  390. renderMode: 'suffix',
  391. renderer: aliasRenderer,
  392. });
  393. export default {
  394. create: createPart,
  395. getCategories: function() {
  396. return categories;
  397. },
  398. };