@finos/legend-query-builder 4.14.71 → 4.14.73

Sign up to get free protection for your applications and to get access to all the features.
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