@itwin/imodel-transformer 2.0.0-dev.6 → 2.0.0-dev.60
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/README.md +13 -27
- package/lib/cjs/Algo.js.map +1 -1
- package/lib/cjs/BigMap.d.ts.map +1 -1
- package/lib/cjs/BigMap.js.map +1 -1
- package/lib/cjs/BranchProvenanceInitializer.d.ts.map +1 -1
- package/lib/cjs/BranchProvenanceInitializer.js +34 -34
- package/lib/cjs/BranchProvenanceInitializer.js.map +1 -1
- 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/ChangesetScanner.d.ts +61 -0
- package/lib/cjs/ChangesetScanner.d.ts.map +1 -0
- package/lib/cjs/ChangesetScanner.js +104 -0
- package/lib/cjs/ChangesetScanner.js.map +1 -0
- package/lib/cjs/ECReferenceTypesCache.d.ts +0 -3
- package/lib/cjs/ECReferenceTypesCache.d.ts.map +1 -1
- package/lib/cjs/ECReferenceTypesCache.js +61 -104
- package/lib/cjs/ECReferenceTypesCache.js.map +1 -1
- package/lib/cjs/ECSqlReaderAsyncIterableIteratorAdapter.d.ts.map +1 -1
- package/lib/cjs/ECSqlReaderAsyncIterableIteratorAdapter.js.map +1 -1
- package/lib/cjs/ElementAspectCleanup.d.ts +16 -0
- package/lib/cjs/ElementAspectCleanup.d.ts.map +1 -0
- package/lib/cjs/ElementAspectCleanup.js +87 -0
- package/lib/cjs/ElementAspectCleanup.js.map +1 -0
- package/lib/cjs/ElementAspectExportCoordinator.d.ts +44 -0
- package/lib/cjs/ElementAspectExportCoordinator.d.ts.map +1 -0
- package/lib/cjs/ElementAspectExportCoordinator.js +148 -0
- package/lib/cjs/ElementAspectExportCoordinator.js.map +1 -0
- package/lib/cjs/ElementAspectExportProcessor.d.ts +44 -0
- package/lib/cjs/ElementAspectExportProcessor.d.ts.map +1 -0
- package/lib/cjs/ElementAspectExportProcessor.js +152 -0
- package/lib/cjs/ElementAspectExportProcessor.js.map +1 -0
- package/lib/cjs/ElementBulkDelete.d.ts +11 -0
- package/lib/cjs/ElementBulkDelete.d.ts.map +1 -0
- package/lib/cjs/ElementBulkDelete.js +55 -0
- package/lib/cjs/ElementBulkDelete.js.map +1 -0
- package/lib/cjs/EntityExistenceCache.d.ts +43 -0
- package/lib/cjs/EntityExistenceCache.d.ts.map +1 -0
- package/lib/cjs/EntityExistenceCache.js +91 -0
- package/lib/cjs/EntityExistenceCache.js.map +1 -0
- package/lib/cjs/EntityMap.d.ts.map +1 -1
- package/lib/cjs/EntityMap.js.map +1 -1
- package/lib/cjs/EntityUnifier.d.ts +8 -8
- package/lib/cjs/EntityUnifier.d.ts.map +1 -1
- package/lib/cjs/EntityUnifier.js +56 -32
- package/lib/cjs/EntityUnifier.js.map +1 -1
- package/lib/cjs/IModelCloneContext.d.ts +9 -3
- package/lib/cjs/IModelCloneContext.d.ts.map +1 -1
- package/lib/cjs/IModelCloneContext.js +66 -31
- package/lib/cjs/IModelCloneContext.js.map +1 -1
- package/lib/cjs/IModelExporter.d.ts +143 -30
- package/lib/cjs/IModelExporter.d.ts.map +1 -1
- package/lib/cjs/IModelExporter.js +893 -178
- package/lib/cjs/IModelExporter.js.map +1 -1
- package/lib/cjs/IModelImporter.d.ts +71 -30
- package/lib/cjs/IModelImporter.d.ts.map +1 -1
- package/lib/cjs/IModelImporter.js +269 -132
- package/lib/cjs/IModelImporter.js.map +1 -1
- package/lib/cjs/IModelTransformContext.d.ts +54 -0
- package/lib/cjs/IModelTransformContext.d.ts.map +1 -0
- package/lib/cjs/IModelTransformContext.js +3 -0
- package/lib/cjs/IModelTransformContext.js.map +1 -0
- package/lib/cjs/IModelTransformer.d.ts +130 -196
- package/lib/cjs/IModelTransformer.d.ts.map +1 -1
- package/lib/cjs/IModelTransformer.js +697 -1155
- package/lib/cjs/IModelTransformer.js.map +1 -1
- package/lib/cjs/IModelTransformerError.d.ts +84 -0
- package/lib/cjs/IModelTransformerError.d.ts.map +1 -0
- package/lib/cjs/IModelTransformerError.js +93 -0
- package/lib/cjs/IModelTransformerError.js.map +1 -0
- package/lib/cjs/ProvenanceManager.d.ts +177 -0
- package/lib/cjs/ProvenanceManager.d.ts.map +1 -0
- package/lib/cjs/ProvenanceManager.js +719 -0
- package/lib/cjs/ProvenanceManager.js.map +1 -0
- package/lib/cjs/SyncTypeResolver.d.ts +34 -0
- package/lib/cjs/SyncTypeResolver.d.ts.map +1 -0
- package/lib/cjs/SyncTypeResolver.js +98 -0
- package/lib/cjs/SyncTypeResolver.js.map +1 -0
- package/lib/cjs/TransformerLoggerCategory.d.ts +1 -1
- package/lib/cjs/TransformerLoggerCategory.js +1 -1
- package/lib/cjs/TransformerLoggerCategory.js.map +1 -1
- package/lib/cjs/TransformerPackageMetadata.d.ts +8 -0
- package/lib/cjs/TransformerPackageMetadata.d.ts.map +1 -0
- package/lib/cjs/TransformerPackageMetadata.js +47 -0
- package/lib/cjs/TransformerPackageMetadata.js.map +1 -0
- package/lib/cjs/imodel-transformer.d.ts +27 -0
- package/lib/cjs/imodel-transformer.d.ts.map +1 -1
- package/lib/cjs/imodel-transformer.js +61 -34
- package/lib/cjs/imodel-transformer.js.map +1 -1
- package/lib/cjs/schema-processing/DynamicSchemaUnionStrategy.d.ts +29 -0
- package/lib/cjs/schema-processing/DynamicSchemaUnionStrategy.d.ts.map +1 -0
- package/lib/cjs/schema-processing/DynamicSchemaUnionStrategy.js +212 -0
- package/lib/cjs/schema-processing/DynamicSchemaUnionStrategy.js.map +1 -0
- package/lib/cjs/schema-processing/SchemaProcessingCoordinator.d.ts +25 -0
- package/lib/cjs/schema-processing/SchemaProcessingCoordinator.d.ts.map +1 -0
- package/lib/cjs/schema-processing/SchemaProcessingCoordinator.js +196 -0
- package/lib/cjs/schema-processing/SchemaProcessingCoordinator.js.map +1 -0
- package/lib/cjs/schema-processing/SchemaProcessingStrategy.d.ts +59 -0
- package/lib/cjs/schema-processing/SchemaProcessingStrategy.d.ts.map +1 -0
- package/lib/cjs/schema-processing/SchemaProcessingStrategy.js +28 -0
- package/lib/cjs/schema-processing/SchemaProcessingStrategy.js.map +1 -0
- package/lib/cjs/schema-processing.d.ts +7 -0
- package/lib/cjs/schema-processing.d.ts.map +1 -0
- package/lib/cjs/schema-processing.js +27 -0
- package/lib/cjs/schema-processing.js.map +1 -0
- package/package.json +65 -43
- package/lib/cjs/DetachedExportElementAspectsStrategy.d.ts +0 -16
- package/lib/cjs/DetachedExportElementAspectsStrategy.d.ts.map +0 -1
- package/lib/cjs/DetachedExportElementAspectsStrategy.js +0 -106
- package/lib/cjs/DetachedExportElementAspectsStrategy.js.map +0 -1
- package/lib/cjs/ElementCascadingDeleter.d.ts +0 -22
- package/lib/cjs/ElementCascadingDeleter.d.ts.map +0 -1
- package/lib/cjs/ElementCascadingDeleter.js +0 -57
- package/lib/cjs/ElementCascadingDeleter.js.map +0 -1
- package/lib/cjs/ExportElementAspectsStrategy.d.ts +0 -35
- package/lib/cjs/ExportElementAspectsStrategy.d.ts.map +0 -1
- package/lib/cjs/ExportElementAspectsStrategy.js +0 -52
- package/lib/cjs/ExportElementAspectsStrategy.js.map +0 -1
- package/lib/cjs/ExportElementAspectsWithElementsStrategy.d.ts +0 -12
- package/lib/cjs/ExportElementAspectsWithElementsStrategy.d.ts.map +0 -1
- package/lib/cjs/ExportElementAspectsWithElementsStrategy.js +0 -47
- package/lib/cjs/ExportElementAspectsWithElementsStrategy.js.map +0 -1
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** @packageDocumentation
|
|
2
|
+
* @module Utils
|
|
3
|
+
*/
|
|
4
|
+
import { EntityReference } from "@itwin/core-common";
|
|
5
|
+
import { IModelDb } from "@itwin/core-backend";
|
|
6
|
+
/** A positive-only read-through cache of entity existence checks, scoped to a single transformation run.
|
|
7
|
+
*
|
|
8
|
+
* Entities are created continuously as a transformation progresses, so a negative
|
|
9
|
+
* ("does not exist") result may become stale at any moment — therefore only positive
|
|
10
|
+
* results are ever cached. Positive results can only be invalidated by deletes, which the
|
|
11
|
+
* transformer routes through [[invalidate]] and [[clearDb]].
|
|
12
|
+
*
|
|
13
|
+
* The cache is keyed by [IModelDb]($core-backend) instance, so same-iModel transformations
|
|
14
|
+
* (where sourceDb === targetDb) share a single set and source/target roles cannot be confused.
|
|
15
|
+
*
|
|
16
|
+
* [IModelImporter]($transformer) delete operations invalidate registered caches. Deletes performed
|
|
17
|
+
* directly through an `EditTxn` while a transformation is active are out-of-band and must not be
|
|
18
|
+
* mixed with transformer operations. A successful high-level `process()` clears the cache when the
|
|
19
|
+
* transformation finalizes; low-level or failed transformations clear it when the transformer is
|
|
20
|
+
* disposed.
|
|
21
|
+
* @internal
|
|
22
|
+
*/
|
|
23
|
+
export declare class EntityExistenceCache {
|
|
24
|
+
private _existsByDb;
|
|
25
|
+
private getDbSet;
|
|
26
|
+
/** Check whether an entity exists in `db`, consulting the cache first.
|
|
27
|
+
* A `true` result is cached; a `false` result is never cached and will be re-queried.
|
|
28
|
+
*/
|
|
29
|
+
exists(db: IModelDb, entityReference: EntityReference): Promise<boolean>;
|
|
30
|
+
/** Read through the cache to check which of the supplied entities exist in `db`, populating it on a miss. */
|
|
31
|
+
existsAll(db: IModelDb, entityReferences: Iterable<EntityReference>): Promise<ReadonlySet<EntityReference>>;
|
|
32
|
+
/** Record that an entity is known to exist in `db` (e.g. it was just imported). */
|
|
33
|
+
markExists(db: IModelDb, entityReference: EntityReference): void;
|
|
34
|
+
/** Remove a single entity from the cache for `db`, forcing a re-query on next check. */
|
|
35
|
+
invalidate(db: IModelDb, entityReference: EntityReference): void;
|
|
36
|
+
/** Drop all cached results for `db`. Used when a delete may cascade to entities the
|
|
37
|
+
* caller cannot enumerate (e.g. element tree deletes that remove descendants and submodels).
|
|
38
|
+
*/
|
|
39
|
+
clearDb(db: IModelDb): void;
|
|
40
|
+
/** Drop all cached results. */
|
|
41
|
+
clear(): void;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=EntityExistenceCache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EntityExistenceCache.d.ts","sourceRoot":"","sources":["../../src/EntityExistenceCache.ts"],"names":[],"mappings":"AAIA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAG/C;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,WAAW,CAA6C;IAEhE,OAAO,CAAC,QAAQ;IAShB;;OAEG;IACU,MAAM,CACjB,EAAE,EAAE,QAAQ,EACZ,eAAe,EAAE,eAAe,GAC/B,OAAO,CAAC,OAAO,CAAC,CAMlB;IAED,6GAA6G;IAChG,SAAS,CACpB,EAAE,EAAE,QAAQ,EACZ,gBAAgB,EAAE,QAAQ,CAAC,eAAe,CAAC,GAC1C,OAAO,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,CAkBvC;IAED,mFAAmF;IAC5E,UAAU,CAAC,EAAE,EAAE,QAAQ,EAAE,eAAe,EAAE,eAAe,GAAG,IAAI,CAEtE;IAED,wFAAwF;IACjF,UAAU,CAAC,EAAE,EAAE,QAAQ,EAAE,eAAe,EAAE,eAAe,GAAG,IAAI,CAEtE;IAED;;OAEG;IACI,OAAO,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAEjC;IAED,+BAA+B;IACxB,KAAK,IAAI,IAAI,CAEnB;CACF"}
|
|
@@ -0,0 +1,91 @@
|
|
|
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
|
+
/** @packageDocumentation
|
|
7
|
+
* @module Utils
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.EntityExistenceCache = void 0;
|
|
11
|
+
const EntityUnifier_1 = require("./EntityUnifier");
|
|
12
|
+
/** A positive-only read-through cache of entity existence checks, scoped to a single transformation run.
|
|
13
|
+
*
|
|
14
|
+
* Entities are created continuously as a transformation progresses, so a negative
|
|
15
|
+
* ("does not exist") result may become stale at any moment — therefore only positive
|
|
16
|
+
* results are ever cached. Positive results can only be invalidated by deletes, which the
|
|
17
|
+
* transformer routes through [[invalidate]] and [[clearDb]].
|
|
18
|
+
*
|
|
19
|
+
* The cache is keyed by [IModelDb]($core-backend) instance, so same-iModel transformations
|
|
20
|
+
* (where sourceDb === targetDb) share a single set and source/target roles cannot be confused.
|
|
21
|
+
*
|
|
22
|
+
* [IModelImporter]($transformer) delete operations invalidate registered caches. Deletes performed
|
|
23
|
+
* directly through an `EditTxn` while a transformation is active are out-of-band and must not be
|
|
24
|
+
* mixed with transformer operations. A successful high-level `process()` clears the cache when the
|
|
25
|
+
* transformation finalizes; low-level or failed transformations clear it when the transformer is
|
|
26
|
+
* disposed.
|
|
27
|
+
* @internal
|
|
28
|
+
*/
|
|
29
|
+
class EntityExistenceCache {
|
|
30
|
+
_existsByDb = new Map();
|
|
31
|
+
getDbSet(db) {
|
|
32
|
+
let set = this._existsByDb.get(db);
|
|
33
|
+
if (set === undefined) {
|
|
34
|
+
set = new Set();
|
|
35
|
+
this._existsByDb.set(db, set);
|
|
36
|
+
}
|
|
37
|
+
return set;
|
|
38
|
+
}
|
|
39
|
+
/** Check whether an entity exists in `db`, consulting the cache first.
|
|
40
|
+
* A `true` result is cached; a `false` result is never cached and will be re-queried.
|
|
41
|
+
*/
|
|
42
|
+
async exists(db, entityReference) {
|
|
43
|
+
const set = this.getDbSet(db);
|
|
44
|
+
if (set.has(entityReference))
|
|
45
|
+
return true;
|
|
46
|
+
const found = await EntityUnifier_1.EntityUnifier.exists(db, { entityReference });
|
|
47
|
+
if (found)
|
|
48
|
+
set.add(entityReference);
|
|
49
|
+
return found;
|
|
50
|
+
}
|
|
51
|
+
/** Read through the cache to check which of the supplied entities exist in `db`, populating it on a miss. */
|
|
52
|
+
async existsAll(db, entityReferences) {
|
|
53
|
+
const dbSet = this.getDbSet(db);
|
|
54
|
+
const found = new Set();
|
|
55
|
+
const unverified = [];
|
|
56
|
+
for (const entityReference of entityReferences) {
|
|
57
|
+
if (dbSet.has(entityReference))
|
|
58
|
+
found.add(entityReference);
|
|
59
|
+
else
|
|
60
|
+
unverified.push(entityReference);
|
|
61
|
+
}
|
|
62
|
+
if (unverified.length === 0)
|
|
63
|
+
return found;
|
|
64
|
+
const queried = await EntityUnifier_1.EntityUnifier.existsAll(db, unverified);
|
|
65
|
+
for (const entityReference of queried) {
|
|
66
|
+
dbSet.add(entityReference);
|
|
67
|
+
found.add(entityReference);
|
|
68
|
+
}
|
|
69
|
+
return found;
|
|
70
|
+
}
|
|
71
|
+
/** Record that an entity is known to exist in `db` (e.g. it was just imported). */
|
|
72
|
+
markExists(db, entityReference) {
|
|
73
|
+
this.getDbSet(db).add(entityReference);
|
|
74
|
+
}
|
|
75
|
+
/** Remove a single entity from the cache for `db`, forcing a re-query on next check. */
|
|
76
|
+
invalidate(db, entityReference) {
|
|
77
|
+
this._existsByDb.get(db)?.delete(entityReference);
|
|
78
|
+
}
|
|
79
|
+
/** Drop all cached results for `db`. Used when a delete may cascade to entities the
|
|
80
|
+
* caller cannot enumerate (e.g. element tree deletes that remove descendants and submodels).
|
|
81
|
+
*/
|
|
82
|
+
clearDb(db) {
|
|
83
|
+
this._existsByDb.delete(db);
|
|
84
|
+
}
|
|
85
|
+
/** Drop all cached results. */
|
|
86
|
+
clear() {
|
|
87
|
+
this._existsByDb.clear();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
exports.EntityExistenceCache = EntityExistenceCache;
|
|
91
|
+
//# sourceMappingURL=EntityExistenceCache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EntityExistenceCache.js","sourceRoot":"","sources":["../../src/EntityExistenceCache.ts"],"names":[],"mappings":";AAAA;;;gGAGgG;AAChG;;GAEG;;;AAIH,mDAAgD;AAEhD;;;;;;;;;;;;;;;;GAgBG;AACH;IACU,WAAW,GAAG,IAAI,GAAG,EAAkC,CAAC;IAExD,QAAQ,CAAC,EAAY;QAC3B,IAAI,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACnC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC;YAChB,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QAChC,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,MAAM,CACjB,EAAY,EACZ,eAAgC;QAEhC,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC9B,IAAI,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC;YAAE,OAAO,IAAI,CAAC;QAC1C,MAAM,KAAK,GAAG,MAAM,6BAAa,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,eAAe,EAAE,CAAC,CAAC;QAClE,IAAI,KAAK;YAAE,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;QACpC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,6GAA6G;IACtG,KAAK,CAAC,SAAS,CACpB,EAAY,EACZ,gBAA2C;QAE3C,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAChC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAmB,CAAC;QACzC,MAAM,UAAU,GAAsB,EAAE,CAAC;QAEzC,KAAK,MAAM,eAAe,IAAI,gBAAgB,EAAE,CAAC;YAC/C,IAAI,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC;gBAAE,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;;gBACtD,UAAU,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACxC,CAAC;QAED,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QAE1C,MAAM,OAAO,GAAG,MAAM,6BAAa,CAAC,SAAS,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;QAC9D,KAAK,MAAM,eAAe,IAAI,OAAO,EAAE,CAAC;YACtC,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;YAC3B,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;QAC7B,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,mFAAmF;IAC5E,UAAU,CAAC,EAAY,EAAE,eAAgC;QAC9D,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IACzC,CAAC;IAED,wFAAwF;IACjF,UAAU,CAAC,EAAY,EAAE,eAAgC;QAC9D,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,eAAe,CAAC,CAAC;IACpD,CAAC;IAED;;OAEG;IACI,OAAO,CAAC,EAAY;QACzB,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC;IAED,+BAA+B;IACxB,KAAK;QACV,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;CACF","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/** @packageDocumentation\n * @module Utils\n */\n\nimport { EntityReference } from \"@itwin/core-common\";\nimport { IModelDb } from \"@itwin/core-backend\";\nimport { EntityUnifier } from \"./EntityUnifier\";\n\n/** A positive-only read-through cache of entity existence checks, scoped to a single transformation run.\n *\n * Entities are created continuously as a transformation progresses, so a negative\n * (\"does not exist\") result may become stale at any moment — therefore only positive\n * results are ever cached. Positive results can only be invalidated by deletes, which the\n * transformer routes through [[invalidate]] and [[clearDb]].\n *\n * The cache is keyed by [IModelDb]($core-backend) instance, so same-iModel transformations\n * (where sourceDb === targetDb) share a single set and source/target roles cannot be confused.\n *\n * [IModelImporter]($transformer) delete operations invalidate registered caches. Deletes performed\n * directly through an `EditTxn` while a transformation is active are out-of-band and must not be\n * mixed with transformer operations. A successful high-level `process()` clears the cache when the\n * transformation finalizes; low-level or failed transformations clear it when the transformer is\n * disposed.\n * @internal\n */\nexport class EntityExistenceCache {\n private _existsByDb = new Map<IModelDb, Set<EntityReference>>();\n\n private getDbSet(db: IModelDb): Set<EntityReference> {\n let set = this._existsByDb.get(db);\n if (set === undefined) {\n set = new Set();\n this._existsByDb.set(db, set);\n }\n return set;\n }\n\n /** Check whether an entity exists in `db`, consulting the cache first.\n * A `true` result is cached; a `false` result is never cached and will be re-queried.\n */\n public async exists(\n db: IModelDb,\n entityReference: EntityReference\n ): Promise<boolean> {\n const set = this.getDbSet(db);\n if (set.has(entityReference)) return true;\n const found = await EntityUnifier.exists(db, { entityReference });\n if (found) set.add(entityReference);\n return found;\n }\n\n /** Read through the cache to check which of the supplied entities exist in `db`, populating it on a miss. */\n public async existsAll(\n db: IModelDb,\n entityReferences: Iterable<EntityReference>\n ): Promise<ReadonlySet<EntityReference>> {\n const dbSet = this.getDbSet(db);\n const found = new Set<EntityReference>();\n const unverified: EntityReference[] = [];\n\n for (const entityReference of entityReferences) {\n if (dbSet.has(entityReference)) found.add(entityReference);\n else unverified.push(entityReference);\n }\n\n if (unverified.length === 0) return found;\n\n const queried = await EntityUnifier.existsAll(db, unverified);\n for (const entityReference of queried) {\n dbSet.add(entityReference);\n found.add(entityReference);\n }\n return found;\n }\n\n /** Record that an entity is known to exist in `db` (e.g. it was just imported). */\n public markExists(db: IModelDb, entityReference: EntityReference): void {\n this.getDbSet(db).add(entityReference);\n }\n\n /** Remove a single entity from the cache for `db`, forcing a re-query on next check. */\n public invalidate(db: IModelDb, entityReference: EntityReference): void {\n this._existsByDb.get(db)?.delete(entityReference);\n }\n\n /** Drop all cached results for `db`. Used when a delete may cascade to entities the\n * caller cannot enumerate (e.g. element tree deletes that remove descendants and submodels).\n */\n public clearDb(db: IModelDb): void {\n this._existsByDb.delete(db);\n }\n\n /** Drop all cached results. */\n public clear(): void {\n this._existsByDb.clear();\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityMap.d.ts","sourceRoot":"","sources":["../../src/EntityMap.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAoB,MAAM,qBAAqB,CAAC;AAGvE,gBAAgB;AAChB,MAAM,MAAM,SAAS,GAAG,eAAe,CAAC;AAExC,gBAAgB;AAChB,qBAAa,SAAS,CAAC,CAAC;IACtB,OAAO,CAAC,IAAI,CAAmB;
|
|
1
|
+
{"version":3,"file":"EntityMap.d.ts","sourceRoot":"","sources":["../../src/EntityMap.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAoB,MAAM,qBAAqB,CAAC;AAGvE,gBAAgB;AAChB,MAAM,MAAM,SAAS,GAAG,eAAe,CAAC;AAExC,gBAAgB;AAChB,qBAAa,SAAS,CAAC,CAAC;IACtB,OAAO,CAAC,IAAI,CAAmB;IAE/B,OAAc,OAAO,CAAC,MAAM,EAAE,cAAc,GAAG,SAAS,CAEvD;IAEM,KAAK,IAAI,IAAI,CAEnB;IAEM,GAAG,CAAC,MAAM,EAAE,cAAc,WAEhC;IAEM,GAAG,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAEvD;IAEM,QAAQ,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAGlD;IAEM,GAAG,CAAC,MAAM,EAAE,cAAc,GAAG,CAAC,GAAG,SAAS,CAEhD;IAEM,QAAQ,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,GAAG,SAAS,CAE3C;IAEM,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAE7C;IAEM,WAAW,CAAC,CAAC,EAAE,SAAS,GAAG,OAAO,CAExC;IAEM,IAAI,wBAEV;IAEM,MAAM,mBAEZ;IAEM,OAAO,6BAEb;IAEM,CAAC,MAAM,CAAC,QAAQ,CAAC,6BAEvB;IAED,IAAW,IAAI,WAEd;CACF"}
|
package/lib/cjs/EntityMap.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityMap.js","sourceRoot":"","sources":["../../src/EntityMap.ts"],"names":[],"mappings":";;;AAQA,sDAAuE;AACvE,qCAAkC;AAKlC,gBAAgB;AAChB
|
|
1
|
+
{"version":3,"file":"EntityMap.js","sourceRoot":"","sources":["../../src/EntityMap.ts"],"names":[],"mappings":";;;AAQA,sDAAuE;AACvE,qCAAkC;AAKlC,gBAAgB;AAChB;IACU,IAAI,GAAG,IAAI,eAAM,EAAK,CAAC;IAExB,MAAM,CAAC,OAAO,CAAC,MAAsB;QAC1C,OAAO,+BAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC;IAEM,KAAK;QACV,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;IAEM,GAAG,CAAC,MAAsB;QAC/B,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAClD,CAAC;IAEM,GAAG,CAAC,MAAsB,EAAE,GAAM;QACvC,OAAO,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC;IACvD,CAAC;IAEM,QAAQ,CAAC,CAAY,EAAE,GAAM;QAClC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IAEM,GAAG,CAAC,MAAsB;QAC/B,OAAO,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAClD,CAAC;IAEM,QAAQ,CAAC,CAAY;QAC1B,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC1B,CAAC;IAEM,MAAM,CAAC,MAAsB;QAClC,OAAO,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IACrD,CAAC;IAEM,WAAW,CAAC,CAAY;QAC7B,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC7B,CAAC;IAEM,IAAI;QACT,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IAC1B,CAAC;IAEM,MAAM;QACX,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;IAC5B,CAAC;IAEM,OAAO;QACZ,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;IAC7B,CAAC;IAEM,CAAC,MAAM,CAAC,QAAQ,CAAC;QACtB,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;IACtC,CAAC;IAED,IAAW,IAAI;QACb,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IACxB,CAAC;CACF","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/** @packageDocumentation\n * @module Utils\n */\nimport { EntityReference } from \"@itwin/core-common\";\nimport { ConcreteEntity, EntityReferences } from \"@itwin/core-backend\";\nimport { BigMap } from \"./BigMap\";\n\n/** @internal */\nexport type EntityKey = EntityReference;\n\n/** @internal */\nexport class EntityMap<V> {\n private _map = new BigMap<V>();\n\n public static makeKey(entity: ConcreteEntity): EntityKey {\n return EntityReferences.from(entity);\n }\n\n public clear(): void {\n return this._map.clear();\n }\n\n public has(entity: ConcreteEntity) {\n return this._map.has(EntityMap.makeKey(entity));\n }\n\n public set(entity: ConcreteEntity, val: V): EntityMap<V> {\n return this.setByKey(EntityMap.makeKey(entity), val);\n }\n\n public setByKey(k: EntityKey, val: V): EntityMap<V> {\n this._map.set(k, val);\n return this;\n }\n\n public get(entity: ConcreteEntity): V | undefined {\n return this.getByKey(EntityMap.makeKey(entity));\n }\n\n public getByKey(k: EntityKey): V | undefined {\n return this._map.get(k);\n }\n\n public delete(entity: ConcreteEntity): boolean {\n return this.deleteByKey(EntityMap.makeKey(entity));\n }\n\n public deleteByKey(k: EntityKey): boolean {\n return this._map.delete(k);\n }\n\n public keys() {\n return this._map.keys();\n }\n\n public values() {\n return this._map.values();\n }\n\n public entries() {\n return this._map.entries();\n }\n\n public [Symbol.iterator]() {\n return this._map[Symbol.iterator]();\n }\n\n public get size() {\n return this._map.size;\n }\n}\n"]}
|
|
@@ -4,18 +4,18 @@
|
|
|
4
4
|
* for entity-generic operations in the transformer
|
|
5
5
|
*/
|
|
6
6
|
import { EntityReference } from "@itwin/core-common";
|
|
7
|
-
import { ConcreteEntity,
|
|
7
|
+
import { ConcreteEntity, IModelDb } from "@itwin/core-backend";
|
|
8
8
|
/** @internal */
|
|
9
9
|
export declare namespace EntityUnifier {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
/** needs to return a widened type otherwise typescript complains when result is used with a narrow type */
|
|
13
|
-
export function updaterFor(db: IModelDb, entity: ConcreteEntity): EntityUpdater;
|
|
14
|
-
export function exists(db: IModelDb, arg: {
|
|
10
|
+
function getReadableType(entity: ConcreteEntity): "element" | "element aspect" | "relationship" | "unknown entity type";
|
|
11
|
+
function exists(db: IModelDb, arg: {
|
|
15
12
|
entity: ConcreteEntity;
|
|
16
13
|
} | {
|
|
17
14
|
entityReference: EntityReference;
|
|
18
|
-
}): boolean
|
|
19
|
-
|
|
15
|
+
}): Promise<boolean>;
|
|
16
|
+
/** Batched existence check: returns the subset of `entityReferences` that exist in `db`,
|
|
17
|
+
* using one query per concrete entity type instead of one query per reference.
|
|
18
|
+
*/
|
|
19
|
+
function existsAll(db: IModelDb, entityReferences: Iterable<EntityReference>): Promise<Set<EntityReference>>;
|
|
20
20
|
}
|
|
21
21
|
//# sourceMappingURL=EntityUnifier.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityUnifier.d.ts","sourceRoot":"","sources":["../../src/EntityUnifier.ts"],"names":[],"mappings":"AAIA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"EntityUnifier.d.ts","sourceRoot":"","sources":["../../src/EntityUnifier.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AAEH,OAAO,EAEL,eAAe,EAEhB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,cAAc,EAMd,QAAQ,EAGT,MAAM,qBAAqB,CAAC;AAU7B,gBAAgB;AAChB,yBAAiB,aAAa,CAAC;IAC7B,SAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,yEAKrD;IAED,SAAsB,MAAM,CAC1B,EAAE,EAAE,QAAQ,EACZ,GAAG,EAAE;QAAE,MAAM,EAAE,cAAc,CAAA;KAAE,GAAG;QAAE,eAAe,EAAE,eAAe,CAAA;KAAE,oBAqBvE;IAED;;OAEG;IACH,SAAsB,SAAS,CAC7B,EAAE,EAAE,QAAQ,EACZ,gBAAgB,EAAE,QAAQ,CAAC,eAAe,CAAC,GAC1C,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CA8B/B;CACF"}
|
package/lib/cjs/EntityUnifier.js
CHANGED
|
@@ -10,10 +10,15 @@
|
|
|
10
10
|
*/
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.EntityUnifier = void 0;
|
|
13
|
-
const assert = require("assert");
|
|
14
13
|
const core_common_1 = require("@itwin/core-common");
|
|
15
14
|
const core_backend_1 = require("@itwin/core-backend");
|
|
16
15
|
const core_bentley_1 = require("@itwin/core-bentley");
|
|
16
|
+
const bisCoreRootClasses = {
|
|
17
|
+
[core_common_1.ConcreteEntityTypes.Model]: core_backend_1.Model,
|
|
18
|
+
[core_common_1.ConcreteEntityTypes.Element]: core_backend_1.Element,
|
|
19
|
+
[core_common_1.ConcreteEntityTypes.ElementAspect]: core_backend_1.ElementAspect,
|
|
20
|
+
[core_common_1.ConcreteEntityTypes.Relationship]: core_backend_1.Relationship,
|
|
21
|
+
};
|
|
17
22
|
/** @internal */
|
|
18
23
|
var EntityUnifier;
|
|
19
24
|
(function (EntityUnifier) {
|
|
@@ -28,40 +33,59 @@ var EntityUnifier;
|
|
|
28
33
|
return "unknown entity type";
|
|
29
34
|
}
|
|
30
35
|
EntityUnifier.getReadableType = getReadableType;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
else
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const [type, id] = "entityReference" in arg
|
|
45
|
-
? core_backend_1.EntityReferences.split(arg.entityReference)
|
|
46
|
-
: [undefined, arg.entity.id];
|
|
47
|
-
const classFullName = "entityReference" in arg
|
|
48
|
-
? // eslint-disable-next-line @itwin/no-internal, @typescript-eslint/no-non-null-assertion
|
|
49
|
-
core_common_1.ConcreteEntityTypes.toBisCoreRootClassFullName(type)
|
|
50
|
-
: `[${arg.entity.schemaName}].[${arg.entity.className}]`;
|
|
51
|
-
if (id === undefined || core_bentley_1.Id64.isInvalid(id))
|
|
36
|
+
async function exists(db, arg) {
|
|
37
|
+
let classFullName;
|
|
38
|
+
let id;
|
|
39
|
+
if ("entityReference" in arg) {
|
|
40
|
+
const [type, entityId] = core_backend_1.EntityReferences.split(arg.entityReference);
|
|
41
|
+
classFullName = bisCoreRootClasses[type].classFullName;
|
|
42
|
+
id = entityId;
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
classFullName = `[${arg.entity.schemaName}].[${arg.entity.className}]`;
|
|
46
|
+
id = arg.entity.id;
|
|
47
|
+
}
|
|
48
|
+
if (core_bentley_1.Id64.isInvalid(id))
|
|
52
49
|
return false;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (matchesResult === core_bentley_1.DbResult.BE_SQLITE_ROW)
|
|
58
|
-
return true;
|
|
59
|
-
if (matchesResult === core_bentley_1.DbResult.BE_SQLITE_DONE)
|
|
60
|
-
return false;
|
|
61
|
-
else
|
|
62
|
-
throw new core_common_1.IModelError(matchesResult, "query failed");
|
|
50
|
+
const query = `SELECT 1 FROM ${classFullName} WHERE ECInstanceId=:id`;
|
|
51
|
+
const params = new core_common_1.QueryBinder().bindId("id", id);
|
|
52
|
+
const reader = db.createQueryReader(query, params, {
|
|
53
|
+
usePrimaryConn: true,
|
|
63
54
|
});
|
|
55
|
+
return reader.step();
|
|
64
56
|
}
|
|
65
57
|
EntityUnifier.exists = exists;
|
|
58
|
+
/** Batched existence check: returns the subset of `entityReferences` that exist in `db`,
|
|
59
|
+
* using one query per concrete entity type instead of one query per reference.
|
|
60
|
+
*/
|
|
61
|
+
async function existsAll(db, entityReferences) {
|
|
62
|
+
const idsByType = new Map();
|
|
63
|
+
for (const entityReference of entityReferences) {
|
|
64
|
+
const [type, id] = core_backend_1.EntityReferences.split(entityReference);
|
|
65
|
+
if (core_bentley_1.Id64.isInvalid(id))
|
|
66
|
+
continue;
|
|
67
|
+
let ids = idsByType.get(type);
|
|
68
|
+
if (ids === undefined) {
|
|
69
|
+
ids = new Set();
|
|
70
|
+
idsByType.set(type, ids);
|
|
71
|
+
}
|
|
72
|
+
ids.add(id);
|
|
73
|
+
}
|
|
74
|
+
const found = new Set();
|
|
75
|
+
for (const [type, ids] of idsByType) {
|
|
76
|
+
const classFullName = bisCoreRootClasses[type].classFullName;
|
|
77
|
+
// Join IdSet so SQLite looks up each id by primary key; InVirtualSet scans the whole table.
|
|
78
|
+
const query = `SELECT e.ECInstanceId FROM ${classFullName} e INNER JOIN IdSet(:ids) s ON s.id = e.ECInstanceId`;
|
|
79
|
+
const params = new core_common_1.QueryBinder().bindIdSet("ids", core_bentley_1.OrderedId64Iterable.sortArray([...ids]));
|
|
80
|
+
const reader = db.createQueryReader(query, params, {
|
|
81
|
+
usePrimaryConn: true,
|
|
82
|
+
});
|
|
83
|
+
while (await reader.step()) {
|
|
84
|
+
found.add(core_backend_1.EntityReferences.fromEntityType(reader.current[0], type));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return found;
|
|
88
|
+
}
|
|
89
|
+
EntityUnifier.existsAll = existsAll;
|
|
66
90
|
})(EntityUnifier || (exports.EntityUnifier = EntityUnifier = {}));
|
|
67
91
|
//# sourceMappingURL=EntityUnifier.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityUnifier.js","sourceRoot":"","sources":["../../src/EntityUnifier.ts"],"names":[],"mappings":";AAAA;;;gGAGgG;AAChG;;;;GAIG;;;AAEH,
|
|
1
|
+
{"version":3,"file":"EntityUnifier.js","sourceRoot":"","sources":["../../src/EntityUnifier.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/** @packageDocumentation\n * @module Utils\n * utilities that unify operations, especially CRUD operations, on entities\n * for entity-generic operations in the transformer\n */\n\nimport {\n ConcreteEntityTypes,\n EntityReference,\n QueryBinder,\n} from \"@itwin/core-common\";\nimport {\n ConcreteEntity,\n // eslint-disable-next-line @typescript-eslint/no-redeclare\n Element,\n ElementAspect,\n Entity,\n EntityReferences,\n IModelDb,\n Model,\n Relationship,\n} from \"@itwin/core-backend\";\nimport { Id64, Id64String, OrderedId64Iterable } from \"@itwin/core-bentley\";\n\nconst bisCoreRootClasses: Record<ConcreteEntityTypes, typeof Entity> = {\n [ConcreteEntityTypes.Model]: Model,\n [ConcreteEntityTypes.Element]: Element,\n [ConcreteEntityTypes.ElementAspect]: ElementAspect,\n [ConcreteEntityTypes.Relationship]: Relationship,\n};\n\n/** @internal */\nexport namespace EntityUnifier {\n export function getReadableType(entity: ConcreteEntity) {\n if (entity instanceof Element) return \"element\";\n else if (entity instanceof ElementAspect) return \"element aspect\";\n else if (entity instanceof Relationship) return \"relationship\";\n else return \"unknown entity type\";\n }\n\n export async function exists(\n db: IModelDb,\n arg: { entity: ConcreteEntity } | { entityReference: EntityReference }\n ) {\n let classFullName: string;\n let id: Id64String;\n if (\"entityReference\" in arg) {\n const [type, entityId] = EntityReferences.split(arg.entityReference);\n classFullName = bisCoreRootClasses[type].classFullName;\n id = entityId;\n } else {\n classFullName = `[${arg.entity.schemaName}].[${arg.entity.className}]`;\n id = arg.entity.id;\n }\n\n if (Id64.isInvalid(id)) return false;\n\n const query = `SELECT 1 FROM ${classFullName} WHERE ECInstanceId=:id`;\n const params = new QueryBinder().bindId(\"id\", id);\n const reader = db.createQueryReader(query, params, {\n usePrimaryConn: true,\n });\n return reader.step();\n }\n\n /** Batched existence check: returns the subset of `entityReferences` that exist in `db`,\n * using one query per concrete entity type instead of one query per reference.\n */\n export async function existsAll(\n db: IModelDb,\n entityReferences: Iterable<EntityReference>\n ): Promise<Set<EntityReference>> {\n const idsByType = new Map<ConcreteEntityTypes, Set<Id64String>>();\n for (const entityReference of entityReferences) {\n const [type, id] = EntityReferences.split(entityReference);\n if (Id64.isInvalid(id)) continue;\n let ids = idsByType.get(type);\n if (ids === undefined) {\n ids = new Set();\n idsByType.set(type, ids);\n }\n ids.add(id);\n }\n\n const found = new Set<EntityReference>();\n for (const [type, ids] of idsByType) {\n const classFullName = bisCoreRootClasses[type].classFullName;\n // Join IdSet so SQLite looks up each id by primary key; InVirtualSet scans the whole table.\n const query = `SELECT e.ECInstanceId FROM ${classFullName} e INNER JOIN IdSet(:ids) s ON s.id = e.ECInstanceId`;\n const params = new QueryBinder().bindIdSet(\n \"ids\",\n OrderedId64Iterable.sortArray([...ids])\n );\n const reader = db.createQueryReader(query, params, {\n usePrimaryConn: true,\n });\n while (await reader.step()) {\n found.add(EntityReferences.fromEntityType(reader.current[0], type));\n }\n }\n return found;\n }\n}\n"]}
|
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
import { Id64String } from "@itwin/core-bentley";
|
|
2
2
|
import { ElementAspectProps, ElementProps, EntityReference } from "@itwin/core-common";
|
|
3
3
|
import { Element, ElementAspect, IModelElementCloneContext, IModelJsNative } from "@itwin/core-backend";
|
|
4
|
+
import { EntityExistenceCache } from "./EntityExistenceCache";
|
|
5
|
+
import type { IModelTransformContext } from "./IModelTransformContext";
|
|
4
6
|
/** The context for transforming a *source* Element to a *target* Element and remapping internal identifiers to the target iModel.
|
|
5
|
-
* @
|
|
7
|
+
* @internal
|
|
6
8
|
*/
|
|
7
|
-
export declare class IModelCloneContext extends IModelElementCloneContext {
|
|
9
|
+
export declare class IModelCloneContext extends IModelElementCloneContext implements IModelTransformContext {
|
|
8
10
|
private _refTypesCache;
|
|
9
11
|
private _aspectRemapTable;
|
|
12
|
+
/** A positive-only cache of entity existence checks, scoped to the current transformation run.
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
readonly existenceCache: EntityExistenceCache;
|
|
10
16
|
/** perform necessary initialization to use a clone context, namely caching the reference types in the source's schemas */
|
|
11
17
|
initialize(): Promise<void>;
|
|
12
18
|
/** Clone the specified source Element into ElementProps for the target iModel.
|
|
13
19
|
* @internal
|
|
14
20
|
*/
|
|
15
|
-
cloneElement(sourceElement: Element, cloneOptions?: IModelJsNative.CloneElementOptions): ElementProps
|
|
21
|
+
cloneElement(sourceElement: Element, cloneOptions?: IModelJsNative.CloneElementOptions): Promise<ElementProps>;
|
|
16
22
|
/** Add a rule that remaps the specified source ElementAspect to the specified target ElementAspect. */
|
|
17
23
|
remapElementAspect(aspectSourceId: Id64String, aspectTargetId: Id64String): void;
|
|
18
24
|
/** Remove a rule that remaps the specified source ElementAspect */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IModelCloneContext.d.ts","sourceRoot":"","sources":["../../src/IModelCloneContext.ts"],"names":[],"mappings":"AAQA,OAAO,
|
|
1
|
+
{"version":3,"file":"IModelCloneContext.d.ts","sourceRoot":"","sources":["../../src/IModelCloneContext.ts"],"names":[],"mappings":"AAQA,OAAO,EAAQ,UAAU,EAAU,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAKL,kBAAkB,EAClB,YAAY,EACZ,eAAe,EAKhB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAEL,OAAO,EACP,aAAa,EAEb,yBAAyB,EACzB,cAAc,EACf,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAG9D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAIvE;;GAEG;AACH,qBAAa,kBACX,SAAQ,yBACR,YAAW,sBAAsB;IAEjC,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,iBAAiB,CAA4B;IAErD;;OAEG;IACH,SAAgB,cAAc,uBAA8B;IAE5D,0HAA0H;IACpG,UAAU,kBAE/B;IAED;;OAEG;IACmB,YAAY,CAChC,aAAa,EAAE,OAAO,EACtB,YAAY,CAAC,EAAE,cAAc,CAAC,mBAAmB,GAChD,OAAO,CAAC,YAAY,CAAC,CAgFvB;IAED,uGAAuG;IAChG,kBAAkB,CACvB,cAAc,EAAE,UAAU,EAC1B,cAAc,EAAE,UAAU,GACzB,IAAI,CAEN;IAED,mEAAmE;IAC5D,mBAAmB,CAAC,cAAc,EAAE,UAAU,GAAG,IAAI,CAE3D;IAED;;OAEG;IACI,kBAAkB,CAAC,cAAc,EAAE,UAAU,GAAG,UAAU,CAEhE;IAED;;OAEG;IACU,kBAAkB,CAC7B,cAAc,EAAE,eAAe,GAC9B,OAAO,CAAC,eAAe,CAAC,CA+H1B;IAED;;OAEG;IACU,kBAAkB,CAC7B,mBAAmB,EAAE,aAAa,GACjC,OAAO,CAAC,kBAAkB,CAAC,CAqD7B;CACF"}
|
|
@@ -8,20 +8,26 @@ exports.IModelCloneContext = void 0;
|
|
|
8
8
|
/** @packageDocumentation
|
|
9
9
|
* @module iModels
|
|
10
10
|
*/
|
|
11
|
-
const
|
|
11
|
+
const node_assert_1 = require("node:assert");
|
|
12
12
|
const core_bentley_1 = require("@itwin/core-bentley");
|
|
13
13
|
const core_common_1 = require("@itwin/core-common");
|
|
14
14
|
const core_backend_1 = require("@itwin/core-backend");
|
|
15
|
+
const ecschema_metadata_1 = require("@itwin/ecschema-metadata");
|
|
15
16
|
const ECReferenceTypesCache_1 = require("./ECReferenceTypesCache");
|
|
16
|
-
const
|
|
17
|
+
const EntityExistenceCache_1 = require("./EntityExistenceCache");
|
|
17
18
|
const TransformerLoggerCategory_1 = require("./TransformerLoggerCategory");
|
|
19
|
+
const BigMap_1 = require("./BigMap");
|
|
18
20
|
const loggerCategory = TransformerLoggerCategory_1.TransformerLoggerCategory.IModelCloneContext;
|
|
19
21
|
/** The context for transforming a *source* Element to a *target* Element and remapping internal identifiers to the target iModel.
|
|
20
|
-
* @
|
|
22
|
+
* @internal
|
|
21
23
|
*/
|
|
22
24
|
class IModelCloneContext extends core_backend_1.IModelElementCloneContext {
|
|
23
25
|
_refTypesCache = new ECReferenceTypesCache_1.ECReferenceTypesCache();
|
|
24
|
-
_aspectRemapTable = new
|
|
26
|
+
_aspectRemapTable = new BigMap_1.BigMap();
|
|
27
|
+
/** A positive-only cache of entity existence checks, scoped to the current transformation run.
|
|
28
|
+
* @internal
|
|
29
|
+
*/
|
|
30
|
+
existenceCache = new EntityExistenceCache_1.EntityExistenceCache();
|
|
25
31
|
/** perform necessary initialization to use a clone context, namely caching the reference types in the source's schemas */
|
|
26
32
|
async initialize() {
|
|
27
33
|
await this._refTypesCache.initAllSchemasInIModel(this.sourceDb);
|
|
@@ -29,16 +35,39 @@ class IModelCloneContext extends core_backend_1.IModelElementCloneContext {
|
|
|
29
35
|
/** Clone the specified source Element into ElementProps for the target iModel.
|
|
30
36
|
* @internal
|
|
31
37
|
*/
|
|
32
|
-
cloneElement(sourceElement, cloneOptions) {
|
|
38
|
+
async cloneElement(sourceElement, cloneOptions) {
|
|
33
39
|
const targetElementProps = this["_nativeContext"].cloneElement(sourceElement.id, cloneOptions);
|
|
40
|
+
// Native same-iModel cloning clears codes for inserts, but identity mappings are updates.
|
|
41
|
+
if (!this.isBetweenIModels &&
|
|
42
|
+
this.findTargetElementId(sourceElement.id) === sourceElement.id) {
|
|
43
|
+
targetElementProps.code.value = sourceElement.code.value;
|
|
44
|
+
if (!core_bentley_1.Id64.isValidId64(targetElementProps.code.spec)) {
|
|
45
|
+
const mappedCodeSpecId = this.findTargetCodeSpecId(sourceElement.code.spec);
|
|
46
|
+
targetElementProps.code.spec = core_bentley_1.Id64.isValidId64(mappedCodeSpecId)
|
|
47
|
+
? mappedCodeSpecId
|
|
48
|
+
: sourceElement.code.spec;
|
|
49
|
+
}
|
|
50
|
+
if (!core_bentley_1.Id64.isValidId64(targetElementProps.code.scope)) {
|
|
51
|
+
const mappedCodeScopeId = this.findTargetElementId(sourceElement.code.scope);
|
|
52
|
+
targetElementProps.code.scope = core_bentley_1.Id64.isValidId64(mappedCodeScopeId)
|
|
53
|
+
? mappedCodeScopeId
|
|
54
|
+
: sourceElement.code.scope;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
34
57
|
// Ensure that all NavigationProperties in targetElementProps have a defined value so "clearing" changes will be part of the JSON used for update
|
|
35
|
-
sourceElement.
|
|
58
|
+
const sourceElementClass = sourceElement.iModel.schemaContext.getSchemaItemSync(sourceElement.schemaItemKey, ecschema_metadata_1.EntityClass);
|
|
59
|
+
(0, node_assert_1.strict)(sourceElementClass !== undefined, `Cannot get metadata for ${sourceElement.classFullName}.`);
|
|
60
|
+
for (const property of sourceElementClass.getPropertiesSync()) {
|
|
61
|
+
// Exclude custom properties because C++ has already handled them.
|
|
62
|
+
if (property.customAttributes?.has("BisCore.CustomHandledProperty"))
|
|
63
|
+
continue;
|
|
64
|
+
const name = property.name;
|
|
36
65
|
if (property.isNavigation() &&
|
|
37
66
|
undefined === sourceElement[core_common_1.ECJsNames.toJsName(name)]) {
|
|
38
67
|
targetElementProps[core_common_1.ECJsNames.toJsName(name)] =
|
|
39
68
|
core_common_1.RelatedElement.none;
|
|
40
69
|
}
|
|
41
|
-
}
|
|
70
|
+
}
|
|
42
71
|
if (this.isBetweenIModels) {
|
|
43
72
|
// The native C++ cloneElement strips off federationGuid, want to put it back if transformation is between iModels
|
|
44
73
|
targetElementProps.federationGuid = sourceElement.federationGuid;
|
|
@@ -55,7 +84,7 @@ class IModelCloneContext extends core_backend_1.IModelElementCloneContext {
|
|
|
55
84
|
targetElementProps.code = core_common_1.Code.createEmpty();
|
|
56
85
|
}
|
|
57
86
|
const jsClass = this.sourceDb.getJsClass(sourceElement.classFullName);
|
|
58
|
-
jsClass["onCloned"](this, sourceElement.toJSON(), targetElementProps);
|
|
87
|
+
await jsClass["onCloned"](this, sourceElement.toJSON(), targetElementProps);
|
|
59
88
|
return targetElementProps;
|
|
60
89
|
}
|
|
61
90
|
/** Add a rule that remaps the specified source ElementAspect to the specified target ElementAspect. */
|
|
@@ -98,7 +127,7 @@ class IModelCloneContext extends core_backend_1.IModelElementCloneContext {
|
|
|
98
127
|
}
|
|
99
128
|
// Check if the model exists, `findTargetElementId` may have worked because the element exists when the model doesn't.
|
|
100
129
|
// That can occur in the transformer since a submodeled element is imported before its submodel.
|
|
101
|
-
if (
|
|
130
|
+
if (await this.existenceCache.exists(this.targetDb, targetId))
|
|
102
131
|
return targetId;
|
|
103
132
|
break;
|
|
104
133
|
}
|
|
@@ -132,7 +161,9 @@ class IModelCloneContext extends core_backend_1.IModelElementCloneContext {
|
|
|
132
161
|
WHERE ECInstanceId=?
|
|
133
162
|
`;
|
|
134
163
|
const params = new core_common_1.QueryBinder().bindId(1, rawId);
|
|
135
|
-
const reader = this.sourceDb.createQueryReader(sql, params
|
|
164
|
+
const reader = this.sourceDb.createQueryReader(sql, params, {
|
|
165
|
+
usePrimaryConn: true,
|
|
166
|
+
});
|
|
136
167
|
const relInSource = await (async () => {
|
|
137
168
|
if (await reader.step()) {
|
|
138
169
|
const sourceId = reader.current[0];
|
|
@@ -162,22 +193,23 @@ class IModelCloneContext extends core_backend_1.IModelElementCloneContext {
|
|
|
162
193
|
if (!core_backend_1.EntityReferences.isValid(relInTarget.sourceId) ||
|
|
163
194
|
!core_backend_1.EntityReferences.isValid(relInTarget.targetId))
|
|
164
195
|
break;
|
|
165
|
-
|
|
166
|
-
const relInTargetId = this.targetDb.withPreparedStatement(`
|
|
196
|
+
const relInTargetSql = `
|
|
167
197
|
SELECT ECInstanceId
|
|
168
198
|
FROM BisCore:ElementRefersToElements
|
|
169
199
|
WHERE SourceECInstanceId=?
|
|
170
200
|
AND TargetECInstanceId=?
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
201
|
+
`;
|
|
202
|
+
const relInTargetParams = new core_common_1.QueryBinder();
|
|
203
|
+
relInTargetParams.bindId(1, core_backend_1.EntityReferences.toId64(relInTarget.sourceId));
|
|
204
|
+
relInTargetParams.bindId(2, core_backend_1.EntityReferences.toId64(relInTarget.targetId));
|
|
205
|
+
const relInTargetResult = await this.targetDb
|
|
206
|
+
.createQueryReader(relInTargetSql, relInTargetParams, {
|
|
207
|
+
usePrimaryConn: true,
|
|
208
|
+
})
|
|
209
|
+
.next();
|
|
210
|
+
const relInTargetId = relInTargetResult.done
|
|
211
|
+
? core_bentley_1.Id64.invalid
|
|
212
|
+
: relInTargetResult.value.id;
|
|
181
213
|
return `r${relInTargetId}`;
|
|
182
214
|
}
|
|
183
215
|
}
|
|
@@ -191,27 +223,30 @@ class IModelCloneContext extends core_backend_1.IModelElementCloneContext {
|
|
|
191
223
|
const targetElementAspectProps = sourceElementAspect.toJSON();
|
|
192
224
|
targetElementAspectProps.id = undefined;
|
|
193
225
|
const targetEntityIds = [];
|
|
194
|
-
sourceElementAspect.
|
|
226
|
+
const sourceElementAspectClass = sourceElementAspect.iModel.schemaContext.getSchemaItemSync(sourceElementAspect.schemaItemKey, ecschema_metadata_1.EntityClass);
|
|
227
|
+
(0, node_assert_1.strict)(sourceElementAspectClass !== undefined, `Cannot get metadata for ${sourceElementAspect.classFullName}.`);
|
|
228
|
+
for (const property of sourceElementAspectClass.getPropertiesSync()) {
|
|
229
|
+
const ecName = property.name;
|
|
230
|
+
const name = core_common_1.ECJsNames.toJsName(ecName);
|
|
195
231
|
if (property.isNavigation()) {
|
|
196
|
-
const sourceNavProp = sourceElementAspect.asAny[
|
|
232
|
+
const sourceNavProp = sourceElementAspect.asAny[name];
|
|
197
233
|
if (sourceNavProp?.id) {
|
|
198
|
-
const navPropRefType = this._refTypesCache.getNavPropRefType(sourceElementAspect.schemaName, sourceElementAspect.className,
|
|
199
|
-
|
|
234
|
+
const navPropRefType = this._refTypesCache.getNavPropRefType(sourceElementAspect.schemaName, sourceElementAspect.className, name);
|
|
235
|
+
(0, node_assert_1.strict)(navPropRefType !== undefined, `nav prop ref type for '${name}' was not in the cache, this is a bug.`);
|
|
200
236
|
targetEntityIds.push(this.findTargetEntityId(core_backend_1.EntityReferences.fromEntityType(sourceNavProp.id, navPropRefType)).then((targetEntityReference) => {
|
|
201
237
|
const targetEntityId = core_backend_1.EntityReferences.toId64(targetEntityReference);
|
|
202
238
|
// spread the property in case toJSON did not deep-clone
|
|
203
|
-
targetElementAspectProps[
|
|
204
|
-
...targetElementAspectProps[
|
|
239
|
+
targetElementAspectProps[name] = {
|
|
240
|
+
...targetElementAspectProps[name],
|
|
205
241
|
id: targetEntityId,
|
|
206
242
|
};
|
|
207
243
|
}));
|
|
208
244
|
}
|
|
209
245
|
}
|
|
210
246
|
else if (property.isPrimitive() && "Id" === property.extendedTypeName) {
|
|
211
|
-
targetElementAspectProps[
|
|
212
|
-
this.findTargetElementId(sourceElementAspect.asAny[core_common_1.ECJsNames.toJsName(name)]);
|
|
247
|
+
targetElementAspectProps[name] = this.findTargetElementId(sourceElementAspect.asAny[name]);
|
|
213
248
|
}
|
|
214
|
-
}
|
|
249
|
+
}
|
|
215
250
|
await Promise.all(targetEntityIds);
|
|
216
251
|
return targetElementAspectProps;
|
|
217
252
|
}
|