@finos/legend-query-builder 4.15.1 → 4.15.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. package/lib/components/data-cube/QueryBuilderDataCube.d.ts.map +1 -1
  2. package/lib/components/data-cube/QueryBuilderDataCube.js +9 -17
  3. package/lib/components/data-cube/QueryBuilderDataCube.js.map +1 -1
  4. package/lib/components/filter/QueryBuilderFilterPanel.js +2 -2
  5. package/lib/components/filter/QueryBuilderFilterPanel.js.map +1 -1
  6. package/lib/components/result/QueryBuilderResultPanel.d.ts.map +1 -1
  7. package/lib/components/result/QueryBuilderResultPanel.js +13 -1
  8. package/lib/components/result/QueryBuilderResultPanel.js.map +1 -1
  9. package/lib/components/result/tds/QueryBuilderTDSGridResult.d.ts.map +1 -1
  10. package/lib/components/result/tds/QueryBuilderTDSGridResult.js +4 -3
  11. package/lib/components/result/tds/QueryBuilderTDSGridResult.js.map +1 -1
  12. package/lib/components/result/tds/QueryBuilderTDSResultShared.d.ts +2 -2
  13. package/lib/components/result/tds/QueryBuilderTDSResultShared.d.ts.map +1 -1
  14. package/lib/components/result/tds/QueryBuilderTDSResultShared.js +157 -19
  15. package/lib/components/result/tds/QueryBuilderTDSResultShared.js.map +1 -1
  16. package/lib/index.css +1 -17
  17. package/lib/index.css.map +1 -1
  18. package/lib/package.json +1 -1
  19. package/lib/stores/data-cube/QueryBuilderDataCubeApplicationEngine.d.ts +1 -3
  20. package/lib/stores/data-cube/QueryBuilderDataCubeApplicationEngine.d.ts.map +1 -1
  21. package/lib/stores/data-cube/QueryBuilderDataCubeApplicationEngine.js +1 -7
  22. package/lib/stores/data-cube/QueryBuilderDataCubeApplicationEngine.js.map +1 -1
  23. package/lib/stores/data-cube/QueryBuilderDataCubeEngine.d.ts +5 -2
  24. package/lib/stores/data-cube/QueryBuilderDataCubeEngine.d.ts.map +1 -1
  25. package/lib/stores/data-cube/QueryBuilderDataCubeEngine.js +14 -2
  26. package/lib/stores/data-cube/QueryBuilderDataCubeEngine.js.map +1 -1
  27. package/lib/stores/data-cube/QueryBuilderDataCubeEngineHelper.d.ts +1 -1
  28. package/lib/stores/data-cube/QueryBuilderDataCubeEngineHelper.d.ts.map +1 -1
  29. package/lib/stores/data-cube/QueryBuilderDataCubeEngineHelper.js +8 -1
  30. package/lib/stores/data-cube/QueryBuilderDataCubeEngineHelper.js.map +1 -1
  31. package/lib/stores/filter/QueryBuilderFilterOperator.d.ts +1 -1
  32. package/lib/stores/filter/QueryBuilderFilterOperator.d.ts.map +1 -1
  33. package/lib/stores/filter/QueryBuilderFilterState.d.ts +1 -1
  34. package/lib/stores/filter/QueryBuilderFilterState.d.ts.map +1 -1
  35. package/lib/stores/filter/QueryBuilderFilterState.js +8 -3
  36. package/lib/stores/filter/QueryBuilderFilterState.js.map +1 -1
  37. package/lib/stores/filter/QueryBuilderFilterStateBuilder.js +1 -1
  38. package/lib/stores/filter/QueryBuilderFilterStateBuilder.js.map +1 -1
  39. package/lib/stores/filter/operators/QueryBuilderFilterOperator_Contain.d.ts +2 -2
  40. package/lib/stores/filter/operators/QueryBuilderFilterOperator_Contain.d.ts.map +1 -1
  41. package/lib/stores/filter/operators/QueryBuilderFilterOperator_Contain.js +3 -3
  42. package/lib/stores/filter/operators/QueryBuilderFilterOperator_Contain.js.map +1 -1
  43. package/lib/stores/filter/operators/QueryBuilderFilterOperator_EndWith.d.ts +2 -2
  44. package/lib/stores/filter/operators/QueryBuilderFilterOperator_EndWith.d.ts.map +1 -1
  45. package/lib/stores/filter/operators/QueryBuilderFilterOperator_EndWith.js +3 -3
  46. package/lib/stores/filter/operators/QueryBuilderFilterOperator_EndWith.js.map +1 -1
  47. package/lib/stores/filter/operators/QueryBuilderFilterOperator_Equal.d.ts +2 -2
  48. package/lib/stores/filter/operators/QueryBuilderFilterOperator_Equal.d.ts.map +1 -1
  49. package/lib/stores/filter/operators/QueryBuilderFilterOperator_Equal.js +2 -2
  50. package/lib/stores/filter/operators/QueryBuilderFilterOperator_Equal.js.map +1 -1
  51. package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThan.d.ts +1 -1
  52. package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThan.d.ts.map +1 -1
  53. package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThan.js +2 -2
  54. package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThan.js.map +1 -1
  55. package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThanEqual.d.ts +1 -1
  56. package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThanEqual.d.ts.map +1 -1
  57. package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThanEqual.js +2 -2
  58. package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThanEqual.js.map +1 -1
  59. package/lib/stores/filter/operators/QueryBuilderFilterOperator_In.d.ts +2 -2
  60. package/lib/stores/filter/operators/QueryBuilderFilterOperator_In.d.ts.map +1 -1
  61. package/lib/stores/filter/operators/QueryBuilderFilterOperator_In.js +2 -2
  62. package/lib/stores/filter/operators/QueryBuilderFilterOperator_In.js.map +1 -1
  63. package/lib/stores/filter/operators/QueryBuilderFilterOperator_IsEmpty.d.ts +2 -2
  64. package/lib/stores/filter/operators/QueryBuilderFilterOperator_IsEmpty.d.ts.map +1 -1
  65. package/lib/stores/filter/operators/QueryBuilderFilterOperator_IsEmpty.js +2 -2
  66. package/lib/stores/filter/operators/QueryBuilderFilterOperator_IsEmpty.js.map +1 -1
  67. package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThan.d.ts +1 -1
  68. package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThan.d.ts.map +1 -1
  69. package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThan.js +2 -2
  70. package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThan.js.map +1 -1
  71. package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThanEqual.d.ts +1 -1
  72. package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThanEqual.d.ts.map +1 -1
  73. package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThanEqual.js +2 -2
  74. package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThanEqual.js.map +1 -1
  75. package/lib/stores/filter/operators/QueryBuilderFilterOperator_StartWith.d.ts +2 -2
  76. package/lib/stores/filter/operators/QueryBuilderFilterOperator_StartWith.d.ts.map +1 -1
  77. package/lib/stores/filter/operators/QueryBuilderFilterOperator_StartWith.js +3 -3
  78. package/lib/stores/filter/operators/QueryBuilderFilterOperator_StartWith.js.map +1 -1
  79. package/lib/stores/shared/LambdaParameterState.d.ts +2 -1
  80. package/lib/stores/shared/LambdaParameterState.d.ts.map +1 -1
  81. package/lib/stores/shared/LambdaParameterState.js +1 -0
  82. package/lib/stores/shared/LambdaParameterState.js.map +1 -1
  83. package/package.json +8 -8
  84. package/src/components/data-cube/QueryBuilderDataCube.tsx +19 -41
  85. package/src/components/filter/QueryBuilderFilterPanel.tsx +2 -2
  86. package/src/components/result/QueryBuilderResultPanel.tsx +23 -3
  87. package/src/components/result/tds/QueryBuilderTDSGridResult.tsx +7 -3
  88. package/src/components/result/tds/QueryBuilderTDSResultShared.tsx +334 -26
  89. package/src/stores/data-cube/QueryBuilderDataCubeApplicationEngine.ts +1 -12
  90. package/src/stores/data-cube/QueryBuilderDataCubeEngine.ts +23 -0
  91. package/src/stores/data-cube/QueryBuilderDataCubeEngineHelper.ts +16 -1
  92. package/src/stores/filter/QueryBuilderFilterOperator.ts +1 -1
  93. package/src/stores/filter/QueryBuilderFilterState.ts +10 -5
  94. package/src/stores/filter/QueryBuilderFilterStateBuilder.ts +1 -1
  95. package/src/stores/filter/operators/QueryBuilderFilterOperator_Contain.ts +3 -5
  96. package/src/stores/filter/operators/QueryBuilderFilterOperator_EndWith.ts +3 -5
  97. package/src/stores/filter/operators/QueryBuilderFilterOperator_Equal.ts +2 -2
  98. package/src/stores/filter/operators/QueryBuilderFilterOperator_GreaterThan.ts +2 -4
  99. package/src/stores/filter/operators/QueryBuilderFilterOperator_GreaterThanEqual.ts +2 -4
  100. package/src/stores/filter/operators/QueryBuilderFilterOperator_In.ts +2 -2
  101. package/src/stores/filter/operators/QueryBuilderFilterOperator_IsEmpty.ts +2 -2
  102. package/src/stores/filter/operators/QueryBuilderFilterOperator_LessThan.ts +2 -4
  103. package/src/stores/filter/operators/QueryBuilderFilterOperator_LessThanEqual.ts +2 -4
  104. package/src/stores/filter/operators/QueryBuilderFilterOperator_StartWith.ts +3 -5
  105. package/src/stores/shared/LambdaParameterState.ts +1 -0
