@finos/legend-query-builder 4.14.71 → 4.14.73

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.
Files changed (84) hide show
  1. package/lib/components/QueryLoader.d.ts.map +1 -1
  2. package/lib/components/QueryLoader.js +12 -34
  3. package/lib/components/QueryLoader.js.map +1 -1
  4. package/lib/components/explorer/QueryBuilderPropertySearchPanel.d.ts.map +1 -1
  5. package/lib/components/explorer/QueryBuilderPropertySearchPanel.js +108 -36
  6. package/lib/components/explorer/QueryBuilderPropertySearchPanel.js.map +1 -1
  7. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.d.ts.map +1 -1
  8. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js +10 -3
  9. package/lib/components/fetch-structure/QueryBuilderPostFilterPanel.js.map +1 -1
  10. package/lib/components/fetch-structure/QueryBuilderResultModifierPanel.d.ts.map +1 -1
  11. package/lib/components/fetch-structure/QueryBuilderResultModifierPanel.js +2 -2
  12. package/lib/components/fetch-structure/QueryBuilderResultModifierPanel.js.map +1 -1
  13. package/lib/components/fetch-structure/QueryBuilderTDSPanel.d.ts.map +1 -1
  14. package/lib/components/fetch-structure/QueryBuilderTDSPanel.js +6 -2
  15. package/lib/components/fetch-structure/QueryBuilderTDSPanel.js.map +1 -1
  16. package/lib/components/filter/QueryBuilderFilterPanel.d.ts.map +1 -1
  17. package/lib/components/filter/QueryBuilderFilterPanel.js +5 -1
  18. package/lib/components/filter/QueryBuilderFilterPanel.js.map +1 -1
  19. package/lib/components/result/QueryBuilderResultPanel.d.ts.map +1 -1
  20. package/lib/components/result/QueryBuilderResultPanel.js +3 -1
  21. package/lib/components/result/QueryBuilderResultPanel.js.map +1 -1
  22. package/lib/components/result/tds/QueryBuilderTDSGridResult.d.ts.map +1 -1
  23. package/lib/components/result/tds/QueryBuilderTDSGridResult.js +5 -2
  24. package/lib/components/result/tds/QueryBuilderTDSGridResult.js.map +1 -1
  25. package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.d.ts +3 -0
  26. package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.d.ts.map +1 -1
  27. package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.js +92 -2
  28. package/lib/components/result/tds/QueryBuilderTDSSimpleGridResult.js.map +1 -1
  29. package/lib/index.css +1 -17
  30. package/lib/index.css.map +1 -1
  31. package/lib/package.json +1 -1
  32. package/lib/stores/QueryBuilderConfig.d.ts +2 -1
  33. package/lib/stores/QueryBuilderConfig.d.ts.map +1 -1
  34. package/lib/stores/QueryBuilderConfig.js +2 -1
  35. package/lib/stores/QueryBuilderConfig.js.map +1 -1
  36. package/lib/stores/QueryBuilderResultState.d.ts.map +1 -1
  37. package/lib/stores/QueryBuilderResultState.js +4 -1
  38. package/lib/stores/QueryBuilderResultState.js.map +1 -1
  39. package/lib/stores/QueryBuilderValueSpecificationHelper.d.ts +1 -1
  40. package/lib/stores/QueryBuilderValueSpecificationHelper.d.ts.map +1 -1
  41. package/lib/stores/QueryBuilderValueSpecificationHelper.js +1 -0
  42. package/lib/stores/QueryBuilderValueSpecificationHelper.js.map +1 -1
  43. package/lib/stores/QueryLoaderState.d.ts +8 -6
  44. package/lib/stores/QueryLoaderState.d.ts.map +1 -1
  45. package/lib/stores/QueryLoaderState.js +30 -7
  46. package/lib/stores/QueryLoaderState.js.map +1 -1
  47. package/lib/stores/explorer/QueryBuilderExplorerState.d.ts +4 -3
  48. package/lib/stores/explorer/QueryBuilderExplorerState.d.ts.map +1 -1
  49. package/lib/stores/explorer/QueryBuilderExplorerState.js +22 -7
  50. package/lib/stores/explorer/QueryBuilderExplorerState.js.map +1 -1
  51. package/lib/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.d.ts.map +1 -1
  52. package/lib/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.js +1 -1
  53. package/lib/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.js.map +1 -1
  54. package/lib/stores/explorer/QueryBuilderPropertySearchState.d.ts +7 -1
  55. package/lib/stores/explorer/QueryBuilderPropertySearchState.d.ts.map +1 -1
  56. package/lib/stores/explorer/QueryBuilderPropertySearchState.js +160 -74
  57. package/lib/stores/explorer/QueryBuilderPropertySearchState.js.map +1 -1
  58. package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.d.ts +4 -1
  59. package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.d.ts.map +1 -1
  60. package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js +23 -12
  61. package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js.map +1 -1
  62. package/lib/stores/filter/QueryBuilderFilterState.d.ts +1 -1
  63. package/lib/stores/filter/QueryBuilderFilterState.d.ts.map +1 -1
  64. package/lib/stores/filter/QueryBuilderFilterState.js +9 -5
  65. package/lib/stores/filter/QueryBuilderFilterState.js.map +1 -1
  66. package/package.json +3 -3
  67. package/src/components/QueryLoader.tsx +37 -54
  68. package/src/components/explorer/QueryBuilderPropertySearchPanel.tsx +249 -226
  69. package/src/components/fetch-structure/QueryBuilderPostFilterPanel.tsx +24 -2
  70. package/src/components/fetch-structure/QueryBuilderResultModifierPanel.tsx +6 -2
  71. package/src/components/fetch-structure/QueryBuilderTDSPanel.tsx +10 -2
  72. package/src/components/filter/QueryBuilderFilterPanel.tsx +10 -1
  73. package/src/components/result/QueryBuilderResultPanel.tsx +3 -1
  74. package/src/components/result/tds/QueryBuilderTDSGridResult.tsx +8 -2
  75. package/src/components/result/tds/QueryBuilderTDSSimpleGridResult.tsx +106 -1
  76. package/src/stores/QueryBuilderConfig.ts +2 -1
  77. package/src/stores/QueryBuilderResultState.ts +4 -0
  78. package/src/stores/QueryBuilderValueSpecificationHelper.ts +2 -1
  79. package/src/stores/QueryLoaderState.ts +43 -17
  80. package/src/stores/explorer/QueryBuilderExplorerState.ts +58 -5
  81. package/src/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.ts +1 -1
  82. package/src/stores/explorer/QueryBuilderPropertySearchState.ts +194 -92
  83. package/src/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.ts +43 -13
  84. package/src/stores/filter/QueryBuilderFilterState.ts +16 -7
