@itwin/imodel-transformer 2.0.0-dev.51 → 2.0.0-dev.53
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/lib/cjs/ChangedElementForest.d.ts +14 -0
- package/lib/cjs/ChangedElementForest.d.ts.map +1 -0
- package/lib/cjs/ChangedElementForest.js +86 -0
- package/lib/cjs/ChangedElementForest.js.map +1 -0
- package/lib/cjs/IModelExporter.d.ts +32 -1
- package/lib/cjs/IModelExporter.d.ts.map +1 -1
- package/lib/cjs/IModelExporter.js +202 -37
- package/lib/cjs/IModelExporter.js.map +1 -1
- package/lib/cjs/imodel-transformer.d.ts +4 -0
- package/lib/cjs/imodel-transformer.d.ts.map +1 -1
- package/lib/cjs/imodel-transformer.js +4 -0
- package/lib/cjs/imodel-transformer.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { IModelDb } from "@itwin/core-backend";
|
|
2
|
+
import { Id64String } from "@itwin/core-bentley";
|
|
3
|
+
/** The minimal parent-child forest containing changed or excluded elements and their ancestors. */
|
|
4
|
+
export declare class ChangedElementForest {
|
|
5
|
+
private readonly _rootsByModel;
|
|
6
|
+
private readonly _childrenByParent;
|
|
7
|
+
private constructor();
|
|
8
|
+
static create(sourceDb: IModelDb, ownedCandidateIds: Id64String[], maximumElementCount: number): Promise<ChangedElementForest | undefined>;
|
|
9
|
+
/** Gets the indexed root element IDs for a model. */
|
|
10
|
+
getModelRoots(modelId: Id64String): readonly Id64String[];
|
|
11
|
+
/** Gets the indexed child element IDs for a parent element. */
|
|
12
|
+
getChildren(parentId: Id64String): readonly Id64String[];
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=ChangedElementForest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChangedElementForest.d.ts","sourceRoot":"","sources":["../../src/ChangedElementForest.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,QAAQ,EACT,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAuB,MAAM,qBAAqB,CAAC;AAGtE,mGAAmG;AACnG,qBAAa,oBAAoB;IAE7B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAI9B,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IALpC,OAAO,eASH;IAEJ,OAAoB,MAAM,CACxB,QAAQ,EAAE,QAAQ,EAClB,iBAAiB,EAAE,UAAU,EAAE,EAC/B,mBAAmB,EAAE,MAAM,GAC1B,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC,CAwD3C;IAED,qDAAqD;IAC9C,aAAa,CAAC,OAAO,EAAE,UAAU,GAAG,SAAS,UAAU,EAAE,CAE/D;IAED,+DAA+D;IACxD,WAAW,CAAC,QAAQ,EAAE,UAAU,GAAG,SAAS,UAAU,EAAE,CAE9D;CACF"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*---------------------------------------------------------------------------------------------
|
|
3
|
+
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
4
|
+
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
5
|
+
*--------------------------------------------------------------------------------------------*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.ChangedElementForest = void 0;
|
|
8
|
+
const core_backend_1 = require("@itwin/core-backend");
|
|
9
|
+
const core_bentley_1 = require("@itwin/core-bentley");
|
|
10
|
+
const core_common_1 = require("@itwin/core-common");
|
|
11
|
+
/** The minimal parent-child forest containing changed or excluded elements and their ancestors. */
|
|
12
|
+
class ChangedElementForest {
|
|
13
|
+
_rootsByModel;
|
|
14
|
+
_childrenByParent;
|
|
15
|
+
constructor(_rootsByModel, _childrenByParent) {
|
|
16
|
+
this._rootsByModel = _rootsByModel;
|
|
17
|
+
this._childrenByParent = _childrenByParent;
|
|
18
|
+
}
|
|
19
|
+
static async create(sourceDb, ownedCandidateIds, maximumElementCount) {
|
|
20
|
+
if (ownedCandidateIds.length === 0) {
|
|
21
|
+
return new ChangedElementForest(new Map(), new Map());
|
|
22
|
+
}
|
|
23
|
+
const sql = `
|
|
24
|
+
WITH RECURSIVE ChangedElementHierarchy (ECInstanceId, ParentId, ModelId) AS (
|
|
25
|
+
SELECT e.ECInstanceId, e.Parent.Id, e.Model.Id
|
|
26
|
+
FROM ${core_backend_1.Element.classFullName} e
|
|
27
|
+
INNER JOIN IdSet(:candidateIds) ids ON ids.id = e.ECInstanceId
|
|
28
|
+
UNION
|
|
29
|
+
SELECT p.ECInstanceId, p.Parent.Id, p.Model.Id
|
|
30
|
+
FROM ${core_backend_1.Element.classFullName} p
|
|
31
|
+
INNER JOIN ChangedElementHierarchy c ON p.ECInstanceId = c.ParentId
|
|
32
|
+
)
|
|
33
|
+
SELECT ECInstanceId, ParentId, ModelId FROM ChangedElementHierarchy
|
|
34
|
+
LIMIT :resultLimit
|
|
35
|
+
`;
|
|
36
|
+
core_bentley_1.OrderedId64Iterable.sortArray(ownedCandidateIds);
|
|
37
|
+
const params = new core_common_1.QueryBinder()
|
|
38
|
+
.bindIdSet("candidateIds", ownedCandidateIds)
|
|
39
|
+
.bindInt("resultLimit", maximumElementCount + 1);
|
|
40
|
+
// QueryBinder serializes the IdSet synchronously, so release this temporary copy before retaining the hierarchy.
|
|
41
|
+
ownedCandidateIds.length = 0;
|
|
42
|
+
const rootsByModel = new Map();
|
|
43
|
+
const childrenByParent = new Map();
|
|
44
|
+
let elementCount = 0;
|
|
45
|
+
let elementLimitExceeded = false;
|
|
46
|
+
for await (const row of sourceDb.createQueryReader(sql, params, {
|
|
47
|
+
usePrimaryConn: true,
|
|
48
|
+
})) {
|
|
49
|
+
if (elementCount >= maximumElementCount) {
|
|
50
|
+
// Consume the single overflow row so the ECSqlReader reaches done; it has no disposal API.
|
|
51
|
+
elementLimitExceeded = true;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
elementCount++;
|
|
55
|
+
const elementId = row[0];
|
|
56
|
+
const parentId = row[1] ?? undefined;
|
|
57
|
+
const modelId = row[2];
|
|
58
|
+
const index = parentId === undefined ? rootsByModel : childrenByParent;
|
|
59
|
+
const key = parentId ?? modelId;
|
|
60
|
+
const siblings = index.get(key);
|
|
61
|
+
if (siblings === undefined)
|
|
62
|
+
index.set(key, [elementId]);
|
|
63
|
+
else
|
|
64
|
+
siblings.push(elementId);
|
|
65
|
+
}
|
|
66
|
+
if (elementLimitExceeded)
|
|
67
|
+
return undefined;
|
|
68
|
+
for (const siblings of rootsByModel.values()) {
|
|
69
|
+
core_bentley_1.OrderedId64Iterable.sortArray(siblings);
|
|
70
|
+
}
|
|
71
|
+
for (const siblings of childrenByParent.values()) {
|
|
72
|
+
core_bentley_1.OrderedId64Iterable.sortArray(siblings);
|
|
73
|
+
}
|
|
74
|
+
return new ChangedElementForest(rootsByModel, childrenByParent);
|
|
75
|
+
}
|
|
76
|
+
/** Gets the indexed root element IDs for a model. */
|
|
77
|
+
getModelRoots(modelId) {
|
|
78
|
+
return this._rootsByModel.get(modelId) ?? [];
|
|
79
|
+
}
|
|
80
|
+
/** Gets the indexed child element IDs for a parent element. */
|
|
81
|
+
getChildren(parentId) {
|
|
82
|
+
return this._childrenByParent.get(parentId) ?? [];
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
exports.ChangedElementForest = ChangedElementForest;
|
|
86
|
+
//# sourceMappingURL=ChangedElementForest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChangedElementForest.js","sourceRoot":"","sources":["../../src/ChangedElementForest.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 {\n // eslint-disable-next-line @typescript-eslint/no-redeclare\n Element,\n IModelDb,\n} from \"@itwin/core-backend\";\nimport { Id64String, OrderedId64Iterable } from \"@itwin/core-bentley\";\nimport { QueryBinder } from \"@itwin/core-common\";\n\n/** The minimal parent-child forest containing changed or excluded elements and their ancestors. */\nexport class ChangedElementForest {\n private constructor(\n private readonly _rootsByModel: ReadonlyMap<\n Id64String,\n readonly Id64String[]\n >,\n private readonly _childrenByParent: ReadonlyMap<\n Id64String,\n readonly Id64String[]\n >\n ) {}\n\n public static async create(\n sourceDb: IModelDb,\n ownedCandidateIds: Id64String[],\n maximumElementCount: number\n ): Promise<ChangedElementForest | undefined> {\n if (ownedCandidateIds.length === 0) {\n return new ChangedElementForest(new Map(), new Map());\n }\n\n const sql = `\n WITH RECURSIVE ChangedElementHierarchy (ECInstanceId, ParentId, ModelId) AS (\n SELECT e.ECInstanceId, e.Parent.Id, e.Model.Id\n FROM ${Element.classFullName} e\n INNER JOIN IdSet(:candidateIds) ids ON ids.id = e.ECInstanceId\n UNION\n SELECT p.ECInstanceId, p.Parent.Id, p.Model.Id\n FROM ${Element.classFullName} p\n INNER JOIN ChangedElementHierarchy c ON p.ECInstanceId = c.ParentId\n )\n SELECT ECInstanceId, ParentId, ModelId FROM ChangedElementHierarchy\n LIMIT :resultLimit\n `;\n OrderedId64Iterable.sortArray(ownedCandidateIds);\n const params = new QueryBinder()\n .bindIdSet(\"candidateIds\", ownedCandidateIds)\n .bindInt(\"resultLimit\", maximumElementCount + 1);\n // QueryBinder serializes the IdSet synchronously, so release this temporary copy before retaining the hierarchy.\n ownedCandidateIds.length = 0;\n const rootsByModel = new Map<Id64String, Id64String[]>();\n const childrenByParent = new Map<Id64String, Id64String[]>();\n let elementCount = 0;\n let elementLimitExceeded = false;\n for await (const row of sourceDb.createQueryReader(sql, params, {\n usePrimaryConn: true,\n })) {\n if (elementCount >= maximumElementCount) {\n // Consume the single overflow row so the ECSqlReader reaches done; it has no disposal API.\n elementLimitExceeded = true;\n continue;\n }\n elementCount++;\n const elementId: Id64String = row[0];\n const parentId: Id64String | undefined = row[1] ?? undefined;\n const modelId: Id64String = row[2];\n const index = parentId === undefined ? rootsByModel : childrenByParent;\n const key = parentId ?? modelId;\n const siblings = index.get(key);\n if (siblings === undefined) index.set(key, [elementId]);\n else siblings.push(elementId);\n }\n\n if (elementLimitExceeded) return undefined;\n\n for (const siblings of rootsByModel.values()) {\n OrderedId64Iterable.sortArray(siblings);\n }\n for (const siblings of childrenByParent.values()) {\n OrderedId64Iterable.sortArray(siblings);\n }\n return new ChangedElementForest(rootsByModel, childrenByParent);\n }\n\n /** Gets the indexed root element IDs for a model. */\n public getModelRoots(modelId: Id64String): readonly Id64String[] {\n return this._rootsByModel.get(modelId) ?? [];\n }\n\n /** Gets the indexed child element IDs for a parent element. */\n public getChildren(parentId: Id64String): readonly Id64String[] {\n return this._childrenByParent.get(parentId) ?? [];\n }\n}\n"]}
|
|
@@ -202,6 +202,10 @@ export declare class IModelExporter {
|
|
|
202
202
|
private _progressCounter;
|
|
203
203
|
/** Optionally cached entity change information */
|
|
204
204
|
private _sourceDbChanges?;
|
|
205
|
+
/** State shared by nested calls in one change-processing element traversal. */
|
|
206
|
+
private _changedElementTraversal?;
|
|
207
|
+
/** Bounds the additional hierarchy retained by the sparse changed-element path. */
|
|
208
|
+
private readonly _changedElementForestElementLimit;
|
|
205
209
|
/**
|
|
206
210
|
* Retrieve the cached entity change information.
|
|
207
211
|
* @note This will only be initialized after [IModelExporter.exportChanges] is invoked or [IModelExporter.initialize] is called.
|
|
@@ -249,7 +253,9 @@ export declare class IModelExporter {
|
|
|
249
253
|
registerHandler(handler: IModelExportHandler): void;
|
|
250
254
|
/** Add a rule to exclude a CodeSpec */
|
|
251
255
|
excludeCodeSpec(codeSpecName: string): void;
|
|
252
|
-
/** Add a rule to exclude a specific Element.
|
|
256
|
+
/** Add a rule to exclude a specific Element.
|
|
257
|
+
* @note Configure exclusions before starting an export operation. Changing exclusions while an export is in progress is unsupported.
|
|
258
|
+
*/
|
|
253
259
|
excludeElement(elementId: Id64String): void;
|
|
254
260
|
/** Add a rule to exclude all Elements in a specified Category. */
|
|
255
261
|
excludeElementsInCategory(categoryId: Id64String): void;
|
|
@@ -333,6 +339,17 @@ export declare class IModelExporter {
|
|
|
333
339
|
*/
|
|
334
340
|
exportModelContents(modelId: Id64String, elementClassFullName?: string, skipRootSubject?: boolean): Promise<void>;
|
|
335
341
|
private exportModelContentsImpl;
|
|
342
|
+
/** Whether the public element traversal methods still have their base implementations. */
|
|
343
|
+
private hasDefaultElementTraversal;
|
|
344
|
+
/** Whether hierarchy traversal can use the streamed query.
|
|
345
|
+
* Changes mode and overrides of the public traversal methods require legacy dispatch.
|
|
346
|
+
*/
|
|
347
|
+
private canUseSetBasedTraversal;
|
|
348
|
+
/** Stream element trees in the legacy depth-first order with one recursive ECSQL query.
|
|
349
|
+
* Rejected subtrees are skipped in the exporter without loading their descendants.
|
|
350
|
+
* @param anchorSelect a SELECT producing `(ECInstanceId, 0)` rows for the tree roots
|
|
351
|
+
*/
|
|
352
|
+
private exportElementTreesStreamed;
|
|
336
353
|
/** Export the sub-models directly below the specified model.
|
|
337
354
|
* @note This method is called from [[exportChanges]] and [[exportAll]], so it only needs to be called directly when exporting a subset of an iModel.
|
|
338
355
|
*/
|
|
@@ -349,16 +366,30 @@ export declare class IModelExporter {
|
|
|
349
366
|
*/
|
|
350
367
|
exportElement(elementId: Id64String): Promise<void>;
|
|
351
368
|
private exportElementImpl;
|
|
369
|
+
/** Runs the export callbacks for a single element without visiting its children.
|
|
370
|
+
* @returns `true` if the element's children should be visited afterwards.
|
|
371
|
+
*/
|
|
372
|
+
private exportElementShallow;
|
|
352
373
|
/** Export the child elements of the specified element from the source iModel.
|
|
353
374
|
* @note This method is called from [[exportChanges]] and [[exportAll]], so it only needs to be called directly when exporting a subset of an iModel.
|
|
354
375
|
*/
|
|
355
376
|
exportChildElements(elementId: Id64String): Promise<void>;
|
|
356
377
|
private exportChildElementsImpl;
|
|
378
|
+
/** Whether change processing may use the sparse hierarchy as the child-id source.
|
|
379
|
+
* Custom traversal overrides retain the previous full element dispatch.
|
|
380
|
+
*/
|
|
381
|
+
private canUseChangedElementForest;
|
|
382
|
+
private getOverriddenElementTraversalMethods;
|
|
383
|
+
private disableChangedElementForest;
|
|
384
|
+
private createChangedElementForest;
|
|
385
|
+
private getChangedElementForest;
|
|
357
386
|
/** Exports all aspects owned by the supplied elements. */
|
|
358
387
|
private exportAspectsForOwners;
|
|
359
388
|
private filterOwnerElementIdsForAspectExport;
|
|
360
389
|
private shouldExportElementHierarchyForAspect;
|
|
361
390
|
private shouldExportModelForAspect;
|
|
391
|
+
private beginChangedElementTraversalScope;
|
|
392
|
+
private endChangedElementTraversalScope;
|
|
362
393
|
private runScopedElementExport;
|
|
363
394
|
/** Apply the element export filter when deciding whether to process an aspect owner. @internal */
|
|
364
395
|
private shouldExportElementForAspect;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IModelExporter.d.ts","sourceRoot":"","sources":["../../src/IModelExporter.ts"],"names":[],"mappings":"AAIA;;GAEG;AAEH,OAAO,EACL,WAAW,EAEX,cAAc,EAGd,OAAO,EACP,aAAa,EACb,kBAAkB,EAElB,mBAAmB,EAEnB,QAAQ,EACR,cAAc,EACd,KAAK,EAEL,YAAY,EACZ,cAAc,EACf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEL,UAAU,EAEV,OAAO,EAEP,UAAU,EAMX,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEL,kBAAkB,EAClB,QAAQ,EAER,oBAAoB,EAEpB,SAAS,EAKV,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAa,MAAM,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAIxE,OAAO,EAAE,8BAA8B,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"IModelExporter.d.ts","sourceRoot":"","sources":["../../src/IModelExporter.ts"],"names":[],"mappings":"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"}
|
|
@@ -18,6 +18,7 @@ const ElementAspectExportProcessor_1 = require("./ElementAspectExportProcessor")
|
|
|
18
18
|
const ElementAspectExportCoordinator_1 = require("./ElementAspectExportCoordinator");
|
|
19
19
|
const IModelTransformerError_1 = require("./IModelTransformerError");
|
|
20
20
|
const ChangesetScanner_1 = require("./ChangesetScanner");
|
|
21
|
+
const ChangedElementForest_1 = require("./ChangedElementForest");
|
|
21
22
|
const loggerCategory = TransformerLoggerCategory_1.TransformerLoggerCategory.IModelExporter;
|
|
22
23
|
/** Handles the events generated by IModelExporter.
|
|
23
24
|
* @note Change information is available when `IModelExportHandler` methods are invoked via [IModelExporter.exportChanges]($transformer), but not available when invoked via [IModelExporter.exportAll]($transformer).
|
|
@@ -172,6 +173,10 @@ class IModelExporter {
|
|
|
172
173
|
_progressCounter = 0;
|
|
173
174
|
/** Optionally cached entity change information */
|
|
174
175
|
_sourceDbChanges;
|
|
176
|
+
/** State shared by nested calls in one change-processing element traversal. */
|
|
177
|
+
_changedElementTraversal;
|
|
178
|
+
/** Bounds the additional hierarchy retained by the sparse changed-element path. */
|
|
179
|
+
_changedElementForestElementLimit = 100_000;
|
|
175
180
|
/**
|
|
176
181
|
* Retrieve the cached entity change information.
|
|
177
182
|
* @note This will only be initialized after [IModelExporter.exportChanges] is invoked or [IModelExporter.initialize] is called.
|
|
@@ -262,7 +267,9 @@ class IModelExporter {
|
|
|
262
267
|
excludeCodeSpec(codeSpecName) {
|
|
263
268
|
this._excludedCodeSpecNames.add(codeSpecName);
|
|
264
269
|
}
|
|
265
|
-
/** Add a rule to exclude a specific Element.
|
|
270
|
+
/** Add a rule to exclude a specific Element.
|
|
271
|
+
* @note Configure exclusions before starting an export operation. Changing exclusions while an export is in progress is unsupported.
|
|
272
|
+
*/
|
|
266
273
|
excludeElement(elementId) {
|
|
267
274
|
this._excludedElementIds.add(elementId);
|
|
268
275
|
}
|
|
@@ -337,27 +344,33 @@ class IModelExporter {
|
|
|
337
344
|
(0, node_assert_1.strict)(this._sourceDbChanges !== undefined, "sourceDbChanges must be initialized.");
|
|
338
345
|
await this.exportCodeSpecs();
|
|
339
346
|
await this.exportFonts();
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
347
|
+
(0, node_assert_1.strict)(this.beginChangedElementTraversalScope(), "exportChanges must own its changed-element traversal scope");
|
|
348
|
+
try {
|
|
349
|
+
await this._elementAspectExportCoordinator.run(async () => {
|
|
350
|
+
if (initOpts.skipPropagateChangesToRootElements) {
|
|
351
|
+
// The root Subject is in the RepositoryModel. Traverse its children
|
|
352
|
+
// separately, then export other top-level repository elements while
|
|
353
|
+
// excluding the root so no element is visited twice.
|
|
354
|
+
await this.exportChildElements(core_common_1.IModel.rootSubjectId);
|
|
355
|
+
await this.exportModelContents(core_common_1.IModel.repositoryModelId, core_backend_1.Element.classFullName, true);
|
|
356
|
+
await this.exportSubModels(core_common_1.IModel.repositoryModelId);
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
await this.exportModel(core_common_1.IModel.repositoryModelId);
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
const aspectOnlyOwnerElementIds = new Set(this._sourceDbChanges.aspectOwnerElementIds);
|
|
363
|
+
for (const elementId of this._sourceDbChanges.element.insertIds) {
|
|
364
|
+
aspectOnlyOwnerElementIds.delete(elementId);
|
|
348
365
|
}
|
|
349
|
-
|
|
350
|
-
|
|
366
|
+
for (const elementId of this._sourceDbChanges.element.updateIds) {
|
|
367
|
+
aspectOnlyOwnerElementIds.delete(elementId);
|
|
351
368
|
}
|
|
352
|
-
|
|
353
|
-
const aspectOnlyOwnerElementIds = new Set(this._sourceDbChanges.aspectOwnerElementIds);
|
|
354
|
-
for (const elementId of this._sourceDbChanges.element.insertIds) {
|
|
355
|
-
aspectOnlyOwnerElementIds.delete(elementId);
|
|
369
|
+
await this.exportAspectsForOwners(await this.filterOwnerElementIdsForAspectExport(aspectOnlyOwnerElementIds));
|
|
356
370
|
}
|
|
357
|
-
|
|
358
|
-
|
|
371
|
+
finally {
|
|
372
|
+
this.endChangedElementTraversalScope();
|
|
359
373
|
}
|
|
360
|
-
await this.exportAspectsForOwners(await this.filterOwnerElementIdsForAspectExport(aspectOnlyOwnerElementIds));
|
|
361
374
|
await this.exportRelationships(core_backend_1.ElementRefersToElements.classFullName);
|
|
362
375
|
// handle deletes
|
|
363
376
|
if (this.visitElements) {
|
|
@@ -609,19 +622,33 @@ class IModelExporter {
|
|
|
609
622
|
!this._sourceDbChanges.model.updateIds.has(modelId)) {
|
|
610
623
|
return; // this optimization assumes that the Model changes (LastMod) any time an Element in the Model changes
|
|
611
624
|
}
|
|
625
|
+
if (this.canUseChangedElementForest() &&
|
|
626
|
+
elementClassFullName === core_backend_1.Element.classFullName) {
|
|
627
|
+
const forest = await this.getChangedElementForest();
|
|
628
|
+
if (forest !== undefined) {
|
|
629
|
+
core_bentley_1.Logger.logTrace(loggerCategory, `exportModelContents(${modelId}) via changed-element index`);
|
|
630
|
+
for (const rootId of forest.getModelRoots(modelId)) {
|
|
631
|
+
if (skipRootSubject && rootId === core_common_1.IModel.rootSubjectId)
|
|
632
|
+
continue;
|
|
633
|
+
await this.exportElement(rootId);
|
|
634
|
+
await this._yieldManager.allowYield();
|
|
635
|
+
}
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
612
639
|
}
|
|
613
640
|
core_bentley_1.Logger.logTrace(loggerCategory, `exportModelContents(${modelId})`);
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
}
|
|
618
|
-
else {
|
|
619
|
-
sql = `SELECT ECInstanceId FROM ${elementClassFullName} WHERE Parent.Id IS NULL AND Model.Id=:modelId ORDER BY ECInstanceId`;
|
|
620
|
-
}
|
|
641
|
+
const rootFilter = skipRootSubject
|
|
642
|
+
? "e.Parent.Id IS NULL AND e.Model.Id=:modelId AND e.ECInstanceId!=:rootSubjectId"
|
|
643
|
+
: "e.Parent.Id IS NULL AND e.Model.Id=:modelId";
|
|
621
644
|
const params = new core_common_1.QueryBinder().bindId("modelId", modelId);
|
|
622
645
|
if (skipRootSubject) {
|
|
623
646
|
params.bindId("rootSubjectId", core_common_1.IModel.rootSubjectId);
|
|
624
647
|
}
|
|
648
|
+
if (this.canUseSetBasedTraversal()) {
|
|
649
|
+
return this.exportElementTreesStreamed(`SELECT e.ECInstanceId, 0 FROM ${elementClassFullName} e WHERE ${rootFilter}`, params);
|
|
650
|
+
}
|
|
651
|
+
const sql = `SELECT e.ECInstanceId FROM ${elementClassFullName} e WHERE ${rootFilter} ORDER BY e.ECInstanceId`;
|
|
625
652
|
for await (const row of this.sourceDb.createQueryReader(sql, params, {
|
|
626
653
|
usePrimaryConn: true,
|
|
627
654
|
})) {
|
|
@@ -629,6 +656,55 @@ class IModelExporter {
|
|
|
629
656
|
await this._yieldManager.allowYield();
|
|
630
657
|
}
|
|
631
658
|
}
|
|
659
|
+
/** Whether the public element traversal methods still have their base implementations. */
|
|
660
|
+
hasDefaultElementTraversal() {
|
|
661
|
+
// The optimized helpers bypass these public overridable methods. Compare function
|
|
662
|
+
// identity so subclass, bound, wrapped, or instrumented methods retain legacy dispatch.
|
|
663
|
+
return (this.exportElement === IModelExporter.prototype.exportElement &&
|
|
664
|
+
this.exportChildElements === IModelExporter.prototype.exportChildElements);
|
|
665
|
+
}
|
|
666
|
+
/** Whether hierarchy traversal can use the streamed query.
|
|
667
|
+
* Changes mode and overrides of the public traversal methods require legacy dispatch.
|
|
668
|
+
*/
|
|
669
|
+
canUseSetBasedTraversal() {
|
|
670
|
+
return (this._sourceDbChanges === undefined && this.hasDefaultElementTraversal());
|
|
671
|
+
}
|
|
672
|
+
/** Stream element trees in the legacy depth-first order with one recursive ECSQL query.
|
|
673
|
+
* Rejected subtrees are skipped in the exporter without loading their descendants.
|
|
674
|
+
* @param anchorSelect a SELECT producing `(ECInstanceId, 0)` rows for the tree roots
|
|
675
|
+
*/
|
|
676
|
+
async exportElementTreesStreamed(anchorSelect, params) {
|
|
677
|
+
// The anchor seeds roots at depth 0; the recursive term follows parent links.
|
|
678
|
+
// SQLite's documented recursive-CTE queue behavior makes this ORDER BY a
|
|
679
|
+
// depth-first priority queue, with ascending IDs breaking ties. Supported
|
|
680
|
+
// iModel databases use SQLite, so the outer SELECT intentionally consumes
|
|
681
|
+
// the CTE rows in this queue order.
|
|
682
|
+
const sql = `
|
|
683
|
+
WITH RECURSIVE ElementTree (ECInstanceId, Depth) AS (
|
|
684
|
+
${anchorSelect}
|
|
685
|
+
UNION ALL
|
|
686
|
+
SELECT c.ECInstanceId, t.Depth + 1 FROM ${core_backend_1.Element.classFullName} c
|
|
687
|
+
JOIN ElementTree t ON c.Parent.Id = t.ECInstanceId
|
|
688
|
+
ORDER BY 2 DESC, 1 ASC
|
|
689
|
+
)
|
|
690
|
+
SELECT ECInstanceId, Depth FROM ElementTree`;
|
|
691
|
+
let pruneDepth;
|
|
692
|
+
for await (const row of this.sourceDb.createQueryReader(sql, params, {
|
|
693
|
+
usePrimaryConn: true,
|
|
694
|
+
})) {
|
|
695
|
+
const elementId = row[0];
|
|
696
|
+
const depth = row[1];
|
|
697
|
+
const isPruned = pruneDepth !== undefined && depth > pruneDepth;
|
|
698
|
+
if (!isPruned) {
|
|
699
|
+
pruneDepth = undefined;
|
|
700
|
+
const visitChildren = await this.exportElementShallow(elementId);
|
|
701
|
+
if (!visitChildren)
|
|
702
|
+
pruneDepth = depth;
|
|
703
|
+
}
|
|
704
|
+
// Keep the streamed loop responsive, including while consuming a rejected subtree.
|
|
705
|
+
await this._yieldManager.allowYield();
|
|
706
|
+
}
|
|
707
|
+
}
|
|
632
708
|
/** Export the sub-models directly below the specified model.
|
|
633
709
|
* @note This method is called from [[exportChanges]] and [[exportAll]], so it only needs to be called directly when exporting a subset of an iModel.
|
|
634
710
|
*/
|
|
@@ -704,21 +780,29 @@ class IModelExporter {
|
|
|
704
780
|
core_bentley_1.Logger.logTrace(loggerCategory, `visitElements=false, skipping exportElement(${elementId})`);
|
|
705
781
|
return;
|
|
706
782
|
}
|
|
707
|
-
|
|
783
|
+
const visitChildren = await this.exportElementShallow(elementId);
|
|
784
|
+
if (visitChildren) {
|
|
785
|
+
return this.exportChildElements(elementId);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
/** Runs the export callbacks for a single element without visiting its children.
|
|
789
|
+
* @returns `true` if the element's children should be visited afterwards.
|
|
790
|
+
*/
|
|
791
|
+
async exportElementShallow(elementId) {
|
|
792
|
+
// Return early if the elementId is already excluded so it does not need to be loaded.
|
|
708
793
|
if (this._excludedElementIds.has(elementId)) {
|
|
709
794
|
core_bentley_1.Logger.logInfo(loggerCategory, `Excluded element ${elementId} by Id`);
|
|
710
795
|
await this.handler.onSkipElement(elementId);
|
|
711
|
-
return;
|
|
796
|
+
return false;
|
|
712
797
|
}
|
|
713
|
-
// are we processing changes?
|
|
714
798
|
const isUpdate = this._sourceDbChanges?.element.insertIds.has(elementId)
|
|
715
799
|
? false
|
|
716
800
|
: this._sourceDbChanges?.element.updateIds.has(elementId)
|
|
717
801
|
? true
|
|
718
802
|
: undefined;
|
|
719
|
-
//
|
|
720
|
-
if (
|
|
721
|
-
return
|
|
803
|
+
// An unchanged element may still connect a changed descendant to its model root.
|
|
804
|
+
if (this._sourceDbChanges !== undefined && isUpdate === undefined) {
|
|
805
|
+
return true;
|
|
722
806
|
}
|
|
723
807
|
const element = this.sourceDb.elements.getElement({
|
|
724
808
|
id: elementId,
|
|
@@ -732,11 +816,10 @@ class IModelExporter {
|
|
|
732
816
|
await this.handler.onExportElement(element, isUpdate);
|
|
733
817
|
await this.trackProgress();
|
|
734
818
|
await this._elementAspectExportCoordinator.addAcceptedOwner(elementId);
|
|
735
|
-
return
|
|
736
|
-
}
|
|
737
|
-
else {
|
|
738
|
-
await this.handler.onSkipElement(element.id);
|
|
819
|
+
return true;
|
|
739
820
|
}
|
|
821
|
+
await this.handler.onSkipElement(element.id);
|
|
822
|
+
return false;
|
|
740
823
|
}
|
|
741
824
|
/** Export the child elements of the specified element from the source iModel.
|
|
742
825
|
* @note This method is called from [[exportChanges]] and [[exportAll]], so it only needs to be called directly when exporting a subset of an iModel.
|
|
@@ -749,7 +832,20 @@ class IModelExporter {
|
|
|
749
832
|
core_bentley_1.Logger.logTrace(loggerCategory, `visitElements=false, skipping exportChildElements(${elementId})`);
|
|
750
833
|
return;
|
|
751
834
|
}
|
|
752
|
-
|
|
835
|
+
if (this.canUseSetBasedTraversal()) {
|
|
836
|
+
core_bentley_1.Logger.logTrace(loggerCategory, `exportChildElements(${elementId})`);
|
|
837
|
+
// Seed the stream with direct children; the helper adds their descendants.
|
|
838
|
+
return this.exportElementTreesStreamed(`SELECT e.ECInstanceId, 0 FROM ${core_backend_1.Element.classFullName} e WHERE e.Parent.Id=:parentId`, new core_common_1.QueryBinder().bindId("parentId", elementId));
|
|
839
|
+
}
|
|
840
|
+
let childElementIds;
|
|
841
|
+
if (this.canUseChangedElementForest()) {
|
|
842
|
+
const forest = await this.getChangedElementForest();
|
|
843
|
+
if (forest !== undefined) {
|
|
844
|
+
core_bentley_1.Logger.logTrace(loggerCategory, `exportChildElements(${elementId}) via changed-element index`);
|
|
845
|
+
childElementIds = forest.getChildren(elementId);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
childElementIds ??= this.sourceDb.elements.queryChildren(elementId);
|
|
753
849
|
if (childElementIds.length > 0) {
|
|
754
850
|
core_bentley_1.Logger.logTrace(loggerCategory, `exportChildElements(${elementId})`);
|
|
755
851
|
for (const childElementId of childElementIds) {
|
|
@@ -757,6 +853,53 @@ class IModelExporter {
|
|
|
757
853
|
}
|
|
758
854
|
}
|
|
759
855
|
}
|
|
856
|
+
/** Whether change processing may use the sparse hierarchy as the child-id source.
|
|
857
|
+
* Custom traversal overrides retain the previous full element dispatch.
|
|
858
|
+
*/
|
|
859
|
+
canUseChangedElementForest() {
|
|
860
|
+
return (this._sourceDbChanges !== undefined &&
|
|
861
|
+
this._changedElementTraversal?.useForest === true &&
|
|
862
|
+
this.hasDefaultElementTraversal());
|
|
863
|
+
}
|
|
864
|
+
getOverriddenElementTraversalMethods() {
|
|
865
|
+
const methods = [];
|
|
866
|
+
if (this.exportElement !== IModelExporter.prototype.exportElement)
|
|
867
|
+
methods.push("exportElement");
|
|
868
|
+
if (this.exportChildElements !== IModelExporter.prototype.exportChildElements)
|
|
869
|
+
methods.push("exportChildElements");
|
|
870
|
+
return methods;
|
|
871
|
+
}
|
|
872
|
+
disableChangedElementForest(reason) {
|
|
873
|
+
if (!this._changedElementTraversal?.useForest)
|
|
874
|
+
return;
|
|
875
|
+
this._changedElementTraversal.useForest = false;
|
|
876
|
+
core_bentley_1.Logger.logInfo(loggerCategory, `Using full element traversal for change processing because ${reason}.`);
|
|
877
|
+
}
|
|
878
|
+
async createChangedElementForest() {
|
|
879
|
+
(0, node_assert_1.strict)(this._sourceDbChanges !== undefined, "changed-element traversal requires sourceDbChanges");
|
|
880
|
+
const excludedElementIds = this._excludedElementIds;
|
|
881
|
+
const candidateCountUpperBound = this._sourceDbChanges.element.insertIds.size +
|
|
882
|
+
this._sourceDbChanges.element.updateIds.size +
|
|
883
|
+
excludedElementIds.size;
|
|
884
|
+
if (candidateCountUpperBound > this._changedElementForestElementLimit) {
|
|
885
|
+
this.disableChangedElementForest(`${candidateCountUpperBound} candidate element references exceed the ${this._changedElementForestElementLimit}-element in-memory index limit`);
|
|
886
|
+
return undefined;
|
|
887
|
+
}
|
|
888
|
+
const forest = await ChangedElementForest_1.ChangedElementForest.create(this.sourceDb, [
|
|
889
|
+
...this._sourceDbChanges.element.insertIds,
|
|
890
|
+
...this._sourceDbChanges.element.updateIds,
|
|
891
|
+
...excludedElementIds,
|
|
892
|
+
], this._changedElementForestElementLimit);
|
|
893
|
+
if (forest === undefined) {
|
|
894
|
+
this.disableChangedElementForest(`the required parent hierarchy exceeds the ${this._changedElementForestElementLimit}-element in-memory index limit`);
|
|
895
|
+
}
|
|
896
|
+
return forest;
|
|
897
|
+
}
|
|
898
|
+
async getChangedElementForest() {
|
|
899
|
+
const traversal = this._changedElementTraversal;
|
|
900
|
+
(0, node_assert_1.strict)(traversal !== undefined, "changed-element index requires an active traversal scope");
|
|
901
|
+
return (traversal.forest ??= this.createChangedElementForest());
|
|
902
|
+
}
|
|
760
903
|
/** Exports all aspects owned by the supplied elements. */
|
|
761
904
|
async exportAspectsForOwners(ownerElementIds) {
|
|
762
905
|
return this._elementAspectExportCoordinator.exportOwners(ownerElementIds);
|
|
@@ -817,8 +960,30 @@ class IModelExporter {
|
|
|
817
960
|
}
|
|
818
961
|
return this.shouldExportModelForAspect(modelFact.parentModelId, elementFacts, modelFacts);
|
|
819
962
|
}
|
|
963
|
+
beginChangedElementTraversalScope() {
|
|
964
|
+
if (this._sourceDbChanges === undefined ||
|
|
965
|
+
this._changedElementTraversal !== undefined) {
|
|
966
|
+
return false;
|
|
967
|
+
}
|
|
968
|
+
this._changedElementTraversal = { useForest: true };
|
|
969
|
+
const overriddenMethods = this.getOverriddenElementTraversalMethods();
|
|
970
|
+
if (this.visitElements && overriddenMethods.length > 0) {
|
|
971
|
+
this.disableChangedElementForest(`${overriddenMethods.join(" and ")} ${overriddenMethods.length === 1 ? "is" : "are"} overridden by the exporter subclass`);
|
|
972
|
+
}
|
|
973
|
+
return true;
|
|
974
|
+
}
|
|
975
|
+
endChangedElementTraversalScope() {
|
|
976
|
+
this._changedElementTraversal = undefined;
|
|
977
|
+
}
|
|
820
978
|
async runScopedElementExport(exportElements) {
|
|
821
|
-
|
|
979
|
+
const ownsChangedElementTraversal = this.beginChangedElementTraversalScope();
|
|
980
|
+
try {
|
|
981
|
+
await this._elementAspectExportCoordinator.run(exportElements);
|
|
982
|
+
}
|
|
983
|
+
finally {
|
|
984
|
+
if (ownsChangedElementTraversal)
|
|
985
|
+
this.endChangedElementTraversalScope();
|
|
986
|
+
}
|
|
822
987
|
}
|
|
823
988
|
/** Apply the element export filter when deciding whether to process an aspect owner. @internal */
|
|
824
989
|
async shouldExportElementForAspect(elementId, elementFact) {
|