@finos/legend-query-builder 4.14.72 → 4.14.73

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