@itwin/presentation-hierarchies 2.0.0-alpha.5 → 2.0.0-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -0
- package/lib/cjs/hierarchies/HierarchyFiltering.d.ts +77 -36
- package/lib/cjs/hierarchies/HierarchyFiltering.d.ts.map +1 -1
- package/lib/cjs/hierarchies/HierarchyFiltering.js +126 -98
- package/lib/cjs/hierarchies/HierarchyFiltering.js.map +1 -1
- package/lib/cjs/hierarchies/HierarchyMerge.d.ts +19 -0
- package/lib/cjs/hierarchies/HierarchyMerge.d.ts.map +1 -0
- package/lib/cjs/hierarchies/HierarchyMerge.js +43 -0
- package/lib/cjs/hierarchies/HierarchyMerge.js.map +1 -0
- package/lib/cjs/hierarchies/HierarchyNode.d.ts +2 -2
- package/lib/cjs/hierarchies/HierarchyNode.d.ts.map +1 -1
- package/lib/cjs/hierarchies/HierarchyNode.js.map +1 -1
- package/lib/cjs/hierarchies/HierarchyNodeKey.d.ts.map +1 -1
- package/lib/cjs/hierarchies/HierarchyNodeKey.js +8 -8
- package/lib/cjs/hierarchies/HierarchyNodeKey.js.map +1 -1
- package/lib/cjs/hierarchies/HierarchyProvider.d.ts +0 -18
- package/lib/cjs/hierarchies/HierarchyProvider.d.ts.map +1 -1
- package/lib/cjs/hierarchies/HierarchyProvider.js +0 -37
- package/lib/cjs/hierarchies/HierarchyProvider.js.map +1 -1
- package/lib/cjs/hierarchies/imodel/FilteringHierarchyDefinition.d.ts +2 -0
- package/lib/cjs/hierarchies/imodel/FilteringHierarchyDefinition.d.ts.map +1 -1
- package/lib/cjs/hierarchies/imodel/FilteringHierarchyDefinition.js +45 -30
- package/lib/cjs/hierarchies/imodel/FilteringHierarchyDefinition.js.map +1 -1
- package/lib/cjs/hierarchies/imodel/IModelHierarchyProvider.d.ts +42 -7
- package/lib/cjs/hierarchies/imodel/IModelHierarchyProvider.d.ts.map +1 -1
- package/lib/cjs/hierarchies/imodel/IModelHierarchyProvider.js +136 -45
- package/lib/cjs/hierarchies/imodel/IModelHierarchyProvider.js.map +1 -1
- package/lib/cjs/hierarchies/imodel/TreeNodesReader.d.ts.map +1 -1
- package/lib/cjs/hierarchies/imodel/TreeNodesReader.js +8 -1
- package/lib/cjs/hierarchies/imodel/TreeNodesReader.js.map +1 -1
- package/lib/cjs/hierarchies/internal/Common.d.ts +3 -0
- package/lib/cjs/hierarchies/internal/Common.d.ts.map +1 -1
- package/lib/cjs/hierarchies/internal/Common.js +12 -1
- package/lib/cjs/hierarchies/internal/Common.js.map +1 -1
- package/lib/cjs/hierarchies/internal/RxjsHierarchyDefinition.d.ts.map +1 -1
- package/lib/cjs/hierarchies/internal/RxjsHierarchyDefinition.js +2 -1
- package/lib/cjs/hierarchies/internal/RxjsHierarchyDefinition.js.map +1 -1
- package/lib/cjs/presentation-hierarchies.d.ts +3 -2
- package/lib/cjs/presentation-hierarchies.d.ts.map +1 -1
- package/lib/cjs/presentation-hierarchies.js +4 -3
- package/lib/cjs/presentation-hierarchies.js.map +1 -1
- package/lib/esm/hierarchies/HierarchyFiltering.d.ts +77 -36
- package/lib/esm/hierarchies/HierarchyFiltering.d.ts.map +1 -1
- package/lib/esm/hierarchies/HierarchyFiltering.js +125 -98
- package/lib/esm/hierarchies/HierarchyFiltering.js.map +1 -1
- package/lib/esm/hierarchies/HierarchyMerge.d.ts +19 -0
- package/lib/esm/hierarchies/HierarchyMerge.d.ts.map +1 -0
- package/lib/esm/hierarchies/HierarchyMerge.js +40 -0
- package/lib/esm/hierarchies/HierarchyMerge.js.map +1 -0
- package/lib/esm/hierarchies/HierarchyNode.d.ts +2 -2
- package/lib/esm/hierarchies/HierarchyNode.d.ts.map +1 -1
- package/lib/esm/hierarchies/HierarchyNode.js.map +1 -1
- package/lib/esm/hierarchies/HierarchyNodeKey.d.ts.map +1 -1
- package/lib/esm/hierarchies/HierarchyNodeKey.js +9 -9
- package/lib/esm/hierarchies/HierarchyNodeKey.js.map +1 -1
- package/lib/esm/hierarchies/HierarchyProvider.d.ts +0 -18
- package/lib/esm/hierarchies/HierarchyProvider.d.ts.map +1 -1
- package/lib/esm/hierarchies/HierarchyProvider.js +1 -36
- package/lib/esm/hierarchies/HierarchyProvider.js.map +1 -1
- package/lib/esm/hierarchies/imodel/FilteringHierarchyDefinition.d.ts +2 -0
- package/lib/esm/hierarchies/imodel/FilteringHierarchyDefinition.d.ts.map +1 -1
- package/lib/esm/hierarchies/imodel/FilteringHierarchyDefinition.js +47 -32
- package/lib/esm/hierarchies/imodel/FilteringHierarchyDefinition.js.map +1 -1
- package/lib/esm/hierarchies/imodel/IModelHierarchyProvider.d.ts +42 -7
- package/lib/esm/hierarchies/imodel/IModelHierarchyProvider.d.ts.map +1 -1
- package/lib/esm/hierarchies/imodel/IModelHierarchyProvider.js +138 -48
- package/lib/esm/hierarchies/imodel/IModelHierarchyProvider.js.map +1 -1
- package/lib/esm/hierarchies/imodel/TreeNodesReader.d.ts.map +1 -1
- package/lib/esm/hierarchies/imodel/TreeNodesReader.js +8 -1
- package/lib/esm/hierarchies/imodel/TreeNodesReader.js.map +1 -1
- package/lib/esm/hierarchies/internal/Common.d.ts +3 -0
- package/lib/esm/hierarchies/internal/Common.d.ts.map +1 -1
- package/lib/esm/hierarchies/internal/Common.js +11 -1
- package/lib/esm/hierarchies/internal/Common.js.map +1 -1
- package/lib/esm/hierarchies/internal/RxjsHierarchyDefinition.d.ts.map +1 -1
- package/lib/esm/hierarchies/internal/RxjsHierarchyDefinition.js +3 -2
- package/lib/esm/hierarchies/internal/RxjsHierarchyDefinition.js.map +1 -1
- package/lib/esm/presentation-hierarchies.d.ts +3 -2
- package/lib/esm/presentation-hierarchies.d.ts.map +1 -1
- package/lib/esm/presentation-hierarchies.js +2 -2
- package/lib/esm/presentation-hierarchies.js.map +1 -1
- package/package.json +7 -7
|
@@ -37,7 +37,10 @@ interface IModelHierarchyProviderProps {
|
|
|
37
37
|
* @see `ECClassHierarchyInspector`
|
|
38
38
|
*/
|
|
39
39
|
imodelAccess: IModelAccess;
|
|
40
|
-
/**
|
|
40
|
+
/**
|
|
41
|
+
* An event that is raised when iModel data, that may affect the hierarchy, changes. The created provider
|
|
42
|
+
* subscribes to the event to know that it needs to reload the data, and unsubscribes on disposal.
|
|
43
|
+
*/
|
|
41
44
|
imodelChanged?: Event<() => void>;
|
|
42
45
|
/**
|
|
43
46
|
* A function that returns a hierarchy definition, describing how the hierarchy that the provider should be create. The
|
|
@@ -66,15 +69,47 @@ interface IModelHierarchyProviderProps {
|
|
|
66
69
|
};
|
|
67
70
|
}
|
|
68
71
|
/**
|
|
69
|
-
* Creates an instance of `HierarchyProvider` that creates a hierarchy based on given iModel and
|
|
72
|
+
* Creates an instance of `HierarchyProvider` that creates a hierarchy based on given the iModel and
|
|
70
73
|
* a hierarchy definition, which defines each hierarchy level through ECSQL queries.
|
|
71
74
|
*
|
|
72
75
|
* @public
|
|
73
76
|
*/
|
|
74
|
-
export declare function createIModelHierarchyProvider(props: IModelHierarchyProviderProps): HierarchyProvider &
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
export declare function createIModelHierarchyProvider(props: IModelHierarchyProviderProps): HierarchyProvider & Disposable;
|
|
78
|
+
/**
|
|
79
|
+
* Props for `createMergedIModelHierarchyProvider`.
|
|
80
|
+
* @alpha
|
|
81
|
+
*/
|
|
82
|
+
interface MergedIModelHierarchyProviderProps extends Omit<IModelHierarchyProviderProps, "imodelAccess" | "imodelChanged"> {
|
|
83
|
+
/**
|
|
84
|
+
* A list of iModels to create merged hierarchy for.
|
|
85
|
+
*
|
|
86
|
+
* **Warning:** These **must** all be different versions of the same iModel, ordered from the earliest to the
|
|
87
|
+
* latest version. Not obeying this rule may result in undefined behavior.
|
|
88
|
+
*/
|
|
89
|
+
imodels: Array<{
|
|
90
|
+
/**
|
|
91
|
+
* An object that provides access to iModel's data and metadata.
|
|
92
|
+
*
|
|
93
|
+
* @see `ECSchemaProvider`
|
|
94
|
+
* @see `LimitingECSqlQueryExecutor`
|
|
95
|
+
* @see `ECClassHierarchyInspector`
|
|
96
|
+
*/
|
|
97
|
+
imodelAccess: IModelAccess;
|
|
98
|
+
/**
|
|
99
|
+
* An event that is raised when iModel data, that may affect the hierarchy, changes. The created provider
|
|
100
|
+
* subscribes to the event to know that it needs to reload the data, and unsubscribes on disposal.
|
|
101
|
+
*/
|
|
102
|
+
imodelChanged?: Event<() => void>;
|
|
103
|
+
}>;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Creates an instance of `HierarchyProvider` that creates a hierarchy based on multiple version of **the same** iModel
|
|
107
|
+
* and a hierarchy definition, which defines each hierarchy level through ECSQL queries.
|
|
108
|
+
*
|
|
109
|
+
* **Warning:** This is an experimental API that **should not be used in production**.
|
|
110
|
+
*
|
|
111
|
+
* @alpha
|
|
112
|
+
*/
|
|
113
|
+
export declare function createMergedIModelHierarchyProvider(props: MergedIModelHierarchyProviderProps): HierarchyProvider & Disposable;
|
|
79
114
|
export {};
|
|
80
115
|
//# sourceMappingURL=IModelHierarchyProvider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IModelHierarchyProvider.d.ts","sourceRoot":"","sources":["../../../../src/hierarchies/imodel/IModelHierarchyProvider.ts"],"names":[],"mappings":"AAKA,OAAO,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"IModelHierarchyProvider.d.ts","sourceRoot":"","sources":["../../../../src/hierarchies/imodel/IModelHierarchyProvider.ts"],"names":[],"mappings":"AAKA,OAAO,gCAAgC,CAAC;AA4BxC,OAAO,EAGL,yBAAyB,EACzB,gBAAgB,EAGhB,KAAK,EAIL,wBAAwB,EAEzB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAGlE,OAAO,EAA0B,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAkBpF,OAAO,EAGL,mBAAmB,EAGpB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAe7E;;;GAGG;AACH,UAAU,uCAAuC;IAC/C;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;CACf;AAED,cAAc;AACd,KAAK,YAAY,GAAG,gBAAgB,GAAG,0BAA0B,GAAG,yBAAyB,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtH;;;GAGG;AACH,UAAU,4BAA4B;IACpC;;;;;;OAMG;IACH,YAAY,EAAE,YAAY,CAAC;IAE3B;;;OAGG;IACH,aAAa,CAAC,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC;IAElC;;;OAGG;IACH,mBAAmB,EAAE,mBAAmB,CAAC;IAEzC,qGAAqG;IACrG,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,sEAAsE;IACtE,gBAAgB,CAAC,EAAE,OAAO,CAAC,uCAAuC,CAAC,CAAC;IAEpE;;;;OAIG;IACH,SAAS,CAAC,EAAE,wBAAwB,CAAC;IAErC,yCAAyC;IACzC,SAAS,CAAC,EAAE;QACV,2DAA2D;QAC3D,KAAK,EAAE,sBAAsB,EAAE,CAAC;KACjC,CAAC;CACH;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,4BAA4B,GAAG,iBAAiB,GAAG,UAAU,CAGjH;AAED;;;GAGG;AACH,UAAU,kCAAmC,SAAQ,IAAI,CAAC,4BAA4B,EAAE,cAAc,GAAG,eAAe,CAAC;IACvH;;;;;OAKG;IACH,OAAO,EAAE,KAAK,CAAC;QACb;;;;;;WAMG;QACH,YAAY,EAAE,YAAY,CAAC;QAE3B;;;WAGG;QACH,aAAa,CAAC,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC;KACnC,CAAC,CAAC;CACJ;AAED;;;;;;;GAOG;AACH,wBAAgB,mCAAmC,CAAC,KAAK,EAAE,kCAAkC,GAAG,iBAAiB,GAAG,UAAU,CAE7H"}
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
4
4
|
*--------------------------------------------------------------------------------------------*/
|
|
5
5
|
import "../internal/DisposePolyfill.js";
|
|
6
|
-
import { catchError, concat, defaultIfEmpty, EMPTY, filter, finalize, from, identity, map, merge, mergeAll, mergeMap, of, Subject, take, takeUntil, tap, } from "rxjs";
|
|
6
|
+
import { catchError, concat, defaultIfEmpty, defer, EMPTY, filter, finalize, from, fromEventPattern, identity, map, merge, mergeAll, mergeMap, of, reduce, Subject, take, takeUntil, tap, } from "rxjs";
|
|
7
7
|
import { assert, BeEvent, Guid, StopWatch } from "@itwin/core-bentley";
|
|
8
|
-
import { createDefaultValueFormatter, formatConcatenatedValue, normalizeFullClassName, } from "@itwin/presentation-shared";
|
|
8
|
+
import { createDefaultValueFormatter, formatConcatenatedValue, InstanceKey, normalizeFullClassName, } from "@itwin/presentation-shared";
|
|
9
9
|
import { RowsLimitExceededError } from "../HierarchyErrors.js";
|
|
10
10
|
import { HierarchyNode } from "../HierarchyNode.js";
|
|
11
11
|
import { HierarchyNodeKey } from "../HierarchyNodeKey.js";
|
|
@@ -20,7 +20,7 @@ import { getRxjsHierarchyDefinition } from "../internal/RxjsHierarchyDefinition.
|
|
|
20
20
|
import { SubscriptionScheduler } from "../internal/SubscriptionScheduler.js";
|
|
21
21
|
import { FilteringHierarchyDefinition } from "./FilteringHierarchyDefinition.js";
|
|
22
22
|
import { HierarchyCache } from "./HierarchyCache.js";
|
|
23
|
-
import { HierarchyNodesDefinition } from "./IModelHierarchyDefinition.js";
|
|
23
|
+
import { HierarchyNodesDefinition, } from "./IModelHierarchyDefinition.js";
|
|
24
24
|
import { NodeSelectClauseColumnNames } from "./NodeSelectQueryFactory.js";
|
|
25
25
|
import { createDetermineChildrenOperator } from "./operators/DetermineChildren.js";
|
|
26
26
|
import { createGroupingOperator } from "./operators/Grouping.js";
|
|
@@ -33,36 +33,56 @@ const LOGGING_NAMESPACE_PERFORMANCE = `${BASE_LOGGING_NAMESPACE_PERFORMANCE}.IMo
|
|
|
33
33
|
const DEFAULT_QUERY_CONCURRENCY = 10;
|
|
34
34
|
const DEFAULT_QUERY_CACHE_SIZE = 1;
|
|
35
35
|
/**
|
|
36
|
-
* Creates an instance of `HierarchyProvider` that creates a hierarchy based on given iModel and
|
|
36
|
+
* Creates an instance of `HierarchyProvider` that creates a hierarchy based on given the iModel and
|
|
37
37
|
* a hierarchy definition, which defines each hierarchy level through ECSQL queries.
|
|
38
38
|
*
|
|
39
39
|
* @public
|
|
40
40
|
*/
|
|
41
41
|
export function createIModelHierarchyProvider(props) {
|
|
42
|
+
const { imodelAccess, imodelChanged, ...restProps } = props;
|
|
43
|
+
return createMergedIModelHierarchyProvider({ ...restProps, imodels: [{ imodelAccess, imodelChanged }] });
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Creates an instance of `HierarchyProvider` that creates a hierarchy based on multiple version of **the same** iModel
|
|
47
|
+
* and a hierarchy definition, which defines each hierarchy level through ECSQL queries.
|
|
48
|
+
*
|
|
49
|
+
* **Warning:** This is an experimental API that **should not be used in production**.
|
|
50
|
+
*
|
|
51
|
+
* @alpha
|
|
52
|
+
*/
|
|
53
|
+
export function createMergedIModelHierarchyProvider(props) {
|
|
42
54
|
return new IModelHierarchyProviderImpl(props);
|
|
43
55
|
}
|
|
44
56
|
class IModelHierarchyProviderImpl {
|
|
45
|
-
|
|
57
|
+
_imodels;
|
|
46
58
|
_hierarchyChanged;
|
|
47
59
|
_valuesFormatter;
|
|
48
60
|
_sourceHierarchyDefinition;
|
|
49
61
|
_activeHierarchyDefinition;
|
|
50
62
|
_localizedStrings;
|
|
51
|
-
|
|
63
|
+
_queryConcurrency;
|
|
64
|
+
_querySchedulers;
|
|
52
65
|
_nodesCache;
|
|
53
66
|
_unsubscribe;
|
|
54
67
|
_dispose = new Subject();
|
|
55
68
|
#componentId;
|
|
56
69
|
#componentName;
|
|
70
|
+
#sourceName;
|
|
57
71
|
constructor(props) {
|
|
72
|
+
if (props.imodels.length === 0) {
|
|
73
|
+
throw new Error(`Creating an iModel hierarchy provider requires at least one iModel.`);
|
|
74
|
+
}
|
|
58
75
|
this.#componentId = Guid.createValue();
|
|
59
76
|
this.#componentName = "IModelHierarchyProviderImpl";
|
|
60
|
-
|
|
77
|
+
/* c8 ignore next */
|
|
78
|
+
this.#sourceName = props.sourceName ?? `${this.#componentName}:${this.#componentId}`;
|
|
79
|
+
this._imodels = props.imodels;
|
|
61
80
|
this._hierarchyChanged = new BeEvent();
|
|
62
81
|
this._activeHierarchyDefinition = this._sourceHierarchyDefinition = getRxjsHierarchyDefinition(props.hierarchyDefinition);
|
|
63
82
|
this._valuesFormatter = props?.formatter ?? createDefaultValueFormatter();
|
|
64
83
|
this._localizedStrings = { other: "Other", unspecified: "Not specified", ...props?.localizedStrings };
|
|
65
|
-
this.
|
|
84
|
+
this._queryConcurrency = props.queryConcurrency ?? DEFAULT_QUERY_CONCURRENCY;
|
|
85
|
+
this._querySchedulers = new Map();
|
|
66
86
|
this.setHierarchyFilter(props.filtering);
|
|
67
87
|
const queryCacheSize = props.queryCacheSize ?? DEFAULT_QUERY_CACHE_SIZE;
|
|
68
88
|
if (queryCacheSize !== 0) {
|
|
@@ -72,11 +92,18 @@ class IModelHierarchyProviderImpl {
|
|
|
72
92
|
variationsCount: 1,
|
|
73
93
|
});
|
|
74
94
|
}
|
|
75
|
-
|
|
76
|
-
|
|
95
|
+
const imodelChangeSubscription = from(this._imodels)
|
|
96
|
+
.pipe(mergeMap(({ imodelAccess, imodelChanged }) => imodelChanged
|
|
97
|
+
? fromEventPattern((handler) => imodelChanged.addListener(handler), (handler) => imodelChanged.removeListener(handler), () => imodelAccess)
|
|
98
|
+
: EMPTY))
|
|
99
|
+
.subscribe(({ imodelKey }) => {
|
|
100
|
+
this.invalidateHierarchyCache(`Data source changed: "${imodelKey}"`);
|
|
77
101
|
this._dispose.next();
|
|
78
102
|
this._hierarchyChanged.raiseEvent();
|
|
79
103
|
});
|
|
104
|
+
this._unsubscribe = () => {
|
|
105
|
+
imodelChangeSubscription.unsubscribe();
|
|
106
|
+
};
|
|
80
107
|
}
|
|
81
108
|
[Symbol.dispose]() {
|
|
82
109
|
this._dispose.next();
|
|
@@ -89,6 +116,17 @@ class IModelHierarchyProviderImpl {
|
|
|
89
116
|
get hierarchyChanged() {
|
|
90
117
|
return this._hierarchyChanged;
|
|
91
118
|
}
|
|
119
|
+
getQueryScheduler(imodelKey) {
|
|
120
|
+
let scheduler = this._querySchedulers.get(imodelKey);
|
|
121
|
+
if (!scheduler) {
|
|
122
|
+
scheduler = new SubscriptionScheduler(this._queryConcurrency);
|
|
123
|
+
this._querySchedulers.set(imodelKey, scheduler);
|
|
124
|
+
}
|
|
125
|
+
return scheduler;
|
|
126
|
+
}
|
|
127
|
+
getPrimaryIModelAccess() {
|
|
128
|
+
return this._imodels[this._imodels.length - 1].imodelAccess;
|
|
129
|
+
}
|
|
92
130
|
invalidateHierarchyCache(reason) {
|
|
93
131
|
doLog({
|
|
94
132
|
category: `${LOGGING_NAMESPACE}.Events`,
|
|
@@ -114,8 +152,9 @@ class IModelHierarchyProviderImpl {
|
|
|
114
152
|
return;
|
|
115
153
|
}
|
|
116
154
|
this._activeHierarchyDefinition = new FilteringHierarchyDefinition({
|
|
117
|
-
imodelAccess: this.
|
|
155
|
+
imodelAccess: this.getPrimaryIModelAccess(),
|
|
118
156
|
source: this._sourceHierarchyDefinition,
|
|
157
|
+
sourceName: this.#sourceName,
|
|
119
158
|
nodeIdentifierPaths: props.paths,
|
|
120
159
|
});
|
|
121
160
|
this.invalidateHierarchyCache("Hierarchy filter set");
|
|
@@ -131,44 +170,51 @@ class IModelHierarchyProviderImpl {
|
|
|
131
170
|
category: LOGGING_NAMESPACE_PERFORMANCE,
|
|
132
171
|
message: /* c8 ignore next */ () => `[${requestContext.requestId}] Requesting hierarchy level definitions for ${createNodeIdentifierForLogging(props.parentNode)}`,
|
|
133
172
|
});
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
if (parentNode && HierarchyNode.isInstancesNode(parentNode)) {
|
|
139
|
-
parentNode = {
|
|
140
|
-
...parentNode,
|
|
141
|
-
key: {
|
|
142
|
-
...parentNode.key,
|
|
143
|
-
instanceKeys: parentNode.key.instanceKeys.filter((ik) => !ik.imodelKey || ik.imodelKey === this._imodelAccess.imodelKey),
|
|
144
|
-
},
|
|
145
|
-
};
|
|
146
|
-
assert(HierarchyNodeKey.isInstances(parentNode.key));
|
|
147
|
-
if (parentNode.key.instanceKeys.length === 0) {
|
|
173
|
+
return from(this._imodels).pipe(mergeMap(({ imodelAccess }, imodelAccessIndex) => {
|
|
174
|
+
let parentNode = props.parentNode;
|
|
175
|
+
if (parentNode && HierarchyNode.isGeneric(parentNode) && parentNode.key.source && parentNode.key.source !== this.#sourceName) {
|
|
148
176
|
return EMPTY;
|
|
149
177
|
}
|
|
150
|
-
|
|
151
|
-
|
|
178
|
+
if (parentNode && HierarchyNode.isInstancesNode(parentNode)) {
|
|
179
|
+
parentNode = {
|
|
180
|
+
...parentNode,
|
|
181
|
+
key: {
|
|
182
|
+
...parentNode.key,
|
|
183
|
+
instanceKeys: parentNode.key.instanceKeys.filter((ik) => !ik.imodelKey || ik.imodelKey === imodelAccess.imodelKey),
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
assert(HierarchyNodeKey.isInstances(parentNode.key));
|
|
187
|
+
if (parentNode.key.instanceKeys.length === 0) {
|
|
188
|
+
return EMPTY;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return this._activeHierarchyDefinition.defineHierarchyLevel({ ...defineHierarchyLevelProps, parentNode }).pipe(mergeAll(), map(
|
|
192
|
+
/* Using `as` to work around TS not understanding that `{ x: A, y: B | C }` is the same as `{ x: A } & ({ y: B } | { y: C })` */
|
|
193
|
+
(hierarchyNodesDefinition) => ({ imodelAccess, imodelAccessIndex, hierarchyNodesDefinition })));
|
|
194
|
+
}), finalize(() => doLog({
|
|
152
195
|
category: LOGGING_NAMESPACE_PERFORMANCE,
|
|
153
196
|
message: /* c8 ignore next */ () => `[${requestContext.requestId}] Received all hierarchy level definitions for ${createNodeIdentifierForLogging(props.parentNode)}`,
|
|
154
197
|
})));
|
|
155
198
|
}
|
|
156
199
|
createSourceNodesObservable(props) {
|
|
157
200
|
// pipe definitions to nodes and put "share replay" on it
|
|
158
|
-
return this.createHierarchyLevelDefinitionsObservable(props).pipe(mergeMap((def) => {
|
|
201
|
+
return this.createHierarchyLevelDefinitionsObservable(props).pipe(mergeMap(({ imodelAccess, imodelAccessIndex, hierarchyNodesDefinition: def }) => defer(() => {
|
|
159
202
|
if (HierarchyNodesDefinition.isGenericNode(def)) {
|
|
160
|
-
return of({
|
|
203
|
+
return of({
|
|
204
|
+
...def.node,
|
|
205
|
+
key: { type: "generic", id: def.node.key, source: this.#sourceName },
|
|
206
|
+
});
|
|
161
207
|
}
|
|
162
|
-
return this.
|
|
163
|
-
queryExecutor:
|
|
208
|
+
return this.getQueryScheduler(imodelAccess.imodelKey).scheduleSubscription(of(def.query).pipe(map((query) => filterQueryByInstanceKeys(query, props.filteredInstanceKeys)), mergeMap((query) => readNodes({
|
|
209
|
+
queryExecutor: imodelAccess,
|
|
164
210
|
query,
|
|
165
211
|
limit: props.hierarchyLevelSizeLimit,
|
|
166
212
|
parser: this._activeHierarchyDefinition.parseNode ? (row) => this._activeHierarchyDefinition.parseNode(row, props.parentNode) : undefined,
|
|
167
213
|
})), map((node) => ({
|
|
168
214
|
...node,
|
|
169
|
-
key: { ...node.key, instanceKeys: node.key.instanceKeys.map((key) => ({ ...key, imodelKey:
|
|
215
|
+
key: { ...node.key, instanceKeys: node.key.instanceKeys.map((key) => ({ ...key, imodelKey: imodelAccess.imodelKey })) },
|
|
170
216
|
}))));
|
|
171
|
-
}), finalize(() => doLog({
|
|
217
|
+
}).pipe(map((node) => ({ imodelAccess, imodelAccessIndex, node })))), mergeNodes, map(({ node }) => node), finalize(() => doLog({
|
|
172
218
|
category: LOGGING_NAMESPACE_PERFORMANCE,
|
|
173
219
|
message: /* c8 ignore next */ () => `[${props.requestContext.requestId}] Read all child nodes ${createNodeIdentifierForLogging(props.parentNode)}`,
|
|
174
220
|
})), shareReplayWithErrors());
|
|
@@ -182,6 +228,7 @@ class IModelHierarchyProviderImpl {
|
|
|
182
228
|
// format `ConcatenatedValue` labels into string labels
|
|
183
229
|
mergeMap((node) => applyLabelsFormatting(node, this._valuesFormatter)),
|
|
184
230
|
// we have `ProcessedHierarchyNode` from here
|
|
231
|
+
// let consumers step-in
|
|
185
232
|
preProcessNodes(this._activeHierarchyDefinition),
|
|
186
233
|
// process hiding
|
|
187
234
|
createHideIfNoChildrenOperator((n) => this.getChildNodesObservables({ parentNode: n, requestContext: props.requestContext }).hasNodes), createHideNodesInHierarchyOperator(
|
|
@@ -192,7 +239,7 @@ class IModelHierarchyProviderImpl {
|
|
|
192
239
|
})));
|
|
193
240
|
}
|
|
194
241
|
createProcessedNodesObservable(preprocessedNodesObservable, props) {
|
|
195
|
-
return preprocessedNodesObservable.pipe(createGroupingOperator(this.
|
|
242
|
+
return preprocessedNodesObservable.pipe(createGroupingOperator(this.getPrimaryIModelAccess(), props.parentNode, this._valuesFormatter, this._localizedStrings, undefined, (gn) => this.onGroupingNodeCreated(gn, props)), finalize(() => doLog({
|
|
196
243
|
category: LOGGING_NAMESPACE_PERFORMANCE,
|
|
197
244
|
message: /* c8 ignore next */ () => `[${props.requestContext.requestId}] Finished grouping child nodes for ${createNodeIdentifierForLogging(props.parentNode)}`,
|
|
198
245
|
})));
|
|
@@ -202,9 +249,7 @@ class IModelHierarchyProviderImpl {
|
|
|
202
249
|
if ("processingParams" in n) {
|
|
203
250
|
delete n.processingParams;
|
|
204
251
|
}
|
|
205
|
-
return
|
|
206
|
-
children: hasChildren(n),
|
|
207
|
-
});
|
|
252
|
+
return { ...n, children: hasChildren(n) };
|
|
208
253
|
}), takeUntil(this._dispose), finalize(() => doLog({
|
|
209
254
|
category: LOGGING_NAMESPACE_PERFORMANCE,
|
|
210
255
|
message: /* c8 ignore next */ () => `[${props.requestContext.requestId}] Finished finalizing child nodes for ${createNodeIdentifierForLogging(props.parentNode)}`,
|
|
@@ -319,11 +364,11 @@ class IModelHierarchyProviderImpl {
|
|
|
319
364
|
return from(parentNode.groupedInstanceKeys);
|
|
320
365
|
}
|
|
321
366
|
assert(!parentNode || HierarchyNode.isGeneric(parentNode) || HierarchyNode.isInstancesNode(parentNode));
|
|
322
|
-
const hierarchyLevelDefinitions = this.createHierarchyLevelDefinitionsObservable({ parentNode, instanceFilter, requestContext });
|
|
323
367
|
// split the definitions based on whether they're for generic nodes or for instance nodes
|
|
324
|
-
const
|
|
368
|
+
const hierarchyLevelDefinitions = this.createHierarchyLevelDefinitionsObservable({ parentNode, instanceFilter, requestContext });
|
|
369
|
+
const [instanceDefs, genericDefs] = partition(hierarchyLevelDefinitions, (x) => HierarchyNodesDefinition.isInstanceNodesQuery(x.hierarchyNodesDefinition));
|
|
325
370
|
// query instance keys and a flag whether they should be hidden
|
|
326
|
-
const instanceKeys = instanceDefs.pipe(mergeMap((def) => this.
|
|
371
|
+
const instanceKeys = instanceDefs.pipe(mergeMap(({ imodelAccess, hierarchyNodesDefinition: def }) => this.getQueryScheduler(imodelAccess.imodelKey).scheduleSubscription(of(def.query).pipe(mergeMap(async (query) => {
|
|
327
372
|
const ecsql = `
|
|
328
373
|
SELECT
|
|
329
374
|
${NodeSelectClauseColumnNames.FullClassName},
|
|
@@ -333,7 +378,7 @@ class IModelHierarchyProviderImpl {
|
|
|
333
378
|
${query.ecsql}
|
|
334
379
|
)
|
|
335
380
|
`;
|
|
336
|
-
const reader =
|
|
381
|
+
const reader = imodelAccess.createQueryReader({ ...query, ecsql }, {
|
|
337
382
|
rowFormat: "Indexes",
|
|
338
383
|
limit: hierarchyLevelSizeLimit,
|
|
339
384
|
restartToken: `${this.#componentName}/${this.#componentId}/node-instance-keys/${Guid.createValue()}`,
|
|
@@ -342,7 +387,7 @@ class IModelHierarchyProviderImpl {
|
|
|
342
387
|
key: {
|
|
343
388
|
className: normalizeFullClassName(row[0]),
|
|
344
389
|
id: row[1],
|
|
345
|
-
imodelKey:
|
|
390
|
+
imodelKey: imodelAccess.imodelKey,
|
|
346
391
|
},
|
|
347
392
|
hide: !!row[2],
|
|
348
393
|
})));
|
|
@@ -352,17 +397,17 @@ class IModelHierarchyProviderImpl {
|
|
|
352
397
|
// hidden items' handling:
|
|
353
398
|
// - if a generic node is hidden, we'll want to retrieve instance keys of its children, otherwise we don't care about it,
|
|
354
399
|
// - if an instance key is hidden, we want to create a merged node similar to what we do in `createHideNodesInHierarchyOperator`
|
|
355
|
-
const hiddenParentNodes = merge(genericDefs.pipe(filter((
|
|
400
|
+
const hiddenParentNodes = merge(genericDefs.pipe(filter(({ hierarchyNodesDefinition }) => !!hierarchyNodesDefinition.node.processingParams?.hideInHierarchy), map(({ hierarchyNodesDefinition }) => ({
|
|
356
401
|
type: "generic",
|
|
357
|
-
id:
|
|
358
|
-
source: this
|
|
402
|
+
id: hierarchyNodesDefinition.node.key,
|
|
403
|
+
source: this.#sourceName,
|
|
359
404
|
}))), hiddenNodeInstanceKeys.pipe(
|
|
360
405
|
// first merge all keys by class
|
|
361
|
-
reduceToMergeMapList(({ key }) => key.className, ({ key }) => key
|
|
406
|
+
reduceToMergeMapList(({ key }) => key.className, ({ key }) => key),
|
|
362
407
|
// then, for each class, create an instance key
|
|
363
|
-
mergeMap((mergedMap) => [...mergedMap.entries()].map(([className,
|
|
408
|
+
mergeMap((mergedMap) => [...mergedMap.entries()].map(([className, keys]) => ({
|
|
364
409
|
type: "instances",
|
|
365
|
-
instanceKeys:
|
|
410
|
+
instanceKeys: keys.map(({ id, imodelKey }) => ({ className, id, imodelKey })),
|
|
366
411
|
}))))).pipe(map((key) => ({
|
|
367
412
|
key,
|
|
368
413
|
parentKeys: [],
|
|
@@ -451,4 +496,49 @@ function filterQueryByInstanceKeys(query, filteredInstanceKeys) {
|
|
|
451
496
|
};
|
|
452
497
|
/* c8 ignore end */
|
|
453
498
|
}
|
|
499
|
+
function mergeNodes(source) {
|
|
500
|
+
return from(source).pipe(reduce((acc, input) => {
|
|
501
|
+
for (let i = 0; i < acc.length; ++i) {
|
|
502
|
+
if (input.imodelAccess === acc[i].imodelAccess) {
|
|
503
|
+
// don't attempt to merge nodes if they come from the same provider
|
|
504
|
+
continue;
|
|
505
|
+
}
|
|
506
|
+
// the first argument for `tryMergeNodes` acts as the primary data source, so we have to make sure we pass
|
|
507
|
+
// the node with higher `imodelAccessIndex` first
|
|
508
|
+
const candidates = input.imodelAccessIndex > acc[i].imodelAccessIndex
|
|
509
|
+
? { imodelAccess: input.imodelAccess, imodelAccessIndex: input.imodelAccessIndex, primary: input.node, secondary: acc[i].node }
|
|
510
|
+
: { imodelAccess: acc[i].imodelAccess, imodelAccessIndex: acc[i].imodelAccessIndex, primary: acc[i].node, secondary: input.node };
|
|
511
|
+
const merged = tryMergeNodes(candidates.primary, candidates.secondary);
|
|
512
|
+
if (merged) {
|
|
513
|
+
acc[i] = { ...acc[i], node: merged, imodelAccess: candidates.imodelAccess, imodelAccessIndex: candidates.imodelAccessIndex };
|
|
514
|
+
return acc;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
acc.push(input);
|
|
518
|
+
return acc;
|
|
519
|
+
}, new Array()), mergeAll());
|
|
520
|
+
}
|
|
521
|
+
function tryMergeInstanceNodes(primary, secondary) {
|
|
522
|
+
if (HierarchyNode.isInstancesNode(primary) &&
|
|
523
|
+
HierarchyNode.isInstancesNode(secondary) &&
|
|
524
|
+
primary.key.instanceKeys.some((lhsKey) => secondary.key.instanceKeys.some((rhsKey) => InstanceKey.equals(lhsKey, rhsKey)))) {
|
|
525
|
+
return {
|
|
526
|
+
...primary,
|
|
527
|
+
key: {
|
|
528
|
+
type: "instances",
|
|
529
|
+
instanceKeys: primary.key.instanceKeys.concat(secondary.key.instanceKeys),
|
|
530
|
+
},
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
return undefined;
|
|
534
|
+
}
|
|
535
|
+
function tryMergeGenericNodes(primary, secondary) {
|
|
536
|
+
if (HierarchyNode.isGeneric(primary) && HierarchyNode.isGeneric(secondary) && primary.key.type === secondary.key.type) {
|
|
537
|
+
return primary;
|
|
538
|
+
}
|
|
539
|
+
return undefined;
|
|
540
|
+
}
|
|
541
|
+
function tryMergeNodes(primary, secondary) {
|
|
542
|
+
return tryMergeInstanceNodes(primary, secondary) ?? tryMergeGenericNodes(primary, secondary) ?? undefined;
|
|
543
|
+
}
|
|
454
544
|
//# sourceMappingURL=IModelHierarchyProvider.js.map
|