LokiAndPromQueryModellerBase.ts 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import { Registry } from '@grafana/data';
  2. import { PromVisualQueryOperationCategory } from '../types';
  3. import { QueryBuilderLabelFilter, QueryBuilderOperation, QueryBuilderOperationDef, VisualQueryModeller } from './types';
  4. export interface VisualQueryBinary<T> {
  5. operator: string;
  6. vectorMatchesType?: 'on' | 'ignoring';
  7. vectorMatches?: string;
  8. query: T;
  9. }
  10. export interface PromLokiVisualQuery {
  11. metric?: string;
  12. labels: QueryBuilderLabelFilter[];
  13. operations: QueryBuilderOperation[];
  14. binaryQueries?: Array<VisualQueryBinary<PromLokiVisualQuery>>;
  15. }
  16. export abstract class LokiAndPromQueryModellerBase implements VisualQueryModeller {
  17. protected operationsRegistry: Registry<QueryBuilderOperationDef>;
  18. private categories: string[] = [];
  19. constructor(getOperations: () => QueryBuilderOperationDef[]) {
  20. this.operationsRegistry = new Registry<QueryBuilderOperationDef>(getOperations);
  21. }
  22. protected setOperationCategories(categories: string[]) {
  23. this.categories = categories;
  24. }
  25. getOperationsForCategory(category: string) {
  26. return this.operationsRegistry.list().filter((op) => op.category === category && !op.hideFromList);
  27. }
  28. getAlternativeOperations(key: string) {
  29. return this.operationsRegistry.list().filter((op) => op.alternativesKey && op.alternativesKey === key);
  30. }
  31. getCategories() {
  32. return this.categories;
  33. }
  34. getOperationDef(id: string): QueryBuilderOperationDef | undefined {
  35. return this.operationsRegistry.getIfExists(id);
  36. }
  37. renderOperations(queryString: string, operations: QueryBuilderOperation[]) {
  38. for (const operation of operations) {
  39. const def = this.operationsRegistry.getIfExists(operation.id);
  40. if (!def) {
  41. throw new Error(`Could not find operation ${operation.id} in the registry`);
  42. }
  43. queryString = def.renderer(operation, def, queryString);
  44. }
  45. return queryString;
  46. }
  47. renderBinaryQueries(queryString: string, binaryQueries?: Array<VisualQueryBinary<PromLokiVisualQuery>>) {
  48. if (binaryQueries) {
  49. for (const binQuery of binaryQueries) {
  50. queryString = `${this.renderBinaryQuery(queryString, binQuery)}`;
  51. }
  52. }
  53. return queryString;
  54. }
  55. private renderBinaryQuery(leftOperand: string, binaryQuery: VisualQueryBinary<PromLokiVisualQuery>) {
  56. let result = leftOperand + ` ${binaryQuery.operator} `;
  57. if (binaryQuery.vectorMatches) {
  58. result += `${binaryQuery.vectorMatchesType}(${binaryQuery.vectorMatches}) `;
  59. }
  60. return result + this.renderQuery(binaryQuery.query, true);
  61. }
  62. renderLabels(labels: QueryBuilderLabelFilter[]) {
  63. if (labels.length === 0) {
  64. return '';
  65. }
  66. let expr = '{';
  67. for (const filter of labels) {
  68. if (expr !== '{') {
  69. expr += ', ';
  70. }
  71. expr += `${filter.label}${filter.op}"${filter.value}"`;
  72. }
  73. return expr + `}`;
  74. }
  75. renderQuery(query: PromLokiVisualQuery, nested?: boolean) {
  76. let queryString = `${query.metric ?? ''}${this.renderLabels(query.labels)}`;
  77. queryString = this.renderOperations(queryString, query.operations);
  78. if (!nested && this.hasBinaryOp(query) && Boolean(query.binaryQueries?.length)) {
  79. queryString = `(${queryString})`;
  80. }
  81. queryString = this.renderBinaryQueries(queryString, query.binaryQueries);
  82. if (nested && (this.hasBinaryOp(query) || Boolean(query.binaryQueries?.length))) {
  83. queryString = `(${queryString})`;
  84. }
  85. return queryString;
  86. }
  87. hasBinaryOp(query: PromLokiVisualQuery): boolean {
  88. return (
  89. query.operations.find((op) => {
  90. const def = this.getOperationDef(op.id);
  91. return def?.category === PromVisualQueryOperationCategory.BinaryOps;
  92. }) !== undefined
  93. );
  94. }
  95. }