@finos/legend-query-builder 4.14.72 → 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 (44) hide show
  1. package/lib/components/explorer/QueryBuilderPropertySearchPanel.d.ts.map +1 -1
  2. package/lib/components/explorer/QueryBuilderPropertySearchPanel.js +108 -36
  3. package/lib/components/explorer/QueryBuilderPropertySearchPanel.js.map +1 -1
  4. package/lib/components/result/QueryBuilderResultPanel.d.ts.map +1 -1
  5. package/lib/components/result/QueryBuilderResultPanel.js +3 -1
  6. package/lib/components/result/QueryBuilderResultPanel.js.map +1 -1
  7. package/lib/index.css +1 -17
  8. package/lib/index.css.map +1 -1
  9. package/lib/package.json +1 -1
  10. package/lib/stores/QueryBuilderConfig.d.ts +2 -1
  11. package/lib/stores/QueryBuilderConfig.d.ts.map +1 -1
  12. package/lib/stores/QueryBuilderConfig.js +2 -1
  13. package/lib/stores/QueryBuilderConfig.js.map +1 -1
  14. package/lib/stores/QueryBuilderResultState.d.ts.map +1 -1
  15. package/lib/stores/QueryBuilderResultState.js +4 -1
  16. package/lib/stores/QueryBuilderResultState.js.map +1 -1
  17. package/lib/stores/explorer/QueryBuilderExplorerState.d.ts +4 -3
  18. package/lib/stores/explorer/QueryBuilderExplorerState.d.ts.map +1 -1
  19. package/lib/stores/explorer/QueryBuilderExplorerState.js +22 -7
  20. package/lib/stores/explorer/QueryBuilderExplorerState.js.map +1 -1
  21. package/lib/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.d.ts.map +1 -1
  22. package/lib/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.js +1 -1
  23. package/lib/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.js.map +1 -1
  24. package/lib/stores/explorer/QueryBuilderPropertySearchState.d.ts +7 -1
  25. package/lib/stores/explorer/QueryBuilderPropertySearchState.d.ts.map +1 -1
  26. package/lib/stores/explorer/QueryBuilderPropertySearchState.js +160 -74
  27. package/lib/stores/explorer/QueryBuilderPropertySearchState.js.map +1 -1
  28. package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.d.ts.map +1 -1
  29. package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js +1 -1
  30. package/lib/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.js.map +1 -1
  31. package/lib/stores/filter/QueryBuilderFilterState.d.ts +1 -1
  32. package/lib/stores/filter/QueryBuilderFilterState.d.ts.map +1 -1
  33. package/lib/stores/filter/QueryBuilderFilterState.js +1 -1
  34. package/lib/stores/filter/QueryBuilderFilterState.js.map +1 -1
  35. package/package.json +3 -3
  36. package/src/components/explorer/QueryBuilderPropertySearchPanel.tsx +249 -226
  37. package/src/components/result/QueryBuilderResultPanel.tsx +3 -1
  38. package/src/stores/QueryBuilderConfig.ts +2 -1
  39. package/src/stores/QueryBuilderResultState.ts +4 -0
  40. package/src/stores/explorer/QueryBuilderExplorerState.ts +58 -5
  41. package/src/stores/explorer/QueryBuilderFuzzySearchAdvancedConfigState.ts +1 -1
  42. package/src/stores/explorer/QueryBuilderPropertySearchState.ts +194 -92
  43. package/src/stores/fetch-structure/tds/post-filter/QueryBuilderPostFilterState.ts +4 -3
  44. package/src/stores/filter/QueryBuilderFilterState.ts +5 -4
