@finos/legend-query-builder 4.1.15 → 4.2.0
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 +6 -1
- package/lib/components/filter/QueryBuilderFilterPanel.d.ts.map +1 -1
- package/lib/components/filter/QueryBuilderFilterPanel.js +189 -13
- package/lib/components/filter/QueryBuilderFilterPanel.js.map +1 -1
- package/lib/index.css +2 -2
- package/lib/index.css.map +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/filter/QueryBuilderFilterOperator.d.ts +1 -1
- package/lib/stores/filter/QueryBuilderFilterOperator.d.ts.map +1 -1
- package/lib/stores/filter/QueryBuilderFilterOperator.js.map +1 -1
- package/lib/stores/filter/QueryBuilderFilterState.d.ts +16 -5
- package/lib/stores/filter/QueryBuilderFilterState.d.ts.map +1 -1
- package/lib/stores/filter/QueryBuilderFilterState.js +78 -18
- package/lib/stores/filter/QueryBuilderFilterState.js.map +1 -1
- package/lib/stores/filter/QueryBuilderFilterStateBuilder.d.ts.map +1 -1
- package/lib/stores/filter/QueryBuilderFilterStateBuilder.js +125 -2
- package/lib/stores/filter/QueryBuilderFilterStateBuilder.js.map +1 -1
- package/lib/stores/filter/QueryBuilderFilterValueSpecificationBuilder.d.ts.map +1 -1
- package/lib/stores/filter/QueryBuilderFilterValueSpecificationBuilder.js +62 -3
- package/lib/stores/filter/QueryBuilderFilterValueSpecificationBuilder.js.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperatorValueSpecificationBuilder.d.ts +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperatorValueSpecificationBuilder.d.ts.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperatorValueSpecificationBuilder.js +12 -192
- package/lib/stores/filter/operators/QueryBuilderFilterOperatorValueSpecificationBuilder.js.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_Contain.d.ts +2 -2
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_Contain.d.ts.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_Contain.js +4 -4
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_Contain.js.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_EndWith.d.ts +2 -2
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_EndWith.d.ts.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_EndWith.js +4 -4
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_EndWith.js.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_Equal.d.ts +2 -2
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_Equal.d.ts.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_Equal.js +4 -4
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_Equal.js.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThan.d.ts +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThan.d.ts.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThan.js +2 -2
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThan.js.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThanEqual.d.ts +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThanEqual.d.ts.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThanEqual.js +2 -2
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_GreaterThanEqual.js.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_In.d.ts +2 -2
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_In.d.ts.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_In.js +4 -4
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_In.js.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_IsEmpty.d.ts +2 -2
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_IsEmpty.d.ts.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_IsEmpty.js +4 -4
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_IsEmpty.js.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThan.d.ts +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThan.d.ts.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThan.js +2 -2
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThan.js.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThanEqual.d.ts +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThanEqual.d.ts.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThanEqual.js +2 -2
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_LessThanEqual.js.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_StartWith.d.ts +2 -2
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_StartWith.d.ts.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_StartWith.js +4 -4
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_StartWith.js.map +1 -1
- package/package.json +1 -1
- package/src/components/filter/QueryBuilderFilterPanel.tsx +355 -24
- package/src/stores/QueryBuilderStateHashUtils.ts +1 -0
- package/src/stores/filter/QueryBuilderFilterOperator.ts +1 -0
- package/src/stores/filter/QueryBuilderFilterState.ts +115 -27
- package/src/stores/filter/QueryBuilderFilterStateBuilder.ts +244 -0
- package/src/stores/filter/QueryBuilderFilterValueSpecificationBuilder.ts +94 -1
- package/src/stores/filter/operators/QueryBuilderFilterOperatorValueSpecificationBuilder.ts +37 -377
- package/src/stores/filter/operators/QueryBuilderFilterOperator_Contain.ts +7 -1
- package/src/stores/filter/operators/QueryBuilderFilterOperator_EndWith.ts +7 -1
- package/src/stores/filter/operators/QueryBuilderFilterOperator_Equal.ts +7 -1
- package/src/stores/filter/operators/QueryBuilderFilterOperator_GreaterThan.ts +2 -0
- package/src/stores/filter/operators/QueryBuilderFilterOperator_GreaterThanEqual.ts +2 -0
- package/src/stores/filter/operators/QueryBuilderFilterOperator_In.ts +7 -1
- package/src/stores/filter/operators/QueryBuilderFilterOperator_IsEmpty.ts +7 -1
- package/src/stores/filter/operators/QueryBuilderFilterOperator_LessThan.ts +2 -0
- package/src/stores/filter/operators/QueryBuilderFilterOperator_LessThanEqual.ts +2 -0
- package/src/stores/filter/operators/QueryBuilderFilterOperator_StartWith.ts +7 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryBuilderFilterOperator_StartWith.js","sourceRoot":"","sources":["../../../../src/stores/filter/operators/QueryBuilderFilterOperator_StartWith.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,OAAO,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AAC9E,OAAO,EACL,cAAc,EAGd,aAAa,GACd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEL,yBAAyB,EACzB,SAAS,GACV,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,yBAAyB,EACzB,8BAA8B,GAC/B,MAAM,0DAA0D,CAAC;AAClE,OAAO,EAAE,iCAAiC,EAAE,MAAM,8CAA8C,CAAC;AACjG,OAAO,EACL,kBAAkB,EAClB,oCAAoC,EACpC,sCAAsC,EACtC,mBAAmB,GACpB,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAAE,kCAAkC,EAAE,MAAM,qCAAqC,CAAC;AACzF,OAAO,EAAE,2BAA2B,EAAE,MAAM,gDAAgD,CAAC;AAE7F,MAAM,OAAO,oCACX,SAAQ,0BAA0B;IAGlC,QAAQ,CAAC,oBAA0C;QACjD,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,uCAAuC,CACrC,oBAA0C;QAE1C,OAAO,CACL,aAAa,CAAC,MAAM;YACpB,oBAAoB,CAAC,uBAAuB,CAAC,kBAAkB,CAAC,IAAI,CAAC,KAAK;iBACvE,WAAW,CAAC,KAAK,CAAC,OAAO,CAC7B,CAAC;IACJ,CAAC;IAED,oCAAoC,CAClC,oBAA0C;QAE1C,MAAM,IAAI,GAAG,oBAAoB,CAAC,KAAK;YACrC,CAAC,CAAC,sCAAsC,CAAC,oBAAoB,CAAC,KAAK,CAAC;YACpE,CAAC,CAAC,SAAS,CAAC;QACd,OAAO,aAAa,CAAC,MAAM,KAAK,IAAI,CAAC;IACvC,CAAC;IAED,8BAA8B,CAC5B,oBAA0C;QAE1C,MAAM,YAAY,GAChB,oBAAoB,CAAC,uBAAuB,CAAC,kBAAkB,CAAC,IAAI,CAAC,KAAK;aACvE,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC;QAC/B,QAAQ,YAAY,CAAC,IAAI,EAAE;YACzB,KAAK,cAAc,CAAC,MAAM,CAAC,CAAC;gBAC1B,OAAO,2BAA2B,CAChC,oBAAoB,CAAC,WAAW,CAAC,iBAAiB,CAAC,iBAAiB;qBACjE,KAAK,EACR,YAAY,CAAC,IAAI,EACjB,oCAAoC,CAAC,YAAY,CAAC,IAAI,CAAC,EACvD,oBAAoB,CAAC,WAAW,CAAC,iBAAiB,CAAC,eAAe,CACnE,CAAC;aACH;YACD;gBACE,MAAM,IAAI,yBAAyB,CACjC,gDAAgD,IAAI,CAAC,QAAQ,CAC3D,oBAAoB,CACrB,uCAAuC,YAAY,CAAC,IAAI,GAAG,CAC7D,CAAC;SACL;IACH,CAAC;IAED,8BAA8B,CAC5B,oBAA0C;
|
|
1
|
+
{"version":3,"file":"QueryBuilderFilterOperator_StartWith.js","sourceRoot":"","sources":["../../../../src/stores/filter/operators/QueryBuilderFilterOperator_StartWith.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -55,6 +55,9 @@ import {
|
|
|
55
55
|
QueryBuilderFilterTreeConditionNodeData,
|
|
56
56
|
QueryBuilderFilterTreeBlankConditionNodeData,
|
|
57
57
|
QueryBuilderFilterTreeGroupNodeData,
|
|
58
|
+
QueryBuilderFilterTreeExistsNodeData,
|
|
59
|
+
QueryBuilderFilterTreeOperationNodeData,
|
|
60
|
+
type QueryBuilderFilterState,
|
|
58
61
|
} from '../../stores/filter/QueryBuilderFilterState.js';
|
|
59
62
|
import { useDrag, useDragLayer, useDrop } from 'react-dnd';
|
|
60
63
|
import {
|
|
@@ -67,12 +70,29 @@ import { QueryBuilderPropertyExpressionBadge } from '../QueryBuilderPropertyExpr
|
|
|
67
70
|
import type { QueryBuilderState } from '../../stores/QueryBuilderState.js';
|
|
68
71
|
import {
|
|
69
72
|
assertErrorThrown,
|
|
73
|
+
assertTrue,
|
|
70
74
|
debounce,
|
|
75
|
+
generateEnumerableNameFromToken,
|
|
76
|
+
getNullableFirstEntry,
|
|
77
|
+
guaranteeNonNullable,
|
|
78
|
+
guaranteeType,
|
|
71
79
|
UnsupportedOperationError,
|
|
72
80
|
} from '@finos/legend-shared';
|
|
73
81
|
import { QUERY_BUILDER_TEST_ID } from '../../__lib__/QueryBuilderTesting.js';
|
|
74
|
-
import {
|
|
75
|
-
|
|
82
|
+
import {
|
|
83
|
+
ActionAlertActionType,
|
|
84
|
+
ActionAlertType,
|
|
85
|
+
useApplicationStore,
|
|
86
|
+
} from '@finos/legend-application';
|
|
87
|
+
import {
|
|
88
|
+
AbstractPropertyExpression,
|
|
89
|
+
extractElementNameFromPath,
|
|
90
|
+
matchFunctionName,
|
|
91
|
+
Multiplicity,
|
|
92
|
+
SimpleFunctionExpression,
|
|
93
|
+
type ValueSpecification,
|
|
94
|
+
VariableExpression,
|
|
95
|
+
} from '@finos/legend-graph';
|
|
76
96
|
import {
|
|
77
97
|
type QueryBuilderProjectionColumnDragSource,
|
|
78
98
|
QueryBuilderSimpleProjectionColumnState,
|
|
@@ -87,6 +107,282 @@ import {
|
|
|
87
107
|
QUERY_BUILDER_VARIABLE_DND_TYPE,
|
|
88
108
|
} from '../shared/BasicValueSpecificationEditor.js';
|
|
89
109
|
import { QueryBuilderTelemetryHelper } from '../../__lib__/QueryBuilderTelemetryHelper.js';
|
|
110
|
+
import { getPropertyChainName } from '../../stores/QueryBuilderPropertyEditorState.js';
|
|
111
|
+
import { QUERY_BUILDER_SUPPORTED_FUNCTIONS } from '../../graph/QueryBuilderMetaModelConst.js';
|
|
112
|
+
|
|
113
|
+
const isCollectionProperty = (
|
|
114
|
+
propertyExpression: AbstractPropertyExpression,
|
|
115
|
+
): boolean => {
|
|
116
|
+
let currentExpression: ValueSpecification | undefined = propertyExpression;
|
|
117
|
+
while (currentExpression instanceof AbstractPropertyExpression) {
|
|
118
|
+
// Check if the property chain can results in column that have multiple values
|
|
119
|
+
if (
|
|
120
|
+
currentExpression.func.value.multiplicity.upperBound === undefined ||
|
|
121
|
+
currentExpression.func.value.multiplicity.upperBound > 1
|
|
122
|
+
) {
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
currentExpression = getNullableFirstEntry(
|
|
126
|
+
currentExpression.parametersValues,
|
|
127
|
+
);
|
|
128
|
+
// Take care of chains of subtype
|
|
129
|
+
while (
|
|
130
|
+
currentExpression instanceof SimpleFunctionExpression &&
|
|
131
|
+
matchFunctionName(
|
|
132
|
+
currentExpression.functionName,
|
|
133
|
+
QUERY_BUILDER_SUPPORTED_FUNCTIONS.SUBTYPE,
|
|
134
|
+
)
|
|
135
|
+
) {
|
|
136
|
+
currentExpression = getNullableFirstEntry(
|
|
137
|
+
currentExpression.parametersValues,
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return false;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* This function updates the filter state when we DnD a property that can accept multiple values.
|
|
146
|
+
*/
|
|
147
|
+
export const buildFilterTreeWithExists = (
|
|
148
|
+
propertyExpression: AbstractPropertyExpression,
|
|
149
|
+
filterState: QueryBuilderFilterState,
|
|
150
|
+
targetDropNode?: QueryBuilderFilterTreeOperationNodeData,
|
|
151
|
+
): void => {
|
|
152
|
+
// 1. Decompose property expression
|
|
153
|
+
const expressions: (AbstractPropertyExpression | SimpleFunctionExpression)[] =
|
|
154
|
+
[];
|
|
155
|
+
let currentPropertyExpression: ValueSpecification = propertyExpression;
|
|
156
|
+
while (
|
|
157
|
+
currentPropertyExpression instanceof AbstractPropertyExpression ||
|
|
158
|
+
(currentPropertyExpression instanceof SimpleFunctionExpression &&
|
|
159
|
+
matchFunctionName(
|
|
160
|
+
currentPropertyExpression.functionName,
|
|
161
|
+
QUERY_BUILDER_SUPPORTED_FUNCTIONS.SUBTYPE,
|
|
162
|
+
))
|
|
163
|
+
) {
|
|
164
|
+
let exp: AbstractPropertyExpression | SimpleFunctionExpression;
|
|
165
|
+
if (currentPropertyExpression instanceof SimpleFunctionExpression) {
|
|
166
|
+
exp = new SimpleFunctionExpression(
|
|
167
|
+
extractElementNameFromPath(QUERY_BUILDER_SUPPORTED_FUNCTIONS.SUBTYPE),
|
|
168
|
+
);
|
|
169
|
+
} else {
|
|
170
|
+
exp = new AbstractPropertyExpression('');
|
|
171
|
+
exp.func = currentPropertyExpression.func;
|
|
172
|
+
}
|
|
173
|
+
// NOTE: we must retain the rest of the parameters as those are derived property parameters
|
|
174
|
+
exp.parametersValues =
|
|
175
|
+
currentPropertyExpression.parametersValues.length > 1
|
|
176
|
+
? currentPropertyExpression.parametersValues.slice(1)
|
|
177
|
+
: [];
|
|
178
|
+
expressions.push(exp);
|
|
179
|
+
currentPropertyExpression = guaranteeNonNullable(
|
|
180
|
+
currentPropertyExpression.parametersValues[0],
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
const rootVariable = guaranteeType(
|
|
184
|
+
currentPropertyExpression,
|
|
185
|
+
VariableExpression,
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
// 2. Traverse the list of decomposed property expression backward, every time we encounter a property of
|
|
189
|
+
// multiplicity many, create a new property expression and keep track of it to later form the lambda chain
|
|
190
|
+
let existsLambdaParamNames: string[] = [];
|
|
191
|
+
let existsLambdaPropertyChains: ValueSpecification[] = [rootVariable];
|
|
192
|
+
let currentParamNameIndex = 0;
|
|
193
|
+
|
|
194
|
+
for (let i = expressions.length - 1; i >= 0; --i) {
|
|
195
|
+
const exp = expressions[i] as
|
|
196
|
+
| AbstractPropertyExpression
|
|
197
|
+
| SimpleFunctionExpression;
|
|
198
|
+
// just keep adding to the property chain
|
|
199
|
+
exp.parametersValues.unshift(
|
|
200
|
+
existsLambdaPropertyChains[
|
|
201
|
+
existsLambdaPropertyChains.length - 1
|
|
202
|
+
] as ValueSpecification,
|
|
203
|
+
);
|
|
204
|
+
existsLambdaPropertyChains[existsLambdaPropertyChains.length - 1] = exp;
|
|
205
|
+
// ... but if the property is of multiplicity multiple, start a new property chain
|
|
206
|
+
if (
|
|
207
|
+
exp instanceof AbstractPropertyExpression &&
|
|
208
|
+
(exp.func.value.multiplicity.upperBound === undefined ||
|
|
209
|
+
exp.func.value.multiplicity.upperBound > 1)
|
|
210
|
+
) {
|
|
211
|
+
// NOTE: we need to find/generate the property chain variable name
|
|
212
|
+
if (currentParamNameIndex > existsLambdaParamNames.length - 1) {
|
|
213
|
+
existsLambdaParamNames.push(
|
|
214
|
+
generateEnumerableNameFromToken(
|
|
215
|
+
existsLambdaParamNames,
|
|
216
|
+
filterState.lambdaParameterName,
|
|
217
|
+
),
|
|
218
|
+
);
|
|
219
|
+
assertTrue(currentParamNameIndex === existsLambdaParamNames.length - 1);
|
|
220
|
+
}
|
|
221
|
+
existsLambdaPropertyChains.push(
|
|
222
|
+
new VariableExpression(
|
|
223
|
+
existsLambdaParamNames[currentParamNameIndex] as string,
|
|
224
|
+
Multiplicity.ONE,
|
|
225
|
+
),
|
|
226
|
+
);
|
|
227
|
+
currentParamNameIndex++;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
let parentNode: QueryBuilderFilterTreeOperationNodeData | undefined =
|
|
231
|
+
undefined;
|
|
232
|
+
if (targetDropNode) {
|
|
233
|
+
if (targetDropNode instanceof QueryBuilderFilterTreeExistsNodeData) {
|
|
234
|
+
// Here we check if the target drop node is an exists tree node, if it is
|
|
235
|
+
// then we try to check in the lambda property chains that it contains the
|
|
236
|
+
// property expression of the target drop node. If we find any lambda property
|
|
237
|
+
// chain we just create exists filter for the rest of the property and add it to the
|
|
238
|
+
// target drop exists node, otherwise we just create exists for all the property chains.
|
|
239
|
+
// For example if we find property chain we create
|
|
240
|
+
// employees->exists($x.name == 'Bob' && $x.id == '1') instead of creating
|
|
241
|
+
// employess->exists($x.name == 'Bob) && employess->exists($x.id == '1')
|
|
242
|
+
const parentPropertyChainIndex = existsLambdaPropertyChains.findIndex(
|
|
243
|
+
(p) =>
|
|
244
|
+
p instanceof AbstractPropertyExpression &&
|
|
245
|
+
p.func.value === targetDropNode.propertyExpression.func.value &&
|
|
246
|
+
p.func.ownerReference.value.path ===
|
|
247
|
+
targetDropNode.propertyExpression.func.ownerReference.value.path,
|
|
248
|
+
);
|
|
249
|
+
if (parentPropertyChainIndex >= 0) {
|
|
250
|
+
parentNode = targetDropNode;
|
|
251
|
+
existsLambdaPropertyChains = existsLambdaPropertyChains.slice(
|
|
252
|
+
parentPropertyChainIndex + 1,
|
|
253
|
+
);
|
|
254
|
+
existsLambdaParamNames = existsLambdaParamNames.slice(
|
|
255
|
+
parentPropertyChainIndex + 1,
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
} else {
|
|
259
|
+
// Here the target drop node is a group operation tree node. So we try to find if there is
|
|
260
|
+
// any exists tree parent node of the target drop node. If there is any exists parent node,
|
|
261
|
+
// we try to check in the lambda property chains that it contains the
|
|
262
|
+
// property expression of the target drop node. If we find any lambda property
|
|
263
|
+
// chain we just create exists filter for the rest of the property and add it to the
|
|
264
|
+
// target drop exists node, otherwise we just create exists for all the property chains.
|
|
265
|
+
// For example if we find property chain we create
|
|
266
|
+
// employees->exists($x.name == 'Bob' && $x.id == '1' && $x.age == '30) instead of creating
|
|
267
|
+
// employess->exists($x.name == 'Bob) && employess->exists($x.id == '1') && employess->exists($x.age == '30')
|
|
268
|
+
let cn: QueryBuilderFilterTreeNodeData | undefined = targetDropNode;
|
|
269
|
+
let parentId = targetDropNode.parentId;
|
|
270
|
+
while (
|
|
271
|
+
parentId &&
|
|
272
|
+
!(cn instanceof QueryBuilderFilterTreeExistsNodeData)
|
|
273
|
+
) {
|
|
274
|
+
cn = filterState.nodes.get(parentId);
|
|
275
|
+
parentId = cn?.parentId;
|
|
276
|
+
}
|
|
277
|
+
if (cn instanceof QueryBuilderFilterTreeExistsNodeData) {
|
|
278
|
+
const parentPropertyChainIndex = existsLambdaPropertyChains.findIndex(
|
|
279
|
+
(p) =>
|
|
280
|
+
p instanceof AbstractPropertyExpression &&
|
|
281
|
+
cn instanceof QueryBuilderFilterTreeExistsNodeData &&
|
|
282
|
+
p.func.value ===
|
|
283
|
+
guaranteeType(cn, QueryBuilderFilterTreeExistsNodeData)
|
|
284
|
+
.propertyExpression.func.value &&
|
|
285
|
+
p.func.ownerReference.value.path ===
|
|
286
|
+
cn.propertyExpression.func.ownerReference.value.path,
|
|
287
|
+
);
|
|
288
|
+
if (parentPropertyChainIndex >= 0) {
|
|
289
|
+
parentNode = targetDropNode;
|
|
290
|
+
existsLambdaPropertyChains = existsLambdaPropertyChains.slice(
|
|
291
|
+
parentPropertyChainIndex + 1,
|
|
292
|
+
);
|
|
293
|
+
existsLambdaParamNames = existsLambdaParamNames.slice(
|
|
294
|
+
parentPropertyChainIndex + 1,
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
} else if (!parentId) {
|
|
298
|
+
parentNode = targetDropNode;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
// 3. Create exists tree node for all the property chains and add them to the filter tree
|
|
303
|
+
for (let i = 0; i < existsLambdaPropertyChains.length - 1; ++i) {
|
|
304
|
+
const existsNode: QueryBuilderFilterTreeExistsNodeData =
|
|
305
|
+
new QueryBuilderFilterTreeExistsNodeData(parentNode?.id);
|
|
306
|
+
existsNode.setPropertyExpression(
|
|
307
|
+
existsLambdaPropertyChains[i] as AbstractPropertyExpression,
|
|
308
|
+
);
|
|
309
|
+
existsNode.lambdaParameterName = existsLambdaParamNames[i];
|
|
310
|
+
filterState.nodes.set(existsNode.id, existsNode);
|
|
311
|
+
filterState.addNodeFromNode(existsNode, parentNode);
|
|
312
|
+
parentNode = existsNode;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// create the filter condition tree node data
|
|
316
|
+
const filterConditionState = new FilterConditionState(
|
|
317
|
+
filterState,
|
|
318
|
+
existsLambdaPropertyChains[
|
|
319
|
+
existsLambdaPropertyChains.length - 1
|
|
320
|
+
] as AbstractPropertyExpression,
|
|
321
|
+
);
|
|
322
|
+
const treeNode = new QueryBuilderFilterTreeConditionNodeData(
|
|
323
|
+
undefined,
|
|
324
|
+
filterConditionState,
|
|
325
|
+
);
|
|
326
|
+
filterState.addNodeFromNode(treeNode, parentNode);
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* This function builds the filter tree when we DnD a node to the filter panel.
|
|
331
|
+
*/
|
|
332
|
+
const buildFilterTree = (
|
|
333
|
+
propertyExpression: AbstractPropertyExpression,
|
|
334
|
+
filterState: QueryBuilderFilterState,
|
|
335
|
+
targetDropNode?: QueryBuilderFilterTreeOperationNodeData | undefined,
|
|
336
|
+
): void => {
|
|
337
|
+
if (isCollectionProperty(propertyExpression)) {
|
|
338
|
+
const propertyChainName = getPropertyChainName(
|
|
339
|
+
propertyExpression,
|
|
340
|
+
filterState.queryBuilderState.explorerState.humanizePropertyName,
|
|
341
|
+
);
|
|
342
|
+
filterState.queryBuilderState.applicationStore.alertService.setActionAlertInfo(
|
|
343
|
+
{
|
|
344
|
+
message: `The property '${propertyChainName}' is a collection. As you are trying to filter on a collection, the filter created will be an exist filter. e.g. There exists at least one '${propertyChainName}' where 'Type' is the value specified.
|
|
345
|
+
If you are looking to create the filter where all values in this collection equal the value specified, rather than at least one value, consider creating post filter instead.`,
|
|
346
|
+
type: ActionAlertType.CAUTION,
|
|
347
|
+
actions: [
|
|
348
|
+
{
|
|
349
|
+
label: 'Cancel',
|
|
350
|
+
type: ActionAlertActionType.PROCEED_WITH_CAUTION,
|
|
351
|
+
default: true,
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
label: 'Proceed',
|
|
355
|
+
type: ActionAlertActionType.PROCEED,
|
|
356
|
+
handler:
|
|
357
|
+
filterState.queryBuilderState.applicationStore.guardUnhandledError(
|
|
358
|
+
async () =>
|
|
359
|
+
buildFilterTreeWithExists(
|
|
360
|
+
propertyExpression,
|
|
361
|
+
filterState,
|
|
362
|
+
targetDropNode,
|
|
363
|
+
),
|
|
364
|
+
),
|
|
365
|
+
},
|
|
366
|
+
],
|
|
367
|
+
},
|
|
368
|
+
);
|
|
369
|
+
} else {
|
|
370
|
+
const filterConditionState = new FilterConditionState(
|
|
371
|
+
filterState,
|
|
372
|
+
propertyExpression,
|
|
373
|
+
);
|
|
374
|
+
const treeNode = new QueryBuilderFilterTreeConditionNodeData(
|
|
375
|
+
undefined,
|
|
376
|
+
filterConditionState,
|
|
377
|
+
);
|
|
378
|
+
filterState.addNodeFromNode(
|
|
379
|
+
treeNode,
|
|
380
|
+
targetDropNode instanceof QueryBuilderFilterTreeGroupNodeData
|
|
381
|
+
? targetDropNode
|
|
382
|
+
: undefined,
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
};
|
|
90
386
|
|
|
91
387
|
export const IS_DRAGGABLE_FILTER_DND_TYPES_FETCH_SUPPORTED = [
|
|
92
388
|
QUERY_BUILDER_FILTER_DND_TYPE.CONDITION,
|
|
@@ -152,6 +448,42 @@ const QueryBuilderFilterGroupConditionEditor = observer(
|
|
|
152
448
|
},
|
|
153
449
|
);
|
|
154
450
|
|
|
451
|
+
const QueryBuilderFilterExistsConditionEditor = observer(
|
|
452
|
+
(props: {
|
|
453
|
+
node: QueryBuilderFilterTreeExistsNodeData;
|
|
454
|
+
humanizePropertyName: boolean;
|
|
455
|
+
isDragOver: boolean;
|
|
456
|
+
isDroppable: boolean;
|
|
457
|
+
}) => {
|
|
458
|
+
const { node, humanizePropertyName, isDragOver, isDroppable } = props;
|
|
459
|
+
|
|
460
|
+
return (
|
|
461
|
+
<div className="query-builder-filter-tree__node__label__content dnd__entry__container">
|
|
462
|
+
<PanelEntryDropZonePlaceholder
|
|
463
|
+
isDragOver={isDragOver}
|
|
464
|
+
isDroppable={isDroppable}
|
|
465
|
+
label={`Add to Exists Group`}
|
|
466
|
+
>
|
|
467
|
+
<div
|
|
468
|
+
className="query-builder-filter-tree__exists-node"
|
|
469
|
+
title="This is an exists filter on the collection property"
|
|
470
|
+
>
|
|
471
|
+
<div className="query-builder-filter-tree__exists-node__label">
|
|
472
|
+
{getPropertyChainName(
|
|
473
|
+
node.propertyExpression,
|
|
474
|
+
humanizePropertyName,
|
|
475
|
+
)}
|
|
476
|
+
</div>
|
|
477
|
+
<div className="query-builder-filter-tree__exists-node__exists--label">
|
|
478
|
+
exists
|
|
479
|
+
</div>
|
|
480
|
+
</div>
|
|
481
|
+
</PanelEntryDropZonePlaceholder>
|
|
482
|
+
</div>
|
|
483
|
+
);
|
|
484
|
+
},
|
|
485
|
+
);
|
|
486
|
+
|
|
155
487
|
const QueryBuilderFilterConditionEditor = observer(
|
|
156
488
|
(props: {
|
|
157
489
|
node: QueryBuilderFilterTreeConditionNodeData;
|
|
@@ -401,7 +733,8 @@ const QueryBuilderFilterTreeNodeContainer = observer(
|
|
|
401
733
|
useState(false);
|
|
402
734
|
const applicationStore = useApplicationStore();
|
|
403
735
|
const filterState = queryBuilderState.filterState;
|
|
404
|
-
const isExpandable =
|
|
736
|
+
const isExpandable =
|
|
737
|
+
node instanceof QueryBuilderFilterTreeOperationNodeData;
|
|
405
738
|
const selectNode = (): void => onNodeSelect?.(node);
|
|
406
739
|
const toggleExpandNode = (): void => node.setIsOpen(!node.isOpen);
|
|
407
740
|
const removeNode = (): void => filterState.removeNodeAndPruneBranch(node);
|
|
@@ -469,12 +802,10 @@ const QueryBuilderFilterTreeNodeContainer = observer(
|
|
|
469
802
|
applicationStore.notificationService.notifyWarning(error.message);
|
|
470
803
|
return;
|
|
471
804
|
}
|
|
472
|
-
if (node instanceof
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
filterConditionState,
|
|
477
|
-
),
|
|
805
|
+
if (node instanceof QueryBuilderFilterTreeOperationNodeData) {
|
|
806
|
+
buildFilterTree(
|
|
807
|
+
filterConditionState.propertyExpressionState.propertyExpression,
|
|
808
|
+
filterState,
|
|
478
809
|
node,
|
|
479
810
|
);
|
|
480
811
|
} else if (node instanceof QueryBuilderFilterTreeConditionNodeData) {
|
|
@@ -609,6 +940,17 @@ const QueryBuilderFilterTreeNodeContainer = observer(
|
|
|
609
940
|
isDragOver={isDragOver}
|
|
610
941
|
/>
|
|
611
942
|
)}
|
|
943
|
+
{node instanceof QueryBuilderFilterTreeExistsNodeData && (
|
|
944
|
+
<QueryBuilderFilterExistsConditionEditor
|
|
945
|
+
node={node}
|
|
946
|
+
humanizePropertyName={
|
|
947
|
+
filterState.queryBuilderState.explorerState
|
|
948
|
+
.humanizePropertyName
|
|
949
|
+
}
|
|
950
|
+
isDroppable={isDroppable}
|
|
951
|
+
isDragOver={isDragOver}
|
|
952
|
+
/>
|
|
953
|
+
)}
|
|
612
954
|
{node instanceof QueryBuilderFilterTreeConditionNodeData && (
|
|
613
955
|
<QueryBuilderFilterConditionEditor
|
|
614
956
|
node={node}
|
|
@@ -697,7 +1039,7 @@ const QueryBuilderFilterTree = observer(
|
|
|
697
1039
|
const getChildNodes = (
|
|
698
1040
|
node: QueryBuilderFilterTreeNodeData,
|
|
699
1041
|
): QueryBuilderFilterTreeNodeData[] =>
|
|
700
|
-
node instanceof
|
|
1042
|
+
node instanceof QueryBuilderFilterTreeOperationNodeData
|
|
701
1043
|
? node.childrenIds.map((id) => filterState.getNode(id))
|
|
702
1044
|
: [];
|
|
703
1045
|
return (
|
|
@@ -801,7 +1143,6 @@ export const QueryBuilderFilterPanel = observer(
|
|
|
801
1143
|
// Drag and Drop
|
|
802
1144
|
const handleDrop = useCallback(
|
|
803
1145
|
(item: QueryBuilderFilterDropTarget, type: string): void => {
|
|
804
|
-
let filterConditionState: FilterConditionState;
|
|
805
1146
|
try {
|
|
806
1147
|
let propertyExpression;
|
|
807
1148
|
if (type === QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE) {
|
|
@@ -825,24 +1166,14 @@ export const QueryBuilderFilterPanel = observer(
|
|
|
825
1166
|
filterState.queryBuilderState.explorerState,
|
|
826
1167
|
);
|
|
827
1168
|
}
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
);
|
|
1169
|
+
// NOTE: unfocus the current node when DnD a new node to the tree
|
|
1170
|
+
filterState.setSelectedNode(undefined);
|
|
1171
|
+
buildFilterTree(propertyExpression, filterState);
|
|
832
1172
|
} catch (error) {
|
|
833
1173
|
assertErrorThrown(error);
|
|
834
1174
|
applicationStore.notificationService.notifyWarning(error.message);
|
|
835
1175
|
return;
|
|
836
1176
|
}
|
|
837
|
-
// NOTE: unfocus the current node when DnD a new node to the tree
|
|
838
|
-
filterState.setSelectedNode(undefined);
|
|
839
|
-
filterState.addNodeFromNode(
|
|
840
|
-
new QueryBuilderFilterTreeConditionNodeData(
|
|
841
|
-
undefined,
|
|
842
|
-
filterConditionState,
|
|
843
|
-
),
|
|
844
|
-
undefined,
|
|
845
|
-
);
|
|
846
1177
|
},
|
|
847
1178
|
[applicationStore, filterState],
|
|
848
1179
|
);
|
|
@@ -84,6 +84,7 @@ export enum QUERY_BUILDER_STATE_HASH_STRUCTURE {
|
|
|
84
84
|
|
|
85
85
|
// filter state
|
|
86
86
|
FILTER_TREE_GROUP_NODE_DATA = 'FILTER_TREE_GROUP_NODE_DATA',
|
|
87
|
+
FILTER_TREE_EXISTS_NODE_DATA = 'FILTER_TREE_EXISTS_NODE_DATA',
|
|
87
88
|
FILTER_TREE_CONDIITION_NODE_DATA = 'FILTER_TREE_CONDITION_NODE_DATA',
|
|
88
89
|
FILTER_TREE_BLANK_CONDITION_NODE_DATA = 'FILTER_TREE_BLANK_CONDITION_NODE_DATA',
|
|
89
90
|
FILTER_CONDITION_STATE = 'FILTER_CONDITION_STATE',
|
|
@@ -43,6 +43,7 @@ export abstract class QueryBuilderFilterOperator implements Hashable {
|
|
|
43
43
|
|
|
44
44
|
abstract buildFilterConditionExpression(
|
|
45
45
|
filterConditionState: FilterConditionState,
|
|
46
|
+
lambdaParameterName?: string | undefined,
|
|
46
47
|
): ValueSpecification;
|
|
47
48
|
|
|
48
49
|
abstract buildFilterConditionState(
|