@itwin/presentation-hierarchies 0.1.6 → 0.2.0
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 +74 -0
- package/lib/cjs/hierarchies/HierarchyDefinition.d.ts +18 -0
- package/lib/cjs/hierarchies/HierarchyDefinition.d.ts.map +1 -1
- package/lib/cjs/hierarchies/HierarchyDefinition.js +6 -4
- package/lib/cjs/hierarchies/HierarchyDefinition.js.map +1 -1
- package/lib/esm/hierarchies/HierarchyDefinition.d.ts +18 -0
- package/lib/esm/hierarchies/HierarchyDefinition.d.ts.map +1 -1
- package/lib/esm/hierarchies/HierarchyDefinition.js +6 -4
- package/lib/esm/hierarchies/HierarchyDefinition.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,79 @@
|
|
|
1
1
|
# @itwin/presentation-hierarchies
|
|
2
2
|
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#642](https://github.com/iTwin/presentation/pull/642): Added `onlyIfNotHandled` flag to hierarchy level definitions that are passed to `createClassBasedHierarchyDefinition`.
|
|
8
|
+
This flag allows to skip instance node hierarchy level definitions if previous ones have defined hierarchy levels for a more specific class.
|
|
9
|
+
This can help to reduce repetition having to check if class doesn't match those of the more specific definitions.
|
|
10
|
+
|
|
11
|
+
Before:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
createClassBasedHierarchyDefinition({
|
|
15
|
+
classHierarchyInspector: inspector,
|
|
16
|
+
hierarchy: {
|
|
17
|
+
childNodes: [
|
|
18
|
+
{
|
|
19
|
+
parentNodeClassName: "BisCore.PhysicalElement",
|
|
20
|
+
definitions: async ({ parentNode }) => getPhysicalElementChildren(parentNode),
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
parentNodeClassName: "BisCore.SpatialElement",
|
|
24
|
+
definitions: async ({ parentNode, parentNodeClassName }) => {
|
|
25
|
+
if (await inspector.classDerivesFrom(parentNodeClassName, "BisCore.PhysicalElement")) {
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return getSpatialElementChildren(parentNode);
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
parentNodeClassName: "BisCore.GeometricElement3d",
|
|
34
|
+
definitions: async ({ parentNode, parentNodeClassName }) => {
|
|
35
|
+
if (await inspector.classDerivesFrom(parentNodeClassName, "BisCore.PhysicalElement")) {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (await inspector.classDerivesFrom(parentNodeClassName, "BisCore.SpatialElement")) {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return getGeometricElement3dChildren(parentNode);
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
After:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
createClassBasedHierarchyDefinition({
|
|
55
|
+
classHierarchyInspector,
|
|
56
|
+
hierarchy: {
|
|
57
|
+
childNodes: [
|
|
58
|
+
{
|
|
59
|
+
parentNodeClassName: "BisCore.PhysicalElement",
|
|
60
|
+
definitions: async ({ parentNode }) => getPhysicalElementChildren(parentNode),
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
parentNodeClassName: "BisCore.SpatialElement",
|
|
64
|
+
onlyIfNotHandled: true,
|
|
65
|
+
definitions: async ({ parentNode }) => getSpatialElementChildren(parentNode),
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
parentNodeClassName: "BisCore.GeometricElement3d",
|
|
69
|
+
onlyIfNotHandled: true,
|
|
70
|
+
definitions: async ({ parentNode }) => getGeometricElement3dChildren(parentNode),
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
3
77
|
## 0.1.6
|
|
4
78
|
|
|
5
79
|
### Patch Changes
|
|
@@ -157,6 +157,24 @@ interface InstancesNodeChildHierarchyLevelDefinition {
|
|
|
157
157
|
* Called to create a hierarchy level definition when the class check passes (see `parentNodeClassName`).
|
|
158
158
|
*/
|
|
159
159
|
definitions: (requestProps: DefineInstanceNodeChildHierarchyLevelProps) => Promise<HierarchyLevelDefinition>;
|
|
160
|
+
/**
|
|
161
|
+
* If set to true, and node matches at least one of the previous definitions, this definition will not be applied.
|
|
162
|
+
*
|
|
163
|
+
* For example:
|
|
164
|
+
* ```ts
|
|
165
|
+
* {
|
|
166
|
+
* parentNodeClassName: "BisCore.GeometricElement3d",
|
|
167
|
+
* definitions: () => ...,
|
|
168
|
+
* },
|
|
169
|
+
* // This will apply to all elements, that are not BisCore.GeometricElement3d
|
|
170
|
+
* {
|
|
171
|
+
* parentNodeClassName: "BisCore.Element",
|
|
172
|
+
* onlyIfNotHandled: true,
|
|
173
|
+
* definitions: () => ...,
|
|
174
|
+
* }
|
|
175
|
+
* ```
|
|
176
|
+
*/
|
|
177
|
+
onlyIfNotHandled?: boolean;
|
|
160
178
|
}
|
|
161
179
|
/**
|
|
162
180
|
* Props for defining child hierarchy level for specific parent custom node.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HierarchyDefinition.d.ts","sourceRoot":"","sources":["../../../src/hierarchies/HierarchyDefinition.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,yBAAyB,EAAE,aAAa,EAAe,MAAM,4BAA4B,CAAC;AACnG,OAAO,EAEL,wBAAwB,EACxB,yBAAyB,EACzB,2BAA2B,EAC3B,4BAA4B,EAC5B,sBAAsB,EACtB,8BAA8B,EAC/B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"HierarchyDefinition.d.ts","sourceRoot":"","sources":["../../../src/hierarchies/HierarchyDefinition.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,yBAAyB,EAAE,aAAa,EAAe,MAAM,4BAA4B,CAAC;AACnG,OAAO,EAEL,wBAAwB,EACxB,yBAAyB,EACzB,2BAA2B,EAC3B,4BAA4B,EAC5B,sBAAsB,EACtB,8BAA8B,EAC/B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGtD,oEAAoE;AACpE,MAAM,WAAW,6BAA6B;IAC5C,oDAAoD;IACpD,IAAI,EAAE,yBAAyB,CAAC;CACjC;AAED,yFAAyF;AACzF,MAAM,WAAW,4BAA4B;IAC3C;;;;OAIG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,KAAK,EAAE,aAAa,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAAG,6BAA6B,GAAG,4BAA4B,CAAC;AACpG,YAAY;AAEZ,yBAAiB,wBAAwB,CAAC;IACxC,SAAgB,YAAY,CAAC,GAAG,EAAE,wBAAwB,GAAG,GAAG,IAAI,6BAA6B,CAEhG;IACD,SAAgB,oBAAoB,CAAC,GAAG,EAAE,wBAAwB,GAAG,GAAG,IAAI,4BAA4B,CAEvG;CACF;AAED;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAAG,wBAAwB,EAAE,CAAC;AAElE;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,EAAE;IAAE,CAAC,UAAU,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,KAAK,2BAA2B,CAAC;AAE7F;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,SAAS,4BAA4B,GAAG,8BAA8B,EAAE,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC;AAExJ;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE,sBAAsB,KAAK,OAAO,CAAC,sBAAsB,CAAC,CAAC;AAElG;;;;;GAKG;AACH,KAAK,6BAA6B,GAAG,IAAI,CAAC,wBAAwB,EAAE,UAAU,CAAC,CAAC;AAEhF;;;GAGG;AACH,MAAM,WAAW,yBAAyB;IACxC,2EAA2E;IAC3E,UAAU,EAAE,6BAA6B,GAAG,SAAS,CAAC;IAEtD,uCAAuC;IACvC,cAAc,CAAC,EAAE,qBAAqB,CAAC;CACxC;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;;;;;OASG;IACH,SAAS,CAAC,EAAE,UAAU,CAAC;IAEvB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAElC;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,iBAAiB,CAAC;IAEpC,+EAA+E;IAC/E,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;CAC3F;AAED;;;;GAIG;AACH,MAAM,MAAM,0CAA0C,GAAG,IAAI,CAAC,yBAAyB,EAAE,YAAY,CAAC,GAAG;IACvG,gCAAgC;IAChC,UAAU,EAAE,IAAI,CAAC,6BAA6B,EAAE,KAAK,CAAC,GAAG;QAAE,GAAG,EAAE,gBAAgB,CAAA;KAAE,CAAC;IAEnF;;;;;;;OAOG;IACH,mBAAmB,EAAE,MAAM,CAAC;IAE5B;;;;;;;OAOG;IACH,qBAAqB,EAAE,UAAU,EAAE,CAAC;CACrC,CAAC;AAEF;;GAEG;AACH,UAAU,0CAA0C;IAClD;;;;;;OAMG;IACH,mBAAmB,EAAE,MAAM,CAAC;IAE5B;;OAEG;IACH,WAAW,EAAE,CAAC,YAAY,EAAE,0CAA0C,KAAK,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAE7G;;;;;;;;;;;;;;;;OAgBG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;;GAIG;AACH,MAAM,MAAM,wCAAwC,GAAG,IAAI,CAAC,yBAAyB,EAAE,YAAY,CAAC,GAAG;IACrG,8BAA8B;IAC9B,UAAU,EAAE,IAAI,CAAC,6BAA6B,EAAE,KAAK,CAAC,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1E,CAAC;AAEF;;GAEG;AACH,UAAU,uCAAuC;IAC/C;;OAEG;IACH,mBAAmB,EAAE,MAAM,CAAC;IAE5B;;OAEG;IACH,WAAW,EAAE,CAAC,YAAY,EAAE,wCAAwC,KAAK,OAAO,CAAC,wBAAwB,CAAC,CAAC;CAC5G;AAED;;;GAGG;AACH,KAAK,kCAAkC,GAAG,0CAA0C,GAAG,uCAAuC,CAAC;AAE/H;;;;GAIG;AACH,MAAM,MAAM,6BAA6B,GAAG,IAAI,CAAC,yBAAyB,EAAE,YAAY,CAAC,CAAC;AAE1F;;GAEG;AACH,UAAU,kCAAkC;IAC1C,gDAAgD;IAChD,uBAAuB,EAAE,yBAAyB,CAAC;IAEnD,8FAA8F;IAC9F,SAAS,EAAE;QACT,4DAA4D;QAC5D,SAAS,EAAE,CAAC,KAAK,EAAE,6BAA6B,KAAK,OAAO,CAAC,wBAAwB,CAAC,CAAC;QAEvF;;;WAGG;QACH,UAAU,EAAE,kCAAkC,EAAE,CAAC;KAClD,CAAC;CACH;AAED;;;;;;GAMG;AACH,wBAAgB,mCAAmC,CAAC,KAAK,EAAE,kCAAkC,GAAG,mBAAmB,CAElH"}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.createClassBasedHierarchyDefinition = exports.HierarchyNodesDefinition = void 0;
|
|
8
8
|
const HierarchyNode_1 = require("./HierarchyNode");
|
|
9
|
+
const rxjs_1 = require("rxjs");
|
|
9
10
|
/** @beta */
|
|
10
11
|
// eslint-disable-next-line @typescript-eslint/no-redeclare
|
|
11
12
|
var HierarchyNodesDefinition;
|
|
@@ -66,12 +67,13 @@ class ClassBasedHierarchyDefinition {
|
|
|
66
67
|
}
|
|
67
68
|
}
|
|
68
69
|
async function createHierarchyLevelDefinitions(classHierarchy, defs, requestProps) {
|
|
69
|
-
|
|
70
|
+
const obs = (0, rxjs_1.from)(defs).pipe((0, rxjs_1.mergeMap)(async (def, idx) => {
|
|
70
71
|
if (await classHierarchy.classDerivesFrom(requestProps.parentNodeClassName, def.parentNodeClassName)) {
|
|
71
|
-
return def
|
|
72
|
+
return { def, idx };
|
|
72
73
|
}
|
|
73
|
-
return
|
|
74
|
-
}))).
|
|
74
|
+
return undefined;
|
|
75
|
+
}), (0, rxjs_1.filter)((x) => !!x), (0, rxjs_1.toArray)(), (0, rxjs_1.concatMap)((x) => x.sort((a, b) => a.idx - b.idx).map(({ def }) => def)), (0, rxjs_1.filter)((def, idx) => !def.onlyIfNotHandled || idx === 0), (0, rxjs_1.mergeMap)(async (def) => def.definitions(requestProps)), (0, rxjs_1.mergeAll)());
|
|
76
|
+
return (0, rxjs_1.firstValueFrom)(obs.pipe((0, rxjs_1.toArray)()));
|
|
75
77
|
}
|
|
76
78
|
function groupInstanceIdsByClass(instanceKeys) {
|
|
77
79
|
const instanceIdsByClass = new Map();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HierarchyDefinition.js","sourceRoot":"","sources":["../../../src/hierarchies/HierarchyDefinition.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n\nimport { Id64String } from \"@itwin/core-bentley\";\nimport { GenericInstanceFilter } from \"@itwin/core-common\";\nimport { ECClassHierarchyInspector, ECSqlQueryDef, InstanceKey } from \"@itwin/presentation-shared\";\nimport {\n HierarchyNode,\n NonGroupingHierarchyNode,\n ParsedCustomHierarchyNode,\n ParsedInstanceHierarchyNode,\n ProcessedCustomHierarchyNode,\n ProcessedHierarchyNode,\n ProcessedInstanceHierarchyNode,\n} from \"./HierarchyNode\";\nimport { InstancesNodeKey } from \"./HierarchyNodeKey\";\n\n/** A nodes definition that returns a single custom defined node. */\nexport interface CustomHierarchyNodeDefinition {\n /** The node to be created in the hierarchy level */\n node: ParsedCustomHierarchyNode;\n}\n\n/** A nodes definition that returns an ECSQL query for selecting nodes from an iModel. */\nexport interface InstanceNodesQueryDefinition {\n /**\n * Full name of the class whose instances are going to be returned. It's okay if the attribute\n * points to a base class of multiple different classes of instances returned by the query, however\n * the more specific this class is, the more efficient hierarchy building process is.\n */\n fullClassName: string;\n /**\n * An ECSQL query that selects nodes from an iModel. `SELECT` clause of the query is expected\n * to be built using `NodeSelectQueryFactory.createSelectClause`.\n */\n query: ECSqlQueryDef;\n}\n\n/**\n * A definition of nodes included in a hierarchy level.\n * @beta\n */\nexport type HierarchyNodesDefinition = CustomHierarchyNodeDefinition | InstanceNodesQueryDefinition;\n/** @beta */\n// eslint-disable-next-line @typescript-eslint/no-redeclare\nexport namespace HierarchyNodesDefinition {\n export function isCustomNode(def: HierarchyNodesDefinition): def is CustomHierarchyNodeDefinition {\n return !!(def as CustomHierarchyNodeDefinition).node;\n }\n export function isInstanceNodesQuery(def: HierarchyNodesDefinition): def is InstanceNodesQueryDefinition {\n return !!(def as InstanceNodesQueryDefinition).query;\n }\n}\n\n/**\n * A definition of a hierarchy level, which may consist of multiple node definitions.\n * @beta\n */\nexport type HierarchyLevelDefinition = HierarchyNodesDefinition[];\n\n/**\n * A type for a function that parses a `ParsedInstanceHierarchyNode` from provided ECSQL `row` object.\n * @beta\n */\nexport type NodeParser = (row: { [columnName: string]: any }) => ParsedInstanceHierarchyNode;\n\n/**\n * A type for a function that pre-processes given node. Unless the function decides not to make any modifications,\n * it should return a new - modified - node, rather than modifying the given one. Returning `undefined` omits the node\n * from the hierarchy.\n *\n * @beta\n */\nexport type NodePreProcessor = <TNode extends ProcessedCustomHierarchyNode | ProcessedInstanceHierarchyNode>(node: TNode) => Promise<TNode | undefined>;\n\n/**\n * A type for a function that post-processes given node. Unless the function decides not to make any modifications,\n * it should return a new - modified - node, rather than modifying the given one.\n *\n * @beta\n */\nexport type NodePostProcessor = (node: ProcessedHierarchyNode) => Promise<ProcessedHierarchyNode>;\n\n/**\n * A type of node that can be passed to `HierarchyDefinition.defineHierarchyLevel`. This basically means\n * a `HierarchyNode` that:\n * - knows nothing about its children,\n * - is either an instances node (key is of `InstancesNodeKey` type) or a custom node (key is of `string` type).\n */\ntype HierarchyDefinitionParentNode = Omit<NonGroupingHierarchyNode, \"children\">;\n\n/**\n * Props for `HierarchyDefinition.defineHierarchyLevel`.\n * @beta\n */\nexport interface DefineHierarchyLevelProps {\n /** Parent node to get children for. Pass `undefined` to get root nodes. */\n parentNode: HierarchyDefinitionParentNode | undefined;\n\n /** Optional hierarchy level filter. */\n instanceFilter?: GenericInstanceFilter;\n}\n\n/**\n * An interface for a factory that knows how define a hierarchy based on a given parent node.\n * @beta\n */\nexport interface HierarchyDefinition {\n /**\n * An optional function for parsing ECInstance node from ECSQL row.\n *\n * Should be used in situations when the `HierarchyDefinition` implementation\n * introduces additional ECSQL columns into the select clause and wants to assign additional\n * data to the nodes it produces.\n *\n * Defaults to a function that parses all `HierarchyNode` attributes from a query, whose SELECT\n * clause is created using `NodeSelectQueryFactory.createSelectClause`.\n */\n parseNode?: NodeParser;\n\n /**\n * An optional function for pre-processing nodes.\n *\n * Pre-processing happens immediately after the nodes are loaded based on `HierarchyLevelDefinition`\n * returned by this `HierarchyDefinition` and before their processing (hiding, grouping, sorting, etc.) starts.\n * The step allows assigning nodes additional data or excluding them from the hierarchy based on some attributes.\n */\n preProcessNode?: NodePreProcessor;\n\n /**\n * An optional function for post-processing nodes.\n *\n * Post-processing happens after the loaded nodes go through all the merging, hiding and grouping\n * steps, but before sorting them. This step allows `HierarchyDefinition` implementations to assign additional data\n * to nodes after they're processed. This is especially true for grouping nodes as they're only created during\n * processing.\n */\n postProcessNode?: NodePostProcessor;\n\n /** A function to create a hierarchy level definition for given parent node. */\n defineHierarchyLevel(props: DefineHierarchyLevelProps): Promise<HierarchyLevelDefinition>;\n}\n\n/**\n * Props for defining child hierarchy level for specific parent instance node.\n * @see `createClassBasedHierarchyDefinition`\n * @beta\n */\nexport type DefineInstanceNodeChildHierarchyLevelProps = Omit<DefineHierarchyLevelProps, \"parentNode\"> & {\n /** The parent instance node. */\n parentNode: Omit<HierarchyDefinitionParentNode, \"key\"> & { key: InstancesNodeKey };\n\n /**\n * Full name of the parent instance node class.\n *\n * The `parentNode.key` also contains information about the instances the parent node is based on. However,\n * an instance node may be based on instances of multiple classes. In case that happens, parent node's instance\n * keys are grouped by class and a hierarchy level definition is requested for each combination of class and\n * instance IDs (with the same `parentNode`).\n */\n parentNodeClassName: string;\n\n /**\n * ECInstanceIds of the parent instance node.\n *\n * The `parentNode.key` also contains information about the instances the parent node is based on. However,\n * an instance node may be based on instances of multiple classes. In case that happens, parent node's instance\n * keys are grouped by class and a hierarchy level definition is requested for each combination of class and\n * instance IDs (with the same `parentNode`).\n */\n parentNodeInstanceIds: Id64String[];\n};\n\n/**\n * A definition of a hierarchy level that should be used for specific class of parent instance nodes.\n */\ninterface InstancesNodeChildHierarchyLevelDefinition {\n /**\n * Full name of the parent instance node's class to match against when checking if this hierarchy\n * level should be used for specific parent instance node.\n *\n * The check is polymorphic, so `BisCore.Element` class would match `BisCore.GeometricElement`, `BisCore.Category` and\n * all other element classes.\n */\n parentNodeClassName: string;\n\n /**\n * Called to create a hierarchy level definition when the class check passes (see `parentNodeClassName`).\n */\n definitions: (requestProps: DefineInstanceNodeChildHierarchyLevelProps) => Promise<HierarchyLevelDefinition>;\n}\n\n/**\n * Props for defining child hierarchy level for specific parent custom node.\n * @see `createClassBasedHierarchyDefinition`\n * @beta\n */\nexport type DefineCustomNodeChildHierarchyLevelProps = Omit<DefineHierarchyLevelProps, \"parentNode\"> & {\n /** The parent custom node. */\n parentNode: Omit<HierarchyDefinitionParentNode, \"key\"> & { key: string };\n};\n\n/**\n * A definition of a hierarchy level for that should be used for specific custom parent nodes.\n */\ninterface CustomNodeChildHierarchyLevelDefinition {\n /**\n * `HierarchyNode.key` of the custom node that this child hierarchy level definition should be used for.\n */\n customParentNodeKey: string;\n\n /**\n * Called to create a hierarchy level definition when the node key check passes (see `customParentNodeKey`).\n */\n definitions: (requestProps: DefineCustomNodeChildHierarchyLevelProps) => Promise<HierarchyLevelDefinition>;\n}\n\n/**\n * A hierarchy level definition associated with either parent instance node's class or custom\n * node's key.\n */\ntype ClassBasedHierarchyLevelDefinition = InstancesNodeChildHierarchyLevelDefinition | CustomNodeChildHierarchyLevelDefinition;\n\n/**\n * Props for defining root hierarchy level.\n * @see `createClassBasedHierarchyDefinition`\n * @beta\n */\nexport type DefineRootHierarchyLevelProps = Omit<DefineHierarchyLevelProps, \"parentNode\">;\n\n/**\n * Props for `createClassBasedHierarchyDefinition`.\n */\ninterface ClassBasedHierarchyDefinitionProps {\n /** Access to ECClass hierarchy in the iModel */\n classHierarchyInspector: ECClassHierarchyInspector;\n\n /** Hierarchy level definitions based on parent instance node's class or custom node's key. */\n hierarchy: {\n /** Called to create the root hierarchy level definition. */\n rootNodes: (props: DefineRootHierarchyLevelProps) => Promise<HierarchyLevelDefinition>;\n\n /**\n * Called to get child hierarchy level definitions based on parent instance node's class\n * or custom node's key.\n */\n childNodes: ClassBasedHierarchyLevelDefinition[];\n };\n}\n\n/**\n * Creates an instance of `HierarchyDefinition` that uses a somewhat declarative approach to define the\n * hierarchy - each hierarchy level is assigned either an instance node's class or custom node's\n * key and they're used to assign hierarchy level definitions based on parent node.\n *\n * @beta\n */\nexport function createClassBasedHierarchyDefinition(props: ClassBasedHierarchyDefinitionProps): HierarchyDefinition {\n return new ClassBasedHierarchyDefinition(props);\n}\n\nclass ClassBasedHierarchyDefinition implements HierarchyDefinition {\n public constructor(private _props: ClassBasedHierarchyDefinitionProps) {}\n\n /**\n * Create hierarchy level definitions for specific hierarchy level.\n * @param parentNode Parent node to create children definitions for.\n */\n public async defineHierarchyLevel(props: DefineHierarchyLevelProps): Promise<HierarchyLevelDefinition> {\n const { parentNode } = props;\n if (!parentNode) {\n return this._props.hierarchy.rootNodes(props);\n }\n\n if (HierarchyNode.isCustom(parentNode)) {\n const defs = this._props.hierarchy.childNodes\n .filter(isCustomNodeChildHierarchyLevelDefinition)\n .filter((def) => def.customParentNodeKey === parentNode.key);\n return (await Promise.all(defs.map(async (def) => def.definitions({ ...props, parentNode })))).flat();\n }\n\n // istanbul ignore else\n if (HierarchyNode.isInstancesNode(parentNode)) {\n const instanceIdsByClass = groupInstanceIdsByClass(parentNode.key.instanceKeys);\n const instancesParentNodeDefs = this._props.hierarchy.childNodes.filter(isInstancesNodeChildHierarchyLevelDefinition);\n return (\n await Promise.all(\n [...instanceIdsByClass.entries()].map(async ([parentNodeClassName, parentNodeInstanceIds]) =>\n createHierarchyLevelDefinitions(this._props.classHierarchyInspector, instancesParentNodeDefs, {\n ...props,\n parentNodeClassName,\n parentNodeInstanceIds,\n parentNode,\n }),\n ),\n )\n ).flat();\n }\n\n // istanbul ignore next\n return [];\n }\n}\n\nasync function createHierarchyLevelDefinitions(\n classHierarchy: ECClassHierarchyInspector,\n defs: InstancesNodeChildHierarchyLevelDefinition[],\n requestProps: DefineInstanceNodeChildHierarchyLevelProps,\n) {\n return (\n await Promise.all(\n defs.map(async (def) => {\n if (await classHierarchy.classDerivesFrom(requestProps.parentNodeClassName, def.parentNodeClassName)) {\n return def.definitions(requestProps);\n }\n return [];\n }),\n )\n ).flat();\n}\n\nfunction groupInstanceIdsByClass(instanceKeys: InstanceKey[]) {\n const instanceIdsByClass = new Map<string, Id64String[]>();\n instanceKeys.forEach((key) => {\n let instanceIds = instanceIdsByClass.get(key.className);\n if (!instanceIds) {\n instanceIds = [];\n instanceIdsByClass.set(key.className, instanceIds);\n }\n instanceIds.push(key.id);\n });\n return instanceIdsByClass;\n}\n\nfunction isCustomNodeChildHierarchyLevelDefinition(def: ClassBasedHierarchyLevelDefinition): def is CustomNodeChildHierarchyLevelDefinition {\n return !!(def as CustomNodeChildHierarchyLevelDefinition).customParentNodeKey;\n}\n\nfunction isInstancesNodeChildHierarchyLevelDefinition(def: ClassBasedHierarchyLevelDefinition): def is InstancesNodeChildHierarchyLevelDefinition {\n return !!(def as InstancesNodeChildHierarchyLevelDefinition).parentNodeClassName;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"HierarchyDefinition.js","sourceRoot":"","sources":["../../../src/hierarchies/HierarchyDefinition.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n\nimport { Id64String } from \"@itwin/core-bentley\";\nimport { GenericInstanceFilter } from \"@itwin/core-common\";\nimport { ECClassHierarchyInspector, ECSqlQueryDef, InstanceKey } from \"@itwin/presentation-shared\";\nimport {\n HierarchyNode,\n NonGroupingHierarchyNode,\n ParsedCustomHierarchyNode,\n ParsedInstanceHierarchyNode,\n ProcessedCustomHierarchyNode,\n ProcessedHierarchyNode,\n ProcessedInstanceHierarchyNode,\n} from \"./HierarchyNode\";\nimport { InstancesNodeKey } from \"./HierarchyNodeKey\";\nimport { concatMap, filter, firstValueFrom, from, mergeAll, mergeMap, toArray } from \"rxjs\";\n\n/** A nodes definition that returns a single custom defined node. */\nexport interface CustomHierarchyNodeDefinition {\n /** The node to be created in the hierarchy level */\n node: ParsedCustomHierarchyNode;\n}\n\n/** A nodes definition that returns an ECSQL query for selecting nodes from an iModel. */\nexport interface InstanceNodesQueryDefinition {\n /**\n * Full name of the class whose instances are going to be returned. It's okay if the attribute\n * points to a base class of multiple different classes of instances returned by the query, however\n * the more specific this class is, the more efficient hierarchy building process is.\n */\n fullClassName: string;\n /**\n * An ECSQL query that selects nodes from an iModel. `SELECT` clause of the query is expected\n * to be built using `NodeSelectQueryFactory.createSelectClause`.\n */\n query: ECSqlQueryDef;\n}\n\n/**\n * A definition of nodes included in a hierarchy level.\n * @beta\n */\nexport type HierarchyNodesDefinition = CustomHierarchyNodeDefinition | InstanceNodesQueryDefinition;\n/** @beta */\n// eslint-disable-next-line @typescript-eslint/no-redeclare\nexport namespace HierarchyNodesDefinition {\n export function isCustomNode(def: HierarchyNodesDefinition): def is CustomHierarchyNodeDefinition {\n return !!(def as CustomHierarchyNodeDefinition).node;\n }\n export function isInstanceNodesQuery(def: HierarchyNodesDefinition): def is InstanceNodesQueryDefinition {\n return !!(def as InstanceNodesQueryDefinition).query;\n }\n}\n\n/**\n * A definition of a hierarchy level, which may consist of multiple node definitions.\n * @beta\n */\nexport type HierarchyLevelDefinition = HierarchyNodesDefinition[];\n\n/**\n * A type for a function that parses a `ParsedInstanceHierarchyNode` from provided ECSQL `row` object.\n * @beta\n */\nexport type NodeParser = (row: { [columnName: string]: any }) => ParsedInstanceHierarchyNode;\n\n/**\n * A type for a function that pre-processes given node. Unless the function decides not to make any modifications,\n * it should return a new - modified - node, rather than modifying the given one. Returning `undefined` omits the node\n * from the hierarchy.\n *\n * @beta\n */\nexport type NodePreProcessor = <TNode extends ProcessedCustomHierarchyNode | ProcessedInstanceHierarchyNode>(node: TNode) => Promise<TNode | undefined>;\n\n/**\n * A type for a function that post-processes given node. Unless the function decides not to make any modifications,\n * it should return a new - modified - node, rather than modifying the given one.\n *\n * @beta\n */\nexport type NodePostProcessor = (node: ProcessedHierarchyNode) => Promise<ProcessedHierarchyNode>;\n\n/**\n * A type of node that can be passed to `HierarchyDefinition.defineHierarchyLevel`. This basically means\n * a `HierarchyNode` that:\n * - knows nothing about its children,\n * - is either an instances node (key is of `InstancesNodeKey` type) or a custom node (key is of `string` type).\n */\ntype HierarchyDefinitionParentNode = Omit<NonGroupingHierarchyNode, \"children\">;\n\n/**\n * Props for `HierarchyDefinition.defineHierarchyLevel`.\n * @beta\n */\nexport interface DefineHierarchyLevelProps {\n /** Parent node to get children for. Pass `undefined` to get root nodes. */\n parentNode: HierarchyDefinitionParentNode | undefined;\n\n /** Optional hierarchy level filter. */\n instanceFilter?: GenericInstanceFilter;\n}\n\n/**\n * An interface for a factory that knows how define a hierarchy based on a given parent node.\n * @beta\n */\nexport interface HierarchyDefinition {\n /**\n * An optional function for parsing ECInstance node from ECSQL row.\n *\n * Should be used in situations when the `HierarchyDefinition` implementation\n * introduces additional ECSQL columns into the select clause and wants to assign additional\n * data to the nodes it produces.\n *\n * Defaults to a function that parses all `HierarchyNode` attributes from a query, whose SELECT\n * clause is created using `NodeSelectQueryFactory.createSelectClause`.\n */\n parseNode?: NodeParser;\n\n /**\n * An optional function for pre-processing nodes.\n *\n * Pre-processing happens immediately after the nodes are loaded based on `HierarchyLevelDefinition`\n * returned by this `HierarchyDefinition` and before their processing (hiding, grouping, sorting, etc.) starts.\n * The step allows assigning nodes additional data or excluding them from the hierarchy based on some attributes.\n */\n preProcessNode?: NodePreProcessor;\n\n /**\n * An optional function for post-processing nodes.\n *\n * Post-processing happens after the loaded nodes go through all the merging, hiding and grouping\n * steps, but before sorting them. This step allows `HierarchyDefinition` implementations to assign additional data\n * to nodes after they're processed. This is especially true for grouping nodes as they're only created during\n * processing.\n */\n postProcessNode?: NodePostProcessor;\n\n /** A function to create a hierarchy level definition for given parent node. */\n defineHierarchyLevel(props: DefineHierarchyLevelProps): Promise<HierarchyLevelDefinition>;\n}\n\n/**\n * Props for defining child hierarchy level for specific parent instance node.\n * @see `createClassBasedHierarchyDefinition`\n * @beta\n */\nexport type DefineInstanceNodeChildHierarchyLevelProps = Omit<DefineHierarchyLevelProps, \"parentNode\"> & {\n /** The parent instance node. */\n parentNode: Omit<HierarchyDefinitionParentNode, \"key\"> & { key: InstancesNodeKey };\n\n /**\n * Full name of the parent instance node class.\n *\n * The `parentNode.key` also contains information about the instances the parent node is based on. However,\n * an instance node may be based on instances of multiple classes. In case that happens, parent node's instance\n * keys are grouped by class and a hierarchy level definition is requested for each combination of class and\n * instance IDs (with the same `parentNode`).\n */\n parentNodeClassName: string;\n\n /**\n * ECInstanceIds of the parent instance node.\n *\n * The `parentNode.key` also contains information about the instances the parent node is based on. However,\n * an instance node may be based on instances of multiple classes. In case that happens, parent node's instance\n * keys are grouped by class and a hierarchy level definition is requested for each combination of class and\n * instance IDs (with the same `parentNode`).\n */\n parentNodeInstanceIds: Id64String[];\n};\n\n/**\n * A definition of a hierarchy level that should be used for specific class of parent instance nodes.\n */\ninterface InstancesNodeChildHierarchyLevelDefinition {\n /**\n * Full name of the parent instance node's class to match against when checking if this hierarchy\n * level should be used for specific parent instance node.\n *\n * The check is polymorphic, so `BisCore.Element` class would match `BisCore.GeometricElement`, `BisCore.Category` and\n * all other element classes.\n */\n parentNodeClassName: string;\n\n /**\n * Called to create a hierarchy level definition when the class check passes (see `parentNodeClassName`).\n */\n definitions: (requestProps: DefineInstanceNodeChildHierarchyLevelProps) => Promise<HierarchyLevelDefinition>;\n\n /**\n * If set to true, and node matches at least one of the previous definitions, this definition will not be applied.\n *\n * For example:\n * ```ts\n * {\n * parentNodeClassName: \"BisCore.GeometricElement3d\",\n * definitions: () => ...,\n * },\n * // This will apply to all elements, that are not BisCore.GeometricElement3d\n * {\n * parentNodeClassName: \"BisCore.Element\",\n * onlyIfNotHandled: true,\n * definitions: () => ...,\n * }\n * ```\n */\n onlyIfNotHandled?: boolean;\n}\n\n/**\n * Props for defining child hierarchy level for specific parent custom node.\n * @see `createClassBasedHierarchyDefinition`\n * @beta\n */\nexport type DefineCustomNodeChildHierarchyLevelProps = Omit<DefineHierarchyLevelProps, \"parentNode\"> & {\n /** The parent custom node. */\n parentNode: Omit<HierarchyDefinitionParentNode, \"key\"> & { key: string };\n};\n\n/**\n * A definition of a hierarchy level for that should be used for specific custom parent nodes.\n */\ninterface CustomNodeChildHierarchyLevelDefinition {\n /**\n * `HierarchyNode.key` of the custom node that this child hierarchy level definition should be used for.\n */\n customParentNodeKey: string;\n\n /**\n * Called to create a hierarchy level definition when the node key check passes (see `customParentNodeKey`).\n */\n definitions: (requestProps: DefineCustomNodeChildHierarchyLevelProps) => Promise<HierarchyLevelDefinition>;\n}\n\n/**\n * A hierarchy level definition associated with either parent instance node's class or custom\n * node's key.\n */\ntype ClassBasedHierarchyLevelDefinition = InstancesNodeChildHierarchyLevelDefinition | CustomNodeChildHierarchyLevelDefinition;\n\n/**\n * Props for defining root hierarchy level.\n * @see `createClassBasedHierarchyDefinition`\n * @beta\n */\nexport type DefineRootHierarchyLevelProps = Omit<DefineHierarchyLevelProps, \"parentNode\">;\n\n/**\n * Props for `createClassBasedHierarchyDefinition`.\n */\ninterface ClassBasedHierarchyDefinitionProps {\n /** Access to ECClass hierarchy in the iModel */\n classHierarchyInspector: ECClassHierarchyInspector;\n\n /** Hierarchy level definitions based on parent instance node's class or custom node's key. */\n hierarchy: {\n /** Called to create the root hierarchy level definition. */\n rootNodes: (props: DefineRootHierarchyLevelProps) => Promise<HierarchyLevelDefinition>;\n\n /**\n * Called to get child hierarchy level definitions based on parent instance node's class\n * or custom node's key.\n */\n childNodes: ClassBasedHierarchyLevelDefinition[];\n };\n}\n\n/**\n * Creates an instance of `HierarchyDefinition` that uses a somewhat declarative approach to define the\n * hierarchy - each hierarchy level is assigned either an instance node's class or custom node's\n * key and they're used to assign hierarchy level definitions based on parent node.\n *\n * @beta\n */\nexport function createClassBasedHierarchyDefinition(props: ClassBasedHierarchyDefinitionProps): HierarchyDefinition {\n return new ClassBasedHierarchyDefinition(props);\n}\n\nclass ClassBasedHierarchyDefinition implements HierarchyDefinition {\n public constructor(private _props: ClassBasedHierarchyDefinitionProps) {}\n\n /**\n * Create hierarchy level definitions for specific hierarchy level.\n * @param parentNode Parent node to create children definitions for.\n */\n public async defineHierarchyLevel(props: DefineHierarchyLevelProps): Promise<HierarchyLevelDefinition> {\n const { parentNode } = props;\n if (!parentNode) {\n return this._props.hierarchy.rootNodes(props);\n }\n\n if (HierarchyNode.isCustom(parentNode)) {\n const defs = this._props.hierarchy.childNodes\n .filter(isCustomNodeChildHierarchyLevelDefinition)\n .filter((def) => def.customParentNodeKey === parentNode.key);\n return (await Promise.all(defs.map(async (def) => def.definitions({ ...props, parentNode })))).flat();\n }\n\n // istanbul ignore else\n if (HierarchyNode.isInstancesNode(parentNode)) {\n const instanceIdsByClass = groupInstanceIdsByClass(parentNode.key.instanceKeys);\n const instancesParentNodeDefs = this._props.hierarchy.childNodes.filter(isInstancesNodeChildHierarchyLevelDefinition);\n return (\n await Promise.all(\n [...instanceIdsByClass.entries()].map(async ([parentNodeClassName, parentNodeInstanceIds]) =>\n createHierarchyLevelDefinitions(this._props.classHierarchyInspector, instancesParentNodeDefs, {\n ...props,\n parentNodeClassName,\n parentNodeInstanceIds,\n parentNode,\n }),\n ),\n )\n ).flat();\n }\n\n // istanbul ignore next\n return [];\n }\n}\n\nasync function createHierarchyLevelDefinitions(\n classHierarchy: ECClassHierarchyInspector,\n defs: InstancesNodeChildHierarchyLevelDefinition[],\n requestProps: DefineInstanceNodeChildHierarchyLevelProps,\n) {\n const obs = from(defs).pipe(\n mergeMap(async (def, idx) => {\n if (await classHierarchy.classDerivesFrom(requestProps.parentNodeClassName, def.parentNodeClassName)) {\n return { def, idx };\n }\n return undefined;\n }),\n filter((x): x is Exclude<typeof x, undefined> => !!x),\n toArray(),\n concatMap((x) => x.sort((a, b) => a.idx - b.idx).map(({ def }) => def)),\n filter((def, idx) => !def.onlyIfNotHandled || idx === 0),\n mergeMap(async (def) => def.definitions(requestProps)),\n mergeAll(),\n );\n return firstValueFrom(obs.pipe(toArray()));\n}\n\nfunction groupInstanceIdsByClass(instanceKeys: InstanceKey[]) {\n const instanceIdsByClass = new Map<string, Id64String[]>();\n instanceKeys.forEach((key) => {\n let instanceIds = instanceIdsByClass.get(key.className);\n if (!instanceIds) {\n instanceIds = [];\n instanceIdsByClass.set(key.className, instanceIds);\n }\n instanceIds.push(key.id);\n });\n return instanceIdsByClass;\n}\n\nfunction isCustomNodeChildHierarchyLevelDefinition(def: ClassBasedHierarchyLevelDefinition): def is CustomNodeChildHierarchyLevelDefinition {\n return !!(def as CustomNodeChildHierarchyLevelDefinition).customParentNodeKey;\n}\n\nfunction isInstancesNodeChildHierarchyLevelDefinition(def: ClassBasedHierarchyLevelDefinition): def is InstancesNodeChildHierarchyLevelDefinition {\n return !!(def as InstancesNodeChildHierarchyLevelDefinition).parentNodeClassName;\n}\n"]}
|
|
@@ -157,6 +157,24 @@ interface InstancesNodeChildHierarchyLevelDefinition {
|
|
|
157
157
|
* Called to create a hierarchy level definition when the class check passes (see `parentNodeClassName`).
|
|
158
158
|
*/
|
|
159
159
|
definitions: (requestProps: DefineInstanceNodeChildHierarchyLevelProps) => Promise<HierarchyLevelDefinition>;
|
|
160
|
+
/**
|
|
161
|
+
* If set to true, and node matches at least one of the previous definitions, this definition will not be applied.
|
|
162
|
+
*
|
|
163
|
+
* For example:
|
|
164
|
+
* ```ts
|
|
165
|
+
* {
|
|
166
|
+
* parentNodeClassName: "BisCore.GeometricElement3d",
|
|
167
|
+
* definitions: () => ...,
|
|
168
|
+
* },
|
|
169
|
+
* // This will apply to all elements, that are not BisCore.GeometricElement3d
|
|
170
|
+
* {
|
|
171
|
+
* parentNodeClassName: "BisCore.Element",
|
|
172
|
+
* onlyIfNotHandled: true,
|
|
173
|
+
* definitions: () => ...,
|
|
174
|
+
* }
|
|
175
|
+
* ```
|
|
176
|
+
*/
|
|
177
|
+
onlyIfNotHandled?: boolean;
|
|
160
178
|
}
|
|
161
179
|
/**
|
|
162
180
|
* Props for defining child hierarchy level for specific parent custom node.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HierarchyDefinition.d.ts","sourceRoot":"","sources":["../../../src/hierarchies/HierarchyDefinition.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,yBAAyB,EAAE,aAAa,EAAe,MAAM,4BAA4B,CAAC;AACnG,OAAO,EAEL,wBAAwB,EACxB,yBAAyB,EACzB,2BAA2B,EAC3B,4BAA4B,EAC5B,sBAAsB,EACtB,8BAA8B,EAC/B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"HierarchyDefinition.d.ts","sourceRoot":"","sources":["../../../src/hierarchies/HierarchyDefinition.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
4
4
|
*--------------------------------------------------------------------------------------------*/
|
|
5
5
|
import { HierarchyNode, } from "./HierarchyNode";
|
|
6
|
+
import { concatMap, filter, firstValueFrom, from, mergeAll, mergeMap, toArray } from "rxjs";
|
|
6
7
|
/** @beta */
|
|
7
8
|
// eslint-disable-next-line @typescript-eslint/no-redeclare
|
|
8
9
|
export var HierarchyNodesDefinition;
|
|
@@ -62,12 +63,13 @@ class ClassBasedHierarchyDefinition {
|
|
|
62
63
|
}
|
|
63
64
|
}
|
|
64
65
|
async function createHierarchyLevelDefinitions(classHierarchy, defs, requestProps) {
|
|
65
|
-
|
|
66
|
+
const obs = from(defs).pipe(mergeMap(async (def, idx) => {
|
|
66
67
|
if (await classHierarchy.classDerivesFrom(requestProps.parentNodeClassName, def.parentNodeClassName)) {
|
|
67
|
-
return def
|
|
68
|
+
return { def, idx };
|
|
68
69
|
}
|
|
69
|
-
return
|
|
70
|
-
}))).
|
|
70
|
+
return undefined;
|
|
71
|
+
}), filter((x) => !!x), toArray(), concatMap((x) => x.sort((a, b) => a.idx - b.idx).map(({ def }) => def)), filter((def, idx) => !def.onlyIfNotHandled || idx === 0), mergeMap(async (def) => def.definitions(requestProps)), mergeAll());
|
|
72
|
+
return firstValueFrom(obs.pipe(toArray()));
|
|
71
73
|
}
|
|
72
74
|
function groupInstanceIdsByClass(instanceKeys) {
|
|
73
75
|
const instanceIdsByClass = new Map();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HierarchyDefinition.js","sourceRoot":"","sources":["../../../src/hierarchies/HierarchyDefinition.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n\nimport { Id64String } from \"@itwin/core-bentley\";\nimport { GenericInstanceFilter } from \"@itwin/core-common\";\nimport { ECClassHierarchyInspector, ECSqlQueryDef, InstanceKey } from \"@itwin/presentation-shared\";\nimport {\n HierarchyNode,\n NonGroupingHierarchyNode,\n ParsedCustomHierarchyNode,\n ParsedInstanceHierarchyNode,\n ProcessedCustomHierarchyNode,\n ProcessedHierarchyNode,\n ProcessedInstanceHierarchyNode,\n} from \"./HierarchyNode\";\nimport { InstancesNodeKey } from \"./HierarchyNodeKey\";\n\n/** A nodes definition that returns a single custom defined node. */\nexport interface CustomHierarchyNodeDefinition {\n /** The node to be created in the hierarchy level */\n node: ParsedCustomHierarchyNode;\n}\n\n/** A nodes definition that returns an ECSQL query for selecting nodes from an iModel. */\nexport interface InstanceNodesQueryDefinition {\n /**\n * Full name of the class whose instances are going to be returned. It's okay if the attribute\n * points to a base class of multiple different classes of instances returned by the query, however\n * the more specific this class is, the more efficient hierarchy building process is.\n */\n fullClassName: string;\n /**\n * An ECSQL query that selects nodes from an iModel. `SELECT` clause of the query is expected\n * to be built using `NodeSelectQueryFactory.createSelectClause`.\n */\n query: ECSqlQueryDef;\n}\n\n/**\n * A definition of nodes included in a hierarchy level.\n * @beta\n */\nexport type HierarchyNodesDefinition = CustomHierarchyNodeDefinition | InstanceNodesQueryDefinition;\n/** @beta */\n// eslint-disable-next-line @typescript-eslint/no-redeclare\nexport namespace HierarchyNodesDefinition {\n export function isCustomNode(def: HierarchyNodesDefinition): def is CustomHierarchyNodeDefinition {\n return !!(def as CustomHierarchyNodeDefinition).node;\n }\n export function isInstanceNodesQuery(def: HierarchyNodesDefinition): def is InstanceNodesQueryDefinition {\n return !!(def as InstanceNodesQueryDefinition).query;\n }\n}\n\n/**\n * A definition of a hierarchy level, which may consist of multiple node definitions.\n * @beta\n */\nexport type HierarchyLevelDefinition = HierarchyNodesDefinition[];\n\n/**\n * A type for a function that parses a `ParsedInstanceHierarchyNode` from provided ECSQL `row` object.\n * @beta\n */\nexport type NodeParser = (row: { [columnName: string]: any }) => ParsedInstanceHierarchyNode;\n\n/**\n * A type for a function that pre-processes given node. Unless the function decides not to make any modifications,\n * it should return a new - modified - node, rather than modifying the given one. Returning `undefined` omits the node\n * from the hierarchy.\n *\n * @beta\n */\nexport type NodePreProcessor = <TNode extends ProcessedCustomHierarchyNode | ProcessedInstanceHierarchyNode>(node: TNode) => Promise<TNode | undefined>;\n\n/**\n * A type for a function that post-processes given node. Unless the function decides not to make any modifications,\n * it should return a new - modified - node, rather than modifying the given one.\n *\n * @beta\n */\nexport type NodePostProcessor = (node: ProcessedHierarchyNode) => Promise<ProcessedHierarchyNode>;\n\n/**\n * A type of node that can be passed to `HierarchyDefinition.defineHierarchyLevel`. This basically means\n * a `HierarchyNode` that:\n * - knows nothing about its children,\n * - is either an instances node (key is of `InstancesNodeKey` type) or a custom node (key is of `string` type).\n */\ntype HierarchyDefinitionParentNode = Omit<NonGroupingHierarchyNode, \"children\">;\n\n/**\n * Props for `HierarchyDefinition.defineHierarchyLevel`.\n * @beta\n */\nexport interface DefineHierarchyLevelProps {\n /** Parent node to get children for. Pass `undefined` to get root nodes. */\n parentNode: HierarchyDefinitionParentNode | undefined;\n\n /** Optional hierarchy level filter. */\n instanceFilter?: GenericInstanceFilter;\n}\n\n/**\n * An interface for a factory that knows how define a hierarchy based on a given parent node.\n * @beta\n */\nexport interface HierarchyDefinition {\n /**\n * An optional function for parsing ECInstance node from ECSQL row.\n *\n * Should be used in situations when the `HierarchyDefinition` implementation\n * introduces additional ECSQL columns into the select clause and wants to assign additional\n * data to the nodes it produces.\n *\n * Defaults to a function that parses all `HierarchyNode` attributes from a query, whose SELECT\n * clause is created using `NodeSelectQueryFactory.createSelectClause`.\n */\n parseNode?: NodeParser;\n\n /**\n * An optional function for pre-processing nodes.\n *\n * Pre-processing happens immediately after the nodes are loaded based on `HierarchyLevelDefinition`\n * returned by this `HierarchyDefinition` and before their processing (hiding, grouping, sorting, etc.) starts.\n * The step allows assigning nodes additional data or excluding them from the hierarchy based on some attributes.\n */\n preProcessNode?: NodePreProcessor;\n\n /**\n * An optional function for post-processing nodes.\n *\n * Post-processing happens after the loaded nodes go through all the merging, hiding and grouping\n * steps, but before sorting them. This step allows `HierarchyDefinition` implementations to assign additional data\n * to nodes after they're processed. This is especially true for grouping nodes as they're only created during\n * processing.\n */\n postProcessNode?: NodePostProcessor;\n\n /** A function to create a hierarchy level definition for given parent node. */\n defineHierarchyLevel(props: DefineHierarchyLevelProps): Promise<HierarchyLevelDefinition>;\n}\n\n/**\n * Props for defining child hierarchy level for specific parent instance node.\n * @see `createClassBasedHierarchyDefinition`\n * @beta\n */\nexport type DefineInstanceNodeChildHierarchyLevelProps = Omit<DefineHierarchyLevelProps, \"parentNode\"> & {\n /** The parent instance node. */\n parentNode: Omit<HierarchyDefinitionParentNode, \"key\"> & { key: InstancesNodeKey };\n\n /**\n * Full name of the parent instance node class.\n *\n * The `parentNode.key` also contains information about the instances the parent node is based on. However,\n * an instance node may be based on instances of multiple classes. In case that happens, parent node's instance\n * keys are grouped by class and a hierarchy level definition is requested for each combination of class and\n * instance IDs (with the same `parentNode`).\n */\n parentNodeClassName: string;\n\n /**\n * ECInstanceIds of the parent instance node.\n *\n * The `parentNode.key` also contains information about the instances the parent node is based on. However,\n * an instance node may be based on instances of multiple classes. In case that happens, parent node's instance\n * keys are grouped by class and a hierarchy level definition is requested for each combination of class and\n * instance IDs (with the same `parentNode`).\n */\n parentNodeInstanceIds: Id64String[];\n};\n\n/**\n * A definition of a hierarchy level that should be used for specific class of parent instance nodes.\n */\ninterface InstancesNodeChildHierarchyLevelDefinition {\n /**\n * Full name of the parent instance node's class to match against when checking if this hierarchy\n * level should be used for specific parent instance node.\n *\n * The check is polymorphic, so `BisCore.Element` class would match `BisCore.GeometricElement`, `BisCore.Category` and\n * all other element classes.\n */\n parentNodeClassName: string;\n\n /**\n * Called to create a hierarchy level definition when the class check passes (see `parentNodeClassName`).\n */\n definitions: (requestProps: DefineInstanceNodeChildHierarchyLevelProps) => Promise<HierarchyLevelDefinition>;\n}\n\n/**\n * Props for defining child hierarchy level for specific parent custom node.\n * @see `createClassBasedHierarchyDefinition`\n * @beta\n */\nexport type DefineCustomNodeChildHierarchyLevelProps = Omit<DefineHierarchyLevelProps, \"parentNode\"> & {\n /** The parent custom node. */\n parentNode: Omit<HierarchyDefinitionParentNode, \"key\"> & { key: string };\n};\n\n/**\n * A definition of a hierarchy level for that should be used for specific custom parent nodes.\n */\ninterface CustomNodeChildHierarchyLevelDefinition {\n /**\n * `HierarchyNode.key` of the custom node that this child hierarchy level definition should be used for.\n */\n customParentNodeKey: string;\n\n /**\n * Called to create a hierarchy level definition when the node key check passes (see `customParentNodeKey`).\n */\n definitions: (requestProps: DefineCustomNodeChildHierarchyLevelProps) => Promise<HierarchyLevelDefinition>;\n}\n\n/**\n * A hierarchy level definition associated with either parent instance node's class or custom\n * node's key.\n */\ntype ClassBasedHierarchyLevelDefinition = InstancesNodeChildHierarchyLevelDefinition | CustomNodeChildHierarchyLevelDefinition;\n\n/**\n * Props for defining root hierarchy level.\n * @see `createClassBasedHierarchyDefinition`\n * @beta\n */\nexport type DefineRootHierarchyLevelProps = Omit<DefineHierarchyLevelProps, \"parentNode\">;\n\n/**\n * Props for `createClassBasedHierarchyDefinition`.\n */\ninterface ClassBasedHierarchyDefinitionProps {\n /** Access to ECClass hierarchy in the iModel */\n classHierarchyInspector: ECClassHierarchyInspector;\n\n /** Hierarchy level definitions based on parent instance node's class or custom node's key. */\n hierarchy: {\n /** Called to create the root hierarchy level definition. */\n rootNodes: (props: DefineRootHierarchyLevelProps) => Promise<HierarchyLevelDefinition>;\n\n /**\n * Called to get child hierarchy level definitions based on parent instance node's class\n * or custom node's key.\n */\n childNodes: ClassBasedHierarchyLevelDefinition[];\n };\n}\n\n/**\n * Creates an instance of `HierarchyDefinition` that uses a somewhat declarative approach to define the\n * hierarchy - each hierarchy level is assigned either an instance node's class or custom node's\n * key and they're used to assign hierarchy level definitions based on parent node.\n *\n * @beta\n */\nexport function createClassBasedHierarchyDefinition(props: ClassBasedHierarchyDefinitionProps): HierarchyDefinition {\n return new ClassBasedHierarchyDefinition(props);\n}\n\nclass ClassBasedHierarchyDefinition implements HierarchyDefinition {\n public constructor(private _props: ClassBasedHierarchyDefinitionProps) {}\n\n /**\n * Create hierarchy level definitions for specific hierarchy level.\n * @param parentNode Parent node to create children definitions for.\n */\n public async defineHierarchyLevel(props: DefineHierarchyLevelProps): Promise<HierarchyLevelDefinition> {\n const { parentNode } = props;\n if (!parentNode) {\n return this._props.hierarchy.rootNodes(props);\n }\n\n if (HierarchyNode.isCustom(parentNode)) {\n const defs = this._props.hierarchy.childNodes\n .filter(isCustomNodeChildHierarchyLevelDefinition)\n .filter((def) => def.customParentNodeKey === parentNode.key);\n return (await Promise.all(defs.map(async (def) => def.definitions({ ...props, parentNode })))).flat();\n }\n\n // istanbul ignore else\n if (HierarchyNode.isInstancesNode(parentNode)) {\n const instanceIdsByClass = groupInstanceIdsByClass(parentNode.key.instanceKeys);\n const instancesParentNodeDefs = this._props.hierarchy.childNodes.filter(isInstancesNodeChildHierarchyLevelDefinition);\n return (\n await Promise.all(\n [...instanceIdsByClass.entries()].map(async ([parentNodeClassName, parentNodeInstanceIds]) =>\n createHierarchyLevelDefinitions(this._props.classHierarchyInspector, instancesParentNodeDefs, {\n ...props,\n parentNodeClassName,\n parentNodeInstanceIds,\n parentNode,\n }),\n ),\n )\n ).flat();\n }\n\n // istanbul ignore next\n return [];\n }\n}\n\nasync function createHierarchyLevelDefinitions(\n classHierarchy: ECClassHierarchyInspector,\n defs: InstancesNodeChildHierarchyLevelDefinition[],\n requestProps: DefineInstanceNodeChildHierarchyLevelProps,\n) {\n return (\n await Promise.all(\n defs.map(async (def) => {\n if (await classHierarchy.classDerivesFrom(requestProps.parentNodeClassName, def.parentNodeClassName)) {\n return def.definitions(requestProps);\n }\n return [];\n }),\n )\n ).flat();\n}\n\nfunction groupInstanceIdsByClass(instanceKeys: InstanceKey[]) {\n const instanceIdsByClass = new Map<string, Id64String[]>();\n instanceKeys.forEach((key) => {\n let instanceIds = instanceIdsByClass.get(key.className);\n if (!instanceIds) {\n instanceIds = [];\n instanceIdsByClass.set(key.className, instanceIds);\n }\n instanceIds.push(key.id);\n });\n return instanceIdsByClass;\n}\n\nfunction isCustomNodeChildHierarchyLevelDefinition(def: ClassBasedHierarchyLevelDefinition): def is CustomNodeChildHierarchyLevelDefinition {\n return !!(def as CustomNodeChildHierarchyLevelDefinition).customParentNodeKey;\n}\n\nfunction isInstancesNodeChildHierarchyLevelDefinition(def: ClassBasedHierarchyLevelDefinition): def is InstancesNodeChildHierarchyLevelDefinition {\n return !!(def as InstancesNodeChildHierarchyLevelDefinition).parentNodeClassName;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"HierarchyDefinition.js","sourceRoot":"","sources":["../../../src/hierarchies/HierarchyDefinition.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n\nimport { Id64String } from \"@itwin/core-bentley\";\nimport { GenericInstanceFilter } from \"@itwin/core-common\";\nimport { ECClassHierarchyInspector, ECSqlQueryDef, InstanceKey } from \"@itwin/presentation-shared\";\nimport {\n HierarchyNode,\n NonGroupingHierarchyNode,\n ParsedCustomHierarchyNode,\n ParsedInstanceHierarchyNode,\n ProcessedCustomHierarchyNode,\n ProcessedHierarchyNode,\n ProcessedInstanceHierarchyNode,\n} from \"./HierarchyNode\";\nimport { InstancesNodeKey } from \"./HierarchyNodeKey\";\nimport { concatMap, filter, firstValueFrom, from, mergeAll, mergeMap, toArray } from \"rxjs\";\n\n/** A nodes definition that returns a single custom defined node. */\nexport interface CustomHierarchyNodeDefinition {\n /** The node to be created in the hierarchy level */\n node: ParsedCustomHierarchyNode;\n}\n\n/** A nodes definition that returns an ECSQL query for selecting nodes from an iModel. */\nexport interface InstanceNodesQueryDefinition {\n /**\n * Full name of the class whose instances are going to be returned. It's okay if the attribute\n * points to a base class of multiple different classes of instances returned by the query, however\n * the more specific this class is, the more efficient hierarchy building process is.\n */\n fullClassName: string;\n /**\n * An ECSQL query that selects nodes from an iModel. `SELECT` clause of the query is expected\n * to be built using `NodeSelectQueryFactory.createSelectClause`.\n */\n query: ECSqlQueryDef;\n}\n\n/**\n * A definition of nodes included in a hierarchy level.\n * @beta\n */\nexport type HierarchyNodesDefinition = CustomHierarchyNodeDefinition | InstanceNodesQueryDefinition;\n/** @beta */\n// eslint-disable-next-line @typescript-eslint/no-redeclare\nexport namespace HierarchyNodesDefinition {\n export function isCustomNode(def: HierarchyNodesDefinition): def is CustomHierarchyNodeDefinition {\n return !!(def as CustomHierarchyNodeDefinition).node;\n }\n export function isInstanceNodesQuery(def: HierarchyNodesDefinition): def is InstanceNodesQueryDefinition {\n return !!(def as InstanceNodesQueryDefinition).query;\n }\n}\n\n/**\n * A definition of a hierarchy level, which may consist of multiple node definitions.\n * @beta\n */\nexport type HierarchyLevelDefinition = HierarchyNodesDefinition[];\n\n/**\n * A type for a function that parses a `ParsedInstanceHierarchyNode` from provided ECSQL `row` object.\n * @beta\n */\nexport type NodeParser = (row: { [columnName: string]: any }) => ParsedInstanceHierarchyNode;\n\n/**\n * A type for a function that pre-processes given node. Unless the function decides not to make any modifications,\n * it should return a new - modified - node, rather than modifying the given one. Returning `undefined` omits the node\n * from the hierarchy.\n *\n * @beta\n */\nexport type NodePreProcessor = <TNode extends ProcessedCustomHierarchyNode | ProcessedInstanceHierarchyNode>(node: TNode) => Promise<TNode | undefined>;\n\n/**\n * A type for a function that post-processes given node. Unless the function decides not to make any modifications,\n * it should return a new - modified - node, rather than modifying the given one.\n *\n * @beta\n */\nexport type NodePostProcessor = (node: ProcessedHierarchyNode) => Promise<ProcessedHierarchyNode>;\n\n/**\n * A type of node that can be passed to `HierarchyDefinition.defineHierarchyLevel`. This basically means\n * a `HierarchyNode` that:\n * - knows nothing about its children,\n * - is either an instances node (key is of `InstancesNodeKey` type) or a custom node (key is of `string` type).\n */\ntype HierarchyDefinitionParentNode = Omit<NonGroupingHierarchyNode, \"children\">;\n\n/**\n * Props for `HierarchyDefinition.defineHierarchyLevel`.\n * @beta\n */\nexport interface DefineHierarchyLevelProps {\n /** Parent node to get children for. Pass `undefined` to get root nodes. */\n parentNode: HierarchyDefinitionParentNode | undefined;\n\n /** Optional hierarchy level filter. */\n instanceFilter?: GenericInstanceFilter;\n}\n\n/**\n * An interface for a factory that knows how define a hierarchy based on a given parent node.\n * @beta\n */\nexport interface HierarchyDefinition {\n /**\n * An optional function for parsing ECInstance node from ECSQL row.\n *\n * Should be used in situations when the `HierarchyDefinition` implementation\n * introduces additional ECSQL columns into the select clause and wants to assign additional\n * data to the nodes it produces.\n *\n * Defaults to a function that parses all `HierarchyNode` attributes from a query, whose SELECT\n * clause is created using `NodeSelectQueryFactory.createSelectClause`.\n */\n parseNode?: NodeParser;\n\n /**\n * An optional function for pre-processing nodes.\n *\n * Pre-processing happens immediately after the nodes are loaded based on `HierarchyLevelDefinition`\n * returned by this `HierarchyDefinition` and before their processing (hiding, grouping, sorting, etc.) starts.\n * The step allows assigning nodes additional data or excluding them from the hierarchy based on some attributes.\n */\n preProcessNode?: NodePreProcessor;\n\n /**\n * An optional function for post-processing nodes.\n *\n * Post-processing happens after the loaded nodes go through all the merging, hiding and grouping\n * steps, but before sorting them. This step allows `HierarchyDefinition` implementations to assign additional data\n * to nodes after they're processed. This is especially true for grouping nodes as they're only created during\n * processing.\n */\n postProcessNode?: NodePostProcessor;\n\n /** A function to create a hierarchy level definition for given parent node. */\n defineHierarchyLevel(props: DefineHierarchyLevelProps): Promise<HierarchyLevelDefinition>;\n}\n\n/**\n * Props for defining child hierarchy level for specific parent instance node.\n * @see `createClassBasedHierarchyDefinition`\n * @beta\n */\nexport type DefineInstanceNodeChildHierarchyLevelProps = Omit<DefineHierarchyLevelProps, \"parentNode\"> & {\n /** The parent instance node. */\n parentNode: Omit<HierarchyDefinitionParentNode, \"key\"> & { key: InstancesNodeKey };\n\n /**\n * Full name of the parent instance node class.\n *\n * The `parentNode.key` also contains information about the instances the parent node is based on. However,\n * an instance node may be based on instances of multiple classes. In case that happens, parent node's instance\n * keys are grouped by class and a hierarchy level definition is requested for each combination of class and\n * instance IDs (with the same `parentNode`).\n */\n parentNodeClassName: string;\n\n /**\n * ECInstanceIds of the parent instance node.\n *\n * The `parentNode.key` also contains information about the instances the parent node is based on. However,\n * an instance node may be based on instances of multiple classes. In case that happens, parent node's instance\n * keys are grouped by class and a hierarchy level definition is requested for each combination of class and\n * instance IDs (with the same `parentNode`).\n */\n parentNodeInstanceIds: Id64String[];\n};\n\n/**\n * A definition of a hierarchy level that should be used for specific class of parent instance nodes.\n */\ninterface InstancesNodeChildHierarchyLevelDefinition {\n /**\n * Full name of the parent instance node's class to match against when checking if this hierarchy\n * level should be used for specific parent instance node.\n *\n * The check is polymorphic, so `BisCore.Element` class would match `BisCore.GeometricElement`, `BisCore.Category` and\n * all other element classes.\n */\n parentNodeClassName: string;\n\n /**\n * Called to create a hierarchy level definition when the class check passes (see `parentNodeClassName`).\n */\n definitions: (requestProps: DefineInstanceNodeChildHierarchyLevelProps) => Promise<HierarchyLevelDefinition>;\n\n /**\n * If set to true, and node matches at least one of the previous definitions, this definition will not be applied.\n *\n * For example:\n * ```ts\n * {\n * parentNodeClassName: \"BisCore.GeometricElement3d\",\n * definitions: () => ...,\n * },\n * // This will apply to all elements, that are not BisCore.GeometricElement3d\n * {\n * parentNodeClassName: \"BisCore.Element\",\n * onlyIfNotHandled: true,\n * definitions: () => ...,\n * }\n * ```\n */\n onlyIfNotHandled?: boolean;\n}\n\n/**\n * Props for defining child hierarchy level for specific parent custom node.\n * @see `createClassBasedHierarchyDefinition`\n * @beta\n */\nexport type DefineCustomNodeChildHierarchyLevelProps = Omit<DefineHierarchyLevelProps, \"parentNode\"> & {\n /** The parent custom node. */\n parentNode: Omit<HierarchyDefinitionParentNode, \"key\"> & { key: string };\n};\n\n/**\n * A definition of a hierarchy level for that should be used for specific custom parent nodes.\n */\ninterface CustomNodeChildHierarchyLevelDefinition {\n /**\n * `HierarchyNode.key` of the custom node that this child hierarchy level definition should be used for.\n */\n customParentNodeKey: string;\n\n /**\n * Called to create a hierarchy level definition when the node key check passes (see `customParentNodeKey`).\n */\n definitions: (requestProps: DefineCustomNodeChildHierarchyLevelProps) => Promise<HierarchyLevelDefinition>;\n}\n\n/**\n * A hierarchy level definition associated with either parent instance node's class or custom\n * node's key.\n */\ntype ClassBasedHierarchyLevelDefinition = InstancesNodeChildHierarchyLevelDefinition | CustomNodeChildHierarchyLevelDefinition;\n\n/**\n * Props for defining root hierarchy level.\n * @see `createClassBasedHierarchyDefinition`\n * @beta\n */\nexport type DefineRootHierarchyLevelProps = Omit<DefineHierarchyLevelProps, \"parentNode\">;\n\n/**\n * Props for `createClassBasedHierarchyDefinition`.\n */\ninterface ClassBasedHierarchyDefinitionProps {\n /** Access to ECClass hierarchy in the iModel */\n classHierarchyInspector: ECClassHierarchyInspector;\n\n /** Hierarchy level definitions based on parent instance node's class or custom node's key. */\n hierarchy: {\n /** Called to create the root hierarchy level definition. */\n rootNodes: (props: DefineRootHierarchyLevelProps) => Promise<HierarchyLevelDefinition>;\n\n /**\n * Called to get child hierarchy level definitions based on parent instance node's class\n * or custom node's key.\n */\n childNodes: ClassBasedHierarchyLevelDefinition[];\n };\n}\n\n/**\n * Creates an instance of `HierarchyDefinition` that uses a somewhat declarative approach to define the\n * hierarchy - each hierarchy level is assigned either an instance node's class or custom node's\n * key and they're used to assign hierarchy level definitions based on parent node.\n *\n * @beta\n */\nexport function createClassBasedHierarchyDefinition(props: ClassBasedHierarchyDefinitionProps): HierarchyDefinition {\n return new ClassBasedHierarchyDefinition(props);\n}\n\nclass ClassBasedHierarchyDefinition implements HierarchyDefinition {\n public constructor(private _props: ClassBasedHierarchyDefinitionProps) {}\n\n /**\n * Create hierarchy level definitions for specific hierarchy level.\n * @param parentNode Parent node to create children definitions for.\n */\n public async defineHierarchyLevel(props: DefineHierarchyLevelProps): Promise<HierarchyLevelDefinition> {\n const { parentNode } = props;\n if (!parentNode) {\n return this._props.hierarchy.rootNodes(props);\n }\n\n if (HierarchyNode.isCustom(parentNode)) {\n const defs = this._props.hierarchy.childNodes\n .filter(isCustomNodeChildHierarchyLevelDefinition)\n .filter((def) => def.customParentNodeKey === parentNode.key);\n return (await Promise.all(defs.map(async (def) => def.definitions({ ...props, parentNode })))).flat();\n }\n\n // istanbul ignore else\n if (HierarchyNode.isInstancesNode(parentNode)) {\n const instanceIdsByClass = groupInstanceIdsByClass(parentNode.key.instanceKeys);\n const instancesParentNodeDefs = this._props.hierarchy.childNodes.filter(isInstancesNodeChildHierarchyLevelDefinition);\n return (\n await Promise.all(\n [...instanceIdsByClass.entries()].map(async ([parentNodeClassName, parentNodeInstanceIds]) =>\n createHierarchyLevelDefinitions(this._props.classHierarchyInspector, instancesParentNodeDefs, {\n ...props,\n parentNodeClassName,\n parentNodeInstanceIds,\n parentNode,\n }),\n ),\n )\n ).flat();\n }\n\n // istanbul ignore next\n return [];\n }\n}\n\nasync function createHierarchyLevelDefinitions(\n classHierarchy: ECClassHierarchyInspector,\n defs: InstancesNodeChildHierarchyLevelDefinition[],\n requestProps: DefineInstanceNodeChildHierarchyLevelProps,\n) {\n const obs = from(defs).pipe(\n mergeMap(async (def, idx) => {\n if (await classHierarchy.classDerivesFrom(requestProps.parentNodeClassName, def.parentNodeClassName)) {\n return { def, idx };\n }\n return undefined;\n }),\n filter((x): x is Exclude<typeof x, undefined> => !!x),\n toArray(),\n concatMap((x) => x.sort((a, b) => a.idx - b.idx).map(({ def }) => def)),\n filter((def, idx) => !def.onlyIfNotHandled || idx === 0),\n mergeMap(async (def) => def.definitions(requestProps)),\n mergeAll(),\n );\n return firstValueFrom(obs.pipe(toArray()));\n}\n\nfunction groupInstanceIdsByClass(instanceKeys: InstanceKey[]) {\n const instanceIdsByClass = new Map<string, Id64String[]>();\n instanceKeys.forEach((key) => {\n let instanceIds = instanceIdsByClass.get(key.className);\n if (!instanceIds) {\n instanceIds = [];\n instanceIdsByClass.set(key.className, instanceIds);\n }\n instanceIds.push(key.id);\n });\n return instanceIdsByClass;\n}\n\nfunction isCustomNodeChildHierarchyLevelDefinition(def: ClassBasedHierarchyLevelDefinition): def is CustomNodeChildHierarchyLevelDefinition {\n return !!(def as CustomNodeChildHierarchyLevelDefinition).customParentNodeKey;\n}\n\nfunction isInstancesNodeChildHierarchyLevelDefinition(def: ClassBasedHierarchyLevelDefinition): def is InstancesNodeChildHierarchyLevelDefinition {\n return !!(def as InstancesNodeChildHierarchyLevelDefinition).parentNodeClassName;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@itwin/presentation-hierarchies",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "A package for creating hierarchies based on data in iTwin.js iModels.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"@itwin/presentation-shared": "^0.3.1"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@itwin/build-tools": "^4.
|
|
36
|
+
"@itwin/build-tools": "^4.7.1",
|
|
37
37
|
"@itwin/eslint-plugin": "^4.0.0",
|
|
38
38
|
"@types/chai": "^4.3.14",
|
|
39
39
|
"@types/chai-as-promised": "^7.1.8",
|