@itwin/imodel-transformer 2.0.0-dev.5 → 2.0.0-dev.51
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 -36
- package/lib/cjs/BranchProvenanceInitializer.js.map +1 -1
- package/lib/cjs/ChangesetScanner.d.ts +60 -0
- package/lib/cjs/ChangesetScanner.d.ts.map +1 -0
- package/lib/cjs/ChangesetScanner.js +101 -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 -103
- 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 +82 -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 +43 -0
- package/lib/cjs/ElementAspectExportProcessor.d.ts.map +1 -0
- package/lib/cjs/ElementAspectExportProcessor.js +167 -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 +55 -32
- package/lib/cjs/EntityUnifier.js.map +1 -1
- package/lib/cjs/IModelCloneContext.d.ts +11 -5
- package/lib/cjs/IModelCloneContext.d.ts.map +1 -1
- package/lib/cjs/IModelCloneContext.js +94 -58
- package/lib/cjs/IModelCloneContext.js.map +1 -1
- package/lib/cjs/IModelExporter.d.ts +109 -35
- package/lib/cjs/IModelExporter.d.ts.map +1 -1
- package/lib/cjs/IModelExporter.js +698 -224
- package/lib/cjs/IModelExporter.js.map +1 -1
- package/lib/cjs/IModelImporter.d.ts +73 -32
- package/lib/cjs/IModelImporter.d.ts.map +1 -1
- package/lib/cjs/IModelImporter.js +278 -144
- 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 +126 -206
- package/lib/cjs/IModelTransformer.d.ts.map +1 -1
- package/lib/cjs/IModelTransformer.js +652 -1198
- 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 +182 -0
- package/lib/cjs/ProvenanceManager.d.ts.map +1 -0
- package/lib/cjs/ProvenanceManager.js +743 -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 +19 -0
- package/lib/cjs/imodel-transformer.d.ts.map +1 -1
- package/lib/cjs/imodel-transformer.js +53 -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
|
@@ -13,8 +13,11 @@ const core_bentley_1 = require("@itwin/core-bentley");
|
|
|
13
13
|
const core_common_1 = require("@itwin/core-common");
|
|
14
14
|
const TransformerLoggerCategory_1 = require("./TransformerLoggerCategory");
|
|
15
15
|
const core_backend_1 = require("@itwin/core-backend");
|
|
16
|
-
const
|
|
17
|
-
const
|
|
16
|
+
const node_assert_1 = require("node:assert");
|
|
17
|
+
const ElementAspectCleanup_1 = require("./ElementAspectCleanup");
|
|
18
|
+
const ecschema_metadata_1 = require("@itwin/ecschema-metadata");
|
|
19
|
+
const IModelTransformerError_1 = require("./IModelTransformerError");
|
|
20
|
+
const ElementBulkDelete_1 = require("./ElementBulkDelete");
|
|
18
21
|
const loggerCategory = TransformerLoggerCategory_1.TransformerLoggerCategory.IModelImporter;
|
|
19
22
|
/** Base class for importing data into an iModel.
|
|
20
23
|
* @see [iModel Transformation and Data Exchange]($docs/learning/transformer/index.md)
|
|
@@ -25,6 +28,23 @@ const loggerCategory = TransformerLoggerCategory_1.TransformerLoggerCategory.IMo
|
|
|
25
28
|
class IModelImporter {
|
|
26
29
|
/** The read/write target iModel. */
|
|
27
30
|
targetDb;
|
|
31
|
+
/** The [[EditTxn]] used for write operations on the target iModel.
|
|
32
|
+
* @beta
|
|
33
|
+
*/
|
|
34
|
+
_editTxn;
|
|
35
|
+
/** The [[EditTxn]] used for write operations on the target iModel.
|
|
36
|
+
* @beta
|
|
37
|
+
*/
|
|
38
|
+
get editTxn() {
|
|
39
|
+
return this._editTxn;
|
|
40
|
+
}
|
|
41
|
+
_elementAspectCleanup;
|
|
42
|
+
/** Deletes replaceable ElementAspects through this importer's customized deletion callback.
|
|
43
|
+
* @internal
|
|
44
|
+
*/
|
|
45
|
+
get elementAspectCleanup() {
|
|
46
|
+
return this._elementAspectCleanup;
|
|
47
|
+
}
|
|
28
48
|
/** resolved initialization options for the importer
|
|
29
49
|
* @beta
|
|
30
50
|
*/
|
|
@@ -38,6 +58,7 @@ class IModelImporter {
|
|
|
38
58
|
* To resolve code values to their intended values call [[IModelImporter.resolveDuplicateCodeValues]].
|
|
39
59
|
*/
|
|
40
60
|
_duplicateCodeValueMap;
|
|
61
|
+
_entityExistenceCaches = new Set();
|
|
41
62
|
/**
|
|
42
63
|
* A set of elementIds that the transformer adds to while exporting elements to indicate that the element already exists in the target.
|
|
43
64
|
* Defaults to an empty set.
|
|
@@ -51,9 +72,10 @@ class IModelImporter {
|
|
|
51
72
|
* @note This set should stay small, as right after the transformer pushes to it, the importer will remove from the set.
|
|
52
73
|
*/
|
|
53
74
|
_elementsToUpdateDuringPreserveIds = new Set([]);
|
|
54
|
-
/** The set of elements that
|
|
55
|
-
* Defaults to an empty set.
|
|
75
|
+
/** The set of target elements that this importer must not directly update or request for deletion.
|
|
76
|
+
* Defaults to an empty set and is populated by consumers or custom transformers.
|
|
56
77
|
* @note Adding an element to this set is typically necessary when remapping a source element to one that already exists in the target and already has the desired properties.
|
|
78
|
+
* @note Deletion protection applies only when the exact element ID is passed to [[deleteElement]] or [[deleteElements]]. It does not protect the element from deletion through a parent, containing model, or other cascading dependency. Consumers that need to preserve such an element must also add every requested deletion root whose cascade would delete it.
|
|
57
79
|
*/
|
|
58
80
|
doNotUpdateElementIds = new Set([]);
|
|
59
81
|
/** This set is ONLY used for elements that are always present even in an "empty" iModel. We will use this set to filter out changes to root elements if [[IModelTransformOptions.skipPropagateChangesToRootElements]] is false. */
|
|
@@ -71,11 +93,12 @@ class IModelImporter {
|
|
|
71
93
|
"geometryGuid", // cannot compare GeometricModel.GeometryGuid values across iModels
|
|
72
94
|
]);
|
|
73
95
|
/** Construct a new IModelImporter
|
|
74
|
-
* @param
|
|
96
|
+
* @param editTxn The [[EditTxn]] to use for write operations on the target iModel. The target db is derived from `editTxn.iModel`.
|
|
75
97
|
* @param options The options that specify how the import should be done.
|
|
76
98
|
*/
|
|
77
|
-
constructor(
|
|
78
|
-
this.targetDb =
|
|
99
|
+
constructor(editTxn, options) {
|
|
100
|
+
this.targetDb = editTxn.iModel;
|
|
101
|
+
this._editTxn = editTxn;
|
|
79
102
|
this.options = {
|
|
80
103
|
autoExtendProjectExtents: options?.autoExtendProjectExtents ?? true,
|
|
81
104
|
preserveElementIdsForFiltering: options?.preserveElementIdsForFiltering ?? false,
|
|
@@ -83,6 +106,19 @@ class IModelImporter {
|
|
|
83
106
|
skipPropagateChangesToRootElements: options?.skipPropagateChangesToRootElements ?? true,
|
|
84
107
|
};
|
|
85
108
|
this._duplicateCodeValueMap = new Map();
|
|
109
|
+
this._elementAspectCleanup = new ElementAspectCleanup_1.ElementAspectCleanup(this.targetDb, this._editTxn, async (aspect) => this.onDeleteElementAspect(aspect));
|
|
110
|
+
}
|
|
111
|
+
/** Register a transformation-scoped existence cache for delete invalidation.
|
|
112
|
+
* @internal
|
|
113
|
+
*/
|
|
114
|
+
registerEntityExistenceCache(cache) {
|
|
115
|
+
this._entityExistenceCaches.add(cache);
|
|
116
|
+
}
|
|
117
|
+
/** Stop invalidating a transformation-scoped existence cache.
|
|
118
|
+
* @internal
|
|
119
|
+
*/
|
|
120
|
+
unregisterEntityExistenceCache(cache) {
|
|
121
|
+
this._entityExistenceCaches.delete(cache);
|
|
86
122
|
}
|
|
87
123
|
/**
|
|
88
124
|
* Checks [[IModelImportOptions.skipPropagateChangesToRootElements]], [[IModelImporter.rootElementIds]], and [[IModelImporter.doNotUpdateElementIds]] and returns true for 'do not update', false for do 'update'.
|
|
@@ -105,9 +141,15 @@ class IModelImporter {
|
|
|
105
141
|
this._elementsToUpdateDuringPreserveIds.add(elementId);
|
|
106
142
|
}
|
|
107
143
|
/** Import the specified ModelProps (either as an insert or an update) into the target iModel. */
|
|
108
|
-
importModel(modelProps) {
|
|
144
|
+
async importModel(modelProps) {
|
|
109
145
|
if (undefined === modelProps.id || !core_bentley_1.Id64.isValidId64(modelProps.id))
|
|
110
|
-
|
|
146
|
+
core_bentley_1.ITwinError.throwError({
|
|
147
|
+
iTwinErrorId: {
|
|
148
|
+
scope: IModelTransformerError_1.IModelTransformerErrorScope,
|
|
149
|
+
key: IModelTransformerError_1.IModelTransformerError.InvalidModelId,
|
|
150
|
+
},
|
|
151
|
+
message: "Model Id not provided, should be the same as the ModeledElementId",
|
|
152
|
+
});
|
|
111
153
|
if (this.doNotUpdateElement(modelProps.id)) {
|
|
112
154
|
core_bentley_1.Logger.logInfo(loggerCategory, `Do not update target model ${modelProps.id}`);
|
|
113
155
|
return;
|
|
@@ -115,14 +157,14 @@ class IModelImporter {
|
|
|
115
157
|
try {
|
|
116
158
|
const model = this.targetDb.models.getModel(modelProps.id); // throws IModelError.NotFound if model does not exist
|
|
117
159
|
if (hasEntityChanged(model, modelProps, this._modelPropertiesToIgnore)) {
|
|
118
|
-
this.onUpdateModel(modelProps);
|
|
160
|
+
await this.onUpdateModel(modelProps);
|
|
119
161
|
}
|
|
120
162
|
}
|
|
121
163
|
catch (error) {
|
|
122
164
|
// catch NotFound error and insertModel
|
|
123
165
|
if (error instanceof core_common_1.IModelError &&
|
|
124
166
|
error.errorNumber === core_bentley_1.IModelStatus.NotFound) {
|
|
125
|
-
this.onInsertModel(modelProps);
|
|
167
|
+
await this.onInsertModel(modelProps);
|
|
126
168
|
return;
|
|
127
169
|
}
|
|
128
170
|
throw error;
|
|
@@ -131,29 +173,35 @@ class IModelImporter {
|
|
|
131
173
|
/** Create a new Model from the specified ModelProps and insert it into the target iModel.
|
|
132
174
|
* @note A subclass may override this method to customize insert behavior but should call `super.onInsertModel`.
|
|
133
175
|
*/
|
|
134
|
-
onInsertModel(modelProps) {
|
|
176
|
+
async onInsertModel(modelProps) {
|
|
135
177
|
try {
|
|
136
|
-
const modelId = this.
|
|
178
|
+
const modelId = this._editTxn.insertModel(modelProps);
|
|
137
179
|
core_bentley_1.Logger.logInfo(loggerCategory, `Inserted ${this.formatModelForLogger(modelProps)}`);
|
|
138
|
-
this.trackProgress();
|
|
180
|
+
await this.trackProgress();
|
|
139
181
|
return modelId;
|
|
140
182
|
}
|
|
141
183
|
catch (error) {
|
|
142
184
|
if (!this.targetDb.containsClass(modelProps.classFullName)) {
|
|
143
|
-
//
|
|
144
|
-
|
|
145
|
-
|
|
185
|
+
// Translate only confirmed missing-class failures; otherwise retain the backend error's identity.
|
|
186
|
+
core_bentley_1.ITwinError.throwError({
|
|
187
|
+
iTwinErrorId: {
|
|
188
|
+
scope: IModelTransformerError_1.IModelTransformerErrorScope,
|
|
189
|
+
key: IModelTransformerError_1.IModelTransformerError.TargetClassNotFound,
|
|
190
|
+
},
|
|
191
|
+
message: `Model class "${modelProps.classFullName}" not found in the target iModel. Was the latest version of the schema imported?`,
|
|
192
|
+
cause: error,
|
|
193
|
+
});
|
|
146
194
|
}
|
|
147
|
-
throw error;
|
|
195
|
+
throw error;
|
|
148
196
|
}
|
|
149
197
|
}
|
|
150
198
|
/** Update an existing Model in the target iModel from the specified ModelProps.
|
|
151
199
|
* @note A subclass may override this method to customize update behavior but should call `super.onUpdateModel`.
|
|
152
200
|
*/
|
|
153
|
-
onUpdateModel(modelProps) {
|
|
154
|
-
this.
|
|
201
|
+
async onUpdateModel(modelProps) {
|
|
202
|
+
this._editTxn.updateModel(modelProps);
|
|
155
203
|
core_bentley_1.Logger.logInfo(loggerCategory, `Updated ${this.formatModelForLogger(modelProps)}`);
|
|
156
|
-
this.trackProgress();
|
|
204
|
+
await this.trackProgress();
|
|
157
205
|
}
|
|
158
206
|
/** Format a Model for the Logger. */
|
|
159
207
|
formatModelForLogger(modelProps) {
|
|
@@ -164,18 +212,18 @@ class IModelImporter {
|
|
|
164
212
|
* Tries to update an element with the specified element properties.
|
|
165
213
|
* If a duplicate code error occurs, it assigns a new unique code value and retries the update
|
|
166
214
|
*/
|
|
167
|
-
tryUpdateElement(elemProps) {
|
|
215
|
+
async tryUpdateElement(elemProps) {
|
|
168
216
|
try {
|
|
169
|
-
this.onUpdateElement(elemProps);
|
|
217
|
+
await this.onUpdateElement(elemProps);
|
|
170
218
|
}
|
|
171
219
|
catch (err) {
|
|
172
220
|
if (err.errorNumber === core_bentley_1.IModelStatus.DuplicateCode) {
|
|
173
|
-
|
|
221
|
+
(0, node_assert_1.strict)(elemProps.code.value !== undefined, "NULL code values are always considered unique and cannot clash");
|
|
174
222
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
175
223
|
this._duplicateCodeValueMap.set(elemProps.id, elemProps.code.value);
|
|
176
224
|
// Using NULL code values as an alternative is not valid because definition elements cannot have NULL code values.
|
|
177
225
|
elemProps.code.value = core_bentley_1.Guid.createValue();
|
|
178
|
-
this.onUpdateElement(elemProps);
|
|
226
|
+
await this.onUpdateElement(elemProps);
|
|
179
227
|
}
|
|
180
228
|
else {
|
|
181
229
|
throw err;
|
|
@@ -183,7 +231,7 @@ class IModelImporter {
|
|
|
183
231
|
}
|
|
184
232
|
}
|
|
185
233
|
/** Import the specified ElementProps (either as an insert or an update) into the target iModel. */
|
|
186
|
-
importElement(elementProps) {
|
|
234
|
+
async importElement(elementProps) {
|
|
187
235
|
if (undefined !== elementProps.id &&
|
|
188
236
|
this.doNotUpdateElement(elementProps.id)) {
|
|
189
237
|
core_bentley_1.Logger.logInfo(loggerCategory, `Do not update target element ${elementProps.id}`);
|
|
@@ -191,7 +239,13 @@ class IModelImporter {
|
|
|
191
239
|
}
|
|
192
240
|
if (this.options.preserveElementIdsForFiltering) {
|
|
193
241
|
if (elementProps.id === undefined) {
|
|
194
|
-
|
|
242
|
+
core_bentley_1.ITwinError.throwError({
|
|
243
|
+
iTwinErrorId: {
|
|
244
|
+
scope: IModelTransformerError_1.IModelTransformerErrorScope,
|
|
245
|
+
key: IModelTransformerError_1.IModelTransformerError.ElementIdRequired,
|
|
246
|
+
},
|
|
247
|
+
message: "elementProps.id must be defined during a preserveIds operation",
|
|
248
|
+
});
|
|
195
249
|
}
|
|
196
250
|
// Categories are the only element that onInserted will immediately insert a new element (their default subcategory)
|
|
197
251
|
// since default subcategories always exist and always will be inserted after their categories, we treat them as an update
|
|
@@ -199,24 +253,24 @@ class IModelImporter {
|
|
|
199
253
|
// Always present elements (0xe, 0x1, 0x10) also will be updated to prevent duplicate inserts.
|
|
200
254
|
if ((isSubCategory(elementProps) && isDefaultSubCategory(elementProps)) ||
|
|
201
255
|
this._rootElementIds.has(elementProps.id)) {
|
|
202
|
-
this.onUpdateElement(elementProps);
|
|
256
|
+
await this.onUpdateElement(elementProps);
|
|
203
257
|
}
|
|
204
258
|
else {
|
|
205
259
|
if (this._elementsToUpdateDuringPreserveIds.has(elementProps.id)) {
|
|
206
|
-
this.tryUpdateElement(elementProps);
|
|
260
|
+
await this.tryUpdateElement(elementProps);
|
|
207
261
|
this._elementsToUpdateDuringPreserveIds.delete(elementProps.id);
|
|
208
262
|
}
|
|
209
263
|
else {
|
|
210
|
-
this.onInsertElement(elementProps);
|
|
264
|
+
await this.onInsertElement(elementProps);
|
|
211
265
|
}
|
|
212
266
|
}
|
|
213
267
|
}
|
|
214
268
|
else {
|
|
215
269
|
if (undefined !== elementProps.id) {
|
|
216
|
-
this.tryUpdateElement(elementProps);
|
|
270
|
+
await this.tryUpdateElement(elementProps);
|
|
217
271
|
}
|
|
218
272
|
else {
|
|
219
|
-
elementProps.id = this.onInsertElement(elementProps); // targetElementProps.id assigned by insertElement
|
|
273
|
+
elementProps.id = await this.onInsertElement(elementProps); // targetElementProps.id assigned by insertElement
|
|
220
274
|
}
|
|
221
275
|
}
|
|
222
276
|
return elementProps.id;
|
|
@@ -225,16 +279,15 @@ class IModelImporter {
|
|
|
225
279
|
* @returns The Id of the newly inserted Element.
|
|
226
280
|
* @note A subclass may override this method to customize insert behavior but should call `super.onInsertElement`.
|
|
227
281
|
*/
|
|
228
|
-
onInsertElement(elementProps) {
|
|
229
|
-
/* eslint-disable @typescript-eslint/no-deprecated */
|
|
282
|
+
async onInsertElement(elementProps) {
|
|
230
283
|
try {
|
|
231
|
-
const elementId = this.
|
|
284
|
+
const elementId = this._editTxn.insertElement(elementProps, {
|
|
232
285
|
forceUseId: this.options.preserveElementIdsForFiltering,
|
|
233
286
|
});
|
|
234
287
|
// set the id like [IModelDb.insertElement]($backend), does, the raw nativeDb method does not
|
|
235
288
|
elementProps.id = elementId;
|
|
236
289
|
core_bentley_1.Logger.logInfo(loggerCategory, `Inserted ${this.formatElementForLogger(elementProps)}`);
|
|
237
|
-
this.trackProgress();
|
|
290
|
+
await this.trackProgress();
|
|
238
291
|
if (this.options.simplifyElementGeometry) {
|
|
239
292
|
this.targetDb.simplifyElementGeometry({
|
|
240
293
|
id: elementId,
|
|
@@ -246,26 +299,35 @@ class IModelImporter {
|
|
|
246
299
|
}
|
|
247
300
|
catch (error) {
|
|
248
301
|
if (!this.targetDb.containsClass(elementProps.classFullName)) {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
302
|
+
core_bentley_1.ITwinError.throwError({
|
|
303
|
+
iTwinErrorId: {
|
|
304
|
+
scope: IModelTransformerError_1.IModelTransformerErrorScope,
|
|
305
|
+
key: IModelTransformerError_1.IModelTransformerError.TargetClassNotFound,
|
|
306
|
+
},
|
|
307
|
+
message: `Element class "${elementProps.classFullName}" not found in the target iModel. Was the latest version of the schema imported?`,
|
|
308
|
+
cause: error,
|
|
309
|
+
});
|
|
252
310
|
}
|
|
253
|
-
throw error;
|
|
311
|
+
throw error;
|
|
254
312
|
}
|
|
255
|
-
/* eslint-enable @typescript-eslint/no-deprecated */
|
|
256
313
|
}
|
|
257
314
|
/** Update an existing Element in the target iModel from the specified ElementProps.
|
|
258
315
|
* @note A subclass may override this method to customize update behavior but should call `super.onUpdateElement`.
|
|
259
316
|
*/
|
|
260
|
-
onUpdateElement(elementProps) {
|
|
317
|
+
async onUpdateElement(elementProps) {
|
|
261
318
|
if (!elementProps.id) {
|
|
262
|
-
|
|
319
|
+
core_bentley_1.ITwinError.throwError({
|
|
320
|
+
iTwinErrorId: {
|
|
321
|
+
scope: IModelTransformerError_1.IModelTransformerErrorScope,
|
|
322
|
+
key: IModelTransformerError_1.IModelTransformerError.ElementIdRequired,
|
|
323
|
+
},
|
|
324
|
+
message: "ElementId not provided",
|
|
325
|
+
});
|
|
263
326
|
}
|
|
264
|
-
this.
|
|
327
|
+
this._editTxn.updateElement(elementProps);
|
|
265
328
|
core_bentley_1.Logger.logInfo(loggerCategory, `Updated ${this.formatElementForLogger(elementProps)}`);
|
|
266
|
-
this.trackProgress();
|
|
329
|
+
await this.trackProgress();
|
|
267
330
|
if (this.options.simplifyElementGeometry) {
|
|
268
|
-
/* eslint-disable-next-line @typescript-eslint/no-deprecated */
|
|
269
331
|
this.targetDb.simplifyElementGeometry({
|
|
270
332
|
id: elementProps.id,
|
|
271
333
|
convertBReps: true,
|
|
@@ -273,34 +335,70 @@ class IModelImporter {
|
|
|
273
335
|
core_bentley_1.Logger.logInfo(loggerCategory, `Simplified element geometry for ${this.formatElementForLogger(elementProps)}`);
|
|
274
336
|
}
|
|
275
337
|
}
|
|
276
|
-
/**
|
|
277
|
-
|
|
278
|
-
|
|
338
|
+
/** Deletes one target element tree through [[deleteElements]]. */
|
|
339
|
+
async deleteElement(elementId) {
|
|
340
|
+
await this.deleteElements(new Set([elementId]));
|
|
341
|
+
}
|
|
342
|
+
/** Adds roots required by code-scope dependencies, then deletes the target element trees in one native operation.
|
|
343
|
+
* @note An override must call `super.onDeleteElements` once to perform the deletion.
|
|
279
344
|
*/
|
|
280
|
-
|
|
281
|
-
(0,
|
|
282
|
-
|
|
283
|
-
this.trackProgress();
|
|
284
|
-
}
|
|
285
|
-
/** Delete the specified Element from the target iModel. */
|
|
286
|
-
deleteElement(elementId) {
|
|
287
|
-
if (this.doNotUpdateElement(elementId)) {
|
|
288
|
-
core_bentley_1.Logger.logInfo(loggerCategory, `Do not delete target element ${elementId}`);
|
|
345
|
+
async onDeleteElements(elementIds) {
|
|
346
|
+
const deleteRoots = await (0, ElementBulkDelete_1.findBulkDeleteRoots)(this.targetDb, elementIds);
|
|
347
|
+
if (deleteRoots.size === 0)
|
|
289
348
|
return;
|
|
349
|
+
const result = this._editTxn.deleteElements([...deleteRoots]);
|
|
350
|
+
if (result.status !== core_backend_1.BulkDeleteElementsStatus.Success) {
|
|
351
|
+
core_bentley_1.ITwinError.throwError({
|
|
352
|
+
iTwinErrorId: {
|
|
353
|
+
scope: IModelTransformerError_1.IModelTransformerErrorScope,
|
|
354
|
+
key: IModelTransformerError_1.IModelTransformerError.ElementBulkDeleteFailed,
|
|
355
|
+
},
|
|
356
|
+
message: `Bulk element deletion failed: status ${core_backend_1.BulkDeleteElementsStatus[result.status]}, ` +
|
|
357
|
+
`SQLite status ${result.sqlDeleteStatus}, failed element IDs: ${[
|
|
358
|
+
...result.failedIds,
|
|
359
|
+
].join(", ")}`,
|
|
360
|
+
status: result.status,
|
|
361
|
+
sqlDeleteStatus: result.sqlDeleteStatus,
|
|
362
|
+
failedIds: new Set(result.failedIds),
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
core_bentley_1.Logger.logInfo(loggerCategory, `Deleted ${elementIds.size} requested element trees using ${deleteRoots.size} native deletion roots`);
|
|
366
|
+
await this.trackProgress(elementIds.size);
|
|
367
|
+
}
|
|
368
|
+
/** Deletes target element trees in one native operation.
|
|
369
|
+
* Requested roots in [[doNotUpdateElementIds]] are skipped. This does not prevent an element in that set from being deleted as part of another root's cascade.
|
|
370
|
+
* @throws [[ElementBulkDeleteError]] if native deletion fails for any root. A partial failure leaves successful deletions pending in the caller-owned transaction. Abandon the transaction before retrying.
|
|
371
|
+
*/
|
|
372
|
+
async deleteElements(elementIds) {
|
|
373
|
+
const idsToDelete = new Set();
|
|
374
|
+
for (const elementId of elementIds) {
|
|
375
|
+
if (!this.doNotUpdateElement(elementId)) {
|
|
376
|
+
idsToDelete.add(elementId);
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
core_bentley_1.Logger.logInfo(loggerCategory, `Do not delete target element ${elementId}`);
|
|
290
380
|
}
|
|
291
|
-
|
|
381
|
+
if (idsToDelete.size === 0)
|
|
382
|
+
return;
|
|
383
|
+
await this.onDeleteElements(idsToDelete);
|
|
384
|
+
// Element deletion cascades can remove descendants and their submodels.
|
|
385
|
+
for (const cache of this._entityExistenceCaches)
|
|
386
|
+
cache.clearDb(this.targetDb);
|
|
292
387
|
}
|
|
293
388
|
/** Delete the specified Model from the target iModel.
|
|
294
389
|
* @note A subclass may override this method to customize delete behavior but should call `super.onDeleteModel`.
|
|
295
390
|
*/
|
|
296
|
-
onDeleteModel(modelId) {
|
|
297
|
-
this.
|
|
391
|
+
async onDeleteModel(modelId) {
|
|
392
|
+
this._editTxn.deleteModel(modelId);
|
|
298
393
|
core_bentley_1.Logger.logInfo(loggerCategory, `Deleted model ${modelId}`);
|
|
299
|
-
this.trackProgress();
|
|
394
|
+
await this.trackProgress();
|
|
300
395
|
}
|
|
301
396
|
/** Delete the specified Model from the target iModel. */
|
|
302
|
-
deleteModel(modelId) {
|
|
303
|
-
this.onDeleteModel(modelId);
|
|
397
|
+
async deleteModel(modelId) {
|
|
398
|
+
await this.onDeleteModel(modelId);
|
|
399
|
+
const modelReference = core_backend_1.EntityReferences.fromEntityType(modelId, core_common_1.ConcreteEntityTypes.Model);
|
|
400
|
+
for (const cache of this._entityExistenceCaches)
|
|
401
|
+
cache.invalidate(this.targetDb, modelReference);
|
|
304
402
|
}
|
|
305
403
|
/** Format an Element for the Logger. */
|
|
306
404
|
formatElementForLogger(elementProps) {
|
|
@@ -312,14 +410,14 @@ class IModelImporter {
|
|
|
312
410
|
return `${elementProps.classFullName} ${namePiece}[${elementProps.id}]`;
|
|
313
411
|
}
|
|
314
412
|
/** Import an ElementUniqueAspect into the target iModel. */
|
|
315
|
-
importElementUniqueAspect(aspectProps) {
|
|
413
|
+
async importElementUniqueAspect(aspectProps) {
|
|
316
414
|
const aspects = this.targetDb.elements.getAspects(aspectProps.element.id, aspectProps.classFullName);
|
|
317
415
|
if (aspects.length === 0) {
|
|
318
416
|
return this.onInsertElementAspect(aspectProps);
|
|
319
417
|
}
|
|
320
418
|
else if (hasEntityChanged(aspects[0], aspectProps)) {
|
|
321
419
|
aspectProps.id = aspects[0].id;
|
|
322
|
-
this.onUpdateElementAspect(aspectProps);
|
|
420
|
+
await this.onUpdateElementAspect(aspectProps);
|
|
323
421
|
}
|
|
324
422
|
return aspects[0].id;
|
|
325
423
|
}
|
|
@@ -329,7 +427,7 @@ class IModelImporter {
|
|
|
329
427
|
* @note For insert vs. update reasons, it is important to process all ElementMultiAspects owned by an Element at once since we don't have aspect-specific provenance.
|
|
330
428
|
* @returns the array of ids of the resulting ElementMultiAspects, in the same order of the aspectPropsArray parameter
|
|
331
429
|
*/
|
|
332
|
-
importElementMultiAspects(aspectPropsArray,
|
|
430
|
+
async importElementMultiAspects(aspectPropsArray,
|
|
333
431
|
/** caller must use this to enforce any aspects added by IModelTransformer are not considered for update */
|
|
334
432
|
filterFunc = () => true) {
|
|
335
433
|
const result = new Array(aspectPropsArray.length).fill(undefined);
|
|
@@ -337,91 +435,96 @@ class IModelImporter {
|
|
|
337
435
|
return result;
|
|
338
436
|
}
|
|
339
437
|
const elementId = aspectPropsArray[0].element.id;
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
438
|
+
const proposedAspectsByClass = new Map();
|
|
439
|
+
aspectPropsArray.forEach((props, index) => {
|
|
440
|
+
const proposedAspects = proposedAspectsByClass.get(props.classFullName) ?? [];
|
|
441
|
+
proposedAspects.push({ props, index });
|
|
442
|
+
proposedAspectsByClass.set(props.classFullName, proposedAspects);
|
|
344
443
|
});
|
|
345
444
|
// Handle ElementMultiAspects in groups by class
|
|
346
|
-
|
|
347
|
-
const proposedAspects = aspectPropsArray
|
|
348
|
-
.map((props, index) => ({ props, index }))
|
|
349
|
-
.filter(({ props }) => aspectClassFullName === props.classFullName);
|
|
445
|
+
for (const [aspectClassFullName, proposedAspects,] of proposedAspectsByClass) {
|
|
350
446
|
const currentAspects = this.targetDb.elements
|
|
351
447
|
.getAspects(elementId, aspectClassFullName)
|
|
352
448
|
.map((props, index) => ({ props, index }))
|
|
353
449
|
.filter(({ props }) => filterFunc(props));
|
|
354
450
|
if (proposedAspects.length >= currentAspects.length) {
|
|
355
|
-
|
|
451
|
+
for (let index = 0; index < proposedAspects.length; index++) {
|
|
452
|
+
const { props, index: resultIndex } = proposedAspects[index];
|
|
356
453
|
let id;
|
|
357
454
|
if (index < currentAspects.length) {
|
|
358
455
|
id = currentAspects[index].props.id;
|
|
359
456
|
props.id = id;
|
|
360
457
|
if (hasEntityChanged(currentAspects[index].props, props)) {
|
|
361
|
-
this.onUpdateElementAspect(props);
|
|
458
|
+
await this.onUpdateElementAspect(props);
|
|
362
459
|
}
|
|
363
460
|
id = props.id;
|
|
364
461
|
}
|
|
365
462
|
else {
|
|
366
|
-
id = this.onInsertElementAspect(props);
|
|
463
|
+
id = await this.onInsertElementAspect(props);
|
|
367
464
|
}
|
|
368
465
|
result[resultIndex] = id;
|
|
369
|
-
}
|
|
466
|
+
}
|
|
370
467
|
}
|
|
371
468
|
else {
|
|
372
|
-
|
|
373
|
-
|
|
469
|
+
for (let index = 0; index < currentAspects.length; index++) {
|
|
470
|
+
const { props } = currentAspects[index];
|
|
374
471
|
if (index < proposedAspects.length) {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
472
|
+
const { props: proposedProps, index: resultIndex } = proposedAspects[index];
|
|
473
|
+
const id = props.id;
|
|
474
|
+
proposedProps.id = id;
|
|
475
|
+
if (hasEntityChanged(props, proposedProps)) {
|
|
476
|
+
await this.onUpdateElementAspect(proposedProps);
|
|
379
477
|
}
|
|
380
478
|
result[resultIndex] = id;
|
|
381
479
|
}
|
|
382
480
|
else {
|
|
383
|
-
this.onDeleteElementAspect(props);
|
|
481
|
+
await this.onDeleteElementAspect(props);
|
|
384
482
|
}
|
|
385
|
-
}
|
|
483
|
+
}
|
|
386
484
|
}
|
|
387
|
-
}
|
|
388
|
-
|
|
485
|
+
}
|
|
486
|
+
(0, node_assert_1.strict)(result.every((r) => r !== undefined));
|
|
389
487
|
return result;
|
|
390
488
|
}
|
|
391
489
|
/** Insert the ElementAspect into the target iModel.
|
|
392
490
|
* @note A subclass may override this method to customize insert behavior but should call `super.onInsertElementAspect`.
|
|
393
491
|
*/
|
|
394
|
-
onInsertElementAspect(aspectProps) {
|
|
492
|
+
async onInsertElementAspect(aspectProps) {
|
|
395
493
|
try {
|
|
396
|
-
const id = this.
|
|
494
|
+
const id = this._editTxn.insertAspect(aspectProps);
|
|
397
495
|
core_bentley_1.Logger.logInfo(loggerCategory, `Inserted ${this.formatElementAspectForLogger(aspectProps)}`);
|
|
398
|
-
this.trackProgress();
|
|
496
|
+
await this.trackProgress();
|
|
399
497
|
return id;
|
|
400
498
|
}
|
|
401
499
|
catch (error) {
|
|
402
500
|
if (!this.targetDb.containsClass(aspectProps.classFullName)) {
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
501
|
+
core_bentley_1.ITwinError.throwError({
|
|
502
|
+
iTwinErrorId: {
|
|
503
|
+
scope: IModelTransformerError_1.IModelTransformerErrorScope,
|
|
504
|
+
key: IModelTransformerError_1.IModelTransformerError.TargetClassNotFound,
|
|
505
|
+
},
|
|
506
|
+
message: `ElementAspect class "${aspectProps.classFullName}" not found in the target iModel. Was the latest version of the schema imported?`,
|
|
507
|
+
cause: error,
|
|
508
|
+
});
|
|
406
509
|
}
|
|
407
|
-
throw error;
|
|
510
|
+
throw error;
|
|
408
511
|
}
|
|
409
512
|
}
|
|
410
513
|
/** Update the ElementAspect within the target iModel.
|
|
411
514
|
* @note A subclass may override this method to customize update behavior but should call `super.onUpdateElementAspect`.
|
|
412
515
|
*/
|
|
413
|
-
onUpdateElementAspect(aspectProps) {
|
|
414
|
-
this.
|
|
516
|
+
async onUpdateElementAspect(aspectProps) {
|
|
517
|
+
this._editTxn.updateAspect(aspectProps);
|
|
415
518
|
core_bentley_1.Logger.logInfo(loggerCategory, `Updated ${this.formatElementAspectForLogger(aspectProps)}`);
|
|
416
|
-
this.trackProgress();
|
|
519
|
+
await this.trackProgress();
|
|
417
520
|
}
|
|
418
521
|
/** Delete the specified ElementAspect from the target iModel.
|
|
419
522
|
* @note A subclass may override this method to customize delete behavior but should call `super.onDeleteElementAspect`.
|
|
420
523
|
*/
|
|
421
|
-
onDeleteElementAspect(targetElementAspect) {
|
|
422
|
-
this.
|
|
524
|
+
async onDeleteElementAspect(targetElementAspect) {
|
|
525
|
+
this._editTxn.deleteAspect(targetElementAspect.id);
|
|
423
526
|
core_bentley_1.Logger.logInfo(loggerCategory, `Deleted ${this.formatElementAspectForLogger(targetElementAspect)}`);
|
|
424
|
-
this.trackProgress();
|
|
527
|
+
await this.trackProgress();
|
|
425
528
|
}
|
|
426
529
|
/** Format an ElementAspect for the Logger. */
|
|
427
530
|
formatElementAspectForLogger(elementAspectProps) {
|
|
@@ -430,7 +533,7 @@ class IModelImporter {
|
|
|
430
533
|
/** Import the specified RelationshipProps (either as an insert or an update) into the target iModel.
|
|
431
534
|
* @returns The instance Id of the inserted or updated Relationship.
|
|
432
535
|
*/
|
|
433
|
-
importRelationship(relationshipProps) {
|
|
536
|
+
async importRelationship(relationshipProps) {
|
|
434
537
|
if (undefined === relationshipProps.sourceId ||
|
|
435
538
|
!core_bentley_1.Id64.isValidId64(relationshipProps.sourceId)) {
|
|
436
539
|
core_bentley_1.Logger.logInfo(loggerCategory, `Ignoring ${relationshipProps.classFullName} instance because of invalid RelationshipProps.sourceId`);
|
|
@@ -451,7 +554,7 @@ class IModelImporter {
|
|
|
451
554
|
// if relationship found, update it
|
|
452
555
|
relationshipProps.id = relationship.id;
|
|
453
556
|
if (hasEntityChanged(relationship, relationshipProps)) {
|
|
454
|
-
this.onUpdateRelationship(relationshipProps);
|
|
557
|
+
await this.onUpdateRelationship(relationshipProps);
|
|
455
558
|
}
|
|
456
559
|
return relationshipProps.id;
|
|
457
560
|
}
|
|
@@ -463,62 +566,75 @@ class IModelImporter {
|
|
|
463
566
|
* @returns The instance Id of the newly inserted relationship.
|
|
464
567
|
* @note A subclass may override this method to customize insert behavior but should call `super.onInsertRelationship`.
|
|
465
568
|
*/
|
|
466
|
-
onInsertRelationship(relationshipProps) {
|
|
569
|
+
async onInsertRelationship(relationshipProps) {
|
|
467
570
|
try {
|
|
468
|
-
const targetRelInstanceId = this.
|
|
571
|
+
const targetRelInstanceId = this._editTxn.insertRelationship(relationshipProps);
|
|
469
572
|
core_bentley_1.Logger.logInfo(loggerCategory, `Inserted ${this.formatRelationshipForLogger(relationshipProps)}`);
|
|
470
|
-
this.trackProgress();
|
|
573
|
+
await this.trackProgress();
|
|
471
574
|
return targetRelInstanceId;
|
|
472
575
|
}
|
|
473
576
|
catch (error) {
|
|
474
577
|
if (!this.targetDb.containsClass(relationshipProps.classFullName)) {
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
578
|
+
core_bentley_1.ITwinError.throwError({
|
|
579
|
+
iTwinErrorId: {
|
|
580
|
+
scope: IModelTransformerError_1.IModelTransformerErrorScope,
|
|
581
|
+
key: IModelTransformerError_1.IModelTransformerError.TargetClassNotFound,
|
|
582
|
+
},
|
|
583
|
+
message: `Relationship class "${relationshipProps.classFullName}" not found in the target iModel. Was the latest version of the schema imported?`,
|
|
584
|
+
cause: error,
|
|
585
|
+
});
|
|
478
586
|
}
|
|
479
|
-
throw error;
|
|
587
|
+
throw error;
|
|
480
588
|
}
|
|
481
589
|
}
|
|
482
590
|
/** Update an existing Relationship in the target iModel from the specified RelationshipProps.
|
|
483
591
|
* @note A subclass may override this method to customize update behavior but should call `super.onUpdateRelationship`.
|
|
484
592
|
*/
|
|
485
|
-
onUpdateRelationship(relationshipProps) {
|
|
593
|
+
async onUpdateRelationship(relationshipProps) {
|
|
486
594
|
if (!relationshipProps.id) {
|
|
487
|
-
|
|
595
|
+
core_bentley_1.ITwinError.throwError({
|
|
596
|
+
iTwinErrorId: {
|
|
597
|
+
scope: IModelTransformerError_1.IModelTransformerErrorScope,
|
|
598
|
+
key: IModelTransformerError_1.IModelTransformerError.RelationshipIdRequired,
|
|
599
|
+
},
|
|
600
|
+
message: "Relationship instance Id not provided",
|
|
601
|
+
});
|
|
488
602
|
}
|
|
489
|
-
this.
|
|
603
|
+
this._editTxn.updateRelationship(relationshipProps);
|
|
490
604
|
core_bentley_1.Logger.logInfo(loggerCategory, `Updated ${this.formatRelationshipForLogger(relationshipProps)}`);
|
|
491
|
-
this.trackProgress();
|
|
605
|
+
await this.trackProgress();
|
|
492
606
|
}
|
|
493
607
|
/** Delete the specified Relationship from the target iModel. */
|
|
494
|
-
onDeleteRelationship(relationshipProps) {
|
|
608
|
+
async onDeleteRelationship(relationshipProps) {
|
|
495
609
|
// Only passing in what deleteInstance actually uses, full relationshipProps is not necessary.
|
|
496
|
-
this.
|
|
610
|
+
this._editTxn.deleteRelationship({
|
|
497
611
|
id: relationshipProps.id,
|
|
498
612
|
classFullName: relationshipProps.classFullName,
|
|
499
613
|
});
|
|
500
614
|
core_bentley_1.Logger.logInfo(loggerCategory, `Deleted relationship ${relationshipProps.classFullName} id=${relationshipProps.id}`);
|
|
501
|
-
this.trackProgress();
|
|
615
|
+
await this.trackProgress();
|
|
502
616
|
}
|
|
503
617
|
/** Delete the specified Relationship from the target iModel. */
|
|
504
|
-
deleteRelationship(relationshipProps) {
|
|
505
|
-
this.onDeleteRelationship(relationshipProps);
|
|
618
|
+
async deleteRelationship(relationshipProps) {
|
|
619
|
+
await this.onDeleteRelationship(relationshipProps);
|
|
506
620
|
}
|
|
507
621
|
/** Format a Relationship for the Logger. */
|
|
508
622
|
formatRelationshipForLogger(relProps) {
|
|
509
623
|
return `${relProps.classFullName} sourceId=[${relProps.sourceId}] targetId=[${relProps.targetId}]`;
|
|
510
624
|
}
|
|
511
625
|
/** Tracks incremental progress */
|
|
512
|
-
trackProgress() {
|
|
513
|
-
this._progressCounter
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
626
|
+
async trackProgress(increment = 1) {
|
|
627
|
+
const previousProgressCounter = this._progressCounter;
|
|
628
|
+
this._progressCounter += increment;
|
|
629
|
+
const progressCallbacks = Math.floor(this._progressCounter / this.progressInterval) -
|
|
630
|
+
Math.floor(previousProgressCounter / this.progressInterval);
|
|
631
|
+
for (let i = 0; i < progressCallbacks; ++i)
|
|
632
|
+
await this.onProgress();
|
|
517
633
|
}
|
|
518
634
|
/** This method is called when IModelImporter has made incremental progress based on the [[progressInterval]] setting.
|
|
519
635
|
* @note A subclass may override this method to report custom progress but should call `super.onProgress`.
|
|
520
636
|
*/
|
|
521
|
-
onProgress() { }
|
|
637
|
+
async onProgress() { }
|
|
522
638
|
/** Optionally compute the projectExtents for the target iModel depending on the options for this IModelImporter.
|
|
523
639
|
* @note This method is automatically called from [IModelTransformer.process]($transformer).
|
|
524
640
|
* @see [IModelDb.computeProjectExtents]($backend), [[autoExtendProjectExtents]]
|
|
@@ -535,13 +651,15 @@ class IModelImporter {
|
|
|
535
651
|
const excludeOutliers = typeof this.options.autoExtendProjectExtents === "object"
|
|
536
652
|
? this.options.autoExtendProjectExtents.excludeOutliers
|
|
537
653
|
: false;
|
|
538
|
-
// If excludeOutliers is true, use the extents without outliers.
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
654
|
+
// If excludeOutliers is true, use the extents without outliers.
|
|
655
|
+
// Otherwise prefer extentsWithOutliers, but fall back to extents if it's undefined or a null range.
|
|
656
|
+
const extentsWithOutliers = computedProjectExtents.extentsWithOutliers;
|
|
657
|
+
const useExtentsWithOutliers = !excludeOutliers && extentsWithOutliers && !extentsWithOutliers.isNull;
|
|
658
|
+
const newProjectExtents = useExtentsWithOutliers
|
|
659
|
+
? extentsWithOutliers
|
|
660
|
+
: computedProjectExtents.extents;
|
|
543
661
|
if (!newProjectExtents.isAlmostEqual(this.targetDb.projectExtents)) {
|
|
544
|
-
this.
|
|
662
|
+
this._editTxn.updateProjectExtents(newProjectExtents);
|
|
545
663
|
core_bentley_1.Logger.logInfo(loggerCategory, `Updated projectExtents=${JSON.stringify(this.targetDb.projectExtents)}`);
|
|
546
664
|
}
|
|
547
665
|
if (!excludeOutliers &&
|
|
@@ -566,7 +684,6 @@ class IModelImporter {
|
|
|
566
684
|
*/
|
|
567
685
|
optimizeGeometry(options) {
|
|
568
686
|
if (options.inlineUniqueGeometryParts) {
|
|
569
|
-
/* eslint-disable-next-line @typescript-eslint/no-deprecated */
|
|
570
687
|
const result = this.targetDb.inlineGeometryParts();
|
|
571
688
|
core_bentley_1.Logger.logInfo(loggerCategory, `Inlined ${result.numRefsInlined} references to ${result.numCandidateParts} geometry parts and deleted ${result.numPartsDeleted} parts.`);
|
|
572
689
|
}
|
|
@@ -575,7 +692,7 @@ class IModelImporter {
|
|
|
575
692
|
for (const [elementId, codeValue] of this._duplicateCodeValueMap) {
|
|
576
693
|
const element = this.targetDb.elements.getElement(elementId);
|
|
577
694
|
element.code.value = codeValue;
|
|
578
|
-
element.
|
|
695
|
+
this._editTxn.updateElement(element.toJSON());
|
|
579
696
|
}
|
|
580
697
|
this._duplicateCodeValueMap.clear();
|
|
581
698
|
}
|
|
@@ -583,7 +700,8 @@ class IModelImporter {
|
|
|
583
700
|
* Needs to be called to perform necessary cleanup operations.
|
|
584
701
|
* By not calling `finalize` there is a risk that data imported into targetDb will not be as expected.
|
|
585
702
|
*
|
|
586
|
-
* @note
|
|
703
|
+
* @note [[IModelTransformer.process]] invokes this method automatically. Call it explicitly after
|
|
704
|
+
* composing the transformer's lower-level subset processing methods.
|
|
587
705
|
*/
|
|
588
706
|
finalize() {
|
|
589
707
|
this.resolveDuplicateCodeValues();
|
|
@@ -598,22 +716,26 @@ exports.IModelImporter = IModelImporter;
|
|
|
598
716
|
*/
|
|
599
717
|
function hasEntityChanged(entity, entityProps, namesToIgnore) {
|
|
600
718
|
let changed = false;
|
|
601
|
-
entity.
|
|
719
|
+
const entityClass = entity.iModel.schemaContext.getSchemaItemSync(entity.schemaItemKey);
|
|
720
|
+
(0, node_assert_1.strict)(ecschema_metadata_1.EntityClass.isEntityClass(entityClass) ||
|
|
721
|
+
ecschema_metadata_1.RelationshipClass.isRelationshipClass(entityClass), `Cannot get metadata for ${entity.classFullName}.`);
|
|
722
|
+
for (const property of entityClass.getPropertiesSync()) {
|
|
723
|
+
const propertyName = property.name;
|
|
602
724
|
if (!changed) {
|
|
603
725
|
if (namesToIgnore && namesToIgnore.has(propertyName)) {
|
|
604
726
|
// skip
|
|
605
727
|
}
|
|
606
|
-
else if (
|
|
607
|
-
changed = hasBinaryValueChanged(entity.asAny[propertyName], entityProps[propertyName]);
|
|
728
|
+
else if (ecschema_metadata_1.PropertyType.Binary === property.propertyType) {
|
|
729
|
+
changed = hasBinaryValueChanged(entity.asAny[core_common_1.ECJsNames.toJsName(propertyName)], entityProps[core_common_1.ECJsNames.toJsName(propertyName)]);
|
|
608
730
|
}
|
|
609
|
-
else if (
|
|
610
|
-
changed = hasNavigationValueChanged(entity.asAny[propertyName], entityProps[propertyName]);
|
|
731
|
+
else if (property.isNavigation()) {
|
|
732
|
+
changed = hasNavigationValueChanged(entity.asAny[core_common_1.ECJsNames.toJsName(propertyName)], entityProps[core_common_1.ECJsNames.toJsName(propertyName)]);
|
|
611
733
|
}
|
|
612
734
|
else {
|
|
613
|
-
changed = hasValueChanged(entity.asAny[propertyName], entityProps[propertyName]);
|
|
735
|
+
changed = hasValueChanged(entity.asAny[core_common_1.ECJsNames.toJsName(propertyName)], entityProps[core_common_1.ECJsNames.toJsName(propertyName)]);
|
|
614
736
|
}
|
|
615
737
|
}
|
|
616
|
-
}
|
|
738
|
+
}
|
|
617
739
|
return changed;
|
|
618
740
|
}
|
|
619
741
|
/** Returns true if the specified binary values are different. */
|
|
@@ -643,9 +765,21 @@ function isDefaultSubCategory(props) {
|
|
|
643
765
|
if (props.id === undefined)
|
|
644
766
|
return false;
|
|
645
767
|
if (!core_bentley_1.Id64.isId64(props.id))
|
|
646
|
-
|
|
768
|
+
core_bentley_1.ITwinError.throwError({
|
|
769
|
+
iTwinErrorId: {
|
|
770
|
+
scope: IModelTransformerError_1.IModelTransformerErrorScope,
|
|
771
|
+
key: IModelTransformerError_1.IModelTransformerError.InvalidSubCategory,
|
|
772
|
+
},
|
|
773
|
+
message: "subcategory had invalid id",
|
|
774
|
+
});
|
|
647
775
|
if (props.parent?.id === undefined)
|
|
648
|
-
|
|
776
|
+
core_bentley_1.ITwinError.throwError({
|
|
777
|
+
iTwinErrorId: {
|
|
778
|
+
scope: IModelTransformerError_1.IModelTransformerErrorScope,
|
|
779
|
+
key: IModelTransformerError_1.IModelTransformerError.InvalidSubCategory,
|
|
780
|
+
},
|
|
781
|
+
message: `subcategory with id ${props.id} had no parent`,
|
|
782
|
+
});
|
|
649
783
|
return props.id === core_backend_1.IModelDb.getDefaultSubCategoryId(props.parent.id);
|
|
650
784
|
}
|
|
651
785
|
//# sourceMappingURL=IModelImporter.js.map
|