@itwin/presentation-hierarchies
Version:
A package for creating hierarchies based on data in iTwin.js iModels.
90 lines • 4.33 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
import { concatMap, filter, firstValueFrom, from, mergeAll, mergeMap, toArray } from "rxjs";
import { HierarchyNode } from "../HierarchyNode.js";
/**
* Creates an instance of `HierarchyDefinition` that uses a somewhat declarative approach to define the
* hierarchy - each hierarchy level is defined by specifying a parent node predicate and child hierarchy
* level definitions, that are used when the predicate passes.
*
* @public
*/
export function createPredicateBasedHierarchyDefinition(props) {
return new PredicateBasedHierarchyDefinition(props);
}
class PredicateBasedHierarchyDefinition {
_props;
parseNode;
preProcessNode;
postProcessNode;
constructor(_props) {
this._props = _props;
if (this._props.parseNode) {
this.parseNode = this._props.parseNode;
}
if (this._props.preProcessNode) {
this.preProcessNode = this._props.preProcessNode;
}
if (this._props.postProcessNode) {
this.postProcessNode = this._props.postProcessNode;
}
}
/**
* Create hierarchy level definitions for specific hierarchy level.
* @param parentNode Parent node to create children definitions for.
*/
async defineHierarchyLevel(props) {
const { parentNode } = props;
if (parentNode && HierarchyNode.isGeneric(parentNode)) {
return firstValueFrom(from(this._props.hierarchy.childNodes).pipe(filter(isGenericNodeChildHierarchyLevelDefinition), mergeMap(async (def) => {
if (await def.parentGenericNodePredicate(parentNode.key)) {
return def.definitions({ ...props, parentNode });
}
return [];
}), mergeAll(), toArray()));
}
if (parentNode && HierarchyNode.isInstancesNode(parentNode)) {
const instancesParentNodeDefs = this._props.hierarchy.childNodes.filter(isInstancesNodeChildHierarchyLevelDefinition);
return firstValueFrom(from(groupInstanceIdsByClass(parentNode.key.instanceKeys).entries()).pipe(mergeMap(async ([parentNodeClassName, parentNodeInstanceIds]) => createHierarchyLevelDefinitions(this._props.classHierarchyInspector, instancesParentNodeDefs, {
...props,
parentNodeClassName,
parentNodeInstanceIds,
parentNode,
})), mergeAll(), toArray()));
}
return this._props.hierarchy.rootNodes(props);
}
}
async function createHierarchyLevelDefinitions(classHierarchy, defs, requestProps) {
return from(defs).pipe(mergeMap(async (def, idx) => {
if (typeof def.parentInstancesNodePredicate === "string" &&
(await classHierarchy.classDerivesFrom(requestProps.parentNodeClassName, def.parentInstancesNodePredicate))) {
return { def, idx };
}
if (typeof def.parentInstancesNodePredicate === "function" && (await def.parentInstancesNodePredicate(requestProps.parentNode.key))) {
return { def, idx };
}
return undefined;
}), 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());
}
function groupInstanceIdsByClass(instanceKeys) {
const instanceIdsByClass = new Map();
instanceKeys.forEach((key) => {
let instanceIds = instanceIdsByClass.get(key.className);
if (!instanceIds) {
instanceIds = [];
instanceIdsByClass.set(key.className, instanceIds);
}
instanceIds.push(key.id);
});
return instanceIdsByClass;
}
function isGenericNodeChildHierarchyLevelDefinition(def) {
return !!def.parentGenericNodePredicate;
}
function isInstancesNodeChildHierarchyLevelDefinition(def) {
return !!def.parentInstancesNodePredicate;
}
//# sourceMappingURL=PredicateBasedHierarchyDefinition.js.map