@@ -31,6 +31,7 @@ import {
31
31
  type MappingModelCoverageAnalysisResult,
32
32
  type EnumMappedProperty,
33
33
  type MappedEntity,
34
+ type ExecutionResultWithMetadata,
34
35
  AbstractPropertyExpression,
35
36
  Class,
36
37
  VariableExpression,
@@ -55,7 +56,6 @@ import {
55
56
  Association,
56
57
  PRIMITIVE_TYPE,
57
58
  TDSExecutionResult,
58
- type ExecutionResult,
59
59
  getAllSubclasses,
60
60
  PropertyExplicitReference,
61
61
  reportGraphAnalytics,
@@ -115,6 +115,7 @@ export abstract class QueryBuilderExplorerTreeNodeData implements TreeNodeData {
115
115
  isPartOfDerivedPropertyBranch: boolean,
116
116
  type: Type,
117
117
  mappingData: QueryBuilderExplorerTreeNodeMappingData,
118
+ childrenIds?: string[] | undefined,
118
119
  ) {
119
120
  makeObservable(this, {
120
121
  isHighlighting: observable,
@@ -131,6 +132,9 @@ export abstract class QueryBuilderExplorerTreeNodeData implements TreeNodeData {
131
132
  this.isPartOfDerivedPropertyBranch = isPartOfDerivedPropertyBranch;
132
133
  this.type = type;
133
134
  this.mappingData = mappingData;
135
+ if (childrenIds) {
136
+ this.childrenIds = childrenIds;
137
+ }
134
138
  this.elementRef = createRef();
135
139
  }
136
140
 
@@ -169,6 +173,7 @@ export class QueryBuilderExplorerTreePropertyNodeData extends QueryBuilderExplor
169
173
  isPartOfDerivedPropertyBranch: boolean,
170
174
  mappingData: QueryBuilderExplorerTreeNodeMappingData,
171
175
  type?: Type | undefined,
176
+ childrenIds?: string[],
172
177
  ) {
173
178
  super(
174
179
  id,
@@ -177,6 +182,7 @@ export class QueryBuilderExplorerTreePropertyNodeData extends QueryBuilderExplor
177
182
  isPartOfDerivedPropertyBranch,
178
183
  type ?? property.genericType.value.rawType,
179
184
  mappingData,
185
+ childrenIds,
180
186
  );
181
187
  this.property = property;
182
188
  this.parentId = parentId;
@@ -197,6 +203,7 @@ export class QueryBuilderExplorerTreeSubTypeNodeData extends QueryBuilderExplore
197
203
  isPartOfDerivedPropertyBranch: boolean,
198
204
  mappingData: QueryBuilderExplorerTreeNodeMappingData,
199
205
  multiplicity: Multiplicity,
206
+ childrenIds?: string[],
200
207
  ) {
201
208
  super(
202
209
  id,
@@ -205,6 +212,7 @@ export class QueryBuilderExplorerTreeSubTypeNodeData extends QueryBuilderExplore
205
212
  isPartOfDerivedPropertyBranch,
206
213
  subclass,
207
214
  mappingData,
215
+ childrenIds,
208
216
  );
209
217
  this.subclass = subclass;
210
218
  this.parentId = parentId;
@@ -652,6 +660,49 @@ const getQueryBuilderTreeData = (
652
660
  return { rootIds, nodes };
653
661
  };
654
662
 
663
+ export const cloneQueryBuilderExplorerTreeNodeData = (
664
+ node: QueryBuilderExplorerTreeNodeData,
665
+ ): QueryBuilderExplorerTreeNodeData => {
666
+ if (node instanceof QueryBuilderExplorerTreeRootNodeData) {
667
+ return new QueryBuilderExplorerTreeRootNodeData(
668
+ node.id,
669
+ node.label,
670
+ node.dndText,
671
+ node.isPartOfDerivedPropertyBranch,
672
+ node.type,
673
+ node.mappingData,
674
+ node.childrenIds,
675
+ );
676
+ } else if (node instanceof QueryBuilderExplorerTreePropertyNodeData) {
677
+ return new QueryBuilderExplorerTreePropertyNodeData(
678
+ node.id,
679
+ node.label,
680
+ node.dndText,
681
+ node.property,
682
+ node.parentId,
683
+ node.isPartOfDerivedPropertyBranch,
684
+ node.mappingData,
685
+ node.type,
686
+ node.childrenIds,
687
+ );
688
+ } else if (node instanceof QueryBuilderExplorerTreeSubTypeNodeData) {
689
+ return new QueryBuilderExplorerTreeSubTypeNodeData(
690
+ node.id,
691
+ node.label,
692
+ node.dndText,
693
+ node.subclass,
694
+ node.parentId,
695
+ node.isPartOfDerivedPropertyBranch,
696
+ node.mappingData,
697
+ node.multiplicity,
698
+ node.childrenIds,
699
+ );
700
+ }
701
+ throw new UnsupportedOperationError(
702
+ `Unable to clone node of type ${node.constructor.name}`,
703
+ );
704
+ };
705
+
655
706
  export class QueryBuilderExplorerPreviewDataState {
656
707
  isGeneratingPreviewData = false;
657
708
  propertyName = '(unknown)';
@@ -957,7 +1008,7 @@ export class QueryBuilderExplorerState {
957
1008
  case PRIMITIVE_TYPE.INTEGER:
958
1009
  case PRIMITIVE_TYPE.DECIMAL:
959
1010
  case PRIMITIVE_TYPE.FLOAT: {
960
- const previewResult =
1011
+ const previewResult = (
961
1012
  (yield this.queryBuilderState.graphManagerState.graphManager.runQuery(
962
1013
  buildNumericPreviewDataQuery(
963
1014
  this.queryBuilderState,
@@ -970,7 +1021,8 @@ export class QueryBuilderExplorerState {
970
1021
  abortController:
971
1022
  this.previewDataState.previewDataAbortController,
972
1023
  },
973
- )) as ExecutionResult;
1024
+ )) as ExecutionResultWithMetadata
1025
+ ).executionResult;
974
1026
  assertType(
975
1027
  previewResult,
976
1028
  TDSExecutionResult,
@@ -998,7 +1050,7 @@ export class QueryBuilderExplorerState {
998
1050
  case PRIMITIVE_TYPE.DATE:
999
1051
  case PRIMITIVE_TYPE.STRICTDATE:
1000
1052
  case PRIMITIVE_TYPE.DATETIME: {
1001
- const previewResult =
1053
+ const previewResult = (
1002
1054
  (yield this.queryBuilderState.graphManagerState.graphManager.runQuery(
1003
1055
  buildNonNumericPreviewDataQuery(
1004
1056
  this.queryBuilderState,
@@ -1011,7 +1063,8 @@ export class QueryBuilderExplorerState {
1011
1063
  abortController:
1012
1064
  this.previewDataState.previewDataAbortController,
1013
1065
  },
1014
- )) as ExecutionResult;
1066
+ )) as ExecutionResultWithMetadata
1067
+ ).executionResult;
1015
1068
  assertType(
1016
1069
  previewResult,
1017
1070
  TDSExecutionResult,
@@ -18,7 +18,7 @@ import { FuzzySearchAdvancedConfigState } from '@finos/legend-shared';
18
18
  import { action, makeObservable, observable } from 'mobx';
19
19
 
20
20
  export class QueryBuilderFuzzySearchAdvancedConfigState extends FuzzySearchAdvancedConfigState {
21
- includeSubTypes = false;
21
+ includeSubTypes = true;
22
22
  includeDocumentation = false;
23
23
 
24
24
  constructor(
@@ -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,8 +19,8 @@ import {
19
19
  type PureModel,
20
20
  type Type,
21
21
  type ValueSpecification,
22
- type ExecutionResult,
23
22
  type SimpleFunctionExpression,
23
+ type ExecutionResultWithMetadata,
24
24
  observe_ValueSpecification,
25
25
  PrimitiveType,
26
26
  CollectionInstanceValue,
@@ -490,7 +490,7 @@ export class PostFilterConditionState implements Hashable {
490
490
  );
491
491
  const value = searchValue ?? rightConditionValue.value;
492
492
  if (performTypeahead(value)) {
493
- const result =
493
+ const result = (
494
494
  (yield this.postFilterState.tdsState.queryBuilderState.graphManagerState.graphManager.runQuery(
495
495
  buildProjectionColumnTypeaheadQuery(
496
496
  this.postFilterState.tdsState.queryBuilderState,
@@ -507,7 +507,8 @@ export class PostFilterConditionState implements Hashable {
507
507
  ),
508
508
  this.postFilterState.tdsState.queryBuilderState.graphManagerState
509
509
  .graph,
510
- )) as ExecutionResult;
510
+ )) as ExecutionResultWithMetadata
511
+ ).executionResult;
511
512
  this.typeaheadSearchResults = buildTypeaheadOptions(result);
512
513
  }
513
514
  this.typeaheadSearchState.pass();
@@ -37,10 +37,10 @@ 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
41
  type Type,
42
+ type ExecutionResultWithMetadata,
43
+ AbstractPropertyExpression,
44
44
  observe_ValueSpecification,
45
45
  CollectionInstanceValue,
46
46
  InstanceValue,
@@ -300,7 +300,7 @@ export class FilterConditionState implements Hashable {
300
300
  );
301
301
  const value = searchValue ?? rightConditionValue.value;
302
302
  if (performTypeahead(value)) {
303
- const result =
303
+ const result = (
304
304
  (yield this.filterState.queryBuilderState.graphManagerState.graphManager.runQuery(
305
305
  buildPropertyTypeaheadQuery(
306
306
  this.filterState.queryBuilderState,
@@ -315,7 +315,8 @@ export class FilterConditionState implements Hashable {
315
315
  .runtimeValue,
316
316
  ),
317
317
  this.filterState.queryBuilderState.graphManagerState.graph,
318
- )) as ExecutionResult;
318
+ )) as ExecutionResultWithMetadata
319
+ ).executionResult;
319
320
  this.typeaheadSearchResults = buildTypeaheadOptions(result);
320
321
  }
321
322
  this.typeaheadSearchState.pass();