query_part.ts 9.7 KB

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