@finos/legend-query-builder 4.18.18 → 4.18.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/components/filter/QueryBuilderFilterPanel.d.ts +7 -1
- package/lib/components/filter/QueryBuilderFilterPanel.d.ts.map +1 -1
- package/lib/components/filter/QueryBuilderFilterPanel.js +28 -2
- package/lib/components/filter/QueryBuilderFilterPanel.js.map +1 -1
- package/lib/components/shared/BasicValueSpecificationEditor.d.ts.map +1 -1
- package/lib/components/shared/BasicValueSpecificationEditor.js +16 -1
- package/lib/components/shared/BasicValueSpecificationEditor.js.map +1 -1
- package/lib/components/shared/QueryBuilderFilterHelper.d.ts.map +1 -1
- package/lib/components/shared/QueryBuilderFilterHelper.js +3 -0
- package/lib/components/shared/QueryBuilderFilterHelper.js.map +1 -1
- package/lib/data-access-overview.css +1 -1
- package/lib/index.css +1 -1
- package/lib/package.json +1 -1
- package/lib/stores/QueryBuilderStateHashUtils.d.ts +1 -0
- package/lib/stores/QueryBuilderStateHashUtils.d.ts.map +1 -1
- package/lib/stores/QueryBuilderStateHashUtils.js +1 -0
- package/lib/stores/QueryBuilderStateHashUtils.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 +11 -1
- package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterStateBuilder.js.map +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 +20 -5
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_In.js.map +1 -1
- package/lib/stores/filter/QueryBuilderFilterState.d.ts +12 -1
- package/lib/stores/filter/QueryBuilderFilterState.d.ts.map +1 -1
- package/lib/stores/filter/QueryBuilderFilterState.js +51 -0
- package/lib/stores/filter/QueryBuilderFilterState.js.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperatorValueSpecificationBuilder.d.ts.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperatorValueSpecificationBuilder.js +26 -2
- package/lib/stores/filter/operators/QueryBuilderFilterOperatorValueSpecificationBuilder.js.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_In.d.ts.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_In.js +20 -7
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_In.js.map +1 -1
- package/lib/stores/shared/ValueSpecificationEditorHelper.d.ts.map +1 -1
- package/lib/stores/shared/ValueSpecificationEditorHelper.js +22 -7
- package/lib/stores/shared/ValueSpecificationEditorHelper.js.map +1 -1
- package/package.json +10 -10
- package/src/components/filter/QueryBuilderFilterPanel.tsx +101 -0
- package/src/components/shared/BasicValueSpecificationEditor.tsx +16 -0
- package/src/components/shared/QueryBuilderFilterHelper.ts +4 -0
- package/src/stores/QueryBuilderStateHashUtils.ts +1 -0
- package/src/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterStateBuilder.ts +22 -0
- package/src/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_In.ts +25 -4
- package/src/stores/filter/QueryBuilderFilterState.ts +87 -1
- package/src/stores/filter/operators/QueryBuilderFilterOperatorValueSpecificationBuilder.ts +43 -0
- package/src/stores/filter/operators/QueryBuilderFilterOperator_In.ts +25 -10
- package/src/stores/shared/ValueSpecificationEditorHelper.ts +22 -6
|
@@ -93,7 +93,8 @@ export type QueryBuilderFilterNodeDropTarget =
|
|
|
93
93
|
export type QueryBuilderFilterValueDropTarget =
|
|
94
94
|
| QueryBuilderVariableDragSource
|
|
95
95
|
| QueryBuilderProjectionColumnDragSource
|
|
96
|
-
| QueryBuilderExplorerTreeDragSource
|
|
96
|
+
| QueryBuilderExplorerTreeDragSource
|
|
97
|
+
| QueryBuilderExplorerTreeRelationColumnDragSource;
|
|
97
98
|
|
|
98
99
|
export type QueryBuilderFilterConditionRearrangeDropTarget =
|
|
99
100
|
QueryBuilderFilterConditionDragSource;
|
|
@@ -237,6 +238,64 @@ export class FilterPropertyExpressionStateConditionValueState extends FilterCond
|
|
|
237
238
|
}
|
|
238
239
|
}
|
|
239
240
|
|
|
241
|
+
// This class is used to represent the value of a filter condition when the value is
|
|
242
|
+
// a relation column accessor (which comes from DND a relation column from the explorer
|
|
243
|
+
// tree or from the fetch structure panel). Used when the filter source is also a
|
|
244
|
+
// relation column, allowing expressions like `$x.colA == $x.colB`.
|
|
245
|
+
export class FilterRelationColumnConditionValueState extends FilterConditionValueState {
|
|
246
|
+
columnName: string;
|
|
247
|
+
columnType: Type;
|
|
248
|
+
columnMultiplicity: Multiplicity;
|
|
249
|
+
|
|
250
|
+
constructor(
|
|
251
|
+
conditionState: FilterConditionState,
|
|
252
|
+
columnName: string,
|
|
253
|
+
columnType: Type,
|
|
254
|
+
columnMultiplicity: Multiplicity,
|
|
255
|
+
) {
|
|
256
|
+
super(conditionState);
|
|
257
|
+
makeObservable(this, {
|
|
258
|
+
columnName: observable,
|
|
259
|
+
columnType: observable,
|
|
260
|
+
columnMultiplicity: observable,
|
|
261
|
+
changeColumn: action,
|
|
262
|
+
});
|
|
263
|
+
this.columnName = columnName;
|
|
264
|
+
this.columnType = columnType;
|
|
265
|
+
this.columnMultiplicity = columnMultiplicity;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
override get type(): Type {
|
|
269
|
+
return this.columnType;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
override get isCollection(): boolean {
|
|
273
|
+
return (
|
|
274
|
+
this.columnMultiplicity.upperBound === undefined ||
|
|
275
|
+
this.columnMultiplicity.upperBound > 1
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
changeColumn(
|
|
280
|
+
columnName: string,
|
|
281
|
+
columnType: Type,
|
|
282
|
+
columnMultiplicity: Multiplicity,
|
|
283
|
+
): void {
|
|
284
|
+
this.columnName = columnName;
|
|
285
|
+
this.columnType = columnType;
|
|
286
|
+
this.columnMultiplicity = columnMultiplicity;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
override get hashCode(): string {
|
|
290
|
+
return hashArray([
|
|
291
|
+
QUERY_BUILDER_STATE_HASH_STRUCTURE.FILTER_CONDITION_RIGHT_VALUE_RELATION_COLUMN,
|
|
292
|
+
this.columnName,
|
|
293
|
+
this.columnMultiplicity.lowerBound,
|
|
294
|
+
this.columnMultiplicity.upperBound ?? '',
|
|
295
|
+
]);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
240
299
|
/**
|
|
241
300
|
* Abstract base class for the left-hand side (source) of a filter condition.
|
|
242
301
|
* This allows filtering on different source types (class properties, relation columns)
|
|
@@ -403,6 +462,7 @@ export class FilterConditionState implements Hashable {
|
|
|
403
462
|
addExistsLambdaParamNames: action,
|
|
404
463
|
buildRightConditionValueFromValueSpec: action,
|
|
405
464
|
buildRightConditionValueFromPropertyExpressionState: action,
|
|
465
|
+
buildRightConditionValueFromRelationColumn: action,
|
|
406
466
|
handleTypeaheadSearch: flow,
|
|
407
467
|
operators: computed,
|
|
408
468
|
hashCode: computed,
|
|
@@ -582,6 +642,32 @@ export class FilterConditionState implements Hashable {
|
|
|
582
642
|
}
|
|
583
643
|
}
|
|
584
644
|
|
|
645
|
+
buildRightConditionValueFromRelationColumn(
|
|
646
|
+
columnName: string,
|
|
647
|
+
columnType: Type,
|
|
648
|
+
columnMultiplicity: Multiplicity,
|
|
649
|
+
): void {
|
|
650
|
+
if (
|
|
651
|
+
this.rightConditionValue instanceof
|
|
652
|
+
FilterRelationColumnConditionValueState
|
|
653
|
+
) {
|
|
654
|
+
this.rightConditionValue.changeColumn(
|
|
655
|
+
columnName,
|
|
656
|
+
columnType,
|
|
657
|
+
columnMultiplicity,
|
|
658
|
+
);
|
|
659
|
+
} else {
|
|
660
|
+
this.setRightConditionValue(
|
|
661
|
+
new FilterRelationColumnConditionValueState(
|
|
662
|
+
this,
|
|
663
|
+
columnName,
|
|
664
|
+
columnType,
|
|
665
|
+
columnMultiplicity,
|
|
666
|
+
),
|
|
667
|
+
);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
|
|
585
671
|
get hashCode(): string {
|
|
586
672
|
return hashArray([
|
|
587
673
|
QUERY_BUILDER_STATE_HASH_STRUCTURE.FILTER_CONDITION_STATE,
|
|
@@ -24,11 +24,14 @@ import {
|
|
|
24
24
|
LambdaFunction,
|
|
25
25
|
FunctionExpression,
|
|
26
26
|
RelationColumn,
|
|
27
|
+
Multiplicity,
|
|
28
|
+
VariableExpression,
|
|
27
29
|
} from '@finos/legend-graph';
|
|
28
30
|
import { guaranteeType, assertTrue } from '@finos/legend-shared';
|
|
29
31
|
import {
|
|
30
32
|
FilterConditionState,
|
|
31
33
|
FilterPropertyExpressionStateConditionValueState,
|
|
34
|
+
FilterRelationColumnConditionValueState,
|
|
32
35
|
FilterRelationColumnSourceState,
|
|
33
36
|
FilterValueSpecConditionValueState,
|
|
34
37
|
type QueryBuilderFilterState,
|
|
@@ -76,6 +79,33 @@ export const buildFilterConditionExpression = (
|
|
|
76
79
|
resolvedLambdaParameterName,
|
|
77
80
|
);
|
|
78
81
|
expression.parametersValues.push(rightConditionPropertyExpression);
|
|
82
|
+
} else if (
|
|
83
|
+
filterConditionState.rightConditionValue &&
|
|
84
|
+
filterConditionState.rightConditionValue instanceof
|
|
85
|
+
FilterRelationColumnConditionValueState
|
|
86
|
+
) {
|
|
87
|
+
const rightValue = filterConditionState.rightConditionValue;
|
|
88
|
+
const relationType =
|
|
89
|
+
filterConditionState.filterState.queryBuilderState.sourceRelationType;
|
|
90
|
+
if (!relationType) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
`Can't build expression for relation column '${rightValue.columnName}': no source relation type`,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
const col = relationType.columns.find(
|
|
96
|
+
(c) => c.name === rightValue.columnName,
|
|
97
|
+
);
|
|
98
|
+
if (!col) {
|
|
99
|
+
throw new Error(
|
|
100
|
+
`Can't find column '${rightValue.columnName}' in relation`,
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
const colFuncExp = new FunctionExpression(col.name);
|
|
104
|
+
colFuncExp.func = col;
|
|
105
|
+
colFuncExp.parametersValues = [
|
|
106
|
+
new VariableExpression(resolvedLambdaParameterName, Multiplicity.ONE),
|
|
107
|
+
];
|
|
108
|
+
expression.parametersValues.push(colFuncExp);
|
|
79
109
|
}
|
|
80
110
|
return expression;
|
|
81
111
|
};
|
|
@@ -221,6 +251,19 @@ export const buildFilterConditionState = (
|
|
|
221
251
|
),
|
|
222
252
|
),
|
|
223
253
|
);
|
|
254
|
+
} else if (
|
|
255
|
+
value instanceof FunctionExpression &&
|
|
256
|
+
value.func instanceof RelationColumn
|
|
257
|
+
) {
|
|
258
|
+
const col = value.func;
|
|
259
|
+
filterConditionState.setRightConditionValue(
|
|
260
|
+
new FilterRelationColumnConditionValueState(
|
|
261
|
+
filterConditionState,
|
|
262
|
+
col.name,
|
|
263
|
+
col.genericType.value.rawType,
|
|
264
|
+
col.multiplicity,
|
|
265
|
+
),
|
|
266
|
+
);
|
|
224
267
|
} else {
|
|
225
268
|
filterConditionState.setRightConditionValue(
|
|
226
269
|
new FilterValueSpecConditionValueState(
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
GenericTypeExplicitReference,
|
|
29
29
|
GenericType,
|
|
30
30
|
Enumeration,
|
|
31
|
+
getPrimitiveTypeInstanceFromEnum,
|
|
31
32
|
PRIMITIVE_TYPE,
|
|
32
33
|
Multiplicity,
|
|
33
34
|
} from '@finos/legend-graph';
|
|
@@ -97,6 +98,15 @@ export class QueryBuilderFilterOperator_In
|
|
|
97
98
|
if (!collectionType) {
|
|
98
99
|
return false;
|
|
99
100
|
}
|
|
101
|
+
// Compare standard primitive equivalents so columns declared with a
|
|
102
|
+
// precise primitive type (e.g. accessor relation columns: Varchar,
|
|
103
|
+
// BigInt, Timestamp) are still recognized as compatible with the
|
|
104
|
+
// standard primitives stored in the value collection.
|
|
105
|
+
const normalizedPropertyTypePath =
|
|
106
|
+
getStandardPrimitiveTypeEquivalent(propertyType) ?? propertyType.path;
|
|
107
|
+
const normalizedCollectionTypePath =
|
|
108
|
+
getStandardPrimitiveTypeEquivalent(collectionType) ??
|
|
109
|
+
collectionType.path;
|
|
100
110
|
if (
|
|
101
111
|
(
|
|
102
112
|
[
|
|
@@ -108,10 +118,7 @@ export class QueryBuilderFilterOperator_In
|
|
|
108
118
|
PRIMITIVE_TYPE.STRICTDATE,
|
|
109
119
|
PRIMITIVE_TYPE.DATETIME,
|
|
110
120
|
] as string[]
|
|
111
|
-
).includes(
|
|
112
|
-
getStandardPrimitiveTypeEquivalent(propertyType) ??
|
|
113
|
-
propertyType.path,
|
|
114
|
-
)
|
|
121
|
+
).includes(normalizedPropertyTypePath)
|
|
115
122
|
) {
|
|
116
123
|
return (
|
|
117
124
|
[
|
|
@@ -123,12 +130,12 @@ export class QueryBuilderFilterOperator_In
|
|
|
123
130
|
PRIMITIVE_TYPE.STRICTDATE,
|
|
124
131
|
PRIMITIVE_TYPE.DATETIME,
|
|
125
132
|
] as string[]
|
|
126
|
-
).includes(
|
|
127
|
-
getStandardPrimitiveTypeEquivalent(collectionType) ??
|
|
128
|
-
collectionType.path,
|
|
129
|
-
);
|
|
133
|
+
).includes(normalizedCollectionTypePath);
|
|
130
134
|
}
|
|
131
|
-
return
|
|
135
|
+
return (
|
|
136
|
+
collectionType === propertyType ||
|
|
137
|
+
normalizedPropertyTypePath === normalizedCollectionTypePath
|
|
138
|
+
);
|
|
132
139
|
} else if (valueSpec instanceof VariableExpression) {
|
|
133
140
|
// check if not a single value
|
|
134
141
|
if (valueSpec.multiplicity.upperBound === 1) {
|
|
@@ -144,9 +151,17 @@ export class QueryBuilderFilterOperator_In
|
|
|
144
151
|
filterConditionState: FilterConditionState,
|
|
145
152
|
): ValueSpecification | undefined {
|
|
146
153
|
const propertyType = filterConditionState.leftConditionType;
|
|
154
|
+
// Normalize precise primitive types (e.g. Varchar, BigInt) to their
|
|
155
|
+
// standard equivalent so the collection's generic type matches the
|
|
156
|
+
// standard primitive values that downstream editors produce.
|
|
157
|
+
const standardPrimitive = getStandardPrimitiveTypeEquivalent(propertyType);
|
|
158
|
+
const collectionType =
|
|
159
|
+
standardPrimitive !== undefined
|
|
160
|
+
? getPrimitiveTypeInstanceFromEnum(standardPrimitive)
|
|
161
|
+
: propertyType;
|
|
147
162
|
return new CollectionInstanceValue(
|
|
148
163
|
Multiplicity.ONE,
|
|
149
|
-
GenericTypeExplicitReference.create(new GenericType(
|
|
164
|
+
GenericTypeExplicitReference.create(new GenericType(collectionType)),
|
|
150
165
|
);
|
|
151
166
|
}
|
|
152
167
|
|
|
@@ -30,7 +30,9 @@ import {
|
|
|
30
30
|
GenericType,
|
|
31
31
|
GenericTypeExplicitReference,
|
|
32
32
|
getEnumValue,
|
|
33
|
+
getPrimitiveTypeInstanceFromEnum,
|
|
33
34
|
PrimitiveInstanceValue,
|
|
35
|
+
PrecisePrimitiveType,
|
|
34
36
|
PrimitiveType,
|
|
35
37
|
PRIMITIVE_TYPE,
|
|
36
38
|
INTERNAL__PropagatedValue,
|
|
@@ -484,11 +486,25 @@ export const convertTextToPrimitiveInstanceValue = (
|
|
|
484
486
|
observerContext: ObserverContext,
|
|
485
487
|
): PrimitiveInstanceValue | null => {
|
|
486
488
|
let result = null;
|
|
489
|
+
// Normalize precise primitive types (e.g. Varchar, BigInt, Timestamp) to
|
|
490
|
+
// their standard primitive equivalent so values entered through the editor
|
|
491
|
+
// are stored as standard PrimitiveInstanceValue regardless of whether the
|
|
492
|
+
// source column was declared with a precise type (e.g. accessor relation
|
|
493
|
+
// columns).
|
|
494
|
+
let resolvedType: PrimitiveType | undefined;
|
|
487
495
|
if (expectedType instanceof PrimitiveType) {
|
|
488
|
-
|
|
496
|
+
resolvedType = expectedType;
|
|
497
|
+
} else if (expectedType instanceof PrecisePrimitiveType) {
|
|
498
|
+
const standard = getStandardPrimitiveTypeEquivalent(expectedType);
|
|
499
|
+
resolvedType = standard
|
|
500
|
+
? getPrimitiveTypeInstanceFromEnum(standard)
|
|
501
|
+
: undefined;
|
|
502
|
+
}
|
|
503
|
+
if (resolvedType) {
|
|
504
|
+
switch (resolvedType.path) {
|
|
489
505
|
case PRIMITIVE_TYPE.STRING: {
|
|
490
506
|
result = new PrimitiveInstanceValue(
|
|
491
|
-
GenericTypeExplicitReference.create(new GenericType(
|
|
507
|
+
GenericTypeExplicitReference.create(new GenericType(resolvedType)),
|
|
492
508
|
);
|
|
493
509
|
instanceValue_setValues(result, [value.toString()], observerContext);
|
|
494
510
|
break;
|
|
@@ -501,11 +517,11 @@ export const convertTextToPrimitiveInstanceValue = (
|
|
|
501
517
|
return null;
|
|
502
518
|
}
|
|
503
519
|
const formattedNumber =
|
|
504
|
-
|
|
520
|
+
resolvedType.path === PRIMITIVE_TYPE.INTEGER
|
|
505
521
|
? Number.parseInt(Number(value).toString(), 10)
|
|
506
522
|
: Number(value);
|
|
507
523
|
result = new PrimitiveInstanceValue(
|
|
508
|
-
GenericTypeExplicitReference.create(new GenericType(
|
|
524
|
+
GenericTypeExplicitReference.create(new GenericType(resolvedType)),
|
|
509
525
|
);
|
|
510
526
|
instanceValue_setValues(result, [formattedNumber], observerContext);
|
|
511
527
|
break;
|
|
@@ -516,7 +532,7 @@ export const convertTextToPrimitiveInstanceValue = (
|
|
|
516
532
|
return null;
|
|
517
533
|
}
|
|
518
534
|
result = new PrimitiveInstanceValue(
|
|
519
|
-
GenericTypeExplicitReference.create(new GenericType(
|
|
535
|
+
GenericTypeExplicitReference.create(new GenericType(resolvedType)),
|
|
520
536
|
);
|
|
521
537
|
instanceValue_setValues(result, [value], observerContext);
|
|
522
538
|
break;
|
|
@@ -532,7 +548,7 @@ export const convertTextToPrimitiveInstanceValue = (
|
|
|
532
548
|
return null;
|
|
533
549
|
}
|
|
534
550
|
result = new PrimitiveInstanceValue(
|
|
535
|
-
GenericTypeExplicitReference.create(new GenericType(
|
|
551
|
+
GenericTypeExplicitReference.create(new GenericType(resolvedType)),
|
|
536
552
|
);
|
|
537
553
|
instanceValue_setValues(result, [value], observerContext);
|
|
538
554
|
break;
|