query_part.ts 8.5 KB

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