@finos/legend-query-builder 4.18.17 → 4.18.19
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/explorer/QueryBuilderRelationExplorerPanel.d.ts.map +1 -1
- package/lib/components/explorer/QueryBuilderRelationExplorerPanel.js +14 -2
- package/lib/components/explorer/QueryBuilderRelationExplorerPanel.js.map +1 -1
- package/lib/components/filter/QueryBuilderFilterPanel.d.ts.map +1 -1
- package/lib/components/filter/QueryBuilderFilterPanel.js +23 -3
- package/lib/components/filter/QueryBuilderFilterPanel.js.map +1 -1
- package/lib/components/sql-playground/SQLPlaygroundGrid.d.ts.map +1 -1
- package/lib/components/sql-playground/SQLPlaygroundGrid.js +4 -1
- package/lib/components/sql-playground/SQLPlaygroundGrid.js.map +1 -1
- package/lib/data-access-overview.css +1 -1
- package/lib/package.json +1 -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 +12 -0
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperatorValueSpecificationBuilder.js.map +1 -1
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_IsEmpty.d.ts +4 -2
- 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 +50 -6
- package/lib/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_IsEmpty.js.map +1 -1
- package/lib/stores/filter/QueryBuilderFilterState.d.ts +4 -2
- package/lib/stores/filter/QueryBuilderFilterState.d.ts.map +1 -1
- package/lib/stores/filter/QueryBuilderFilterState.js +8 -1
- 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 +19 -3
- package/lib/stores/filter/QueryBuilderFilterStateBuilder.js.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperatorValueSpecificationBuilder.d.ts.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperatorValueSpecificationBuilder.js +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperatorValueSpecificationBuilder.js.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_IsEmpty.d.ts.map +1 -1
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_IsEmpty.js +14 -5
- package/lib/stores/filter/operators/QueryBuilderFilterOperator_IsEmpty.js.map +1 -1
- package/package.json +10 -10
- package/src/components/explorer/QueryBuilderRelationExplorerPanel.tsx +22 -0
- package/src/components/filter/QueryBuilderFilterPanel.tsx +46 -0
- package/src/components/sql-playground/SQLPlaygroundGrid.tsx +15 -2
- package/src/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperatorValueSpecificationBuilder.ts +13 -0
- package/src/stores/fetch-structure/tds/post-filter/operators/QueryBuilderPostFilterOperator_IsEmpty.ts +91 -6
- package/src/stores/filter/QueryBuilderFilterState.ts +13 -1
- package/src/stores/filter/QueryBuilderFilterStateBuilder.ts +24 -3
- package/src/stores/filter/operators/QueryBuilderFilterOperatorValueSpecificationBuilder.ts +1 -0
- package/src/stores/filter/operators/QueryBuilderFilterOperator_IsEmpty.ts +16 -10
|
@@ -115,6 +115,7 @@ import {
|
|
|
115
115
|
import {
|
|
116
116
|
type QueryBuilderProjectionColumnDragSource,
|
|
117
117
|
QueryBuilderSimpleProjectionColumnState,
|
|
118
|
+
QueryBuilderRelationColumnProjectionColumnState,
|
|
118
119
|
QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE,
|
|
119
120
|
} from '../../stores/fetch-structure/tds/projection/QueryBuilderProjectionColumnState.js';
|
|
120
121
|
import type { QueryBuilderFilterOperator } from '../../stores/filter/QueryBuilderFilterOperator.js';
|
|
@@ -1277,6 +1278,25 @@ const QueryBuilderFilterTreeNodeContainer = observer(
|
|
|
1277
1278
|
const sourceState = new FilterRelationColumnSourceState(
|
|
1278
1279
|
columnNode.column.name,
|
|
1279
1280
|
columnNode.type,
|
|
1281
|
+
columnNode.column.multiplicity,
|
|
1282
|
+
);
|
|
1283
|
+
filterConditionState = new FilterConditionState(
|
|
1284
|
+
filterState,
|
|
1285
|
+
sourceState,
|
|
1286
|
+
);
|
|
1287
|
+
} else if (
|
|
1288
|
+
type === QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE &&
|
|
1289
|
+
(item as QueryBuilderProjectionColumnDragSource)
|
|
1290
|
+
.columnState instanceof
|
|
1291
|
+
QueryBuilderRelationColumnProjectionColumnState
|
|
1292
|
+
) {
|
|
1293
|
+
const projColState = (
|
|
1294
|
+
item as QueryBuilderProjectionColumnDragSource
|
|
1295
|
+
).columnState as QueryBuilderRelationColumnProjectionColumnState;
|
|
1296
|
+
const sourceState = new FilterRelationColumnSourceState(
|
|
1297
|
+
projColState.column.name,
|
|
1298
|
+
projColState.column.genericType.value.rawType,
|
|
1299
|
+
projColState.column.multiplicity,
|
|
1280
1300
|
);
|
|
1281
1301
|
filterConditionState = new FilterConditionState(
|
|
1282
1302
|
filterState,
|
|
@@ -1706,6 +1726,32 @@ export const QueryBuilderFilterPanel = observer(
|
|
|
1706
1726
|
const sourceState = new FilterRelationColumnSourceState(
|
|
1707
1727
|
columnNode.column.name,
|
|
1708
1728
|
columnNode.type,
|
|
1729
|
+
columnNode.column.multiplicity,
|
|
1730
|
+
);
|
|
1731
|
+
const filterConditionState = new FilterConditionState(
|
|
1732
|
+
filterState,
|
|
1733
|
+
sourceState,
|
|
1734
|
+
);
|
|
1735
|
+
const treeNode = new QueryBuilderFilterTreeConditionNodeData(
|
|
1736
|
+
undefined,
|
|
1737
|
+
filterConditionState,
|
|
1738
|
+
);
|
|
1739
|
+
treeNode.setIsNewlyAdded(true);
|
|
1740
|
+
filterState.setSelectedNode(undefined);
|
|
1741
|
+
filterState.addNodeFromNode(treeNode, undefined);
|
|
1742
|
+
} else if (
|
|
1743
|
+
type === QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE &&
|
|
1744
|
+
(item as QueryBuilderProjectionColumnDragSource)
|
|
1745
|
+
.columnState instanceof
|
|
1746
|
+
QueryBuilderRelationColumnProjectionColumnState
|
|
1747
|
+
) {
|
|
1748
|
+
const projColState = (
|
|
1749
|
+
item as QueryBuilderProjectionColumnDragSource
|
|
1750
|
+
).columnState as QueryBuilderRelationColumnProjectionColumnState;
|
|
1751
|
+
const sourceState = new FilterRelationColumnSourceState(
|
|
1752
|
+
projColState.column.name,
|
|
1753
|
+
projColState.column.genericType.value.rawType,
|
|
1754
|
+
projColState.column.multiplicity,
|
|
1709
1755
|
);
|
|
1710
1756
|
const filterConditionState = new FilterConditionState(
|
|
1711
1757
|
filterState,
|
|
@@ -19,6 +19,7 @@ import { BlankPanelContent, clsx } from '@finos/legend-art';
|
|
|
19
19
|
import { useCallback } from 'react';
|
|
20
20
|
import {
|
|
21
21
|
at,
|
|
22
|
+
isBoolean,
|
|
22
23
|
isString,
|
|
23
24
|
parseCSVString,
|
|
24
25
|
isNonNullable,
|
|
@@ -63,12 +64,24 @@ const parseExecutionResultData = (
|
|
|
63
64
|
};
|
|
64
65
|
|
|
65
66
|
const TDSResultCellRenderer = observer((params: DataGridCellRendererParams) => {
|
|
66
|
-
const cellValue = params.value as
|
|
67
|
-
|
|
67
|
+
const cellValue = params.value as
|
|
68
|
+
| string
|
|
69
|
+
| number
|
|
70
|
+
| boolean
|
|
71
|
+
| null
|
|
72
|
+
| undefined;
|
|
73
|
+
const formattedCellValue = ():
|
|
74
|
+
| string
|
|
75
|
+
| number
|
|
76
|
+
| boolean
|
|
77
|
+
| null
|
|
78
|
+
| undefined => {
|
|
68
79
|
if (isNumber(cellValue)) {
|
|
69
80
|
return Intl.NumberFormat('en-US', {
|
|
70
81
|
maximumFractionDigits: 4,
|
|
71
82
|
}).format(Number(cellValue));
|
|
83
|
+
} else if (isBoolean(cellValue)) {
|
|
84
|
+
return String(cellValue);
|
|
72
85
|
}
|
|
73
86
|
return cellValue;
|
|
74
87
|
};
|
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
} from '../../../../../graph/QueryBuilderMetaModelConst.js';
|
|
41
41
|
import type { QueryBuilderTDSColumnState } from '../../QueryBuilderTDSColumnState.js';
|
|
42
42
|
import { getTDSColumnDerivedProperyFromType } from '../../QueryBuilderTDSHelper.js';
|
|
43
|
+
import { QueryBuilderRelationColumnProjectionColumnState } from '../../projection/QueryBuilderProjectionColumnState.js';
|
|
43
44
|
|
|
44
45
|
export const buildtdsPropertyExpressionFromColState = (
|
|
45
46
|
filterConditionState: PostFilterConditionState,
|
|
@@ -64,6 +65,18 @@ export const buildtdsPropertyExpressionFromColState = (
|
|
|
64
65
|
_funcExp.func = col;
|
|
65
66
|
_funcExp.parametersValues = [variableName];
|
|
66
67
|
return _funcExp;
|
|
68
|
+
} else if (
|
|
69
|
+
colState instanceof QueryBuilderRelationColumnProjectionColumnState
|
|
70
|
+
) {
|
|
71
|
+
// Fallback when parent lambda isn't available yet (e.g. when an operator
|
|
72
|
+
// is asked to build its expression in isolation): the projection state
|
|
73
|
+
// already carries the `RelationColumn`, so build the column accessor
|
|
74
|
+
// directly.
|
|
75
|
+
const col = colState.column;
|
|
76
|
+
const _funcExp = new FunctionExpression(col.name);
|
|
77
|
+
_funcExp.func = col;
|
|
78
|
+
_funcExp.parametersValues = [variableName];
|
|
79
|
+
return _funcExp;
|
|
67
80
|
} else {
|
|
68
81
|
const tdsPropertyExpression = new AbstractPropertyExpression('');
|
|
69
82
|
let tdsDerivedPropertyName: TDS_COLUMN_GETTER;
|
|
@@ -17,25 +17,38 @@
|
|
|
17
17
|
import {
|
|
18
18
|
type Type,
|
|
19
19
|
type ValueSpecification,
|
|
20
|
-
|
|
20
|
+
FunctionExpression,
|
|
21
21
|
type LambdaFunction,
|
|
22
22
|
Enumeration,
|
|
23
23
|
PrimitiveType,
|
|
24
24
|
PrecisePrimitiveType,
|
|
25
|
+
SimpleFunctionExpression,
|
|
26
|
+
matchFunctionName,
|
|
25
27
|
} from '@finos/legend-graph';
|
|
26
28
|
import { QueryBuilderPostFilterOperator } from '../QueryBuilderPostFilterOperator.js';
|
|
27
29
|
import { buildPostFilterConditionState } from '../QueryBuilderPostFilterStateBuilder.js';
|
|
28
30
|
import {
|
|
29
|
-
type PostFilterConditionState,
|
|
30
31
|
type QueryBuilderPostFilterState,
|
|
32
|
+
PostFilterConditionState,
|
|
31
33
|
PostFilterValueSpecConditionValueState,
|
|
32
34
|
} from '../QueryBuilderPostFilterState.js';
|
|
33
|
-
import {
|
|
35
|
+
import {
|
|
36
|
+
QueryBuilderRelationColumnProjectionColumnState,
|
|
37
|
+
QueryBuilderSimpleProjectionColumnState,
|
|
38
|
+
} from '../../projection/QueryBuilderProjectionColumnState.js';
|
|
34
39
|
import { buildPostFilterConditionExpressionHelper } from './QueryBuilderPostFilterOperatorValueSpecificationBuilder.js';
|
|
35
|
-
import {
|
|
40
|
+
import { getTDSColumnState } from '../../QueryBuilderTDSHelper.js';
|
|
41
|
+
import {
|
|
42
|
+
buildNotExpression,
|
|
43
|
+
isPropertyExpressionChainOptional,
|
|
44
|
+
unwrapNotExpression,
|
|
45
|
+
} from '../../../../QueryBuilderValueSpecificationHelper.js';
|
|
36
46
|
import { type Hashable, hashArray } from '@finos/legend-shared';
|
|
37
47
|
import { QUERY_BUILDER_STATE_HASH_STRUCTURE } from '../../../../QueryBuilderStateHashUtils.js';
|
|
38
|
-
import {
|
|
48
|
+
import {
|
|
49
|
+
QUERY_BUILDER_SUPPORTED_FUNCTIONS,
|
|
50
|
+
TDS_COLUMN_GETTER,
|
|
51
|
+
} from '../../../../../graph/QueryBuilderMetaModelConst.js';
|
|
39
52
|
|
|
40
53
|
export class QueryBuilderPostFilterOperator_IsEmpty
|
|
41
54
|
extends QueryBuilderPostFilterOperator
|
|
@@ -84,6 +97,15 @@ export class QueryBuilderPostFilterOperator_IsEmpty
|
|
|
84
97
|
.propertyExpression,
|
|
85
98
|
);
|
|
86
99
|
}
|
|
100
|
+
if (
|
|
101
|
+
postFilterState.leftConditionValue instanceof
|
|
102
|
+
QueryBuilderRelationColumnProjectionColumnState
|
|
103
|
+
) {
|
|
104
|
+
return (
|
|
105
|
+
postFilterState.leftConditionValue.column.multiplicity.lowerBound ===
|
|
106
|
+
0
|
|
107
|
+
);
|
|
108
|
+
}
|
|
87
109
|
return true;
|
|
88
110
|
}
|
|
89
111
|
return false;
|
|
@@ -99,10 +121,18 @@ export class QueryBuilderPostFilterOperator_IsEmpty
|
|
|
99
121
|
postFilterConditionState: PostFilterConditionState,
|
|
100
122
|
parentExpression: LambdaFunction | undefined,
|
|
101
123
|
): ValueSpecification | undefined {
|
|
124
|
+
// For relation-column projections there is no `TDSRow.isNull` derived
|
|
125
|
+
// property to lean on, so wrap the column expression in `isEmpty(...)`
|
|
126
|
+
// (mirrors how the where-filter `is empty` operator builds its lambda).
|
|
127
|
+
const operatorFunctionFullPath =
|
|
128
|
+
postFilterConditionState.leftConditionValue instanceof
|
|
129
|
+
QueryBuilderRelationColumnProjectionColumnState
|
|
130
|
+
? QUERY_BUILDER_SUPPORTED_FUNCTIONS.IS_EMPTY
|
|
131
|
+
: undefined;
|
|
102
132
|
return buildPostFilterConditionExpressionHelper(
|
|
103
133
|
postFilterConditionState,
|
|
104
134
|
this,
|
|
105
|
-
|
|
135
|
+
operatorFunctionFullPath,
|
|
106
136
|
parentExpression,
|
|
107
137
|
);
|
|
108
138
|
}
|
|
@@ -111,6 +141,24 @@ export class QueryBuilderPostFilterOperator_IsEmpty
|
|
|
111
141
|
postFilterState: QueryBuilderPostFilterState,
|
|
112
142
|
expression: FunctionExpression,
|
|
113
143
|
): PostFilterConditionState | undefined {
|
|
144
|
+
// Round-trip: handle the relation-column variant emitted as
|
|
145
|
+
// `isEmpty($row.<col>)` (no TDSRow getter available).
|
|
146
|
+
if (
|
|
147
|
+
expression instanceof SimpleFunctionExpression &&
|
|
148
|
+
matchFunctionName(
|
|
149
|
+
expression.functionName,
|
|
150
|
+
QUERY_BUILDER_SUPPORTED_FUNCTIONS.IS_EMPTY,
|
|
151
|
+
) &&
|
|
152
|
+
expression.parametersValues.length === 1 &&
|
|
153
|
+
expression.parametersValues[0] instanceof FunctionExpression
|
|
154
|
+
) {
|
|
155
|
+
const columnFuncExp = expression.parametersValues[0];
|
|
156
|
+
const columnState = getTDSColumnState(
|
|
157
|
+
postFilterState.tdsState,
|
|
158
|
+
columnFuncExp.functionName,
|
|
159
|
+
);
|
|
160
|
+
return new PostFilterConditionState(postFilterState, columnState, this);
|
|
161
|
+
}
|
|
114
162
|
return buildPostFilterConditionState(
|
|
115
163
|
postFilterState,
|
|
116
164
|
expression,
|
|
@@ -135,6 +183,43 @@ export class QueryBuilderPostFilterOperator_IsNotEmpty extends QueryBuilderPostF
|
|
|
135
183
|
return TDS_COLUMN_GETTER.IS_NOT_NULL;
|
|
136
184
|
}
|
|
137
185
|
|
|
186
|
+
override buildPostFilterConditionExpression(
|
|
187
|
+
postFilterConditionState: PostFilterConditionState,
|
|
188
|
+
parentExpression: LambdaFunction | undefined,
|
|
189
|
+
): ValueSpecification | undefined {
|
|
190
|
+
// For relation-column projections, `is not empty` has no TDS column getter
|
|
191
|
+
// shortcut either; build it as `not(isEmpty(...))` instead.
|
|
192
|
+
if (
|
|
193
|
+
postFilterConditionState.leftConditionValue instanceof
|
|
194
|
+
QueryBuilderRelationColumnProjectionColumnState
|
|
195
|
+
) {
|
|
196
|
+
const inner = super.buildPostFilterConditionExpression(
|
|
197
|
+
postFilterConditionState,
|
|
198
|
+
parentExpression,
|
|
199
|
+
);
|
|
200
|
+
return inner ? buildNotExpression(inner) : undefined;
|
|
201
|
+
}
|
|
202
|
+
return super.buildPostFilterConditionExpression(
|
|
203
|
+
postFilterConditionState,
|
|
204
|
+
parentExpression,
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
override buildPostFilterConditionState(
|
|
209
|
+
postFilterState: QueryBuilderPostFilterState,
|
|
210
|
+
expression: FunctionExpression,
|
|
211
|
+
): PostFilterConditionState | undefined {
|
|
212
|
+
// Round-trip: unwrap a leading `not(...)` (relation-column variant) before
|
|
213
|
+
// delegating to the IsEmpty builder.
|
|
214
|
+
if (expression instanceof SimpleFunctionExpression) {
|
|
215
|
+
const inner = unwrapNotExpression(expression);
|
|
216
|
+
if (inner) {
|
|
217
|
+
return super.buildPostFilterConditionState(postFilterState, inner);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return super.buildPostFilterConditionState(postFilterState, expression);
|
|
221
|
+
}
|
|
222
|
+
|
|
138
223
|
override get hashCode(): string {
|
|
139
224
|
return hashArray([
|
|
140
225
|
QUERY_BUILDER_STATE_HASH_STRUCTURE.POST_FILTER_OPERATOR_IS_NOT_EMPTY,
|
|
@@ -308,11 +308,21 @@ export class FilterPropertyExpressionSourceState extends FilterConditionSourceSt
|
|
|
308
308
|
export class FilterRelationColumnSourceState extends FilterConditionSourceState {
|
|
309
309
|
readonly columnName: string;
|
|
310
310
|
readonly columnType: Type;
|
|
311
|
+
readonly columnMultiplicity: Multiplicity;
|
|
311
312
|
|
|
312
|
-
constructor(
|
|
313
|
+
constructor(
|
|
314
|
+
columnName: string,
|
|
315
|
+
columnType: Type,
|
|
316
|
+
columnMultiplicity: Multiplicity,
|
|
317
|
+
) {
|
|
313
318
|
super();
|
|
314
319
|
this.columnName = columnName;
|
|
315
320
|
this.columnType = columnType;
|
|
321
|
+
this.columnMultiplicity = columnMultiplicity;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
get multiplicity(): Multiplicity {
|
|
325
|
+
return this.columnMultiplicity;
|
|
316
326
|
}
|
|
317
327
|
|
|
318
328
|
get type(): Type {
|
|
@@ -361,6 +371,8 @@ export class FilterRelationColumnSourceState extends FilterConditionSourceState
|
|
|
361
371
|
return hashArray([
|
|
362
372
|
QUERY_BUILDER_STATE_HASH_STRUCTURE.FILTER_CONDITION_SOURCE_RELATION_COLUMN,
|
|
363
373
|
this.columnName,
|
|
374
|
+
this.columnMultiplicity.lowerBound,
|
|
375
|
+
this.columnMultiplicity.upperBound ?? '',
|
|
364
376
|
]);
|
|
365
377
|
}
|
|
366
378
|
}
|
|
@@ -331,10 +331,31 @@ const processFilterTree = (
|
|
|
331
331
|
filterConditionState.sourceState instanceof
|
|
332
332
|
FilterRelationColumnSourceState
|
|
333
333
|
) {
|
|
334
|
-
|
|
334
|
+
// For a relation-column source the raw expression can be one of:
|
|
335
|
+
// - `isEmpty(col($x))` (IsEmpty / other unary ops)
|
|
336
|
+
// - `not(isEmpty(col($x)))` (IsNotEmpty)
|
|
337
|
+
// - `op(col($x), value)` (binary ops like equal, lessThan, ...)
|
|
338
|
+
// Walk down through any `not(...)` and any wrapping function call
|
|
339
|
+
// until we find the relation-column accessor `col($x)`, then read
|
|
340
|
+
// its variable parameter.
|
|
341
|
+
let current: ValueSpecification | undefined = expression;
|
|
342
|
+
while (
|
|
343
|
+
current instanceof SimpleFunctionExpression &&
|
|
344
|
+
!(
|
|
345
|
+
current.parametersValues[0] instanceof FunctionExpression &&
|
|
346
|
+
current.parametersValues[0].parametersValues[0] instanceof
|
|
347
|
+
VariableExpression
|
|
348
|
+
)
|
|
349
|
+
) {
|
|
350
|
+
current = current.parametersValues[0];
|
|
351
|
+
}
|
|
352
|
+
const columnAccessor =
|
|
353
|
+
current instanceof SimpleFunctionExpression
|
|
354
|
+
? current.parametersValues[0]
|
|
355
|
+
: current;
|
|
335
356
|
const varExpr = guaranteeType(
|
|
336
|
-
|
|
337
|
-
?
|
|
357
|
+
columnAccessor instanceof FunctionExpression
|
|
358
|
+
? columnAccessor.parametersValues[0]
|
|
338
359
|
: undefined,
|
|
339
360
|
VariableExpression,
|
|
340
361
|
`Can't process filter expression: relation column filter must reference a variable`,
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
type QueryBuilderFilterState,
|
|
19
19
|
type FilterConditionState,
|
|
20
20
|
FilterPropertyExpressionSourceState,
|
|
21
|
+
FilterRelationColumnSourceState,
|
|
21
22
|
} from '../QueryBuilderFilterState.js';
|
|
22
23
|
import { QueryBuilderFilterOperator } from '../QueryBuilderFilterOperator.js';
|
|
23
24
|
import {
|
|
@@ -52,16 +53,21 @@ export class QueryBuilderFilterOperator_IsEmpty
|
|
|
52
53
|
filterConditionState: FilterConditionState,
|
|
53
54
|
): boolean {
|
|
54
55
|
const propertyType = filterConditionState.leftConditionType;
|
|
55
|
-
|
|
56
|
-
if (
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
56
|
+
const sourceState = filterConditionState.sourceState;
|
|
57
|
+
// First check if source is optional (multiplicity lower bound === 0)
|
|
58
|
+
if (sourceState instanceof FilterPropertyExpressionSourceState) {
|
|
59
|
+
if (
|
|
60
|
+
!isPropertyExpressionChainOptional(
|
|
61
|
+
filterConditionState.propertyExpressionState.propertyExpression,
|
|
62
|
+
)
|
|
63
|
+
) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
} else if (sourceState instanceof FilterRelationColumnSourceState) {
|
|
67
|
+
if (sourceState.columnMultiplicity.lowerBound !== 0) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
65
71
|
return false;
|
|
66
72
|
}
|
|
67
73
|
return (
|