query_part.ts 9.6 KB

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