UNPKG

@itwin/presentation-components

Version:

React components based on iTwin.js Presentation library

153 lines 6.43 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ /** @packageDocumentation * @module Internal */ import { compareStrings, Guid, Id64, LRUDictionary } from "@itwin/core-bentley"; import { QueryBinder, QueryRowFormat } from "@itwin/core-common"; /* c8 ignore start */ /** @internal */ export class ECClassInfo { id; name; label; _baseClasses; _derivedClasses; constructor(id, name, label, _baseClasses, _derivedClasses) { this.id = id; this.name = name; this.label = label; this._baseClasses = _baseClasses; this._derivedClasses = _derivedClasses; } get baseClassIds() { return Array.from(this._baseClasses); } get derivedClassIds() { return Array.from(this._derivedClasses); } isBaseOf(idOrInfo) { if (typeof idOrInfo === "string") { return idOrInfo === this.id || this._derivedClasses.has(idOrInfo); } return idOrInfo.id === this.id || this._derivedClasses.has(idOrInfo.id); } isDerivedFrom(idOrInfo) { if (typeof idOrInfo === "string") { return idOrInfo === this.id || this._baseClasses.has(idOrInfo); } return idOrInfo.id === this.id || this._baseClasses.has(idOrInfo.id); } } /** @internal */ export class ECMetadataProvider { _queryReaderFactory; _classInfoCache = new LRUDictionary(50, compareKeys); #componentId; #componentName; constructor(_queryReaderFactory) { this._queryReaderFactory = _queryReaderFactory; this.#componentId = Guid.createValue(); this.#componentName = "ECMetadataProvider"; } async getECClassInfo(idNameOrSchema, className) { // load class info using class id if (Id64.isId64(idNameOrSchema)) { return this.getClassInfoById(idNameOrSchema); } // load class info using class full name: <schemaName>:<className> const fullName = className ? `${idNameOrSchema}:${className}` : idNameOrSchema; return this.getClassInfoByFullName(fullName); } async getClassInfoById(id) { let classInfo = this._classInfoCache.get({ id, name: "" }); if (!classInfo) { const classQuery = ` ${classQueryBase} WHERE classDef.ECInstanceId = :id `; classInfo = await this.createECClassInfo(this._queryReaderFactory(classQuery, QueryBinder.from({ id }), { rowFormat: QueryRowFormat.UseJsPropertyNames, restartToken: `${this.#componentName}/${this.#componentId}/class-by-id/${id}`, })); classInfo && this._classInfoCache.set({ id: classInfo.id, name: classInfo.name }, classInfo); } return classInfo; } async getClassInfoByFullName(name) { let classInfo = this._classInfoCache.get({ id: "", name }); if (!classInfo) { const classQuery = ` ${classQueryBase} WHERE classDef.Name = :className AND schemaDef.Name = :schemaName `; const [schemaName, className] = this.splitFullClassName(name); classInfo = await this.createECClassInfo(this._queryReaderFactory(classQuery, QueryBinder.from({ schemaName, className }), { rowFormat: QueryRowFormat.UseJsPropertyNames, restartToken: `${this.#componentName}/${this.#componentId}/class-by-name/${name}`, })); classInfo && this._classInfoCache.set({ id: classInfo.id, name: classInfo.name }, classInfo); } return classInfo; } async createECClassInfo(reader) { while (await reader.step()) { const classHierarchy = await this.queryClassHierarchyInfo(reader.current.id); return new ECClassInfo(reader.current.id, reader.current.name, reader.current.label, classHierarchy.baseClasses, classHierarchy.derivedClasses); } return undefined; } async queryClassHierarchyInfo(id) { const classHierarchyQuery = ` SELECT chc.TargetECInstanceId baseId, chc.SourceECInstanceId derivedId FROM meta.ClassHasAllBaseClasses chc WHERE chc.SourceECInstanceId = :id OR chc.TargetECInstanceId = :id `; const hierarchy = { baseClasses: new Set(), derivedClasses: new Set() }; const reader = this._queryReaderFactory(classHierarchyQuery, QueryBinder.from({ id }), { rowFormat: QueryRowFormat.UseJsPropertyNames, restartToken: `${this.#componentName}/${this.#componentId}/class-hierarchy/${id}`, }); while (await reader.step()) { if (reader.current.baseId === id) { hierarchy.derivedClasses.add(reader.current.derivedId); } if (reader.current.derivedId === id) { hierarchy.baseClasses.add(reader.current.baseId); } } return hierarchy; } splitFullClassName(fullName) { const [schemaName, className] = fullName.split(fullName.includes(".") ? "." : ":"); return [schemaName, className]; } } const classQueryBase = ` SELECT classDef.ECInstanceId id, (schemaDef.Name || ':' || classDef.Name) name, COALESCE(classDef.DisplayLabel, classDef.name) label FROM meta.ECClassDef classDef JOIN meta.ECSchemaDef schemaDef ON classDef.Schema.Id = schemaDef.ECInstanceId `; const metadataProviders = new Map(); /** @internal */ export function getIModelMetadataProvider(imodel) { let metadataProvider = metadataProviders.get(imodel.key); if (!metadataProvider) { metadataProvider = new ECMetadataProvider((ecsql, params, config) => imodel.createQueryReader(ecsql, params, config)); metadataProviders.set(imodel.key, metadataProvider); /* c8 ignore next 3 */ imodel.onClose.addOnce(() => { metadataProviders.delete(imodel.key); }); } return metadataProvider; } function compareKeys(lhs, rhs) { if (lhs.id.length !== 0 && rhs.id.length !== 0) { return compareStrings(lhs.id, rhs.id); } return compareStrings(lhs.name, rhs.name); } //# sourceMappingURL=ECMetadataProvider.js.map