@@ -22,12 +22,13 @@ import {
22
22
  import { observer } from 'mobx-react-lite';
23
23
  import { flowResult } from 'mobx';
24
24
  import {
25
- type TDSExecutionResult,
25
+ type AbstractPropertyExpression,
26
26
  type Enumeration,
27
- InstanceValue,
28
- EnumValueInstanceValue,
29
- EnumValueExplicitReference,
30
27
  type ExecutionResult,
28
+ type TDSExecutionResult,
29
+ EnumValueExplicitReference,
30
+ EnumValueInstanceValue,
31
+ InstanceValue,
31
32
  RelationalExecutionActivities,
32
33
  } from '@finos/legend-graph';
33
34
  import { format as formatSQL } from 'sql-formatter';
@@ -47,6 +48,7 @@ import { forwardRef } from 'react';
47
48
  import {
48
49
  QueryBuilderDerivationProjectionColumnState,
49
50
  QueryBuilderProjectionColumnState,
51
+ QueryBuilderSimpleProjectionColumnState,
50
52
  } from '../../../stores/fetch-structure/tds/projection/QueryBuilderProjectionColumnState.js';
51
53
  import {
52
54
  type QueryBuilderPostFilterTreeNodeData,
@@ -81,6 +83,30 @@ import {
81
83
  } from '../../../stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_IsEmpty.js';
82
84
  import { getTDSColumnState } from '../../../stores/fetch-structure/tds/QueryBuilderTDSHelper.js';
83
85
  import type { QueryBuilderTDSColumnState } from '../../../stores/fetch-structure/tds/QueryBuilderTDSColumnState.js';
86
+ import {
87
+ type QueryBuilderFilterState,
88
+ type QueryBuilderFilterTreeNodeData,
89
+ FilterConditionState,
90
+ FilterValueSpecConditionValueState,
91
+ isCollectionProperty,
92
+ QueryBuilderFilterTreeConditionNodeData,
93
+ } from '../../../stores/filter/QueryBuilderFilterState.js';
94
+ import { QueryBuilderAggregateColumnState } from '../../../stores/fetch-structure/tds/aggregation/QueryBuilderAggregationState.js';
95
+ import type { QueryBuilderFilterOperator } from '../../../stores/filter/QueryBuilderFilterOperator.js';
96
+ import {
97
+ QueryBuilderFilterOperator_Equal,
98
+ QueryBuilderFilterOperator_NotEqual,
99
+ } from '../../../stores/filter/operators/QueryBuilderFilterOperator_Equal.js';
100
+ import {
101
+ QueryBuilderFilterOperator_In,
102
+ QueryBuilderFilterOperator_NotIn,
103
+ } from '../../../stores/filter/operators/QueryBuilderFilterOperator_In.js';
104
+ import {
105
+ QueryBuilderFilterOperator_IsEmpty,
106
+ QueryBuilderFilterOperator_IsNotEmpty,
107
+ } from '../../../stores/filter/operators/QueryBuilderFilterOperator_IsEmpty.js';
108
+ import type { QueryBuilderState } from '../../../stores/QueryBuilderState.js';
109
+ import type { QueryBuilderPropertyExpressionState } from '../../../stores/QueryBuilderPropertyEditorState.js';
84
110
 
85
111
  export const tryToFormatSql = (sql: string): string => {
86
112
  try {
@@ -139,6 +165,13 @@ export type IQueryRendererParamsWithGridType = DataGridCellRendererParams & {
139
165
  tdsExecutionResult: TDSExecutionResult;
140
166
  };
141
167
 
168
+ const filterEqualOperator = new QueryBuilderFilterOperator_Equal();
169
+ const filterNotEqualOperator = new QueryBuilderFilterOperator_NotEqual();
170
+ const filterInOperator = new QueryBuilderFilterOperator_In();
171
+ const filterNotInOperator = new QueryBuilderFilterOperator_NotIn();
172
+ const filterEmptyOperator = new QueryBuilderFilterOperator_IsEmpty();
173
+ const filterNotEmptyOperator = new QueryBuilderFilterOperator_IsNotEmpty();
174
+
142
175
  const postFilterEqualOperator = new QueryBuilderPostFilterOperator_Equal();
143
176
  const postFilterInOperator = new QueryBuilderPostFilterOperator_In();
144
177
  const postFilterEmptyOperator = new QueryBuilderPostFilterOperator_IsEmpty();
@@ -148,6 +181,22 @@ const postFilterNotEqualOperator =
148
181
  new QueryBuilderPostFilterOperator_NotEqual();
149
182
  const postFilterNotInOperator = new QueryBuilderPostFilterOperator_NotIn();
150
183
 
184
+ const getExistingFilterNode = (
185
+ operators: QueryBuilderFilterOperator[],
186
+ propertyExpressionState: QueryBuilderPropertyExpressionState | undefined,
187
+ filterState: QueryBuilderFilterState,
188
+ ): QueryBuilderFilterTreeNodeData | undefined =>
189
+ Array.from(filterState.nodes.values())
190
+ .filter(filterByType(QueryBuilderFilterTreeConditionNodeData))
191
+ .filter(
192
+ (node) =>
193
+ node.condition.propertyExpressionState.path ===
194
+ propertyExpressionState?.path &&
195
+ operators
196
+ .map((op) => op.getLabel())
197
+ .includes(node.condition.operator.getLabel()),
198
+ )[0];
199
+
151
200
  const getExistingPostFilterNode = (
152
201
  operators: QueryBuilderPostFilterOperator[],
153
202
  projectionColumnName: string | undefined,
@@ -173,7 +222,7 @@ const getExistingPostFilterNode = (
173
222
  const updateFilterConditionValue = (
174
223
  conditionValue: InstanceValue,
175
224
  _cellData: QueryBuilderTDSResultCellData,
176
- tdsState: QueryBuilderTDSState,
225
+ queryBuilderState: QueryBuilderState,
177
226
  ): void => {
178
227
  if (_cellData.value) {
179
228
  instanceValue_setValue(
@@ -188,11 +237,58 @@ const updateFilterConditionValue = (
188
237
  )
189
238
  : _cellData.value,
190
239
  0,
191
- tdsState.queryBuilderState.observerContext,
240
+ queryBuilderState.observerContext,
192
241
  );
193
242
  }
194
243
  };
195
244
 
245
+ const generateNewFilterConditionNodeData = (
246
+ applicationStore: ApplicationStore<
247
+ LegendApplicationConfig,
248
+ LegendApplicationPluginManager<LegendApplicationPlugin>
249
+ >,
250
+ operator: QueryBuilderFilterOperator,
251
+ _cellData: QueryBuilderTDSResultCellData,
252
+ filterState: QueryBuilderFilterState,
253
+ propertyExpression: AbstractPropertyExpression | undefined,
254
+ ): void => {
255
+ let filterConditionState: FilterConditionState;
256
+ try {
257
+ if (propertyExpression) {
258
+ filterConditionState = new FilterConditionState(
259
+ filterState,
260
+ propertyExpression,
261
+ operator,
262
+ );
263
+
264
+ const defaultFilterConditionValue =
265
+ filterConditionState.operator.getDefaultFilterConditionValue(
266
+ filterConditionState,
267
+ );
268
+
269
+ filterConditionState.buildRightConditionValueFromValueSpec(
270
+ defaultFilterConditionValue,
271
+ );
272
+ updateFilterConditionValue(
273
+ defaultFilterConditionValue as InstanceValue,
274
+ _cellData,
275
+ filterState.queryBuilderState,
276
+ );
277
+ filterState.addNodeFromNode(
278
+ new QueryBuilderFilterTreeConditionNodeData(
279
+ undefined,
280
+ filterConditionState,
281
+ ),
282
+ undefined,
283
+ );
284
+ }
285
+ } catch (error) {
286
+ assertErrorThrown(error);
287
+ applicationStore.notificationService.notifyWarning(error.message);
288
+ return;
289
+ }
290
+ };
291
+
196
292
  const generateNewPostFilterConditionNodeData = async (
197
293
  applicationStore: ApplicationStore<
198
294
  LegendApplicationConfig,
@@ -235,7 +331,7 @@ const generateNewPostFilterConditionNodeData = async (
235
331
  updateFilterConditionValue(
236
332
  defaultFilterConditionValue as InstanceValue,
237
333
  _cellData,
238
- tdsState,
334
+ tdsState.queryBuilderState,
239
335
  );
240
336
  tdsState.postFilterState.addNodeFromNode(
241
337
  new QueryBuilderPostFilterTreeConditionNodeData(
@@ -252,6 +348,91 @@ const generateNewPostFilterConditionNodeData = async (
252
348
  }
253
349
  };
254
350
 
351
+ const updateExistingFilterConditionNodeData = (
352
+ existingPreFilterNode: QueryBuilderFilterTreeNodeData,
353
+ isFilterBy: boolean,
354
+ _cellData: QueryBuilderTDSResultCellData,
355
+ operator: QueryBuilderFilterOperator,
356
+ data: QueryBuilderTDSResultCellData | null,
357
+ queryBuilderState: QueryBuilderState,
358
+ ): void => {
359
+ if (operator === filterEmptyOperator || operator === filterNotEmptyOperator) {
360
+ const conditionState = (
361
+ existingPreFilterNode as QueryBuilderFilterTreeConditionNodeData
362
+ ).condition;
363
+ if (conditionState.operator.getLabel() !== operator.getLabel()) {
364
+ conditionState.changeOperator(
365
+ isFilterBy ? filterEmptyOperator : filterNotEmptyOperator,
366
+ );
367
+ }
368
+ return;
369
+ }
370
+ const conditionState = (
371
+ existingPreFilterNode as QueryBuilderFilterTreeConditionNodeData
372
+ ).condition;
373
+
374
+ const rightSide = conditionState.rightConditionValue;
375
+ if (rightSide instanceof FilterValueSpecConditionValueState) {
376
+ if (conditionState.operator.getLabel() === operator.getLabel()) {
377
+ const doesValueAlreadyExist =
378
+ rightSide.value instanceof InstanceValue &&
379
+ (rightSide.value instanceof EnumValueInstanceValue
380
+ ? rightSide.value.values.map((ef) => ef.value.name)
381
+ : rightSide.value.values
382
+ ).includes(_cellData.value);
383
+
384
+ if (!doesValueAlreadyExist) {
385
+ const currentValueSpecificaton = rightSide.value;
386
+ const newValueSpecification =
387
+ conditionState.operator.getDefaultFilterConditionValue(
388
+ conditionState,
389
+ );
390
+ updateFilterConditionValue(
391
+ newValueSpecification as InstanceValue,
392
+ _cellData,
393
+ queryBuilderState,
394
+ );
395
+ conditionState.changeOperator(
396
+ isFilterBy ? filterInOperator : filterNotInOperator,
397
+ );
398
+ instanceValue_setValues(
399
+ rightSide.value as InstanceValue,
400
+ [currentValueSpecificaton, newValueSpecification],
401
+ queryBuilderState.observerContext,
402
+ );
403
+ }
404
+ } else {
405
+ const doesValueAlreadyExist =
406
+ rightSide.value instanceof InstanceValue &&
407
+ rightSide.value.values
408
+ .filter((v) => v instanceof InstanceValue)
409
+ .map((v) =>
410
+ v instanceof EnumValueInstanceValue
411
+ ? v.values.map((ef) => ef.value.name)
412
+ : v.values,
413
+ )
414
+ .flat()
415
+ .includes(_cellData.value ?? data?.value);
416
+
417
+ if (!doesValueAlreadyExist) {
418
+ const newValueSpecification = (
419
+ isFilterBy ? filterEqualOperator : filterNotEqualOperator
420
+ ).getDefaultFilterConditionValue(conditionState);
421
+ updateFilterConditionValue(
422
+ newValueSpecification as InstanceValue,
423
+ _cellData,
424
+ queryBuilderState,
425
+ );
426
+ instanceValue_setValues(
427
+ rightSide.value as InstanceValue,
428
+ [...(rightSide.value as InstanceValue).values, newValueSpecification],
429
+ queryBuilderState.observerContext,
430
+ );
431
+ }
432
+ }
433
+ }
434
+ };
435
+
255
436
  const updateExistingPostFilterConditionNodeData = (
256
437
  existingPostFilterNode: QueryBuilderPostFilterTreeNodeData,
257
438
  isFilterBy: boolean,
@@ -297,7 +478,7 @@ const updateExistingPostFilterConditionNodeData = (
297
478
  updateFilterConditionValue(
298
479
  newValueSpecification as InstanceValue,
299
480
  _cellData,
300
- tdsState,
481
+ tdsState.queryBuilderState,
301
482
  );
302
483
  conditionState.changeOperator(
303
484
  isFilterBy ? postFilterInOperator : postFilterNotInOperator,
@@ -328,7 +509,7 @@ const updateExistingPostFilterConditionNodeData = (
328
509
  updateFilterConditionValue(
329
510
  newValueSpecification as InstanceValue,
330
511
  _cellData,
331
- tdsState,
512
+ tdsState.queryBuilderState,
332
513
  );
333
514
  instanceValue_setValues(
334
515
  rightSide.value as InstanceValue,
@@ -343,6 +524,25 @@ const updateExistingPostFilterConditionNodeData = (
343
524
  const getFilterOperator = (
344
525
  isFilterBy: boolean,
345
526
  _cellData: QueryBuilderTDSResultCellData,
527
+ ): QueryBuilderFilterOperator => {
528
+ if (isFilterBy) {
529
+ if (_cellData.value === null) {
530
+ return filterEmptyOperator;
531
+ } else {
532
+ return filterEqualOperator;
533
+ }
534
+ } else {
535
+ if (_cellData.value === null) {
536
+ return filterNotEmptyOperator;
537
+ } else {
538
+ return filterNotEqualOperator;
539
+ }
540
+ }
541
+ };
542
+
543
+ const getPostFilterOperator = (
544
+ isFilterBy: boolean,
545
+ _cellData: QueryBuilderTDSResultCellData,
346
546
  ): QueryBuilderPostFilterOperator => {
347
547
  if (isFilterBy) {
348
548
  if (_cellData.value === null) {
@@ -359,7 +559,7 @@ const getFilterOperator = (
359
559
  }
360
560
  };
361
561
 
362
- const filterByOrOutValue = (
562
+ const preFilterByOrOutValue = (
363
563
  applicationStore: ApplicationStore<
364
564
  LegendApplicationConfig,
365
565
  LegendApplicationPluginManager<LegendApplicationPlugin>
@@ -367,13 +567,58 @@ const filterByOrOutValue = (
367
567
  isFilterBy: boolean,
368
568
  _cellData: QueryBuilderTDSResultCellData,
369
569
  data: QueryBuilderTDSResultCellData | null,
370
- tdsState: QueryBuilderTDSState,
570
+ propertyExpressionState: QueryBuilderPropertyExpressionState,
571
+ queryBuilderState: QueryBuilderState,
371
572
  ): void => {
372
- tdsState.setShowPostFilterPanel(true);
573
+ queryBuilderState.filterState.setShowPanel(true);
373
574
  const operator = getFilterOperator(isFilterBy, _cellData);
374
- const tdsColState = data?.columnName
375
- ? getTDSColumnState(tdsState, data.columnName)
376
- : undefined;
575
+ const existingPreFilterNode = getExistingFilterNode(
576
+ _cellData.value === null
577
+ ? [filterEmptyOperator, filterNotEmptyOperator]
578
+ : isFilterBy
579
+ ? [filterEqualOperator, filterInOperator]
580
+ : [filterNotEqualOperator, filterNotInOperator],
581
+ propertyExpressionState,
582
+ queryBuilderState.filterState,
583
+ );
584
+ if (existingPreFilterNode) {
585
+ updateExistingFilterConditionNodeData(
586
+ existingPreFilterNode,
587
+ isFilterBy,
588
+ _cellData,
589
+ operator,
590
+ data,
591
+ queryBuilderState,
592
+ );
593
+ } else {
594
+ try {
595
+ generateNewFilterConditionNodeData(
596
+ applicationStore,
597
+ operator,
598
+ _cellData,
599
+ queryBuilderState.filterState,
600
+ propertyExpressionState.propertyExpression,
601
+ );
602
+ } catch (error) {
603
+ assertErrorThrown(error);
604
+ applicationStore.alertUnhandledError(error);
605
+ }
606
+ }
607
+ };
608
+
609
+ const postFilterByOrOutValue = async (
610
+ applicationStore: ApplicationStore<
611
+ LegendApplicationConfig,
612
+ LegendApplicationPluginManager<LegendApplicationPlugin>
613
+ >,
614
+ isFilterBy: boolean,
615
+ _cellData: QueryBuilderTDSResultCellData,
616
+ data: QueryBuilderTDSResultCellData | null,
617
+ tdsColState: QueryBuilderTDSColumnState,
618
+ tdsState: QueryBuilderTDSState,
619
+ ): Promise<void> => {
620
+ tdsState.setShowPostFilterPanel(true);
621
+ const operator = getPostFilterOperator(isFilterBy, _cellData);
377
622
  const existingPostFilterNode = getExistingPostFilterNode(
378
623
  _cellData.value === null
379
624
  ? [postFilterEmptyOperator, postFilterNotEmptyOperator]
@@ -394,17 +639,69 @@ const filterByOrOutValue = (
394
639
  tdsState,
395
640
  );
396
641
  } else {
397
- generateNewPostFilterConditionNodeData(
642
+ try {
643
+ await generateNewPostFilterConditionNodeData(
644
+ applicationStore,
645
+ operator,
646
+ _cellData,
647
+ tdsState,
648
+ tdsColState,
649
+ );
650
+ } catch (error) {
651
+ assertErrorThrown(error);
652
+ applicationStore.alertUnhandledError(error);
653
+ }
654
+ }
655
+ };
656
+
657
+ const filterByOrOutValue = async (
658
+ applicationStore: ApplicationStore<
659
+ LegendApplicationConfig,
660
+ LegendApplicationPluginManager<LegendApplicationPlugin>
661
+ >,
662
+ isFilterBy: boolean,
663
+ _cellData: QueryBuilderTDSResultCellData,
664
+ data: QueryBuilderTDSResultCellData | null,
665
+ tdsState: QueryBuilderTDSState,
666
+ ): Promise<void> => {
667
+ const tdsColState = data?.columnName
668
+ ? getTDSColumnState(tdsState, _cellData.columnName)
669
+ : _cellData.columnName
670
+ ? getTDSColumnState(tdsState, _cellData.columnName)
671
+ : undefined;
672
+ if (
673
+ tdsColState instanceof QueryBuilderDerivationProjectionColumnState ||
674
+ tdsColState instanceof QueryBuilderAggregateColumnState ||
675
+ (tdsColState instanceof QueryBuilderSimpleProjectionColumnState &&
676
+ isCollectionProperty(
677
+ tdsColState.propertyExpressionState.propertyExpression,
678
+ ))
679
+ ) {
680
+ await postFilterByOrOutValue(
398
681
  applicationStore,
399
- operator,
682
+ isFilterBy,
400
683
  _cellData,
401
- tdsState,
684
+ data,
402
685
  tdsColState,
403
- ).catch(applicationStore.alertUnhandledError);
686
+ tdsState,
687
+ );
688
+ } else if (tdsColState instanceof QueryBuilderSimpleProjectionColumnState) {
689
+ preFilterByOrOutValue(
690
+ applicationStore,
691
+ isFilterBy,
692
+ _cellData,
693
+ data,
694
+ tdsColState.propertyExpressionState,
695
+ tdsState.queryBuilderState,
696
+ );
697
+ } else {
698
+ applicationStore.notificationService.notifyError(
699
+ `Can't filter column '${data?.columnName ? data.columnName : _cellData.columnName}'`,
700
+ );
404
701
  }
405
702
  };
406
703
 
407
- export const filterByOrOutValues = (
704
+ export const filterByOrOutValues = async (
408
705
  applicationStore: ApplicationStore<
409
706
  LegendApplicationConfig,
410
707
  LegendApplicationPluginManager<LegendApplicationPlugin>
@@ -412,10 +709,17 @@ export const filterByOrOutValues = (
412
709
  data: QueryBuilderTDSResultCellData | null,
413
710
  isFilterBy: boolean,
414
711
  tdsState: QueryBuilderTDSState,
415
- ): void => {
416
- tdsState.queryBuilderState.resultState.selectedCells.forEach((_cellData) => {
417
- filterByOrOutValue(applicationStore, isFilterBy, _cellData, data, tdsState);
418
- });
712
+ ): Promise<void> => {
713
+ for (const _cellData of tdsState.queryBuilderState.resultState
714
+ .selectedCells) {
715
+ await filterByOrOutValue(
716
+ applicationStore,
717
+ isFilterBy,
718
+ _cellData,
719
+ data,
720
+ tdsState,
721
+ );
722
+ }
419
723
  };
420
724
 
421
725
  export const QueryBuilderGridResultContextMenu = observer(
@@ -440,7 +744,9 @@ export const QueryBuilderGridResultContextMenu = observer(
440
744
  <MenuContentItem
441
745
  disabled={!tdsColState}
442
746
  onClick={(): void => {
443
- filterByOrOutValues(applicationStore, data, true, tdsState);
747
+ filterByOrOutValues(applicationStore, data, true, tdsState).catch(
748
+ tdsState.queryBuilderState.applicationStore.alertUnhandledError,
749
+ );
444
750
  }}
445
751
  >
446
752
  Filter By
@@ -448,7 +754,9 @@ export const QueryBuilderGridResultContextMenu = observer(
448
754
  <MenuContentItem
449
755
  disabled={!tdsColState}
450
756
  onClick={(): void => {
451
- filterByOrOutValues(applicationStore, data, false, tdsState);
757
+ filterByOrOutValues(applicationStore, data, false, tdsState).catch(
758
+ tdsState.queryBuilderState.applicationStore.alertUnhandledError,
759
+ );
452
760
  }}
453
761
  >
454
762
  Filter Out
@@ -19,10 +19,7 @@ import {
19
19
  shouldDisplayVirtualAssistantDocumentationEntry,
20
20
  type GenericLegendApplicationStore,
21
21
  } from '@finos/legend-application';
22
- import {
23
- DataCubeApplicationEngine,
24
- type ActionAlert,
25
- } from '@finos/legend-data-cube';
22
+ import { DataCubeApplicationEngine } from '@finos/legend-data-cube';
26
23
  import { LogEvent, type DocumentationEntry } from '@finos/legend-shared';
27
24
 
28
25
  export class QueryBuilderDataCubeApplicationEngine extends DataCubeApplicationEngine {
@@ -58,14 +55,6 @@ export class QueryBuilderDataCubeApplicationEngine extends DataCubeApplicationEn
58
55
  this.application.layoutService.setWindowTitle(title);
59
56
  }
60
57
 
61
- alertAction(alertInfo: ActionAlert | undefined) {
62
- this.currentActionAlert = alertInfo;
63
- }
64
-
65
- alertUnhandledError(error: Error) {
66
- this.application.alertUnhandledError(error);
67
- }
68
-
69
58
  logDebug(message: string, ...data: unknown[]) {
70
59
  this.application.logService.debug(
71
60
  LogEvent.create(APPLICATION_EVENT.DEBUG),
@@ -28,6 +28,7 @@ import {
28
28
  type GraphManagerState,
29
29
  type PureModel,
30
30
  type V1_ValueSpecification,
31
+ type ParameterValue,
31
32
  } from '@finos/legend-graph';
32
33
  import {
33
34
  _elementPtr,
@@ -67,9 +68,13 @@ export class QueryBuilderDataCubeEngine extends DataCubeEngine {
67
68
  readonly graphState: GraphManagerState;
68
69
  readonly selectInitialQuery: RawLambda;
69
70
  readonly mappingPath: string | undefined;
71
+ readonly parameterValues: ParameterValue[] | undefined;
70
72
  readonly runtimePath: string;
73
+ _parameters: object | undefined;
74
+
71
75
  constructor(
72
76
  selectQuery: RawLambda,
77
+ parameterValues: ParameterValue[] | undefined,
73
78
  mappingPath: string | undefined,
74
79
  runtimePath: string,
75
80
  graphManagerState: GraphManagerState,
@@ -79,6 +84,7 @@ export class QueryBuilderDataCubeEngine extends DataCubeEngine {
79
84
  this.selectInitialQuery = selectQuery;
80
85
  this.mappingPath = mappingPath;
81
86
  this.runtimePath = runtimePath;
87
+ this.parameterValues = parameterValues;
82
88
  }
83
89
 
84
90
  get sourceLabel(): string {
@@ -105,6 +111,7 @@ export class QueryBuilderDataCubeEngine extends DataCubeEngine {
105
111
  ) {
106
112
  srcFuncExp = srcFuncExp.body[0];
107
113
  }
114
+ this._parameters = this.selectInitialQuery.parameters;
108
115
  const fromFuncExp = new V1_AppliedFunction();
109
116
  fromFuncExp.function = _functionName(SUPPORTED_FUNCTIONS.FROM);
110
117
  fromFuncExp.parameters = [srcFuncExp];
@@ -159,6 +166,8 @@ export class QueryBuilderDataCubeEngine extends DataCubeEngine {
159
166
  // we return undefined as we assume the grid license is set at the application level where query builder is built
160
167
  return Promise.resolve({
161
168
  gridClientLicense: undefined,
169
+ simpleSampleDataTableName: '',
170
+ complexSampleDataTableName: '',
162
171
  });
163
172
  }
164
173
  override async getQueryTypeahead(
@@ -191,6 +200,16 @@ export class QueryBuilderDataCubeEngine extends DataCubeEngine {
191
200
  );
192
201
  }
193
202
 
203
+ override getQueryCode(
204
+ query: V1_ValueSpecification,
205
+ pretty?: boolean | undefined,
206
+ ): Promise<string> {
207
+ return this.graphState.graphManager.valueSpecificationToPureCode(
208
+ V1_serializeValueSpecification(query, []),
209
+ pretty,
210
+ );
211
+ }
212
+
194
213
  override getQueryRelationType(
195
214
  query: V1_ValueSpecification,
196
215
  ): Promise<RelationType> {
@@ -227,12 +246,16 @@ export class QueryBuilderDataCubeEngine extends DataCubeEngine {
227
246
  executedSQL: string;
228
247
  }> {
229
248
  const lambda = this.buildRawLambdaFromValueSpec(query);
249
+ lambda.parameters = this._parameters;
230
250
  const [executionWithMetadata, queryString] = await Promise.all([
231
251
  this.graphState.graphManager.runQuery(
232
252
  lambda,
233
253
  undefined,
234
254
  undefined,
235
255
  this.graph,
256
+ {
257
+ parameterValues: this.parameterValues ?? [],
258
+ },
236
259
  ),
237
260
  this.graphState.graphManager.lambdaToPureCode(lambda),
238
261
  ]);
@@ -15,9 +15,13 @@
15
15
  */
16
16
 
17
17
  import { type DataCubeEngine } from '@finos/legend-data-cube';
18
- import type { QueryBuilderState } from '../QueryBuilderState.js';
18
+ import {
19
+ QUERY_BUILDER_LAMBDA_WRITER_MODE,
20
+ type QueryBuilderState,
21
+ } from '../QueryBuilderState.js';
19
22
  import { RuntimePointer } from '@finos/legend-graph';
20
23
  import { QueryBuilderDataCubeEngine } from './QueryBuilderDataCubeEngine.js';
24
+ import { buildExecutionParameterValues } from '../shared/LambdaParameterState.js';
21
25
 
22
26
  export const createDataCubeEngineFromQueryBuilder = (
23
27
  queryBuilderState: QueryBuilderState,
@@ -31,11 +35,22 @@ export const createDataCubeEngineFromQueryBuilder = (
31
35
  if (!runtime) {
32
36
  return undefined;
33
37
  }
38
+ const currentLambdaWriterMode = queryBuilderState.lambdaWriteMode;
39
+ // ensure we write in new tds mode
40
+ queryBuilderState.setLambdaWriteMode(
41
+ QUERY_BUILDER_LAMBDA_WRITER_MODE.TYPED_FETCH_STRUCTURE,
42
+ );
43
+ const parameterValues = buildExecutionParameterValues(
44
+ queryBuilderState.parametersState.parameterStates,
45
+ queryBuilderState.graphManagerState,
46
+ );
34
47
  const queryBuilderEngine = new QueryBuilderDataCubeEngine(
35
48
  queryBuilderState.buildQuery(),
49
+ parameterValues,
36
50
  queryBuilderState.executionContextState.mapping?.path,
37
51
  runtime,
38
52
  queryBuilderState.graphManagerState,
39
53
  );
54
+ queryBuilderState.setLambdaWriteMode(currentLambdaWriterMode);
40
55
  return queryBuilderEngine;
41
56
  };
@@ -27,7 +27,7 @@ import type {
27
27
  export abstract class QueryBuilderFilterOperator implements Hashable {
28
28
  readonly uuid = uuid();
29
29
 
30
- abstract getLabel(filterConditionState: FilterConditionState): string;
30
+ abstract getLabel(): string;
31
31
 
32
32
  abstract isCompatibleWithFilterConditionProperty(
33
33
  filterConditionState: FilterConditionState,
@@ -246,6 +246,7 @@ export class FilterConditionState implements Hashable {
246
246
  constructor(
247
247
  filterState: QueryBuilderFilterState,
248
248
  propertyExpression: AbstractPropertyExpression,
249
+ operator?: QueryBuilderFilterOperator,
249
250
  ) {
250
251
  makeObservable(this, {
251
252
  propertyExpressionState: observable,
@@ -271,11 +272,15 @@ export class FilterConditionState implements Hashable {
271
272
  );
272
273
 
273
274
  // operator
274
- assertTrue(
275
- this.operators.length !== 0,
276
- `Can't find an operator for property '${this.propertyExpressionState.path}': no operators registered`,
277
- );
278
- this.operator = this.operators[0] as QueryBuilderFilterOperator;
275
+ if (operator) {
276
+ this.operator = operator;
277
+ } else {
278
+ assertTrue(
279
+ this.operators.length !== 0,
280
+ `Can't find an operator for property '${this.propertyExpressionState.path}': no operators registered`,
281
+ );
282
+ this.operator = this.operators[0] as QueryBuilderFilterOperator;
283
+ }
279
284
  this.buildRightConditionValueFromValueSpec(
280
285
  this.operator.getDefaultFilterConditionValue(this),
281
286
  );
@@ -332,7 +332,7 @@ const processFilterTree = (
332
332
  assertTrue(
333
333
  parentLambdaVariableName === variableName,
334
334
  `Can't process ${extractElementNameFromPath(
335
- filterConditionState.operator.getLabel(filterConditionState),
335
+ filterConditionState.operator.getLabel(),
336
336
  )}() expression: expects variable used in lambda body '${variableName}' to match lambda parameter '${parentLambdaVariableName}'`,
337
337
  );
338
338
  filterState.addNodeFromNode(