@@ -23,15 +23,16 @@ import {
23
23
  PRIMITIVE_TYPE,
24
24
  CORE_PURE_PATH,
25
25
  PURE_DOC_TAG,
26
+ Enumeration,
26
27
  } from '@finos/legend-graph';
27
28
  import {
29
+ type FuzzySearchEngineSortFunctionArg,
28
30
  ActionState,
29
31
  FuzzySearchEngine,
30
32
  addUniqueEntry,
31
33
  deleteEntry,
32
34
  guaranteeNonNullable,
33
35
  isNonNullable,
34
- type FuzzySearchEngineSortFunctionArg,
35
36
  } from '@finos/legend-shared';
36
37
  import {
37
38
  observable,
@@ -47,11 +48,13 @@ import {
47
48
  QUERY_BUILDER_PROPERTY_SEARCH_MAX_NODES,
48
49
  } from '../QueryBuilderConfig.js';
49
50
  import {
51
+ type QueryBuilderExplorerTreeNodeData,
50
52
  getQueryBuilderPropertyNodeData,
51
53
  getQueryBuilderSubTypeNodeData,
52
- type QueryBuilderExplorerTreeNodeData,
53
54
  QueryBuilderExplorerTreePropertyNodeData,
54
55
  QueryBuilderExplorerTreeSubTypeNodeData,
56
+ cloneQueryBuilderExplorerTreeNodeData,
57
+ QueryBuilderExplorerTreeRootNodeData,
55
58
  } from './QueryBuilderExplorerState.js';
56
59
  import type { QueryBuilderState } from '../QueryBuilderState.js';
57
60
  import { QueryBuilderFuzzySearchAdvancedConfigState } from './QueryBuilderFuzzySearchAdvancedConfigState.js';
@@ -74,7 +77,8 @@ export class QueryBuilderPropertySearchState {
74
77
  * is that we could interact with the searched nodes, i.e. drag them to
75
78
  * various panels to create filter, fetch-structure, etc.
76
79
  */
77
- indexedExplorerTreeNodes: QueryBuilderExplorerTreeNodeData[] = [];
80
+ indexedExplorerTreeNodeMap: Map<string, QueryBuilderExplorerTreeNodeData> =
81
+ new Map();
78
82
 
79
83
  // search
80
84
  searchEngine: FuzzySearchEngine<QueryBuilderExplorerTreeNodeData>;
@@ -89,8 +93,10 @@ export class QueryBuilderPropertySearchState {
89
93
  showSearchConfigurationMenu = false;
90
94
 
91
95
  // filter
96
+ includeOneMany = false;
92
97
  typeFilters = [
93
98
  QUERY_BUILDER_PROPERTY_SEARCH_TYPE.CLASS,
99
+ QUERY_BUILDER_PROPERTY_SEARCH_TYPE.ENUMERATION,
94
100
  QUERY_BUILDER_PROPERTY_SEARCH_TYPE.STRING,
95
101
  QUERY_BUILDER_PROPERTY_SEARCH_TYPE.BOOLEAN,
96
102
  QUERY_BUILDER_PROPERTY_SEARCH_TYPE.NUMBER,
@@ -99,14 +105,16 @@ export class QueryBuilderPropertySearchState {
99
105
 
100
106
  constructor(queryBuilderState: QueryBuilderState) {
101
107
  makeObservable(this, {
102
- indexedExplorerTreeNodes: observable,
108
+ indexedExplorerTreeNodeMap: observable,
103
109
  searchText: observable,
104
110
  searchResults: observable,
105
111
  isOverSearchLimit: observable,
106
112
  isSearchPanelOpen: observable,
107
113
  isSearchPanelHidden: observable,
108
114
  showSearchConfigurationMenu: observable,
115
+ includeOneMany: observable,
109
116
  typeFilters: observable,
117
+ indexedExplorerTreeNodes: computed,
110
118
  filteredSearchResults: computed,
111
119
  search: action,
112
120
  resetSearch: action,
@@ -116,6 +124,8 @@ export class QueryBuilderPropertySearchState {
116
124
  setShowSearchConfigurationMenu: action,
117
125
  setIsSearchPanelOpen: action,
118
126
  setIsSearchPanelHidden: action,
127
+ setIncludeOneMany: action,
128
+ setFilterOnlyType: action,
119
129
  toggleFilterForType: action,
120
130
  initialize: action,
121
131
  });
@@ -156,9 +166,22 @@ export class QueryBuilderPropertySearchState {
156
166
  resetSearch(): void {
157
167
  this.searchText = '';
158
168
  this.searchResults = [];
169
+ this.indexedExplorerTreeNodes.forEach((node) => {
170
+ if (!(node instanceof QueryBuilderExplorerTreeRootNodeData)) {
171
+ node.setIsOpen(false);
172
+ }
173
+ });
159
174
  this.searchState.complete();
160
175
  }
161
176
 
177
+ setIncludeOneMany(val: boolean): void {
178
+ this.includeOneMany = val;
179
+ }
180
+
181
+ setFilterOnlyType(val: QUERY_BUILDER_PROPERTY_SEARCH_TYPE): void {
182
+ this.typeFilters = [val];
183
+ }
184
+
162
185
  toggleFilterForType(val: QUERY_BUILDER_PROPERTY_SEARCH_TYPE): void {
163
186
  if (this.typeFilters.includes(val)) {
164
187
  deleteEntry(this.typeFilters, val);
@@ -167,6 +190,29 @@ export class QueryBuilderPropertySearchState {
167
190
  }
168
191
  }
169
192
 
193
+ isNodeMultiple(node: QueryBuilderExplorerTreeNodeData): boolean {
194
+ // Check if node or any ancestors are one-many nodes.
195
+ let currNode: QueryBuilderExplorerTreeNodeData | undefined = node;
196
+ while (currNode) {
197
+ if (
198
+ (currNode instanceof QueryBuilderExplorerTreeSubTypeNodeData &&
199
+ (currNode.multiplicity.upperBound === undefined ||
200
+ currNode.multiplicity.upperBound > 1)) ||
201
+ (currNode instanceof QueryBuilderExplorerTreePropertyNodeData &&
202
+ (currNode.property.multiplicity.upperBound === undefined ||
203
+ currNode.property.multiplicity.upperBound > 1))
204
+ ) {
205
+ return true;
206
+ }
207
+ currNode =
208
+ currNode instanceof QueryBuilderExplorerTreePropertyNodeData ||
209
+ currNode instanceof QueryBuilderExplorerTreeSubTypeNodeData
210
+ ? this.indexedExplorerTreeNodeMap.get(currNode.parentId)
211
+ : undefined;
212
+ }
213
+ return false;
214
+ }
215
+
170
216
  async search(): Promise<void> {
171
217
  if (!this.searchText) {
172
218
  this.setSearchResults([]);
@@ -175,6 +221,12 @@ export class QueryBuilderPropertySearchState {
175
221
 
176
222
  this.searchState.inProgress();
177
223
 
224
+ this.indexedExplorerTreeNodes.forEach((node) => {
225
+ if (!(node instanceof QueryBuilderExplorerTreeRootNodeData)) {
226
+ node.setIsOpen(false);
227
+ }
228
+ });
229
+
178
230
  // Perform the search in a setTimeout so we can execute it asynchronously and
179
231
  // show the loading indicator while search is in progress.
180
232
  return new Promise((resolve) =>
@@ -210,18 +262,13 @@ export class QueryBuilderPropertySearchState {
210
262
  return node;
211
263
  })
212
264
  .filter((node) => {
213
- // Filter out property nodes if their parent class node is already in the results.
214
- if (node.type instanceof Class) {
215
- return true;
216
- } else if (
217
- node instanceof QueryBuilderExplorerTreePropertyNodeData
265
+ // Filter out nodes if their parent class node is already in the results.
266
+ if (
267
+ (node instanceof QueryBuilderExplorerTreePropertyNodeData ||
268
+ node instanceof QueryBuilderExplorerTreeSubTypeNodeData) &&
269
+ classNodes.has(node.parentId)
218
270
  ) {
219
- if (this.searchText.toLowerCase() === node.label.toLowerCase()) {
220
- return true;
221
- } else if (classNodes.has(node.parentId)) {
222
- classNodes.get(node.parentId)?.setIsOpen(true);
223
- return false;
224
- }
271
+ return false;
225
272
  }
226
273
  return true;
227
274
  });
@@ -260,22 +307,26 @@ export class QueryBuilderPropertySearchState {
260
307
  // show the loading indicator while initialization is in progress.
261
308
  return new Promise((resolve) =>
262
309
  setTimeout(() => {
263
- this.indexedExplorerTreeNodes = [];
310
+ const treeData =
311
+ this.queryBuilderState.explorerState.nonNullableTreeData;
312
+ const rootNodeMap = new Map(
313
+ treeData.rootIds
314
+ .map((rootId) => treeData.nodes.get(rootId))
315
+ .filter(isNonNullable)
316
+ .map((rootNode) => [rootNode.id, rootNode]),
317
+ );
318
+ this.indexedExplorerTreeNodeMap = new Map();
264
319
 
265
320
  let currentLevelPropertyNodes: QueryBuilderExplorerTreeNodeData[] = [];
266
321
  let nextLevelPropertyNodes: QueryBuilderExplorerTreeNodeData[] = [];
267
322
 
268
323
  // Get all the children of the root node(s)
269
324
  Array.from(
270
- this.queryBuilderState.explorerState.nonNullableTreeData.rootIds
325
+ treeData.rootIds
271
326
  .map((rootId) =>
272
- this.queryBuilderState.explorerState.nonNullableTreeData.nodes
327
+ treeData.nodes
273
328
  .get(rootId)
274
- ?.childrenIds.map((childId) =>
275
- this.queryBuilderState.explorerState.nonNullableTreeData.nodes.get(
276
- childId,
277
- ),
278
- ),
329
+ ?.childrenIds.map((childId) => treeData.nodes.get(childId)),
279
330
  )
280
331
  .flat()
281
332
  .filter(isNonNullable)
@@ -287,24 +338,54 @@ export class QueryBuilderPropertySearchState {
287
338
  ),
288
339
  ).forEach((node) => {
289
340
  if (node.mappingData.mapped && !node.isPartOfDerivedPropertyBranch) {
290
- currentLevelPropertyNodes.push(node);
291
- this.indexedExplorerTreeNodes.push(node);
341
+ const clonedNode = cloneQueryBuilderExplorerTreeNodeData(node);
342
+ currentLevelPropertyNodes.push(clonedNode);
343
+ this.indexedExplorerTreeNodeMap.set(clonedNode.id, clonedNode);
292
344
  }
293
345
  });
294
346
 
295
347
  // ensure we don't navigate more nodes than the limit so we could
296
348
  // keep the initialization/indexing time within acceptable range
297
349
  const NODE_LIMIT =
298
- this.indexedExplorerTreeNodes.length +
350
+ this.indexedExplorerTreeNodeMap.size +
299
351
  QUERY_BUILDER_PROPERTY_SEARCH_MAX_NODES;
300
352
  const addNode = (node: QueryBuilderExplorerTreeNodeData): void =>
301
353
  runInAction(() => {
302
- if (this.indexedExplorerTreeNodes.length > NODE_LIMIT) {
354
+ if (this.indexedExplorerTreeNodeMap.size > NODE_LIMIT) {
303
355
  return;
304
356
  }
305
- this.indexedExplorerTreeNodes.push(node);
357
+ const clonedNode = cloneQueryBuilderExplorerTreeNodeData(node);
358
+ this.indexedExplorerTreeNodeMap.set(clonedNode.id, clonedNode);
306
359
  });
307
360
 
361
+ // helper function to check if a node has the same type as one of its
362
+ // ancestor nodes. This allows us to avoid including circular dependencies
363
+ // in the indexed nodes list.
364
+ const nodeHasSameTypeAsAncestor = (
365
+ node: QueryBuilderExplorerTreeNodeData,
366
+ ): boolean => {
367
+ if (
368
+ node instanceof QueryBuilderExplorerTreePropertyNodeData ||
369
+ node instanceof QueryBuilderExplorerTreeSubTypeNodeData
370
+ ) {
371
+ let ancestor =
372
+ this.indexedExplorerTreeNodeMap.get(node.parentId) ??
373
+ rootNodeMap.get(node.parentId);
374
+ while (ancestor) {
375
+ if (node.type === ancestor.type) {
376
+ return true;
377
+ }
378
+ ancestor =
379
+ ancestor instanceof QueryBuilderExplorerTreePropertyNodeData ||
380
+ ancestor instanceof QueryBuilderExplorerTreeSubTypeNodeData
381
+ ? (this.indexedExplorerTreeNodeMap.get(ancestor.parentId) ??
382
+ rootNodeMap.get(ancestor.parentId))
383
+ : undefined;
384
+ }
385
+ }
386
+ return false;
387
+ };
388
+
308
389
  // limit the depth of navigation to keep the initialization/indexing
309
390
  // time within acceptable range
310
391
  let currentDepth = 1;
@@ -336,8 +417,10 @@ export class QueryBuilderPropertySearchState {
336
417
  ),
337
418
  );
338
419
  if (
339
- propertyTreeNodeData?.mappingData.mapped &&
340
- !propertyTreeNodeData.isPartOfDerivedPropertyBranch
420
+ propertyTreeNodeData &&
421
+ propertyTreeNodeData.mappingData.mapped &&
422
+ !propertyTreeNodeData.isPartOfDerivedPropertyBranch &&
423
+ !nodeHasSameTypeAsAncestor(propertyTreeNodeData)
341
424
  ) {
342
425
  nextLevelPropertyNodes.push(propertyTreeNodeData);
343
426
  addNode(propertyTreeNodeData);
@@ -353,7 +436,10 @@ export class QueryBuilderPropertySearchState {
353
436
  .mappingModelCoverageAnalysisResult,
354
437
  ),
355
438
  );
356
- if (subTypeTreeNodeData.mappingData.mapped) {
439
+ if (
440
+ subTypeTreeNodeData.mappingData.mapped &&
441
+ !nodeHasSameTypeAsAncestor(subTypeTreeNodeData)
442
+ ) {
357
443
  nextLevelPropertyNodes.push(subTypeTreeNodeData);
358
444
  addNode(subTypeTreeNodeData);
359
445
  }
@@ -365,7 +451,7 @@ export class QueryBuilderPropertySearchState {
365
451
  // number of indexed nodes to figure out if we should proceed further
366
452
  if (
367
453
  !currentLevelPropertyNodes.length &&
368
- this.indexedExplorerTreeNodes.length < NODE_LIMIT
454
+ this.indexedExplorerTreeNodeMap.size < NODE_LIMIT
369
455
  ) {
370
456
  currentLevelPropertyNodes = nextLevelPropertyNodes;
371
457
  nextLevelPropertyNodes = [];
@@ -388,21 +474,25 @@ export class QueryBuilderPropertySearchState {
388
474
  threshold: 0.2,
389
475
  keys: [
390
476
  {
391
- name: 'path',
477
+ name: 'label',
392
478
  weight: 4,
479
+ },
480
+ {
481
+ name: 'path',
482
+ weight: 2,
393
483
  getFn: (node) => {
394
- const parentNode = this.indexedExplorerTreeNodes.find(
395
- (pn) =>
396
- node instanceof
397
- QueryBuilderExplorerTreePropertyNodeData &&
398
- node.parentId === pn.id,
399
- );
400
-
401
- const fullPath =
402
- parentNode instanceof
403
- QueryBuilderExplorerTreeSubTypeNodeData
484
+ const parentNode =
485
+ node instanceof QueryBuilderExplorerTreePropertyNodeData ||
486
+ node instanceof QueryBuilderExplorerTreeSubTypeNodeData
487
+ ? this.indexedExplorerTreeNodeMap.get(node.parentId)
488
+ : undefined;
489
+
490
+ const fullPath = parentNode
491
+ ? parentNode instanceof
492
+ QueryBuilderExplorerTreeSubTypeNodeData
404
493
  ? prettyPropertyNameForSubType(node.id)
405
- : prettyPropertyNameFromNodeId(node.id);
494
+ : prettyPropertyNameFromNodeId(node.id)
495
+ : '';
406
496
 
407
497
  return fullPath;
408
498
  },
@@ -471,61 +561,73 @@ export class QueryBuilderPropertySearchState {
471
561
  );
472
562
  }
473
563
 
474
- get filteredSearchResults(): QueryBuilderExplorerTreeNodeData[] {
475
- return this.searchResults.filter((node) => {
476
- if (this.typeFilters.includes(QUERY_BUILDER_PROPERTY_SEARCH_TYPE.CLASS)) {
477
- if (node.type instanceof Class) {
478
- return true;
479
- }
564
+ get indexedExplorerTreeNodes(): QueryBuilderExplorerTreeNodeData[] {
565
+ return Array.from(this.indexedExplorerTreeNodeMap.values());
566
+ }
567
+
568
+ isNodeIncludedInFilter(node: QueryBuilderExplorerTreeNodeData): boolean {
569
+ if (!this.includeOneMany && this.isNodeMultiple(node)) {
570
+ return false;
571
+ }
572
+ if (this.typeFilters.includes(QUERY_BUILDER_PROPERTY_SEARCH_TYPE.CLASS)) {
573
+ if (node.type instanceof Class) {
574
+ return true;
480
575
  }
481
- if (
482
- this.typeFilters.includes(QUERY_BUILDER_PROPERTY_SEARCH_TYPE.STRING)
483
- ) {
484
- if (node.type === PrimitiveType.STRING) {
485
- return true;
486
- }
576
+ }
577
+ if (
578
+ this.typeFilters.includes(QUERY_BUILDER_PROPERTY_SEARCH_TYPE.ENUMERATION)
579
+ ) {
580
+ if (node.type instanceof Enumeration) {
581
+ return true;
487
582
  }
583
+ }
584
+ if (this.typeFilters.includes(QUERY_BUILDER_PROPERTY_SEARCH_TYPE.STRING)) {
585
+ if (node.type === PrimitiveType.STRING) {
586
+ return true;
587
+ }
588
+ }
589
+ if (this.typeFilters.includes(QUERY_BUILDER_PROPERTY_SEARCH_TYPE.NUMBER)) {
488
590
  if (
489
- this.typeFilters.includes(QUERY_BUILDER_PROPERTY_SEARCH_TYPE.NUMBER)
591
+ node.type instanceof PrimitiveType &&
592
+ (
593
+ [
594
+ PRIMITIVE_TYPE.NUMBER,
595
+ PRIMITIVE_TYPE.DECIMAL,
596
+ PRIMITIVE_TYPE.INTEGER,
597
+ PRIMITIVE_TYPE.FLOAT,
598
+ ] as string[]
599
+ ).includes(node.type.name)
490
600
  ) {
491
- if (
492
- node.type instanceof PrimitiveType &&
493
- (
494
- [
495
- PRIMITIVE_TYPE.NUMBER,
496
- PRIMITIVE_TYPE.DECIMAL,
497
- PRIMITIVE_TYPE.INTEGER,
498
- PRIMITIVE_TYPE.FLOAT,
499
- ] as string[]
500
- ).includes(node.type.name)
501
- ) {
502
- return true;
503
- }
601
+ return true;
504
602
  }
603
+ }
604
+ if (this.typeFilters.includes(QUERY_BUILDER_PROPERTY_SEARCH_TYPE.BOOLEAN)) {
605
+ if (node.type === PrimitiveType.BOOLEAN) {
606
+ return true;
607
+ }
608
+ }
609
+ if (this.typeFilters.includes(QUERY_BUILDER_PROPERTY_SEARCH_TYPE.DATE)) {
505
610
  if (
506
- this.typeFilters.includes(QUERY_BUILDER_PROPERTY_SEARCH_TYPE.BOOLEAN)
611
+ node.type instanceof PrimitiveType &&
612
+ (
613
+ [
614
+ PRIMITIVE_TYPE.DATE,
615
+ PRIMITIVE_TYPE.DATETIME,
616
+ PRIMITIVE_TYPE.STRICTDATE,
617
+ PRIMITIVE_TYPE.STRICTTIME,
618
+ PRIMITIVE_TYPE.LATESTDATE,
619
+ ] as string[]
620
+ ).includes(node.type.name)
507
621
  ) {
508
- if (node.type === PrimitiveType.BOOLEAN) {
509
- return true;
510
- }
622
+ return true;
511
623
  }
512
- if (this.typeFilters.includes(QUERY_BUILDER_PROPERTY_SEARCH_TYPE.DATE)) {
513
- if (
514
- node.type instanceof PrimitiveType &&
515
- (
516
- [
517
- PRIMITIVE_TYPE.DATE,
518
- PRIMITIVE_TYPE.DATETIME,
519
- PRIMITIVE_TYPE.STRICTDATE,
520
- PRIMITIVE_TYPE.STRICTTIME,
521
- PRIMITIVE_TYPE.LATESTDATE,
522
- ] as string[]
523
- ).includes(node.type.name)
524
- ) {
525
- return true;
526
- }
527
- }
528
- return false;
529
- });
624
+ }
625
+ return false;
626
+ }
627
+
628
+ get filteredSearchResults(): QueryBuilderExplorerTreeNodeData[] {
629
+ return this.searchResults.filter((node) =>
630
+ this.isNodeIncludedInFilter(node),
631
+ );
530
632
  }
531
633
  }
@@ -19,13 +19,13 @@ import {
19
19
  type PureModel,
20
20
  type Type,
21
21
  type ValueSpecification,
22
- type ExecutionResult,
23
- type VariableExpression,
24
22
  type SimpleFunctionExpression,
23
+ type ExecutionResultWithMetadata,
25
24
  observe_ValueSpecification,
26
25
  PrimitiveType,
27
26
  CollectionInstanceValue,
28
27
  InstanceValue,
28
+ VariableExpression,
29
29
  } from '@finos/legend-graph';
30
30
  import {
31
31
  type GeneratorFn,
@@ -74,11 +74,13 @@ import type { QueryBuilderTDSColumnState } from '../QueryBuilderTDSColumnState.j
74
74
  import {
75
75
  getCollectionValueSpecificationType,
76
76
  getNonCollectionValueSpecificationType,
77
+ isTypeCompatibleForAssignment,
77
78
  isValidInstanceValue,
78
79
  isValueExpressionReferencedInValue,
79
80
  } from '../../../QueryBuilderValueSpecificationHelper.js';
80
81
  import { buildtdsPropertyExpressionFromColState } from './operators/QueryBuilderPostFilterOperatorValueSpecificationBuilder.js';
81
82
  import { TDS_COLUMN_GETTER } from '../../../../graph/QueryBuilderMetaModelConst.js';
83
+ import type { QueryBuilderFilterTreeNodeData } from '../../../filter/QueryBuilderFilterState.js';
82
84
 
83
85
  export enum QUERY_BUILDER_POST_FILTER_DND_TYPE {
84
86
  GROUP_CONDITION = 'QUERY_BUILDER_POST_FILTER_DND_TYPE.GROUP_CONDITION',
@@ -488,7 +490,7 @@ export class PostFilterConditionState implements Hashable {
488
490
  );
489
491
  const value = searchValue ?? rightConditionValue.value;
490
492
  if (performTypeahead(value)) {
491
- const result =
493
+ const result = (
492
494
  (yield this.postFilterState.tdsState.queryBuilderState.graphManagerState.graphManager.runQuery(
493
495
  buildProjectionColumnTypeaheadQuery(
494
496
  this.postFilterState.tdsState.queryBuilderState,
@@ -505,7 +507,8 @@ export class PostFilterConditionState implements Hashable {
505
507
  ),
506
508
  this.postFilterState.tdsState.queryBuilderState.graphManagerState
507
509
  .graph,
508
- )) as ExecutionResult;
510
+ )) as ExecutionResultWithMetadata
511
+ ).executionResult;
509
512
  this.typeaheadSearchResults = buildTypeaheadOptions(result);
510
513
  }
511
514
  this.typeaheadSearchState.pass();
@@ -1011,15 +1014,45 @@ export class QueryBuilderPostFilterState
1011
1014
  );
1012
1015
  }
1013
1016
 
1017
+ isInvalidValueSpecPostFilterValue(
1018
+ node: QueryBuilderPostFilterTreeNodeData,
1019
+ ): boolean {
1020
+ return (
1021
+ node instanceof QueryBuilderPostFilterTreeConditionNodeData &&
1022
+ node.condition.rightConditionValue instanceof
1023
+ PostFilterValueSpecConditionValueState &&
1024
+ ((node.condition.rightConditionValue.value instanceof InstanceValue &&
1025
+ !isValidInstanceValue(node.condition.rightConditionValue.value)) ||
1026
+ (node.condition.rightConditionValue.value instanceof
1027
+ VariableExpression &&
1028
+ !isTypeCompatibleForAssignment(
1029
+ node.condition.leftConditionValue.getColumnType(),
1030
+ node.condition.rightConditionValue.type,
1031
+ )))
1032
+ );
1033
+ }
1034
+
1035
+ isInvalidTDSColumnPostFilterValue(
1036
+ node: QueryBuilderFilterTreeNodeData,
1037
+ ): boolean {
1038
+ return (
1039
+ node instanceof QueryBuilderPostFilterTreeConditionNodeData &&
1040
+ node.condition.rightConditionValue instanceof
1041
+ PostFilterTDSColumnValueConditionValueState &&
1042
+ !isTypeCompatibleForAssignment(
1043
+ node.condition.leftConditionValue.getColumnType(),
1044
+ node.condition.rightConditionValue.type,
1045
+ )
1046
+ );
1047
+ }
1048
+
1014
1049
  get allValidationIssues(): string[] {
1015
1050
  const validationIssues: string[] = [];
1016
1051
  Array.from(this.nodes.values()).forEach((node) => {
1017
1052
  if (node instanceof QueryBuilderPostFilterTreeConditionNodeData) {
1018
1053
  if (
1019
- node.condition.rightConditionValue instanceof
1020
- PostFilterValueSpecConditionValueState &&
1021
- node.condition.rightConditionValue.value instanceof InstanceValue &&
1022
- !isValidInstanceValue(node.condition.rightConditionValue.value)
1054
+ this.isInvalidValueSpecPostFilterValue(node) ||
1055
+ this.isInvalidTDSColumnPostFilterValue(node)
1023
1056
  ) {
1024
1057
  validationIssues.push(
1025
1058
  `Filter value for ${node.condition.leftConditionValue.columnName} is missing or invalid`,
@@ -1042,11 +1075,8 @@ export class QueryBuilderPostFilterState
1042
1075
  get hasInvalidFilterValues(): boolean {
1043
1076
  return Array.from(this.nodes.values()).some(
1044
1077
  (node) =>
1045
- node instanceof QueryBuilderPostFilterTreeConditionNodeData &&
1046
- node.condition.rightConditionValue instanceof
1047
- PostFilterValueSpecConditionValueState &&
1048
- node.condition.rightConditionValue.value instanceof InstanceValue &&
1049
- !isValidInstanceValue(node.condition.rightConditionValue.value),
1078
+ this.isInvalidValueSpecPostFilterValue(node) ||
1079
+ this.isInvalidTDSColumnPostFilterValue(node),
1050
1080
  );
1051
1081
  }
1052
1082
 
@@ -37,15 +37,15 @@ import type { QueryBuilderExplorerTreeDragSource } from '../explorer/QueryBuilde
37
37
  import { QueryBuilderPropertyExpressionState } from '../QueryBuilderPropertyEditorState.js';
38
38
  import type { QueryBuilderState } from '../QueryBuilderState.js';
39
39
  import {
40
- type ExecutionResult,
41
- AbstractPropertyExpression,
42
40
  type ValueSpecification,
43
- type VariableExpression,
44
41
  type Type,
42
+ type ExecutionResultWithMetadata,
43
+ AbstractPropertyExpression,
45
44
  observe_ValueSpecification,
46
45
  CollectionInstanceValue,
47
46
  InstanceValue,
48
47
  SimpleFunctionExpression,
48
+ VariableExpression,
49
49
  matchFunctionName,
50
50
  } from '@finos/legend-graph';
51
51
  import { DEFAULT_LAMBDA_VARIABLE_NAME } from '../QueryBuilderConfig.js';
@@ -61,6 +61,7 @@ import { QUERY_BUILDER_STATE_HASH_STRUCTURE } from '../QueryBuilderStateHashUtil
61
61
  import {
62
62
  getCollectionValueSpecificationType,
63
63
  getNonCollectionValueSpecificationType,
64
+ isTypeCompatibleForAssignment,
64
65
  isValidInstanceValue,
65
66
  isValueExpressionReferencedInValue,
66
67
  } from '../QueryBuilderValueSpecificationHelper.js';
@@ -299,7 +300,7 @@ export class FilterConditionState implements Hashable {
299
300
  );
300
301
  const value = searchValue ?? rightConditionValue.value;
301
302
  if (performTypeahead(value)) {
302
- const result =
303
+ const result = (
303
304
  (yield this.filterState.queryBuilderState.graphManagerState.graphManager.runQuery(
304
305
  buildPropertyTypeaheadQuery(
305
306
  this.filterState.queryBuilderState,
@@ -314,7 +315,8 @@ export class FilterConditionState implements Hashable {
314
315
  .runtimeValue,
315
316
  ),
316
317
  this.filterState.queryBuilderState.graphManagerState.graph,
317
- )) as ExecutionResult;
318
+ )) as ExecutionResultWithMetadata
319
+ ).executionResult;
318
320
  this.typeaheadSearchResults = buildTypeaheadOptions(result);
319
321
  }
320
322
  this.typeaheadSearchState.pass();
@@ -1185,8 +1187,15 @@ export class QueryBuilderFilterState
1185
1187
  node instanceof QueryBuilderFilterTreeConditionNodeData &&
1186
1188
  node.condition.rightConditionValue instanceof
1187
1189
  FilterValueSpecConditionValueState &&
1188
- node.condition.rightConditionValue.value instanceof InstanceValue &&
1189
- !isValidInstanceValue(node.condition.rightConditionValue.value)
1190
+ ((node.condition.rightConditionValue.value instanceof InstanceValue &&
1191
+ !isValidInstanceValue(node.condition.rightConditionValue.value)) ||
1192
+ (node.condition.rightConditionValue.value instanceof
1193
+ VariableExpression &&
1194
+ !isTypeCompatibleForAssignment(
1195
+ node.condition.propertyExpressionState.propertyExpression.func.value
1196
+ .genericType.value.rawType,
1197
+ node.condition.rightConditionValue.value.genericType?.value.rawType,
1198
+ )))
1190
1199
  );
1191
1200
  }
1192
1201