UNPKG

@itwin/unified-selection

Version:

Package for managing unified selection in iTwin.js applications.

191 lines 8.31 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ import { Id64 } from "@itwin/core-bentley"; import { formIdBindings, genericExecuteQuery } from "./Utils.js"; /** * Computes selection from given element IDs. * @public */ export async function* computeSelection(props) { const { queryExecutor, elementIds, scope } = props; if (typeof scope === "string") { yield* computeSelection({ queryExecutor, elementIds, scope: { id: scope } }); return; } const nonTransientIds = []; for (const id of Id64.iterable(elementIds)) { if (!Id64.isTransient(id)) { nonTransientIds.push(id); } } switch (scope.id) { case "element": yield* computeElementSelection(queryExecutor, nonTransientIds, scope.ancestorLevel ?? 0); return; case "category": yield* computeCategorySelection(queryExecutor, nonTransientIds); return; case "model": yield* computeModelSelection(queryExecutor, nonTransientIds); return; case "functional": yield* computeFunctionalElementSelection(queryExecutor, nonTransientIds, scope.ancestorLevel ?? 0); return; } } async function* computeElementSelection(queryExecutor, elementIds, ancestorLevel) { const bindings = []; const recurseUntilRoot = ancestorLevel < 0; const ctes = [ ` AncestorElements(ECInstanceId, ECClassId, Depth, ParentId) AS ( SELECT ECInstanceId, ECClassId, ${formAncestorLevelBinding(ancestorLevel, bindings)}, Parent.Id FROM BisCore.Element WHERE ${formIdBindings("ECInstanceId", elementIds, bindings)} UNION ALL SELECT pe.ECInstanceId, pe.ECClassId, a.Depth - 1, pe.Parent.Id FROM AncestorElements a JOIN BisCore.Element pe ON pe.ECInstanceId = a.ParentId WHERE ${recurseUntilRoot ? "" : "Depth > 0 AND"} ParentId IS NOT NULL ) `, ]; const ecsql = ` SELECT DISTINCT ECInstanceId, ec_classname(ECClassId, 's.c') AS ClassName FROM AncestorElements WHERE ${recurseUntilRoot ? "" : "Depth = 0 OR"} ParentId IS NULL `; yield* executeQuery(queryExecutor, { ctes, ecsql, bindings }); } async function* computeCategorySelection(queryExecutor, ids) { const bindings = []; const ecsql = [ ` SELECT DISTINCT c.ECInstanceId, ec_classname(c.ECClassId, 's.c') AS ClassName FROM BisCore.Category c JOIN BisCore.GeometricElement2d ge ON ge.Category.Id = c.ECInstanceId WHERE ${formIdBindings("ge.ECInstanceId", ids, bindings)} `, ` SELECT DISTINCT c.ECInstanceId, ec_classname(c.ECClassId, 's.c') AS ClassName FROM BisCore.Category c JOIN BisCore.GeometricElement3d ge ON ge.Category.Id = c.ECInstanceId WHERE ${formIdBindings("ge.ECInstanceId", ids, bindings)} `, ].join(" UNION ALL "); yield* executeQuery(queryExecutor, { ecsql, bindings }); } async function* computeModelSelection(queryExecutor, ids) { const bindings = []; const ecsql = ` SELECT DISTINCT m.ECInstanceId, ec_classname(m.ECClassId, 's.c') AS ClassName FROM BisCore.Model m JOIN BisCore.Element e ON e.Model.Id = m.ECInstanceId WHERE ${formIdBindings("e.ECInstanceId", ids, bindings)} `; yield* executeQuery(queryExecutor, { ecsql, bindings }); } async function* computeFunctionalElementSelection(queryExecutor, ids, ancestorLevel) { const bindings = []; const recurseUntilRoot = ancestorLevel < 0; const ctes = [ ` Elements2dOrNearestFunctionalElements(OriginalECInstanceId, OriginalECClassId, ECInstanceId, ECClassId, ParentId) AS ( SELECT ECInstanceId, ECClassId, ECInstanceId, ECClassId, Parent.Id FROM BisCore.Element WHERE ${formIdBindings("ECInstanceId", ids, bindings)} AND ECClassId IS NOT (BisCore.GeometricElement3d) UNION ALL SELECT e2onfe.OriginalECInstanceId, e2onfe.OriginalECClassId, COALESCE(dgrfe.TargetECInstanceId, pe.ECInstanceId), COALESCE(dgrfe.TargetECClassId, pe.ECClassId), pe.Parent.Id FROM Elements2dOrNearestFunctionalElements e2onfe LEFT JOIN BisCore.Element pe ON pe.ECInstanceId = e2onfe.ParentId LEFT JOIN Functional.DrawingGraphicRepresentsFunctionalElement dgrfe ON dgrfe.SourceECInstanceId = e2onfe.ECInstanceId WHERE e2onfe.ECClassId IS NOT (Functional.FunctionalElement) AND (e2onfe.ParentId IS NOT NULL OR dgrfe.TargetECInstanceId IS NOT NULL) ) `, ` Element2dNearestFunctionalElements(OriginalECInstanceId, ECInstanceId, ECClassId) AS ( SELECT OriginalECInstanceId, ECInstanceId, ECClassId FROM Elements2dOrNearestFunctionalElements WHERE ECClassId IS (Functional.FunctionalElement) ) `, ` Elements2dWithoutFunctionalElement(ECInstanceId, ECClassId) AS ( SELECT e2wfe.OriginalECInstanceId, OriginalECClassId FROM Elements2dOrNearestFunctionalElements e2wfe LEFT JOIN Element2dNearestFunctionalElements e2nfe ON e2nfe.OriginalECInstanceId = e2wfe.OriginalECInstanceId WHERE e2wfe.ParentId IS NULL AND e2nfe.ECInstanceId IS NULL ) `, ` Elements2d(ECInstanceId, ECClassId) AS ( SELECT ECInstanceId, ECClassId FROM Element2dNearestFunctionalElements UNION SELECT ECInstanceId, ECClassId FROM Elements2dWithoutFunctionalElement ) `, ` Element2dAncestorElements(ECInstanceId, ECClassId, Depth, ParentId) AS ( SELECT e.ECInstanceId, e.ECClassId, ${formAncestorLevelBinding(ancestorLevel, bindings)}, e.Parent.Id FROM BisCore.Element e JOIN Elements2d e2d ON e2d.ECInstanceId = e.ECInstanceId UNION ALL SELECT pe.ECInstanceId, pe.ECClassId, e2ae.Depth - 1, pe.Parent.Id FROM Element2dAncestorElements e2ae JOIN BisCore.Element pe ON pe.ECInstanceId = e2ae.ParentId WHERE ${recurseUntilRoot ? "" : "Depth > 0 AND"} ParentId IS NOT NULL ) `, ` Element3dAncestorElements(ECInstanceId, ECClassId, Depth, ParentId) AS ( SELECT ge.ECInstanceId, ge.ECClassId, ${formAncestorLevelBinding(ancestorLevel, bindings)}, ge.Parent.Id FROM BisCore.GeometricElement3d ge WHERE ${formIdBindings("ge.ECInstanceId", ids, bindings)} UNION ALL SELECT pe.ECInstanceId, pe.ECClassId, e3ae.Depth - 1, pe.Parent.Id FROM Element3dAncestorElements e3ae JOIN BisCore.Element pe ON pe.ECInstanceId = e3ae.ParentId WHERE ${recurseUntilRoot ? "" : "Depth > 0 AND"} ParentId IS NOT NULL ) `, ` Element3dAncestorRelatedFunctionalElement(ECInstanceId, ClassName) AS ( SELECT COALESCE(peff.TargetECInstanceId, e3ae.ECInstanceId), ec_classname(COALESCE(peff.TargetECClassId, e3ae.ECClassId), 's.c') FROM Element3dAncestorElements e3ae LEFT JOIN Functional.PhysicalElementFulfillsFunction peff ON peff.SourceECInstanceId = e3ae.ECInstanceId WHERE ${recurseUntilRoot ? "" : "e3ae.Depth = 0 OR"} e3ae.ParentId IS NULL ) `, ]; const ecsql = [ ` SELECT DISTINCT ECInstanceId, ec_classname(ECClassId, 's.c') AS ClassName FROM Element2dAncestorElements WHERE ${recurseUntilRoot ? "" : "Depth = 0 OR"} ParentId IS NULL `, ` SELECT DISTINCT ECInstanceId, ClassName FROM Element3dAncestorRelatedFunctionalElement `, ].join(" UNION "); yield* executeQuery(queryExecutor, { ctes, ecsql, bindings }); } function formAncestorLevelBinding(ancestorLevel, bindings) { bindings.push({ type: "int", value: ancestorLevel }); return "?"; } async function* executeQuery(queryExecutor, query) { yield* genericExecuteQuery(queryExecutor, query, (row) => ({ className: row.ClassName, id: row.ECInstanceId, })); } //# sourceMappingURL=SelectionScope.js.map