@finos/legend-query-builder 4.9.4 → 4.10.1
Sign up to get free protection for your applications and to get access to all the features.
- package/lib/__lib__/QueryBuilderTesting.d.ts +4 -1
- package/lib/__lib__/QueryBuilderTesting.d.ts.map +1 -1
- package/lib/__lib__/QueryBuilderTesting.js +5 -1
- package/lib/__lib__/QueryBuilderTesting.js.map +1 -1
- package/lib/components/QueryBuilderResultPanel.d.ts.map +1 -1
- package/lib/components/QueryBuilderResultPanel.js +80 -90
- package/lib/components/QueryBuilderResultPanel.js.map +1 -1
- package/lib/components/__test-utils__/QueryBuilderComponentTestUtils.d.ts +1 -0
- package/lib/components/__test-utils__/QueryBuilderComponentTestUtils.d.ts.map +1 -1
- package/lib/components/__test-utils__/QueryBuilderComponentTestUtils.js +13 -1
- package/lib/components/__test-utils__/QueryBuilderComponentTestUtils.js.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.d.ts +2 -2
- package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.d.ts.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js +42 -24
- package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderTDSPanel.d.ts.map +1 -1
- package/lib/components/fetch-structure/QueryBuilderTDSPanel.js +1 -1
- package/lib/components/fetch-structure/QueryBuilderTDSPanel.js.map +1 -1
- package/lib/components/filter/QueryBuilderFilterPanel.d.ts +3 -2
- package/lib/components/filter/QueryBuilderFilterPanel.d.ts.map +1 -1
- package/lib/components/filter/QueryBuilderFilterPanel.js +145 -8
- package/lib/components/filter/QueryBuilderFilterPanel.js.map +1 -1
- package/lib/index.css +16 -0
- package/lib/package.json +1 -1
- package/lib/stores/QueryBuilderConstantsState.d.ts +5 -1
- package/lib/stores/QueryBuilderConstantsState.d.ts.map +1 -1
- package/lib/stores/QueryBuilderConstantsState.js +14 -1
- package/lib/stores/QueryBuilderConstantsState.js.map +1 -1
- package/lib/stores/QueryBuilderResultState.d.ts +3 -0
- package/lib/stores/QueryBuilderResultState.d.ts.map +1 -1
- package/lib/stores/QueryBuilderResultState.js +31 -2
- package/lib/stores/QueryBuilderResultState.js.map +1 -1
- package/lib/stores/QueryBuilderStateHashUtils.d.ts +2 -0
- package/lib/stores/QueryBuilderStateHashUtils.d.ts.map +1 -1
- package/lib/stores/QueryBuilderStateHashUtils.js +2 -0
- package/lib/stores/QueryBuilderStateHashUtils.js.map +1 -1
- package/lib/stores/QueryBuilderValueSpecificationBuilder.d.ts.map +1 -1
- package/lib/stores/QueryBuilderValueSpecificationBuilder.js +3 -23
- package/lib/stores/QueryBuilderValueSpecificationBuilder.js.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterOperator.js +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterOperator.js.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.d.ts +31 -5
- package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js +125 -30
- package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterStateBuilder.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterStateBuilder.js +21 -8
- package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterStateBuilder.js.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperatorValueSpecificationBuilder.d.ts +3 -1
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperatorValueSpecificationBuilder.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperatorValueSpecificationBuilder.js +20 -17
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperatorValueSpecificationBuilder.js.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_Contain.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_Contain.js +4 -6
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_Contain.js.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_EndWith.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_EndWith.js +4 -6
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_EndWith.js.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_Equal.d.ts +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_Equal.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_Equal.js +10 -10
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_Equal.js.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_GreaterThan.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_GreaterThan.js +10 -10
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_GreaterThan.js.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_GreaterThanEqual.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_GreaterThanEqual.js +5 -5
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_GreaterThanEqual.js.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_In.d.ts +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_In.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_In.js +32 -27
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_In.js.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_IsEmpty.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_IsEmpty.js +10 -5
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_IsEmpty.js.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_LessThan.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_LessThan.js +10 -10
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_LessThan.js.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_LessThanEqual.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_LessThanEqual.js +5 -5
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_LessThanEqual.js.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_StartWith.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_StartWith.js +4 -6
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_StartWith.js.map +1 -1
- package/lib/stores/fetch-structure/tds/projection/QueryBuilderProjectionColumnState.d.ts.map +1 -1
- package/lib/stores/fetch-structure/tds/projection/QueryBuilderProjectionColumnState.js +17 -3
- package/lib/stores/fetch-structure/tds/projection/QueryBuilderProjectionColumnState.js.map +1 -1
- package/lib/stores/filter/QueryBuilderFilterState.d.ts +7 -1
- package/lib/stores/filter/QueryBuilderFilterState.d.ts.map +1 -1
- package/lib/stores/filter/QueryBuilderFilterState.js +27 -0
- package/lib/stores/filter/QueryBuilderFilterState.js.map +1 -1
- package/package.json +5 -5
- package/src/__lib__/QueryBuilderTesting.ts +5 -1
- package/src/components/QueryBuilderResultPanel.tsx +127 -135
- package/src/components/__test-utils__/QueryBuilderComponentTestUtils.tsx +25 -1
- package/src/components/fetch-structure/QueryBuilderPostFilterPanel.tsx +102 -49
- package/src/components/fetch-structure/QueryBuilderTDSPanel.tsx +6 -2
- package/src/components/filter/QueryBuilderFilterPanel.tsx +239 -21
- package/src/stores/QueryBuilderConstantsState.ts +30 -0
- package/src/stores/QueryBuilderResultState.ts +36 -1
- package/src/stores/QueryBuilderStateHashUtils.ts +2 -0
- package/src/stores/QueryBuilderValueSpecificationBuilder.ts +4 -50
- package/src/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterOperator.ts +1 -1
- package/src/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.ts +180 -34
- package/src/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterStateBuilder.ts +38 -9
- package/src/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperatorValueSpecificationBuilder.ts +36 -20
- package/src/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_Contain.ts +5 -6
- package/src/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_EndWith.ts +6 -6
- package/src/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_Equal.ts +12 -13
- package/src/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_GreaterThan.ts +10 -9
- package/src/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_GreaterThanEqual.ts +5 -4
- package/src/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_In.ts +48 -43
- package/src/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_IsEmpty.ts +12 -4
- package/src/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_LessThan.ts +10 -9
- package/src/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_LessThanEqual.ts +5 -4
- package/src/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_StartWith.ts +6 -6
- package/src/stores/fetch-structure/tds/projection/QueryBuilderProjectionColumnState.ts +26 -4
- package/src/stores/filter/QueryBuilderFilterState.ts +40 -1
@@ -61,7 +61,13 @@ import {
|
|
61
61
|
} from '@finos/legend-shared';
|
62
62
|
import { flowResult } from 'mobx';
|
63
63
|
import { observer } from 'mobx-react-lite';
|
64
|
-
import
|
64
|
+
import React, {
|
65
|
+
forwardRef,
|
66
|
+
useCallback,
|
67
|
+
useMemo,
|
68
|
+
useRef,
|
69
|
+
useState,
|
70
|
+
} from 'react';
|
65
71
|
import { useDrop, useDrag, useDragLayer } from 'react-dnd';
|
66
72
|
import { QueryBuilderAggregateColumnState } from '../../stores/fetch-structure/tds/aggregation/QueryBuilderAggregationState.js';
|
67
73
|
import type { QueryBuilderPostFilterOperator } from '../../stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterOperator.js';
|
@@ -74,6 +80,8 @@ import {
|
|
74
80
|
QueryBuilderPostFilterTreeGroupNodeData,
|
75
81
|
QueryBuilderPostFilterTreeBlankConditionNodeData,
|
76
82
|
QUERY_BUILDER_POST_FILTER_DND_TYPE,
|
83
|
+
PostFilterValueSpecConditionValueState,
|
84
|
+
PostFilterTDSColumnValueConditionValueState,
|
77
85
|
} from '../../stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js';
|
78
86
|
import {
|
79
87
|
type QueryBuilderProjectionColumnState,
|
@@ -203,14 +211,14 @@ const QueryBuilderPostFilterGroupConditionEditor = observer(
|
|
203
211
|
|
204
212
|
export const QueryBuilderColumnBadge = observer(
|
205
213
|
(props: {
|
206
|
-
|
214
|
+
colState: QueryBuilderTDSColumnState;
|
207
215
|
onColumnChange: (
|
208
216
|
columnState: QueryBuilderProjectionColumnState,
|
209
217
|
) => Promise<void>;
|
210
218
|
}) => {
|
211
|
-
const {
|
219
|
+
const { colState, onColumnChange } = props;
|
212
220
|
const applicationStore = useApplicationStore();
|
213
|
-
const type =
|
221
|
+
const type = colState.getColumnType();
|
214
222
|
const handleDrop = useCallback(
|
215
223
|
(item: QueryBuilderProjectionColumnDragSource): Promise<void> =>
|
216
224
|
onColumnChange(item.columnState),
|
@@ -261,12 +269,12 @@ export const QueryBuilderColumnBadge = observer(
|
|
261
269
|
)}
|
262
270
|
<div
|
263
271
|
className="query-builder-column-badge__property"
|
264
|
-
title={`${
|
272
|
+
title={`${colState.columnName}`}
|
265
273
|
>
|
266
|
-
{
|
274
|
+
{colState.columnName}
|
267
275
|
</div>
|
268
276
|
<QueryBuilderColumnInfoTooltip
|
269
|
-
columnState={
|
277
|
+
columnState={colState}
|
270
278
|
placement="bottom-end"
|
271
279
|
>
|
272
280
|
<div className="query-builder-column-badge__property__info">
|
@@ -291,13 +299,15 @@ const QueryBuilderPostFilterConditionEditor = observer(
|
|
291
299
|
const applicationStore = useApplicationStore();
|
292
300
|
const changeOperator = (val: QueryBuilderPostFilterOperator) => (): void =>
|
293
301
|
node.condition.changeOperator(val);
|
302
|
+
const rightConditionValue = node.condition.rightConditionValue;
|
294
303
|
const changeColumn = async (
|
295
304
|
columnState: QueryBuilderProjectionColumnState,
|
296
305
|
): Promise<void> => {
|
297
306
|
const currentColState =
|
298
|
-
node.condition.
|
299
|
-
|
300
|
-
|
307
|
+
node.condition.leftConditionValue instanceof
|
308
|
+
QueryBuilderAggregateColumnState
|
309
|
+
? node.condition.leftConditionValue.projectionColumnState
|
310
|
+
: node.condition.leftConditionValue;
|
301
311
|
if (currentColState !== columnState) {
|
302
312
|
await flowResult(node.condition.changeColumn(columnState));
|
303
313
|
}
|
@@ -306,12 +316,13 @@ const QueryBuilderPostFilterConditionEditor = observer(
|
|
306
316
|
const handleDrop = useCallback(
|
307
317
|
(item: QueryBuilderVariableDragSource): void => {
|
308
318
|
const parameterType = item.variable.genericType?.value.rawType;
|
309
|
-
const conditionValueType =
|
319
|
+
const conditionValueType =
|
320
|
+
node.condition.leftConditionValue.getColumnType();
|
310
321
|
if (
|
311
322
|
conditionValueType &&
|
312
323
|
isTypeCompatibleForAssignment(parameterType, conditionValueType)
|
313
324
|
) {
|
314
|
-
node.condition.
|
325
|
+
node.condition.buildFromValueSpec(item.variable);
|
315
326
|
} else {
|
316
327
|
applicationStore.notificationService.notifyWarning(
|
317
328
|
`Incompatible parameter type ${parameterType?.name}. ${parameterType?.name} is not compatible with type ${conditionValueType?.name}.`,
|
@@ -339,7 +350,7 @@ const QueryBuilderPostFilterConditionEditor = observer(
|
|
339
350
|
[handleDrop],
|
340
351
|
);
|
341
352
|
const resetNode = (): void => {
|
342
|
-
node.condition.
|
353
|
+
node.condition.buildFromValueSpec(
|
343
354
|
node.condition.operator.getDefaultFilterConditionValue(node.condition),
|
344
355
|
);
|
345
356
|
};
|
@@ -355,7 +366,7 @@ const QueryBuilderPostFilterConditionEditor = observer(
|
|
355
366
|
node.condition.typeaheadSearchState.complete();
|
356
367
|
};
|
357
368
|
const changeValueSpecification = (val: ValueSpecification): void => {
|
358
|
-
node.condition.
|
369
|
+
node.condition.buildFromValueSpec(val);
|
359
370
|
};
|
360
371
|
const selectorConfig = {
|
361
372
|
values: node.condition.typeaheadSearchResults,
|
@@ -371,6 +382,70 @@ const QueryBuilderPostFilterConditionEditor = observer(
|
|
371
382
|
monitor.getItemType() === QUERY_BUILDER_WINDOW_COLUMN_DND_TYPE),
|
372
383
|
}));
|
373
384
|
|
385
|
+
const renderRightVal = (): React.ReactNode => {
|
386
|
+
if (
|
387
|
+
rightConditionValue instanceof PostFilterValueSpecConditionValueState &&
|
388
|
+
rightConditionValue.value
|
389
|
+
) {
|
390
|
+
return (
|
391
|
+
<div
|
392
|
+
ref={dropConnector}
|
393
|
+
className="query-builder-post-filter-tree__condition-node__value"
|
394
|
+
>
|
395
|
+
<PanelEntryDropZonePlaceholder
|
396
|
+
isDragOver={isFilterValueDragOver}
|
397
|
+
label="Change Filter Value"
|
398
|
+
>
|
399
|
+
<BasicValueSpecificationEditor
|
400
|
+
valueSpecification={rightConditionValue.value}
|
401
|
+
setValueSpecification={changeValueSpecification}
|
402
|
+
graph={graph}
|
403
|
+
obseverContext={queryBuilderState.observerContext}
|
404
|
+
typeCheckOption={{
|
405
|
+
expectedType: guaranteeNonNullable(
|
406
|
+
node.condition.leftConditionValue.getColumnType(),
|
407
|
+
),
|
408
|
+
}}
|
409
|
+
resetValue={resetNode}
|
410
|
+
selectorConfig={selectorConfig}
|
411
|
+
isConstant={queryBuilderState.constantState.isValueSpecConstant(
|
412
|
+
rightConditionValue.value,
|
413
|
+
)}
|
414
|
+
/>
|
415
|
+
</PanelEntryDropZonePlaceholder>
|
416
|
+
</div>
|
417
|
+
);
|
418
|
+
} else if (
|
419
|
+
rightConditionValue instanceof
|
420
|
+
PostFilterTDSColumnValueConditionValueState
|
421
|
+
) {
|
422
|
+
const changeRightCol = async (
|
423
|
+
columnState: QueryBuilderProjectionColumnState,
|
424
|
+
): Promise<void> => {
|
425
|
+
rightConditionValue.changeCol(columnState);
|
426
|
+
};
|
427
|
+
return (
|
428
|
+
<div
|
429
|
+
ref={dropConnector}
|
430
|
+
className="query-builder-post-filter-tree__condition-node__value"
|
431
|
+
>
|
432
|
+
<PanelEntryDropZonePlaceholder
|
433
|
+
isDragOver={isFilterValueDragOver}
|
434
|
+
label="Change Filter Value"
|
435
|
+
>
|
436
|
+
<div className="query-builder-post-filter-tree__condition-node__property">
|
437
|
+
<QueryBuilderColumnBadge
|
438
|
+
colState={rightConditionValue.tdsColumn}
|
439
|
+
onColumnChange={changeRightCol}
|
440
|
+
/>
|
441
|
+
</div>
|
442
|
+
</PanelEntryDropZonePlaceholder>
|
443
|
+
</div>
|
444
|
+
);
|
445
|
+
}
|
446
|
+
return null;
|
447
|
+
};
|
448
|
+
|
374
449
|
return (
|
375
450
|
<div className="query-builder-post-filter-tree__node__label__content dnd__entry__container">
|
376
451
|
<PanelEntryDropZonePlaceholder
|
@@ -381,7 +456,7 @@ const QueryBuilderPostFilterConditionEditor = observer(
|
|
381
456
|
<div className="query-builder-post-filter-tree__condition-node">
|
382
457
|
<div className="query-builder-post-filter-tree__condition-node__property">
|
383
458
|
<QueryBuilderColumnBadge
|
384
|
-
|
459
|
+
colState={node.condition.leftConditionValue}
|
385
460
|
onColumnChange={changeColumn}
|
386
461
|
/>
|
387
462
|
</div>
|
@@ -414,34 +489,7 @@ const QueryBuilderPostFilterConditionEditor = observer(
|
|
414
489
|
<CaretDownIcon />
|
415
490
|
</div>
|
416
491
|
</DropdownMenu>
|
417
|
-
{
|
418
|
-
<div
|
419
|
-
ref={dropConnector}
|
420
|
-
className="query-builder-post-filter-tree__condition-node__value"
|
421
|
-
>
|
422
|
-
<PanelEntryDropZonePlaceholder
|
423
|
-
isDragOver={isFilterValueDragOver}
|
424
|
-
label="Change Filter Value"
|
425
|
-
>
|
426
|
-
<BasicValueSpecificationEditor
|
427
|
-
valueSpecification={node.condition.value}
|
428
|
-
setValueSpecification={changeValueSpecification}
|
429
|
-
graph={graph}
|
430
|
-
obseverContext={queryBuilderState.observerContext}
|
431
|
-
typeCheckOption={{
|
432
|
-
expectedType: guaranteeNonNullable(
|
433
|
-
node.condition.columnState.getColumnType(),
|
434
|
-
),
|
435
|
-
}}
|
436
|
-
resetValue={resetNode}
|
437
|
-
selectorConfig={selectorConfig}
|
438
|
-
isConstant={queryBuilderState.constantState.isValueSpecConstant(
|
439
|
-
node.condition.value,
|
440
|
-
)}
|
441
|
-
/>
|
442
|
-
</PanelEntryDropZonePlaceholder>
|
443
|
-
</div>
|
444
|
-
)}
|
492
|
+
{renderRightVal()}
|
445
493
|
</div>
|
446
494
|
</PanelEntryDropZonePlaceholder>
|
447
495
|
</div>
|
@@ -538,9 +586,8 @@ const QueryBuilderPostFilterTreeNodeContainer = observer(
|
|
538
586
|
postFilterState,
|
539
587
|
columnState,
|
540
588
|
undefined,
|
541
|
-
undefined,
|
542
589
|
);
|
543
|
-
conditionState.
|
590
|
+
conditionState.buildFromValueSpec(
|
544
591
|
conditionState.operator.getDefaultFilterConditionValue(
|
545
592
|
conditionState,
|
546
593
|
),
|
@@ -648,6 +695,9 @@ const QueryBuilderPostFilterTreeNodeContainer = observer(
|
|
648
695
|
>
|
649
696
|
<div
|
650
697
|
ref={ref}
|
698
|
+
data-testid={
|
699
|
+
QUERY_BUILDER_TEST_ID.QUERY_BUILDER_POST_FILTER_TREE_NODE_CONTENT
|
700
|
+
}
|
651
701
|
className={clsx(
|
652
702
|
'tree-view__node__container query-builder-post-filter-tree__node__container',
|
653
703
|
{
|
@@ -679,6 +729,10 @@ const QueryBuilderPostFilterTreeNodeContainer = observer(
|
|
679
729
|
<div
|
680
730
|
className={clsx(
|
681
731
|
'tree-view__node__label query-builder-post-filter-tree__node__label',
|
732
|
+
{
|
733
|
+
'query-builder-post-filter-tree__node__label--expandable':
|
734
|
+
isExpandable,
|
735
|
+
},
|
682
736
|
)}
|
683
737
|
>
|
684
738
|
{node instanceof QueryBuilderPostFilterTreeGroupNodeData && (
|
@@ -894,9 +948,8 @@ const QueryBuilderPostFilterPanelContent = observer(
|
|
894
948
|
postFilterState,
|
895
949
|
aggregateColumnState ?? columnState,
|
896
950
|
undefined,
|
897
|
-
undefined,
|
898
951
|
);
|
899
|
-
postFilterConditionState.
|
952
|
+
postFilterConditionState.buildFromValueSpec(
|
900
953
|
postFilterConditionState.operator.getDefaultFilterConditionValue(
|
901
954
|
postFilterConditionState,
|
902
955
|
),
|
@@ -959,7 +1012,7 @@ const QueryBuilderPostFilterPanelContent = observer(
|
|
959
1012
|
<div className="panel__header__actions">
|
960
1013
|
<DropdownMenu
|
961
1014
|
className="panel__header__action"
|
962
|
-
title="Show Filter Options Menu..."
|
1015
|
+
title="Show Post-Filter Options Menu..."
|
963
1016
|
content={
|
964
1017
|
<MenuContent>
|
965
1018
|
<MenuContentItem onClick={createCondition}>
|
@@ -1091,7 +1144,7 @@ export const QueryBuilderPostFilterPanel = observer(
|
|
1091
1144
|
|
1092
1145
|
return (
|
1093
1146
|
<div
|
1094
|
-
data-testid={QUERY_BUILDER_TEST_ID.
|
1147
|
+
data-testid={QUERY_BUILDER_TEST_ID.QUERY_BUILDER_POST_FILTER_PANEL}
|
1095
1148
|
className="panel"
|
1096
1149
|
>
|
1097
1150
|
{fetchStructureImplementation instanceof QueryBuilderTDSState && (
|
@@ -688,7 +688,6 @@ const QueryBuilderProjectionColumnEditor = observer(
|
|
688
688
|
}),
|
689
689
|
[handleDrop],
|
690
690
|
);
|
691
|
-
|
692
691
|
return (
|
693
692
|
<PanelDnDEntry
|
694
693
|
ref={ref}
|
@@ -732,7 +731,12 @@ const QueryBuilderProjectionColumnEditor = observer(
|
|
732
731
|
onOpen={onContextMenuOpen}
|
733
732
|
onClose={onContextMenuClose}
|
734
733
|
>
|
735
|
-
<div
|
734
|
+
<div
|
735
|
+
data-testid={
|
736
|
+
QUERY_BUILDER_TEST_ID.QUERY_BUILDER_TDS_PROJECTION_COLUMN
|
737
|
+
}
|
738
|
+
className="query-builder__projection__column__container"
|
739
|
+
>
|
736
740
|
<PanelEntryDragHandle
|
737
741
|
isDragging={false}
|
738
742
|
dragSourceConnector={dragHandleRef}
|
@@ -113,6 +113,7 @@ import {
|
|
113
113
|
import { QueryBuilderTelemetryHelper } from '../../__lib__/QueryBuilderTelemetryHelper.js';
|
114
114
|
import { getPropertyChainName } from '../../stores/QueryBuilderPropertyEditorState.js';
|
115
115
|
import { QUERY_BUILDER_SUPPORTED_FUNCTIONS } from '../../graph/QueryBuilderMetaModelConst.js';
|
116
|
+
import { buildPropertyExpressionChain } from '../../stores/QueryBuilderValueSpecificationBuilderHelper.js';
|
116
117
|
|
117
118
|
const isCollectionProperty = (
|
118
119
|
propertyExpression: AbstractPropertyExpression,
|
@@ -151,7 +152,7 @@ const isCollectionProperty = (
|
|
151
152
|
export const buildFilterTreeWithExists = (
|
152
153
|
propertyExpression: AbstractPropertyExpression,
|
153
154
|
filterState: QueryBuilderFilterState,
|
154
|
-
targetDropNode?:
|
155
|
+
targetDropNode?: QueryBuilderFilterTreeNodeData,
|
155
156
|
): void => {
|
156
157
|
// 1. Decompose property expression
|
157
158
|
const expressions: (AbstractPropertyExpression | SimpleFunctionExpression)[] =
|
@@ -294,7 +295,21 @@ export const buildFilterTreeWithExists = (
|
|
294
295
|
.value.path,
|
295
296
|
);
|
296
297
|
if (parentPropertyChainIndex >= 0) {
|
297
|
-
parentNode
|
298
|
+
// Here we choose parentNode based on what the type of targetDropNode
|
299
|
+
// 1. QueryBuilderFilterTreeConditionNodeData: In this case we would want to
|
300
|
+
// add a new group condition from the targetDropNode and add new exists node
|
301
|
+
// getting created as it's child so the parent would be the new group node
|
302
|
+
// 2. QueryBuilderFilterTreeGroupNodeData: Parent node would be same as
|
303
|
+
// targetDropNode
|
304
|
+
// 3. QueryBuilderFilterTreeBlankConditionNodeData: parentNode would be the
|
305
|
+
// parent of the targetDropNode. At the end we would deelete this blank node
|
306
|
+
// that got created.
|
307
|
+
parentNode =
|
308
|
+
targetDropNode instanceof QueryBuilderFilterTreeConditionNodeData
|
309
|
+
? filterState.newGroupConditionFromNode(targetDropNode)
|
310
|
+
: targetDropNode instanceof QueryBuilderFilterTreeGroupNodeData
|
311
|
+
? targetDropNode
|
312
|
+
: filterState.getParentNode(targetDropNode);
|
298
313
|
existsLambdaPropertyChains = existsLambdaPropertyChains.slice(
|
299
314
|
parentPropertyChainIndex + 1,
|
300
315
|
);
|
@@ -303,7 +318,12 @@ export const buildFilterTreeWithExists = (
|
|
303
318
|
);
|
304
319
|
}
|
305
320
|
} else if (!parentId) {
|
306
|
-
parentNode =
|
321
|
+
parentNode =
|
322
|
+
targetDropNode instanceof QueryBuilderFilterTreeConditionNodeData
|
323
|
+
? filterState.newGroupConditionFromNode(targetDropNode)
|
324
|
+
: targetDropNode instanceof QueryBuilderFilterTreeGroupNodeData
|
325
|
+
? targetDropNode
|
326
|
+
: filterState.getParentNode(targetDropNode);
|
307
327
|
}
|
308
328
|
}
|
309
329
|
}
|
@@ -332,6 +352,127 @@ export const buildFilterTreeWithExists = (
|
|
332
352
|
filterConditionState,
|
333
353
|
);
|
334
354
|
filterState.addNodeFromNode(treeNode, parentNode);
|
355
|
+
if (targetDropNode instanceof QueryBuilderFilterTreeBlankConditionNodeData) {
|
356
|
+
filterState.removeNodeAndPruneBranch(targetDropNode);
|
357
|
+
}
|
358
|
+
};
|
359
|
+
|
360
|
+
export const buildPropertyExpressionFromExistsNode = (
|
361
|
+
filterState: QueryBuilderFilterState,
|
362
|
+
existsNode: QueryBuilderFilterTreeExistsNodeData,
|
363
|
+
node: QueryBuilderFilterTreeConditionNodeData,
|
364
|
+
): AbstractPropertyExpression => {
|
365
|
+
let nodeParent = filterState.getParentNode(node);
|
366
|
+
let existsLambdaParameterNames: string[] = [];
|
367
|
+
let existsLambdaExpressions: AbstractPropertyExpression[] = [];
|
368
|
+
existsLambdaExpressions.push(
|
369
|
+
node.condition.propertyExpressionState.propertyExpression,
|
370
|
+
);
|
371
|
+
existsLambdaParameterNames.push(
|
372
|
+
nodeParent?.lambdaParameterName ?? filterState.lambdaParameterName,
|
373
|
+
);
|
374
|
+
while (nodeParent && nodeParent.id !== existsNode.id) {
|
375
|
+
if (nodeParent instanceof QueryBuilderFilterTreeExistsNodeData) {
|
376
|
+
existsLambdaExpressions.push(
|
377
|
+
nodeParent.propertyExpressionState.propertyExpression,
|
378
|
+
);
|
379
|
+
existsLambdaParameterNames.push(
|
380
|
+
nodeParent.lambdaParameterName ?? filterState.lambdaParameterName,
|
381
|
+
);
|
382
|
+
}
|
383
|
+
nodeParent = filterState.getParentNode(nodeParent);
|
384
|
+
}
|
385
|
+
if (nodeParent?.id === existsNode.id) {
|
386
|
+
existsLambdaExpressions.push(
|
387
|
+
existsNode.propertyExpressionState.propertyExpression,
|
388
|
+
);
|
389
|
+
existsLambdaParameterNames.push(
|
390
|
+
existsNode.lambdaParameterName ?? filterState.lambdaParameterName,
|
391
|
+
);
|
392
|
+
}
|
393
|
+
existsLambdaParameterNames = existsLambdaParameterNames.reverse();
|
394
|
+
existsLambdaExpressions = existsLambdaExpressions.reverse();
|
395
|
+
|
396
|
+
const initialPropertyExpression = guaranteeNonNullable(
|
397
|
+
existsLambdaExpressions[0],
|
398
|
+
);
|
399
|
+
existsLambdaParameterNames = existsLambdaParameterNames.slice(1);
|
400
|
+
existsLambdaExpressions = existsLambdaExpressions.slice(1);
|
401
|
+
|
402
|
+
let flattenedPropertyExpressionChain = new AbstractPropertyExpression('');
|
403
|
+
flattenedPropertyExpressionChain.func = initialPropertyExpression.func;
|
404
|
+
flattenedPropertyExpressionChain.parametersValues = [
|
405
|
+
...initialPropertyExpression.parametersValues,
|
406
|
+
];
|
407
|
+
for (const exp of existsLambdaExpressions) {
|
408
|
+
// when rebuilding the property expression chain, disregard the initial variable that starts the chain
|
409
|
+
const expressions: (
|
410
|
+
| AbstractPropertyExpression
|
411
|
+
| SimpleFunctionExpression
|
412
|
+
)[] = [];
|
413
|
+
let currentExpression: ValueSpecification = exp;
|
414
|
+
while (
|
415
|
+
currentExpression instanceof AbstractPropertyExpression ||
|
416
|
+
(currentExpression instanceof SimpleFunctionExpression &&
|
417
|
+
matchFunctionName(
|
418
|
+
currentExpression.functionName,
|
419
|
+
QUERY_BUILDER_SUPPORTED_FUNCTIONS.SUBTYPE,
|
420
|
+
))
|
421
|
+
) {
|
422
|
+
if (currentExpression instanceof SimpleFunctionExpression) {
|
423
|
+
const functionExpression = new SimpleFunctionExpression(
|
424
|
+
extractElementNameFromPath(QUERY_BUILDER_SUPPORTED_FUNCTIONS.SUBTYPE),
|
425
|
+
);
|
426
|
+
functionExpression.parametersValues.unshift(
|
427
|
+
guaranteeNonNullable(currentExpression.parametersValues[1]),
|
428
|
+
);
|
429
|
+
expressions.push(functionExpression);
|
430
|
+
} else if (currentExpression instanceof AbstractPropertyExpression) {
|
431
|
+
const propertyExp = new AbstractPropertyExpression('');
|
432
|
+
propertyExp.func = currentExpression.func;
|
433
|
+
// NOTE: we must retain the rest of the parameters as those are derived property parameters
|
434
|
+
propertyExp.parametersValues =
|
435
|
+
currentExpression.parametersValues.length > 1
|
436
|
+
? currentExpression.parametersValues.slice(1)
|
437
|
+
: [];
|
438
|
+
expressions.push(propertyExp);
|
439
|
+
}
|
440
|
+
currentExpression = guaranteeNonNullable(
|
441
|
+
currentExpression.parametersValues[0],
|
442
|
+
);
|
443
|
+
}
|
444
|
+
assertTrue(
|
445
|
+
expressions.length > 0,
|
446
|
+
`Can't process exists() expression: exists() usage with non-chain property expression is not supported`,
|
447
|
+
);
|
448
|
+
for (let i = 0; i < expressions.length - 1; ++i) {
|
449
|
+
(
|
450
|
+
expressions[i] as AbstractPropertyExpression | SimpleFunctionExpression
|
451
|
+
).parametersValues.unshift(
|
452
|
+
expressions[i + 1] as
|
453
|
+
| AbstractPropertyExpression
|
454
|
+
| SimpleFunctionExpression,
|
455
|
+
);
|
456
|
+
}
|
457
|
+
(
|
458
|
+
expressions[expressions.length - 1] as
|
459
|
+
| AbstractPropertyExpression
|
460
|
+
| SimpleFunctionExpression
|
461
|
+
).parametersValues.unshift(flattenedPropertyExpressionChain);
|
462
|
+
flattenedPropertyExpressionChain = guaranteeType(
|
463
|
+
expressions[0],
|
464
|
+
AbstractPropertyExpression,
|
465
|
+
`Can't process exists() expression: can't flatten to a property expression`,
|
466
|
+
);
|
467
|
+
}
|
468
|
+
return guaranteeType(
|
469
|
+
buildPropertyExpressionChain(
|
470
|
+
flattenedPropertyExpressionChain,
|
471
|
+
filterState.queryBuilderState,
|
472
|
+
existsNode.lambdaParameterName ?? filterState.lambdaParameterName,
|
473
|
+
),
|
474
|
+
AbstractPropertyExpression,
|
475
|
+
);
|
335
476
|
};
|
336
477
|
|
337
478
|
/**
|
@@ -340,7 +481,7 @@ export const buildFilterTreeWithExists = (
|
|
340
481
|
const buildFilterTree = (
|
341
482
|
propertyExpression: AbstractPropertyExpression,
|
342
483
|
filterState: QueryBuilderFilterState,
|
343
|
-
targetDropNode?:
|
484
|
+
targetDropNode?: QueryBuilderFilterTreeNodeData | undefined,
|
344
485
|
): void => {
|
345
486
|
if (isCollectionProperty(propertyExpression)) {
|
346
487
|
const propertyChainName = getPropertyChainName(
|
@@ -383,12 +524,88 @@ const buildFilterTree = (
|
|
383
524
|
undefined,
|
384
525
|
filterConditionState,
|
385
526
|
);
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
527
|
+
// Check if there are any exists node present in the parent nodes of the target.
|
528
|
+
// This would change the way we build the filter tree
|
529
|
+
let cn: QueryBuilderFilterTreeNodeData | undefined = targetDropNode;
|
530
|
+
let existsNode: QueryBuilderFilterTreeExistsNodeData | undefined =
|
531
|
+
undefined;
|
532
|
+
let parentId = targetDropNode?.parentId;
|
533
|
+
while (parentId) {
|
534
|
+
cn = filterState.nodes.get(parentId);
|
535
|
+
parentId = cn?.parentId;
|
536
|
+
if (cn instanceof QueryBuilderFilterTreeExistsNodeData) {
|
537
|
+
existsNode = cn;
|
538
|
+
}
|
539
|
+
}
|
540
|
+
if (cn instanceof QueryBuilderFilterTreeExistsNodeData) {
|
541
|
+
existsNode = cn;
|
542
|
+
}
|
543
|
+
if (targetDropNode instanceof QueryBuilderFilterTreeGroupNodeData) {
|
544
|
+
if (existsNode) {
|
545
|
+
filterState.newGroupConditionFromNode(
|
546
|
+
existsNode,
|
547
|
+
treeNode,
|
548
|
+
targetDropNode.groupOperation,
|
549
|
+
);
|
550
|
+
} else {
|
551
|
+
filterState.addNodeFromNode(treeNode, targetDropNode);
|
552
|
+
}
|
553
|
+
} else if (
|
554
|
+
targetDropNode instanceof QueryBuilderFilterTreeBlankConditionNodeData
|
555
|
+
) {
|
556
|
+
if (existsNode) {
|
557
|
+
filterState.queryBuilderState.applicationStore.notificationService.notifyError(
|
558
|
+
`Can't drag and drop here: property expression of target and source doesn't match`,
|
559
|
+
);
|
560
|
+
} else {
|
561
|
+
filterState.replaceBlankNodeWithNode(treeNode, targetDropNode);
|
562
|
+
}
|
563
|
+
} else if (
|
564
|
+
existsNode &&
|
565
|
+
targetDropNode instanceof QueryBuilderFilterTreeExistsNodeData
|
566
|
+
) {
|
567
|
+
filterState.newGroupConditionFromNode(existsNode, treeNode);
|
568
|
+
} else if (
|
569
|
+
targetDropNode instanceof QueryBuilderFilterTreeConditionNodeData
|
570
|
+
) {
|
571
|
+
const parentNode = filterState.getParentNode(targetDropNode);
|
572
|
+
if (
|
573
|
+
existsNode &&
|
574
|
+
parentNode instanceof QueryBuilderFilterTreeExistsNodeData &&
|
575
|
+
parentNode.childrenIds.length === 1
|
576
|
+
) {
|
577
|
+
filterState.newGroupConditionFromNode(
|
578
|
+
existsNode,
|
579
|
+
treeNode,
|
580
|
+
QUERY_BUILDER_GROUP_OPERATION.AND,
|
581
|
+
);
|
582
|
+
} else if (
|
583
|
+
existsNode &&
|
584
|
+
parentNode instanceof QueryBuilderFilterTreeGroupNodeData
|
585
|
+
) {
|
586
|
+
const propertyExpression1 = buildPropertyExpressionFromExistsNode(
|
587
|
+
filterState,
|
588
|
+
existsNode,
|
589
|
+
targetDropNode,
|
590
|
+
);
|
591
|
+
filterState.removeNodeAndPruneBranch(targetDropNode);
|
592
|
+
filterState.newGroupConditionFromNode(
|
593
|
+
existsNode,
|
594
|
+
treeNode,
|
595
|
+
parentNode.groupOperation,
|
596
|
+
);
|
597
|
+
const newParentNode = filterState.getParentNode(treeNode);
|
598
|
+
buildFilterTreeWithExists(
|
599
|
+
propertyExpression1,
|
600
|
+
filterState,
|
601
|
+
newParentNode,
|
602
|
+
);
|
603
|
+
} else {
|
604
|
+
filterState.newGroupWithConditionFromNode(treeNode, targetDropNode);
|
605
|
+
}
|
606
|
+
} else {
|
607
|
+
filterState.addNodeFromNode(treeNode, undefined);
|
608
|
+
}
|
392
609
|
}
|
393
610
|
};
|
394
611
|
|
@@ -604,7 +821,12 @@ const QueryBuilderFilterConditionEditor = observer(
|
|
604
821
|
};
|
605
822
|
|
606
823
|
return (
|
607
|
-
<div
|
824
|
+
<div
|
825
|
+
className="query-builder-filter-tree__node__label__content dnd__entry__container"
|
826
|
+
data-testid={
|
827
|
+
QUERY_BUILDER_TEST_ID.QUERY_BUILDER_FILTER_TREE_CONDITION_NODE_CONTENT
|
828
|
+
}
|
829
|
+
>
|
608
830
|
<PanelEntryDropZonePlaceholder
|
609
831
|
isDragOver={isDragOver}
|
610
832
|
label="Add New Logical Group"
|
@@ -845,21 +1067,17 @@ const QueryBuilderFilterTreeNodeContainer = observer(
|
|
845
1067
|
node,
|
846
1068
|
);
|
847
1069
|
} else if (node instanceof QueryBuilderFilterTreeConditionNodeData) {
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
filterConditionState,
|
852
|
-
),
|
1070
|
+
buildFilterTree(
|
1071
|
+
filterConditionState.propertyExpressionState.propertyExpression,
|
1072
|
+
filterState,
|
853
1073
|
node,
|
854
1074
|
);
|
855
1075
|
} else if (
|
856
1076
|
node instanceof QueryBuilderFilterTreeBlankConditionNodeData
|
857
1077
|
) {
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
filterConditionState,
|
862
|
-
),
|
1078
|
+
buildFilterTree(
|
1079
|
+
filterConditionState.propertyExpressionState.propertyExpression,
|
1080
|
+
filterState,
|
863
1081
|
node,
|
864
1082
|
);
|
865
1083
|
}
|
@@ -24,6 +24,12 @@ import {
|
|
24
24
|
buildSourceInformationSourceId,
|
25
25
|
ParserError,
|
26
26
|
GRAPH_MANAGER_EVENT,
|
27
|
+
SimpleFunctionExpression,
|
28
|
+
PrimitiveInstanceValue,
|
29
|
+
PrimitiveType,
|
30
|
+
extractElementNameFromPath,
|
31
|
+
SUPPORTED_FUNCTIONS,
|
32
|
+
INTERNAL__UnknownValueSpecification,
|
27
33
|
} from '@finos/legend-graph';
|
28
34
|
import {
|
29
35
|
type Hashable,
|
@@ -70,6 +76,22 @@ export abstract class QueryBuilderConstantExpressionState implements Hashable {
|
|
70
76
|
this.variable.name,
|
71
77
|
]);
|
72
78
|
}
|
79
|
+
|
80
|
+
buildLetExpression(): SimpleFunctionExpression {
|
81
|
+
const leftSide = new PrimitiveInstanceValue(
|
82
|
+
GenericTypeExplicitReference.create(
|
83
|
+
new GenericType(PrimitiveType.STRING),
|
84
|
+
),
|
85
|
+
);
|
86
|
+
leftSide.values = [this.variable.name];
|
87
|
+
const letFunc = new SimpleFunctionExpression(
|
88
|
+
extractElementNameFromPath(SUPPORTED_FUNCTIONS.LET),
|
89
|
+
);
|
90
|
+
letFunc.parametersValues = [leftSide, this.buildLetAssignmentValue()];
|
91
|
+
return letFunc;
|
92
|
+
}
|
93
|
+
|
94
|
+
abstract buildLetAssignmentValue(): ValueSpecification;
|
73
95
|
}
|
74
96
|
|
75
97
|
export class QueryBuilderSimpleConstantExpressionState
|
@@ -141,6 +163,10 @@ export class QueryBuilderSimpleConstantExpressionState
|
|
141
163
|
}
|
142
164
|
}
|
143
165
|
|
166
|
+
override buildLetAssignmentValue(): ValueSpecification {
|
167
|
+
return this.value;
|
168
|
+
}
|
169
|
+
|
144
170
|
override get hashCode(): string {
|
145
171
|
return hashArray([
|
146
172
|
QUERY_BUILDER_STATE_HASH_STRUCTURE.CONSTANT_EXPRESSION_STATE,
|
@@ -272,6 +298,10 @@ export class QueryBuilderCalculatedConstantExpressionState
|
|
272
298
|
setValue(val: PlainObject): void {
|
273
299
|
this.value = val;
|
274
300
|
}
|
301
|
+
|
302
|
+
override buildLetAssignmentValue(): ValueSpecification {
|
303
|
+
return new INTERNAL__UnknownValueSpecification(this.value);
|
304
|
+
}
|
275
305
|
}
|
276
306
|
|
277
307
|
export class QueryBuilderConstantsState implements Hashable {
|