@itwin/imodel-transformer 2.0.0-dev.72 → 2.0.0-dev.74
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 +11 -0
- package/lib/Algo.d.ts.map +1 -0
- package/lib/{cjs/Algo.js → Algo.js} +1 -4
- package/lib/Algo.js.map +1 -0
- package/lib/BigMap.d.ts.map +1 -0
- package/lib/{cjs/BigMap.js → BigMap.js} +1 -5
- package/lib/BigMap.js.map +1 -0
- package/lib/BranchProvenanceInitializer.d.ts.map +1 -0
- package/lib/{cjs/BranchProvenanceInitializer.js → BranchProvenanceInitializer.js} +34 -37
- package/lib/BranchProvenanceInitializer.js.map +1 -0
- package/lib/ChangedElementForest.d.ts.map +1 -0
- package/lib/{cjs/ChangedElementForest.js → ChangedElementForest.js} +12 -14
- package/lib/ChangedElementForest.js.map +1 -0
- package/lib/{cjs/ChangesetScanner.d.ts → ChangesetScanner.d.ts} +2 -2
- package/lib/ChangesetScanner.d.ts.map +1 -0
- package/lib/{cjs/ChangesetScanner.js → ChangesetScanner.js} +19 -24
- package/lib/ChangesetScanner.js.map +1 -0
- package/lib/ECReferenceTypesCache.d.ts.map +1 -0
- package/lib/{cjs/ECReferenceTypesCache.js → ECReferenceTypesCache.js} +32 -37
- package/lib/ECReferenceTypesCache.js.map +1 -0
- package/lib/ECSqlReaderAsyncIterableIteratorAdapter.d.ts.map +1 -0
- package/lib/{cjs/ECSqlReaderAsyncIterableIteratorAdapter.js → ECSqlReaderAsyncIterableIteratorAdapter.js} +2 -7
- package/lib/ECSqlReaderAsyncIterableIteratorAdapter.js.map +1 -0
- package/lib/ElementAspectCleanup.d.ts.map +1 -0
- package/lib/{cjs/ElementAspectCleanup.js → ElementAspectCleanup.js} +9 -13
- package/lib/ElementAspectCleanup.js.map +1 -0
- package/lib/ElementAspectExportCoordinator.d.ts.map +1 -0
- package/lib/{cjs/ElementAspectExportCoordinator.js → ElementAspectExportCoordinator.js} +1 -5
- package/lib/ElementAspectExportCoordinator.js.map +1 -0
- package/lib/ElementAspectExportProcessor.d.ts.map +1 -0
- package/lib/{cjs/ElementAspectExportProcessor.js → ElementAspectExportProcessor.js} +10 -14
- package/lib/ElementAspectExportProcessor.js.map +1 -0
- package/lib/ElementBulkDelete.d.ts.map +1 -0
- package/lib/{cjs/ElementBulkDelete.js → ElementBulkDelete.js} +9 -12
- package/lib/{cjs/ElementBulkDelete.js.map → ElementBulkDelete.js.map} +1 -1
- package/lib/EntityExistenceCache.d.ts.map +1 -0
- package/lib/{cjs/EntityExistenceCache.js → EntityExistenceCache.js} +4 -8
- package/lib/EntityExistenceCache.js.map +1 -0
- package/lib/EntityUnifier.d.ts.map +1 -0
- package/lib/{cjs/EntityUnifier.js → EntityUnifier.js} +21 -22
- package/lib/EntityUnifier.js.map +1 -0
- package/lib/{cjs/IModelCloneContext.d.ts → IModelCloneContext.d.ts} +2 -2
- package/lib/IModelCloneContext.d.ts.map +1 -0
- package/lib/{cjs/IModelCloneContext.js → IModelCloneContext.js} +52 -56
- package/lib/IModelCloneContext.js.map +1 -0
- package/lib/{cjs/IModelExporter.d.ts → IModelExporter.d.ts} +1 -1
- package/lib/IModelExporter.d.ts.map +1 -0
- package/lib/{cjs/IModelExporter.js → IModelExporter.js} +165 -174
- package/lib/IModelExporter.js.map +1 -0
- package/lib/{cjs/IModelImporter.d.ts → IModelImporter.d.ts} +3 -3
- package/lib/IModelImporter.d.ts.map +1 -0
- package/lib/{cjs/IModelImporter.js → IModelImporter.js} +104 -109
- package/lib/IModelImporter.js.map +1 -0
- package/lib/IModelTransformContext.d.ts.map +1 -0
- package/lib/IModelTransformContext.js +2 -0
- package/lib/IModelTransformContext.js.map +1 -0
- package/lib/{cjs/IModelTransformer.d.ts → IModelTransformer.d.ts} +9 -6
- package/lib/IModelTransformer.d.ts.map +1 -0
- package/lib/{cjs/IModelTransformer.js → IModelTransformer.js} +297 -337
- package/lib/IModelTransformer.js.map +1 -0
- package/lib/IModelTransformerError.d.ts.map +1 -0
- package/lib/{cjs/IModelTransformerError.js → IModelTransformerError.js} +3 -6
- package/lib/IModelTransformerError.js.map +1 -0
- package/lib/{cjs/ProvenanceManager.d.ts → ProvenanceManager.d.ts} +3 -3
- package/lib/ProvenanceManager.d.ts.map +1 -0
- package/lib/{cjs/ProvenanceManager.js → ProvenanceManager.js} +69 -73
- package/lib/ProvenanceManager.js.map +1 -0
- package/lib/SourceClassKinds.d.ts.map +1 -0
- package/lib/{cjs/SourceClassKinds.js → SourceClassKinds.js} +1 -5
- package/lib/SourceClassKinds.js.map +1 -0
- package/lib/SyncTypeResolver.d.ts.map +1 -0
- package/lib/{cjs/SyncTypeResolver.js → SyncTypeResolver.js} +15 -19
- package/lib/SyncTypeResolver.js.map +1 -0
- package/lib/TransformerLoggerCategory.d.ts.map +1 -0
- package/lib/{cjs/TransformerLoggerCategory.js → TransformerLoggerCategory.js} +2 -5
- package/lib/TransformerLoggerCategory.js.map +1 -0
- package/lib/TransformerPackageMetadata.d.ts.map +1 -0
- package/lib/TransformerPackageMetadata.js +8 -0
- package/lib/TransformerPackageMetadata.js.map +1 -0
- package/lib/{cjs/imodel-transformer.d.ts → imodel-transformer.d.ts} +9 -9
- package/lib/imodel-transformer.d.ts.map +1 -0
- package/lib/imodel-transformer.js +88 -0
- package/lib/imodel-transformer.js.map +1 -0
- package/lib/{cjs/schema-processing → schema-processing}/DynamicSchemaUnionStrategy.d.ts +1 -1
- package/lib/schema-processing/DynamicSchemaUnionStrategy.d.ts.map +1 -0
- package/lib/{cjs/schema-processing → schema-processing}/DynamicSchemaUnionStrategy.js +16 -20
- package/lib/schema-processing/DynamicSchemaUnionStrategy.js.map +1 -0
- package/lib/{cjs/schema-processing → schema-processing}/SchemaProcessingCoordinator.d.ts +2 -2
- package/lib/schema-processing/SchemaProcessingCoordinator.d.ts.map +1 -0
- package/lib/{cjs/schema-processing → schema-processing}/SchemaProcessingCoordinator.js +15 -52
- package/lib/schema-processing/SchemaProcessingCoordinator.js.map +1 -0
- package/lib/schema-processing/SchemaProcessingStrategy.d.ts.map +1 -0
- package/lib/{cjs/schema-processing → schema-processing}/SchemaProcessingStrategy.js +1 -5
- package/lib/schema-processing/SchemaProcessingStrategy.js.map +1 -0
- package/lib/schema-processing.d.ts +7 -0
- package/lib/schema-processing.d.ts.map +1 -0
- package/lib/schema-processing.js +11 -0
- package/lib/schema-processing.js.map +1 -0
- package/package.json +14 -14
- package/lib/cjs/Algo.d.ts.map +0 -1
- package/lib/cjs/Algo.js.map +0 -1
- package/lib/cjs/BigMap.d.ts.map +0 -1
- package/lib/cjs/BigMap.js.map +0 -1
- package/lib/cjs/BranchProvenanceInitializer.d.ts.map +0 -1
- package/lib/cjs/BranchProvenanceInitializer.js.map +0 -1
- package/lib/cjs/ChangedElementForest.d.ts.map +0 -1
- package/lib/cjs/ChangedElementForest.js.map +0 -1
- package/lib/cjs/ChangesetScanner.d.ts.map +0 -1
- package/lib/cjs/ChangesetScanner.js.map +0 -1
- package/lib/cjs/ECReferenceTypesCache.d.ts.map +0 -1
- package/lib/cjs/ECReferenceTypesCache.js.map +0 -1
- package/lib/cjs/ECSqlReaderAsyncIterableIteratorAdapter.d.ts.map +0 -1
- package/lib/cjs/ECSqlReaderAsyncIterableIteratorAdapter.js.map +0 -1
- package/lib/cjs/ElementAspectCleanup.d.ts.map +0 -1
- package/lib/cjs/ElementAspectCleanup.js.map +0 -1
- package/lib/cjs/ElementAspectExportCoordinator.d.ts.map +0 -1
- package/lib/cjs/ElementAspectExportCoordinator.js.map +0 -1
- package/lib/cjs/ElementAspectExportProcessor.d.ts.map +0 -1
- package/lib/cjs/ElementAspectExportProcessor.js.map +0 -1
- package/lib/cjs/ElementBulkDelete.d.ts.map +0 -1
- package/lib/cjs/EntityExistenceCache.d.ts.map +0 -1
- package/lib/cjs/EntityExistenceCache.js.map +0 -1
- package/lib/cjs/EntityUnifier.d.ts.map +0 -1
- package/lib/cjs/EntityUnifier.js.map +0 -1
- package/lib/cjs/IModelCloneContext.d.ts.map +0 -1
- package/lib/cjs/IModelCloneContext.js.map +0 -1
- package/lib/cjs/IModelExporter.d.ts.map +0 -1
- package/lib/cjs/IModelExporter.js.map +0 -1
- package/lib/cjs/IModelImporter.d.ts.map +0 -1
- package/lib/cjs/IModelImporter.js.map +0 -1
- package/lib/cjs/IModelTransformContext.d.ts.map +0 -1
- package/lib/cjs/IModelTransformContext.js +0 -3
- package/lib/cjs/IModelTransformContext.js.map +0 -1
- package/lib/cjs/IModelTransformer.d.ts.map +0 -1
- package/lib/cjs/IModelTransformer.js.map +0 -1
- package/lib/cjs/IModelTransformerError.d.ts.map +0 -1
- package/lib/cjs/IModelTransformerError.js.map +0 -1
- package/lib/cjs/ProvenanceManager.d.ts.map +0 -1
- package/lib/cjs/ProvenanceManager.js.map +0 -1
- package/lib/cjs/SourceClassKinds.d.ts.map +0 -1
- package/lib/cjs/SourceClassKinds.js.map +0 -1
- package/lib/cjs/SyncTypeResolver.d.ts.map +0 -1
- package/lib/cjs/SyncTypeResolver.js.map +0 -1
- package/lib/cjs/TransformerLoggerCategory.d.ts.map +0 -1
- package/lib/cjs/TransformerLoggerCategory.js.map +0 -1
- package/lib/cjs/TransformerPackageMetadata.d.ts.map +0 -1
- package/lib/cjs/TransformerPackageMetadata.js +0 -47
- package/lib/cjs/TransformerPackageMetadata.js.map +0 -1
- package/lib/cjs/imodel-transformer.d.ts.map +0 -1
- package/lib/cjs/imodel-transformer.js +0 -125
- package/lib/cjs/imodel-transformer.js.map +0 -1
- package/lib/cjs/schema-processing/DynamicSchemaUnionStrategy.d.ts.map +0 -1
- package/lib/cjs/schema-processing/DynamicSchemaUnionStrategy.js.map +0 -1
- package/lib/cjs/schema-processing/SchemaProcessingCoordinator.d.ts.map +0 -1
- package/lib/cjs/schema-processing/SchemaProcessingCoordinator.js.map +0 -1
- package/lib/cjs/schema-processing/SchemaProcessingStrategy.d.ts.map +0 -1
- package/lib/cjs/schema-processing/SchemaProcessingStrategy.js.map +0 -1
- package/lib/cjs/schema-processing.d.ts +0 -7
- package/lib/cjs/schema-processing.d.ts.map +0 -1
- package/lib/cjs/schema-processing.js +0 -27
- package/lib/cjs/schema-processing.js.map +0 -1
- /package/lib/{cjs/Algo.d.ts → Algo.d.ts} +0 -0
- /package/lib/{cjs/BigMap.d.ts → BigMap.d.ts} +0 -0
- /package/lib/{cjs/BranchProvenanceInitializer.d.ts → BranchProvenanceInitializer.d.ts} +0 -0
- /package/lib/{cjs/ChangedElementForest.d.ts → ChangedElementForest.d.ts} +0 -0
- /package/lib/{cjs/ECReferenceTypesCache.d.ts → ECReferenceTypesCache.d.ts} +0 -0
- /package/lib/{cjs/ECSqlReaderAsyncIterableIteratorAdapter.d.ts → ECSqlReaderAsyncIterableIteratorAdapter.d.ts} +0 -0
- /package/lib/{cjs/ElementAspectCleanup.d.ts → ElementAspectCleanup.d.ts} +0 -0
- /package/lib/{cjs/ElementAspectExportCoordinator.d.ts → ElementAspectExportCoordinator.d.ts} +0 -0
- /package/lib/{cjs/ElementAspectExportProcessor.d.ts → ElementAspectExportProcessor.d.ts} +0 -0
- /package/lib/{cjs/ElementBulkDelete.d.ts → ElementBulkDelete.d.ts} +0 -0
- /package/lib/{cjs/EntityExistenceCache.d.ts → EntityExistenceCache.d.ts} +0 -0
- /package/lib/{cjs/EntityUnifier.d.ts → EntityUnifier.d.ts} +0 -0
- /package/lib/{cjs/IModelTransformContext.d.ts → IModelTransformContext.d.ts} +0 -0
- /package/lib/{cjs/IModelTransformerError.d.ts → IModelTransformerError.d.ts} +0 -0
- /package/lib/{cjs/SourceClassKinds.d.ts → SourceClassKinds.d.ts} +0 -0
- /package/lib/{cjs/SyncTypeResolver.d.ts → SyncTypeResolver.d.ts} +0 -0
- /package/lib/{cjs/TransformerLoggerCategory.d.ts → TransformerLoggerCategory.d.ts} +0 -0
- /package/lib/{cjs/TransformerPackageMetadata.d.ts → TransformerPackageMetadata.d.ts} +0 -0
- /package/lib/{cjs/schema-processing → schema-processing}/SchemaProcessingStrategy.d.ts +0 -0
|
@@ -1,39 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.TemplateModelCloner = exports.IModelTransformer = void 0;
|
|
37
1
|
/*---------------------------------------------------------------------------------------------
|
|
38
2
|
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
39
3
|
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
@@ -41,73 +5,62 @@ exports.TemplateModelCloner = exports.IModelTransformer = void 0;
|
|
|
41
5
|
/** @packageDocumentation
|
|
42
6
|
* @module iModels
|
|
43
7
|
*/
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
8
|
+
import * as path from "node:path";
|
|
9
|
+
import * as Semver from "semver";
|
|
10
|
+
import { strict as nodeAssert } from "node:assert";
|
|
11
|
+
import { assert, Guid, Id64, IModelStatus, ITwinError, Logger, } from "@itwin/core-bentley";
|
|
12
|
+
import * as ECSchemaMetaData from "@itwin/ecschema-metadata";
|
|
13
|
+
import { Angle, AxisIndex, Matrix3d, Point3d, Transform, Vector3d, } from "@itwin/core-geometry";
|
|
14
|
+
import { BriefcaseManager, ChangeSummaryManager, ChannelRootAspect, DefinitionElement, DefinitionModel, DefinitionPartition, EditTxn,
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-redeclare
|
|
16
|
+
Element, ElementRefersToElements, EntityReferences, ExternalSourceAspect, GeometricElement, GeometricElement3d, IModelDb, IModelHost, InformationPartitionElement, KnownLocations, RecipeDefinitionElement, Schema, Subject, } from "@itwin/core-backend";
|
|
17
|
+
import { Code, ConcreteEntityTypes, ECJsNames, IModel, IModelError, Placement2d, Placement3d, QueryBinder, } from "@itwin/core-common";
|
|
18
|
+
import { ChangedInstanceIds, IModelExporter, IModelExportHandler, } from "./IModelExporter.js";
|
|
19
|
+
import { IModelImporter } from "./IModelImporter.js";
|
|
20
|
+
import { TransformerLoggerCategory } from "./TransformerLoggerCategory.js";
|
|
21
|
+
import { IModelCloneContext } from "./IModelCloneContext.js";
|
|
22
|
+
import { rangesFromRangeAndSkipped } from "./Algo.js";
|
|
23
|
+
import { SyncTypeResolver } from "./SyncTypeResolver.js";
|
|
24
|
+
import { ProvenanceManager } from "./ProvenanceManager.js";
|
|
25
|
+
import { NewerVersionSchemaImportStrategy, } from "./schema-processing/SchemaProcessingStrategy.js";
|
|
26
|
+
import { SchemaProcessingCoordinator } from "./schema-processing/SchemaProcessingCoordinator.js";
|
|
27
|
+
import { ChangesetScanner, } from "./ChangesetScanner.js";
|
|
28
|
+
import { IModelTransformerError, IModelTransformerErrorScope, } from "./IModelTransformerError.js";
|
|
29
|
+
const loggerCategory = TransformerLoggerCategory.IModelTransformer;
|
|
64
30
|
/** Key of a relationship's source and target element ids. */
|
|
65
31
|
function relationshipEndpointsKey(sourceId, targetId) {
|
|
66
32
|
return `${sourceId}|${targetId}`;
|
|
67
33
|
}
|
|
68
34
|
/**
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
* which matches the possible containers of references in [Element.requiredReferenceKeys]($backend).
|
|
35
|
+
* Get the Id64 held by a required reference.
|
|
36
|
+
* [Element.requiredReferenceKeys]($backend) hold either a raw Id64String or a RelatedElement-like object with an `id` property.
|
|
72
37
|
* @internal
|
|
73
38
|
*/
|
|
74
|
-
function
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
core_bentley_1.ITwinError.throwError({
|
|
94
|
-
iTwinErrorId: {
|
|
95
|
-
scope: IModelTransformerError_1.IModelTransformerErrorScope,
|
|
96
|
-
key: IModelTransformerError_1.IModelTransformerError.InvalidEntityReference,
|
|
97
|
-
},
|
|
98
|
-
message: [
|
|
99
|
-
`Id64 container '${JSON.stringify(idContainer)}' is unsupported.`,
|
|
100
|
-
"Currently only singular Id64 strings or prop-like objects containing an 'id' property are supported.",
|
|
101
|
-
].join("\n"),
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
return results;
|
|
39
|
+
function requiredReferenceId(idContainer) {
|
|
40
|
+
if (idContainer === undefined)
|
|
41
|
+
return undefined;
|
|
42
|
+
if (typeof idContainer === "string") {
|
|
43
|
+
assert(() => Id64.isValidId64(idContainer));
|
|
44
|
+
return idContainer;
|
|
45
|
+
}
|
|
46
|
+
if (idContainer && typeof idContainer === "object" && "id" in idContainer)
|
|
47
|
+
return idContainer.id;
|
|
48
|
+
ITwinError.throwError({
|
|
49
|
+
iTwinErrorId: {
|
|
50
|
+
scope: IModelTransformerErrorScope,
|
|
51
|
+
key: IModelTransformerError.InvalidEntityReference,
|
|
52
|
+
},
|
|
53
|
+
message: [
|
|
54
|
+
`Id64 container '${JSON.stringify(idContainer)}' is unsupported.`,
|
|
55
|
+
"Currently only singular Id64 strings or prop-like objects containing an 'id' property are supported.",
|
|
56
|
+
].join("\n"),
|
|
57
|
+
});
|
|
105
58
|
}
|
|
106
59
|
/** Base class used to transform a source iModel into a different target iModel.
|
|
107
60
|
* @see [iModel Transformation and Data Exchange]($docs/learning/transformer/index.md), [IModelExporter]($transformer), [IModelImporter]($transformer)
|
|
108
61
|
* @beta
|
|
109
62
|
*/
|
|
110
|
-
class IModelTransformer extends
|
|
63
|
+
export class IModelTransformer extends IModelExportHandler {
|
|
111
64
|
/** The IModelExporter that will export from the source iModel. */
|
|
112
65
|
exporter;
|
|
113
66
|
_schemaProcessingCoordinator;
|
|
@@ -176,11 +129,11 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
176
129
|
_isProvenanceInitTransform;
|
|
177
130
|
/** The element classes that are considered to define provenance in the iModel */
|
|
178
131
|
static get provenanceElementClasses() {
|
|
179
|
-
return
|
|
132
|
+
return ProvenanceManager.provenanceElementClasses;
|
|
180
133
|
}
|
|
181
134
|
/** The element aspect classes that are considered to define provenance in the iModel */
|
|
182
135
|
static get provenanceElementAspectClasses() {
|
|
183
|
-
return
|
|
136
|
+
return ProvenanceManager.provenanceElementAspectClasses;
|
|
184
137
|
}
|
|
185
138
|
/** Construct a new IModelTransformer
|
|
186
139
|
* @param args The required arguments including source and target.
|
|
@@ -194,23 +147,23 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
194
147
|
...options,
|
|
195
148
|
// non-falsy defaults
|
|
196
149
|
cloneUsingBinaryGeometry: options?.cloneUsingBinaryGeometry ?? true,
|
|
197
|
-
targetScopeElementId: options?.targetScopeElementId ??
|
|
150
|
+
targetScopeElementId: options?.targetScopeElementId ?? IModel.rootSubjectId,
|
|
198
151
|
danglingReferencesBehavior: options?.danglingReferencesBehavior ?? "reject",
|
|
199
152
|
branchRelationshipDataBehavior: options?.branchRelationshipDataBehavior ?? "reject",
|
|
200
153
|
skipPropagateChangesToRootElements: options?.skipPropagateChangesToRootElements ?? true,
|
|
201
154
|
tryAlignGeolocation: options?.tryAlignGeolocation ?? false,
|
|
202
155
|
};
|
|
203
156
|
// check if authorization client is defined
|
|
204
|
-
if (
|
|
205
|
-
|
|
157
|
+
if (IModelHost.authorizationClient === undefined) {
|
|
158
|
+
Logger.logWarning(loggerCategory, "Authorization client is not set in IModelHost. If the transformer needs an accessToken, then it will fail.");
|
|
206
159
|
}
|
|
207
160
|
this._isProvenanceInitTransform = this._options
|
|
208
161
|
.wasSourceIModelCopiedToTarget
|
|
209
162
|
? true
|
|
210
163
|
: undefined;
|
|
211
164
|
// initialize exporter and sourceDb
|
|
212
|
-
if (source instanceof
|
|
213
|
-
this.exporter = new
|
|
165
|
+
if (source instanceof IModelDb) {
|
|
166
|
+
this.exporter = new IModelExporter(source);
|
|
214
167
|
}
|
|
215
168
|
else {
|
|
216
169
|
this.exporter = source;
|
|
@@ -223,11 +176,11 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
223
176
|
IModelTransformer.provenanceElementClasses.forEach((cls) => this.exporter.excludeElementClass(cls.classFullName));
|
|
224
177
|
IModelTransformer.provenanceElementAspectClasses.forEach((cls) => this.exporter.excludeElementAspectClass(cls.classFullName));
|
|
225
178
|
}
|
|
226
|
-
this.exporter.excludeElementAspectClass(
|
|
179
|
+
this.exporter.excludeElementAspectClass(ChannelRootAspect.classFullName); // Channel boundaries within the source iModel are not relevant to the target iModel
|
|
227
180
|
this.exporter.excludeElementAspectClass("BisCore:TextAnnotationData"); // This ElementAspect is auto-created by the BisCore:TextAnnotation2d/3d element handlers
|
|
228
181
|
// initialize importer and targetDb
|
|
229
|
-
if (target instanceof
|
|
230
|
-
this.importer = new
|
|
182
|
+
if (target instanceof EditTxn) {
|
|
183
|
+
this.importer = new IModelImporter(target, {
|
|
231
184
|
preserveElementIdsForFiltering: this._options.preserveElementIdsForFiltering,
|
|
232
185
|
skipPropagateChangesToRootElements: this._options.skipPropagateChangesToRootElements,
|
|
233
186
|
});
|
|
@@ -239,7 +192,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
239
192
|
this.targetDb = this.importer.targetDb;
|
|
240
193
|
this._targetEditTxn = this.importer.editTxn;
|
|
241
194
|
this._sourceEditTxn = options?.sourceEditTxn;
|
|
242
|
-
this._schemaProcessingCoordinator = new
|
|
195
|
+
this._schemaProcessingCoordinator = new SchemaProcessingCoordinator({
|
|
243
196
|
exporter: this.exporter,
|
|
244
197
|
targetDb: this.targetDb,
|
|
245
198
|
getSchemaExportDirectory: () => this._schemaExportDir,
|
|
@@ -248,24 +201,24 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
248
201
|
});
|
|
249
202
|
this.exporter.elementAspectExportCoordinator.setPreparation(async (excludedClasses, elementIds) => this.prepareElementAspects(excludedClasses, elementIds));
|
|
250
203
|
// create the IModelCloneContext, it must be initialized later
|
|
251
|
-
this._cloneContext = new
|
|
204
|
+
this._cloneContext = new IModelCloneContext(this.sourceDb, this.targetDb);
|
|
252
205
|
this.importer.registerEntityExistenceCache(this._cloneContext.existenceCache);
|
|
253
206
|
this.setCodeValueBehavior("exact");
|
|
254
|
-
this._syncTypeResolver = new
|
|
255
|
-
this._provenanceManager = new
|
|
207
|
+
this._syncTypeResolver = new SyncTypeResolver(this.sourceDb, this.targetDb, this._options.targetScopeElementId, !!this._isProvenanceInitTransform, !!this._options.argsForProcessChanges);
|
|
208
|
+
this._provenanceManager = new ProvenanceManager(this._options.targetScopeElementId, this._options, this._cloneContext, this._syncTypeResolver, this._targetEditTxn, this._sourceEditTxn);
|
|
256
209
|
if (this._options.tryAlignGeolocation) {
|
|
257
210
|
if (this.sourceDb.geographicCoordinateSystem ||
|
|
258
211
|
this.targetDb.geographicCoordinateSystem) {
|
|
259
|
-
|
|
212
|
+
Logger.logTrace(loggerCategory, "Aligning Additional transforms between imodels due to imodels containing GeographicCoordinateSystem data");
|
|
260
213
|
this._linearSpatialTransform =
|
|
261
214
|
this.calculateTransformFromHelmertTransforms();
|
|
262
215
|
}
|
|
263
216
|
else if (this.sourceDb.ecefLocation && this.targetDb.ecefLocation) {
|
|
264
|
-
|
|
217
|
+
Logger.logTrace(loggerCategory, "Aligning ECEF Location's between imodels due to imodels not containing GeographicCoordinateSystem data");
|
|
265
218
|
this._linearSpatialTransform = this.calculateEcefTransform();
|
|
266
219
|
}
|
|
267
220
|
else
|
|
268
|
-
|
|
221
|
+
Logger.logTrace(loggerCategory, "No Geolcation data to align, both GCS and ECEF are undefined");
|
|
269
222
|
}
|
|
270
223
|
}
|
|
271
224
|
/** validates that the importer set on the transformer has the same values for its shared options as the transformer.
|
|
@@ -274,20 +227,20 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
274
227
|
validateSharedOptionsMatch() {
|
|
275
228
|
if (Boolean(this._options.preserveElementIdsForFiltering) !==
|
|
276
229
|
this.importer.options.preserveElementIdsForFiltering) {
|
|
277
|
-
|
|
230
|
+
ITwinError.throwError({
|
|
278
231
|
iTwinErrorId: {
|
|
279
|
-
scope:
|
|
280
|
-
key:
|
|
232
|
+
scope: IModelTransformerErrorScope,
|
|
233
|
+
key: IModelTransformerError.ImporterOptionMismatch,
|
|
281
234
|
},
|
|
282
235
|
message: "A custom importer was passed as a target but its 'preserveElementIdsForFiltering' option is out of sync with the transformer's option.",
|
|
283
236
|
});
|
|
284
237
|
}
|
|
285
238
|
if (Boolean(this._options.skipPropagateChangesToRootElements) !==
|
|
286
239
|
this.importer.options.skipPropagateChangesToRootElements) {
|
|
287
|
-
|
|
240
|
+
ITwinError.throwError({
|
|
288
241
|
iTwinErrorId: {
|
|
289
|
-
scope:
|
|
290
|
-
key:
|
|
242
|
+
scope: IModelTransformerErrorScope,
|
|
243
|
+
key: IModelTransformerError.ImporterOptionMismatch,
|
|
291
244
|
},
|
|
292
245
|
message: "A custom importer was passed as a target but its 'skipPropagateChangesToRootElements' option is out of sync with the transformer's option.",
|
|
293
246
|
});
|
|
@@ -295,25 +248,25 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
295
248
|
}
|
|
296
249
|
/** Dispose any native resources associated with this IModelTransformer. */
|
|
297
250
|
dispose() {
|
|
298
|
-
|
|
251
|
+
Logger.logTrace(loggerCategory, "dispose()");
|
|
299
252
|
this.importer.unregisterEntityExistenceCache(this._cloneContext.existenceCache);
|
|
300
253
|
this._cloneContext.existenceCache.clear();
|
|
301
254
|
this._cloneContext[Symbol.dispose]();
|
|
302
255
|
}
|
|
303
256
|
/** Log current settings that affect IModelTransformer's behavior. */
|
|
304
257
|
logSettings() {
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
258
|
+
Logger.logInfo(TransformerLoggerCategory.IModelExporter, `this.exporter.visitElements=${this.exporter.visitElements}`);
|
|
259
|
+
Logger.logInfo(TransformerLoggerCategory.IModelExporter, `this.exporter.visitRelationships=${this.exporter.visitRelationships}`);
|
|
260
|
+
Logger.logInfo(TransformerLoggerCategory.IModelExporter, `this.exporter.wantGeometry=${this.exporter.wantGeometry}`);
|
|
261
|
+
Logger.logInfo(TransformerLoggerCategory.IModelExporter, `this.exporter.wantSystemSchemas=${this.exporter.wantSystemSchemas}`);
|
|
262
|
+
Logger.logInfo(TransformerLoggerCategory.IModelExporter, `this.exporter.wantTemplateModels=${this.exporter.wantTemplateModels}`);
|
|
263
|
+
Logger.logInfo(loggerCategory, `this.targetScopeElementId=${this.targetScopeElementId}`);
|
|
264
|
+
Logger.logInfo(loggerCategory, `this._noProvenance=${this._options.noProvenance}`);
|
|
265
|
+
Logger.logInfo(loggerCategory, `this._includeSourceProvenance=${this._options.includeSourceProvenance}`);
|
|
266
|
+
Logger.logInfo(loggerCategory, `this._cloneUsingBinaryGeometry=${this._options.cloneUsingBinaryGeometry}`);
|
|
267
|
+
Logger.logInfo(loggerCategory, `this._wasSourceIModelCopiedToTarget=${this._options.wasSourceIModelCopiedToTarget}`);
|
|
268
|
+
Logger.logInfo(TransformerLoggerCategory.IModelImporter, `this.importer.autoExtendProjectExtents=${JSON.stringify(this.importer.options.autoExtendProjectExtents)}`);
|
|
269
|
+
Logger.logInfo(TransformerLoggerCategory.IModelImporter, `this.importer.simplifyElementGeometry=${this.importer.options.simplifyElementGeometry}`);
|
|
317
270
|
}
|
|
318
271
|
/**
|
|
319
272
|
* Previously the transformer would insert provenance always pointing to the "target" relationship.
|
|
@@ -394,34 +347,34 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
394
347
|
* @note This can be called more than once for an element in arbitrary order, so it should not have side-effects.
|
|
395
348
|
*/
|
|
396
349
|
async onTransformElement(sourceElement) {
|
|
397
|
-
|
|
350
|
+
Logger.logTrace(loggerCategory, `onTransformElement(${sourceElement.id}) "${sourceElement.getDisplayLabel()}"`);
|
|
398
351
|
const targetElementProps = await this._cloneContext.cloneElement(sourceElement, {
|
|
399
352
|
binaryGeometry: this._options.cloneUsingBinaryGeometry,
|
|
400
353
|
});
|
|
401
354
|
// Special case: source element is the root subject
|
|
402
|
-
if (sourceElement.id ===
|
|
355
|
+
if (sourceElement.id === IModel.rootSubjectId) {
|
|
403
356
|
const targetElementId = this.context.findTargetElementId(sourceElement.id);
|
|
404
357
|
// When remapping rootSubject from source to non root subject in target, the code.scope gets remapped incorrectly.
|
|
405
358
|
// This is because the rootSubject has no parent and its code.scope is unique in that it is the id of itself.
|
|
406
359
|
// For all other subjects which do have parents the code.scope and its parent should be in agreement.
|
|
407
|
-
if (targetElementId !==
|
|
408
|
-
targetElementId !==
|
|
360
|
+
if (targetElementId !== Id64.invalid &&
|
|
361
|
+
targetElementId !== IModel.rootSubjectId) {
|
|
409
362
|
const targetElement = this.targetDb.elements.getElement(targetElementId);
|
|
410
363
|
targetElementProps.parent =
|
|
411
364
|
targetElement.parent ?? targetElementProps.parent;
|
|
412
365
|
targetElementProps.code.scope = targetElement.code.scope;
|
|
413
366
|
}
|
|
414
367
|
}
|
|
415
|
-
if (sourceElement instanceof
|
|
368
|
+
if (sourceElement instanceof Subject) {
|
|
416
369
|
if (targetElementProps.jsonProperties?.Subject?.Job) {
|
|
417
370
|
// don't propagate source channels into target (legacy bridge case)
|
|
418
371
|
targetElementProps.jsonProperties.Subject.Job = undefined;
|
|
419
372
|
}
|
|
420
373
|
}
|
|
421
374
|
if (this._linearSpatialTransform !== undefined &&
|
|
422
|
-
sourceElement instanceof
|
|
375
|
+
sourceElement instanceof GeometricElement3d) {
|
|
423
376
|
// can check the sourceElement since this IModelTransformer does not remap classes
|
|
424
|
-
const placement =
|
|
377
|
+
const placement = Placement3d.fromJSON(targetElementProps.placement);
|
|
425
378
|
if (placement.isValid) {
|
|
426
379
|
placement.multiplyTransform(this._linearSpatialTransform);
|
|
427
380
|
targetElementProps.placement = placement;
|
|
@@ -440,25 +393,25 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
440
393
|
const srcEcefLoc = this.sourceDb.ecefLocation;
|
|
441
394
|
const targetEcefLoc = this.targetDb.ecefLocation;
|
|
442
395
|
if (srcEcefLoc === undefined || targetEcefLoc === undefined) {
|
|
443
|
-
|
|
396
|
+
ITwinError.throwError({
|
|
444
397
|
iTwinErrorId: {
|
|
445
|
-
scope:
|
|
446
|
-
key:
|
|
398
|
+
scope: IModelTransformerErrorScope,
|
|
399
|
+
key: IModelTransformerError.GeolocationUnavailable,
|
|
447
400
|
},
|
|
448
401
|
message: "Both source and target ECEF locations must be defined to calculate the transform.",
|
|
449
402
|
});
|
|
450
403
|
}
|
|
451
404
|
if (srcEcefLoc.getTransform().isAlmostEqual(targetEcefLoc.getTransform())) {
|
|
452
|
-
|
|
405
|
+
Logger.logTrace(loggerCategory, "ECEF data is already aligned. No spatial transforms needed.");
|
|
453
406
|
return undefined;
|
|
454
407
|
}
|
|
455
408
|
const srcSpatialToECEF = srcEcefLoc.getTransform(); // converts relative to ECEF in relation to source
|
|
456
409
|
const targetECEFToSpatial = targetEcefLoc.getTransform().inverse(); // converts ECEF to relative in relation to target
|
|
457
410
|
if (!targetECEFToSpatial) {
|
|
458
|
-
|
|
411
|
+
ITwinError.throwError({
|
|
459
412
|
iTwinErrorId: {
|
|
460
|
-
scope:
|
|
461
|
-
key:
|
|
413
|
+
scope: IModelTransformerErrorScope,
|
|
414
|
+
key: IModelTransformerError.GeolocationUnavailable,
|
|
462
415
|
},
|
|
463
416
|
message: "Failed to invert target ECEF transform.",
|
|
464
417
|
});
|
|
@@ -468,48 +421,48 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
468
421
|
}
|
|
469
422
|
static convertHelmertToTransform(helmert) {
|
|
470
423
|
if (!helmert) {
|
|
471
|
-
return
|
|
424
|
+
return Transform.createIdentity();
|
|
472
425
|
}
|
|
473
|
-
const rotationXY =
|
|
426
|
+
const rotationXY = Matrix3d.createRotationAroundAxisIndex(AxisIndex.Z, Angle.createDegrees(helmert?.rotDeg));
|
|
474
427
|
rotationXY.scaleColumnsInPlace(helmert.scale, helmert.scale, 1.0);
|
|
475
|
-
const translation =
|
|
476
|
-
const helmertTransform =
|
|
428
|
+
const translation = Vector3d.create(helmert.translationX, helmert.translationY, helmert.translationZ);
|
|
429
|
+
const helmertTransform = Transform.createRefs(translation, rotationXY);
|
|
477
430
|
return helmertTransform;
|
|
478
431
|
}
|
|
479
432
|
calculateTransformFromHelmertTransforms() {
|
|
480
433
|
if (this.sourceDb.geographicCoordinateSystem?.horizontalCRS === undefined ||
|
|
481
434
|
this.sourceDb.geographicCoordinateSystem?.verticalCRS === undefined) {
|
|
482
|
-
|
|
435
|
+
ITwinError.throwError({
|
|
483
436
|
iTwinErrorId: {
|
|
484
|
-
scope:
|
|
485
|
-
key:
|
|
437
|
+
scope: IModelTransformerErrorScope,
|
|
438
|
+
key: IModelTransformerError.GeographicCoordinateSystemUnavailable,
|
|
486
439
|
},
|
|
487
440
|
message: "Source iModel does not have a geographic coordinate system defined.",
|
|
488
441
|
});
|
|
489
442
|
}
|
|
490
443
|
if (this.targetDb.geographicCoordinateSystem?.horizontalCRS === undefined ||
|
|
491
444
|
this.targetDb.geographicCoordinateSystem.verticalCRS === undefined) {
|
|
492
|
-
|
|
445
|
+
ITwinError.throwError({
|
|
493
446
|
iTwinErrorId: {
|
|
494
|
-
scope:
|
|
495
|
-
key:
|
|
447
|
+
scope: IModelTransformerErrorScope,
|
|
448
|
+
key: IModelTransformerError.GeographicCoordinateSystemUnavailable,
|
|
496
449
|
},
|
|
497
450
|
message: "Target iModel does not have a geographic coordinate system defined.",
|
|
498
451
|
});
|
|
499
452
|
}
|
|
500
453
|
if (!this.sourceDb.geographicCoordinateSystem.horizontalCRS.equals(this.targetDb.geographicCoordinateSystem.horizontalCRS) ||
|
|
501
454
|
!this.sourceDb.geographicCoordinateSystem.verticalCRS.equals(this.targetDb.geographicCoordinateSystem.verticalCRS)) {
|
|
502
|
-
|
|
455
|
+
ITwinError.throwError({
|
|
503
456
|
iTwinErrorId: {
|
|
504
|
-
scope:
|
|
505
|
-
key:
|
|
457
|
+
scope: IModelTransformerErrorScope,
|
|
458
|
+
key: IModelTransformerError.GeographicCoordinateSystemMismatch,
|
|
506
459
|
},
|
|
507
460
|
message: "Source and target geographic coordinate systems must match to calculate the spatial transform.",
|
|
508
461
|
});
|
|
509
462
|
}
|
|
510
463
|
if (this.sourceDb.geographicCoordinateSystem.additionalTransform ===
|
|
511
464
|
this.targetDb.geographicCoordinateSystem.additionalTransform) {
|
|
512
|
-
|
|
465
|
+
Logger.logTrace(loggerCategory, "Geolocation data is already aligned. No spatial transforms needed.");
|
|
513
466
|
return undefined;
|
|
514
467
|
}
|
|
515
468
|
const srcScale = this.sourceDb.geographicCoordinateSystem.additionalTransform
|
|
@@ -517,10 +470,10 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
517
470
|
const targetScale = this.targetDb.geographicCoordinateSystem.additionalTransform
|
|
518
471
|
?.helmert2DWithZOffset?.scale ?? 1;
|
|
519
472
|
if (srcScale !== targetScale) {
|
|
520
|
-
|
|
473
|
+
ITwinError.throwError({
|
|
521
474
|
iTwinErrorId: {
|
|
522
|
-
scope:
|
|
523
|
-
key:
|
|
475
|
+
scope: IModelTransformerErrorScope,
|
|
476
|
+
key: IModelTransformerError.GeographicCoordinateSystemMismatch,
|
|
524
477
|
},
|
|
525
478
|
message: "Spatial transform is non rigid. Source and target Helmert transforms must have the same scale to calculate a rigid spatial transform.",
|
|
526
479
|
});
|
|
@@ -530,10 +483,10 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
530
483
|
const targetTransformInv = IModelTransformer.convertHelmertToTransform(this.targetDb.geographicCoordinateSystem.additionalTransform
|
|
531
484
|
?.helmert2DWithZOffset).inverse(); // negates target helmert transform that is applied at render time
|
|
532
485
|
if (!targetTransformInv) {
|
|
533
|
-
|
|
486
|
+
ITwinError.throwError({
|
|
534
487
|
iTwinErrorId: {
|
|
535
|
-
scope:
|
|
536
|
-
key:
|
|
488
|
+
scope: IModelTransformerErrorScope,
|
|
489
|
+
key: IModelTransformerError.GeolocationUnavailable,
|
|
537
490
|
},
|
|
538
491
|
message: "Failed to invert target Helmert transform.",
|
|
539
492
|
});
|
|
@@ -549,6 +502,26 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
549
502
|
* A source relationship deleted and recreated with the same endpoints maps to the same target relationship, which must not be deleted.
|
|
550
503
|
*/
|
|
551
504
|
_reimportedTargetRelationshipIds = new Set();
|
|
505
|
+
/** Same-iModel only: whether elements of an ECClassId are non-recipe DefinitionElements that are reused in place. */
|
|
506
|
+
_sameIModelReusableDefinitionClasses = new Map();
|
|
507
|
+
isSameIModelReusableDefinition(elementId) {
|
|
508
|
+
// Reading ECClassId through a cached SQLite statement avoids loading the whole referenced element.
|
|
509
|
+
// bis_Element holds every element, and the primary connection sees uncommitted inserts.
|
|
510
|
+
const classId = this.sourceDb.withPreparedSqliteStatement("SELECT ECClassId FROM bis_Element WHERE Id=?", (stmt) => {
|
|
511
|
+
stmt.bindId(1, elementId);
|
|
512
|
+
return stmt.nextRow() ? stmt.getValueId(0) : undefined;
|
|
513
|
+
});
|
|
514
|
+
if (classId === undefined)
|
|
515
|
+
return false;
|
|
516
|
+
let isReusable = this._sameIModelReusableDefinitionClasses.get(classId);
|
|
517
|
+
if (isReusable === undefined) {
|
|
518
|
+
// Class inheritance needs EC metadata, so classify each class once in ECSQL.
|
|
519
|
+
isReusable = this.sourceDb.withQueryReader(`SELECT 1 FROM ${DefinitionElement.classFullName}
|
|
520
|
+
WHERE ECInstanceId=? AND ECClassId IS NOT (${RecipeDefinitionElement.classFullName})`, (reader) => reader.step(), QueryBinder.from([elementId]));
|
|
521
|
+
this._sameIModelReusableDefinitionClasses.set(classId, isReusable);
|
|
522
|
+
}
|
|
523
|
+
return isReusable;
|
|
524
|
+
}
|
|
552
525
|
/** Returns true if a change within sourceElement is detected.
|
|
553
526
|
* @param sourceElement The Element from the source iModel
|
|
554
527
|
* @note A subclass can override this method to provide custom change detection behavior.
|
|
@@ -570,7 +543,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
570
543
|
wantBRepData: this.exporter.wantGeometry,
|
|
571
544
|
});
|
|
572
545
|
const targetId = this.context.findTargetElementId(sourceElementId);
|
|
573
|
-
if (
|
|
546
|
+
if (Id64.isInvalid(targetId)) {
|
|
574
547
|
throw new Error(`source-target element mapping not found for element "${sourceElementId}" when completing partially committed elements. This is a bug.`);
|
|
575
548
|
}
|
|
576
549
|
const targetProps = await this.onTransformElement(sourceElement);
|
|
@@ -581,7 +554,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
581
554
|
for (const sourceAspectId of this._partiallyCommittedAspectIds) {
|
|
582
555
|
const sourceAspect = this.sourceDb.elements.getAspect(sourceAspectId);
|
|
583
556
|
const targetAspectId = this.context.findTargetAspectId(sourceAspectId);
|
|
584
|
-
if (
|
|
557
|
+
if (Id64.isInvalid(targetAspectId)) {
|
|
585
558
|
throw new Error(`source-target aspect mapping not found for aspect "${sourceAspectId}" when completing partially committed aspects. This is a bug.`);
|
|
586
559
|
}
|
|
587
560
|
const targetAspectProps = await this.onTransformElementAspect(sourceAspect);
|
|
@@ -597,20 +570,20 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
597
570
|
markSourceEntityExists(entity) {
|
|
598
571
|
if (this._options.danglingReferencesBehavior !== "reject")
|
|
599
572
|
return;
|
|
600
|
-
this._cloneContext.existenceCache.markExists(this.sourceDb,
|
|
573
|
+
this._cloneContext.existenceCache.markExists(this.sourceDb, EntityReferences.from(entity));
|
|
601
574
|
}
|
|
602
575
|
async doAllReferencesExistInTarget(entity) {
|
|
603
576
|
let allReferencesExist = true;
|
|
604
577
|
const checkedReferences = [];
|
|
605
578
|
for (const referenceId of entity.getReferenceIds()) {
|
|
606
|
-
const referencedEntityId =
|
|
607
|
-
if (referencedEntityId ===
|
|
608
|
-
referencedEntityId ===
|
|
579
|
+
const referencedEntityId = EntityReferences.toId64(referenceId);
|
|
580
|
+
if (referencedEntityId === IModel.repositoryModelId ||
|
|
581
|
+
referencedEntityId === IModel.dictionaryId ||
|
|
609
582
|
referencedEntityId === "0xe") {
|
|
610
583
|
continue;
|
|
611
584
|
}
|
|
612
585
|
if (allReferencesExist &&
|
|
613
|
-
!
|
|
586
|
+
!EntityReferences.isValid(await this.context.findTargetEntityId(referenceId))) {
|
|
614
587
|
// if we care about references existing then we cannot return early and must check all other references.
|
|
615
588
|
if (this._options.danglingReferencesBehavior === "ignore") {
|
|
616
589
|
return false;
|
|
@@ -633,10 +606,10 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
633
606
|
const found = await this._cloneContext.existenceCache.existsAll(this.sourceDb, referenceIds);
|
|
634
607
|
for (const referenceId of referenceIds) {
|
|
635
608
|
if (!found.has(referenceId)) {
|
|
636
|
-
|
|
609
|
+
ITwinError.throwError({
|
|
637
610
|
iTwinErrorId: {
|
|
638
|
-
scope:
|
|
639
|
-
key:
|
|
611
|
+
scope: IModelTransformerErrorScope,
|
|
612
|
+
key: IModelTransformerError.DanglingReference,
|
|
640
613
|
},
|
|
641
614
|
message: [
|
|
642
615
|
`Found a reference to an element "${referenceId}" that doesn't exist while looking for references of "${entity.id}".`,
|
|
@@ -655,11 +628,11 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
655
628
|
*/
|
|
656
629
|
async processElement(sourceElementId) {
|
|
657
630
|
await this.initialize();
|
|
658
|
-
if (sourceElementId ===
|
|
659
|
-
|
|
631
|
+
if (sourceElementId === IModel.rootSubjectId) {
|
|
632
|
+
ITwinError.throwError({
|
|
660
633
|
iTwinErrorId: {
|
|
661
|
-
scope:
|
|
662
|
-
key:
|
|
634
|
+
scope: IModelTransformerErrorScope,
|
|
635
|
+
key: IModelTransformerError.RootSubjectNotProcessable,
|
|
663
636
|
},
|
|
664
637
|
message: "The root Subject should not be directly imported",
|
|
665
638
|
});
|
|
@@ -690,49 +663,38 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
690
663
|
*/
|
|
691
664
|
async preExportElement(sourceElement) {
|
|
692
665
|
if (!this.hasElementChanged(sourceElement)) {
|
|
693
|
-
|
|
666
|
+
Logger.logTrace(loggerCategory, `Skipping unchanged element (${sourceElement.id}, ${sourceElement.getDisplayLabel()}).`);
|
|
694
667
|
return;
|
|
695
668
|
}
|
|
696
669
|
const elemClass = sourceElement.constructor;
|
|
697
|
-
const unresolvedReferences =
|
|
698
|
-
|
|
699
|
-
const idContainer = sourceElement.asAny[referenceKey];
|
|
700
|
-
const referenceType = elemClass.requiredReferenceKeyTypeMap[referenceKey];
|
|
670
|
+
const unresolvedReferences = [];
|
|
671
|
+
for (const referenceKey of elemClass.requiredReferenceKeys) {
|
|
701
672
|
// For now we just consider all required references to be elements (as they are in biscore), and do not support
|
|
702
673
|
// entities that refuse to be inserted without a different kind of entity (e.g. aspect or relationship) first being inserted
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
.flat();
|
|
728
|
-
if (unresolvedReferences.length > 0) {
|
|
729
|
-
for (const reference of unresolvedReferences) {
|
|
730
|
-
const processState = await this.getElemTransformState(reference);
|
|
731
|
-
if (processState.needsElemImport)
|
|
732
|
-
await this.resolveRequiredElement(sourceElement.id, reference);
|
|
733
|
-
if (processState.needsModelImport)
|
|
734
|
-
await this.exporter.exportModel(reference);
|
|
735
|
-
}
|
|
674
|
+
const referenceType = elemClass.requiredReferenceKeyTypeMap[referenceKey];
|
|
675
|
+
assert(referenceType === ConcreteEntityTypes.Element ||
|
|
676
|
+
referenceType === ConcreteEntityTypes.Model);
|
|
677
|
+
const referenceId = requiredReferenceId(sourceElement.asAny[referenceKey]);
|
|
678
|
+
if (referenceId === undefined ||
|
|
679
|
+
referenceId === Id64.invalid ||
|
|
680
|
+
referenceId === IModel.rootSubjectId // not allowed to directly export the root subject
|
|
681
|
+
)
|
|
682
|
+
continue;
|
|
683
|
+
// Within the same iModel, reuse existing DefinitionElements instead of copying them.
|
|
684
|
+
// Same-iModel transformations, including TemplateModelCloner, rely on this.
|
|
685
|
+
// This also replaces any existing mapping for the definition with an identity mapping.
|
|
686
|
+
if (!this.context.isBetweenIModels &&
|
|
687
|
+
this.isSameIModelReusableDefinition(referenceId))
|
|
688
|
+
this.context.remapElement(referenceId, referenceId);
|
|
689
|
+
if (!Id64.isValid(this.context.findTargetElementId(referenceId)))
|
|
690
|
+
unresolvedReferences.push(referenceId);
|
|
691
|
+
}
|
|
692
|
+
for (const reference of unresolvedReferences) {
|
|
693
|
+
const processState = await this.getElemTransformState(reference);
|
|
694
|
+
if (processState.needsElemImport)
|
|
695
|
+
await this.resolveRequiredElement(sourceElement.id, reference);
|
|
696
|
+
if (processState.needsModelImport)
|
|
697
|
+
await this.exporter.exportModel(reference);
|
|
736
698
|
}
|
|
737
699
|
}
|
|
738
700
|
/** Makes sure an element that a changed element requires is mapped in the target before the changed element is imported.
|
|
@@ -761,7 +723,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
761
723
|
if (accepted)
|
|
762
724
|
await this.findExistingTargetElement(reference, await this.onTransformElement(reference));
|
|
763
725
|
}
|
|
764
|
-
if (
|
|
726
|
+
if (Id64.isValid(this.context.findTargetElementId(referenceId)))
|
|
765
727
|
return;
|
|
766
728
|
let message;
|
|
767
729
|
if (referenceChanged)
|
|
@@ -770,10 +732,10 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
770
732
|
message = `Element ${elementId} requires unchanged element ${referenceId}, which is not in the target iModel. Change processing does not insert unchanged elements; to insert element ${referenceId}, add it in addCustomChanges.`;
|
|
771
733
|
else
|
|
772
734
|
message = `Element ${elementId} requires element ${referenceId}, which the export filter rejects. Accept element ${referenceId}, or reject element ${elementId} and every element that requires it.`;
|
|
773
|
-
|
|
735
|
+
ITwinError.throwError({
|
|
774
736
|
iTwinErrorId: {
|
|
775
|
-
scope:
|
|
776
|
-
key:
|
|
737
|
+
scope: IModelTransformerErrorScope,
|
|
738
|
+
key: IModelTransformerError.DependencyMappingMissing,
|
|
777
739
|
},
|
|
778
740
|
message,
|
|
779
741
|
});
|
|
@@ -786,27 +748,27 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
786
748
|
if (this.context.isBetweenIModels &&
|
|
787
749
|
sourceElement.federationGuid !== undefined) {
|
|
788
750
|
const targetElementId = this.targetDb.elements.getIdFromFederationGuid(sourceElement.federationGuid);
|
|
789
|
-
if (targetElementId !== undefined &&
|
|
751
|
+
if (targetElementId !== undefined && Id64.isValid(targetElementId)) {
|
|
790
752
|
this.context.remapElement(sourceElement.id, targetElementId); // record that the targetElement was found
|
|
791
753
|
return targetElementId;
|
|
792
754
|
}
|
|
793
755
|
}
|
|
794
756
|
// check by Code as long as the CodeScope is valid (invalid means a missing reference so not worth checking)
|
|
795
|
-
if (!
|
|
796
|
-
return
|
|
757
|
+
if (!Id64.isValidId64(targetElementProps.code.scope))
|
|
758
|
+
return Id64.invalid;
|
|
797
759
|
// respond the same way to undefined code value as the @see Code class, but don't use that class because it trims
|
|
798
760
|
// whitespace from the value, and there are iModels out there with untrimmed whitespace that we ought not to trim
|
|
799
761
|
targetElementProps.code.value = targetElementProps.code.value ?? "";
|
|
800
762
|
// empty code values are stored as NULL and are never unique, so they cannot identify an existing target element
|
|
801
|
-
if (
|
|
802
|
-
return
|
|
763
|
+
if (Code.isEmpty(targetElementProps.code))
|
|
764
|
+
return Id64.invalid;
|
|
803
765
|
const maybeTargetElementId = this.queryElementIdByCode(this.targetDb, targetElementProps.code);
|
|
804
766
|
if (maybeTargetElementId === undefined)
|
|
805
|
-
return
|
|
767
|
+
return Id64.invalid;
|
|
806
768
|
const maybeTargetElem = this.targetDb.elements.getElement(maybeTargetElementId);
|
|
807
769
|
if (maybeTargetElem.classFullName !== targetElementProps.classFullName) {
|
|
808
|
-
targetElementProps.code =
|
|
809
|
-
return
|
|
770
|
+
targetElementProps.code = Code.createEmpty(); // clear out invalid code
|
|
771
|
+
return Id64.invalid;
|
|
810
772
|
}
|
|
811
773
|
// ensure code remapping doesn't change the target class
|
|
812
774
|
this.context.remapElement(sourceElement.id, maybeTargetElementId); // record that the targetElement was found by Code
|
|
@@ -815,12 +777,12 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
815
777
|
}
|
|
816
778
|
async getElemTransformState(elementId) {
|
|
817
779
|
const dbHasModel = async (db, id) => {
|
|
818
|
-
const maybeModelId =
|
|
780
|
+
const maybeModelId = EntityReferences.fromEntityType(id, ConcreteEntityTypes.Model);
|
|
819
781
|
return this._cloneContext.existenceCache.exists(db, maybeModelId);
|
|
820
782
|
};
|
|
821
783
|
const isSubModeled = await dbHasModel(this.sourceDb, elementId);
|
|
822
784
|
const idOfElemInTarget = this.context.findTargetElementId(elementId);
|
|
823
|
-
const isElemInTarget =
|
|
785
|
+
const isElemInTarget = Id64.invalid !== idOfElemInTarget;
|
|
824
786
|
const needsModelImport = isSubModeled &&
|
|
825
787
|
(!isElemInTarget || !(await dbHasModel(this.targetDb, idOfElemInTarget)));
|
|
826
788
|
return { needsElemImport: !isElemInTarget, needsModelImport };
|
|
@@ -833,25 +795,25 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
833
795
|
// and the cached ECSQL API (withPreparedStatement) is deprecated. Results match the ECSQL query because CodeValue
|
|
834
796
|
// is COLLATE NOCASE, ix_bis_Element_Code is unique, and the primary connection sees uncommitted target inserts.
|
|
835
797
|
queryElementIdByCode(iModel, code) {
|
|
836
|
-
if (
|
|
837
|
-
|
|
798
|
+
if (Id64.isInvalid(code.spec))
|
|
799
|
+
ITwinError.throwError({
|
|
838
800
|
iTwinErrorId: {
|
|
839
|
-
scope:
|
|
840
|
-
key:
|
|
801
|
+
scope: IModelTransformerErrorScope,
|
|
802
|
+
key: IModelTransformerError.InvalidCode,
|
|
841
803
|
},
|
|
842
804
|
message: "Invalid CodeSpec",
|
|
843
805
|
});
|
|
844
806
|
if (code.value === undefined)
|
|
845
|
-
|
|
807
|
+
ITwinError.throwError({
|
|
846
808
|
iTwinErrorId: {
|
|
847
|
-
scope:
|
|
848
|
-
key:
|
|
809
|
+
scope: IModelTransformerErrorScope,
|
|
810
|
+
key: IModelTransformerError.InvalidCode,
|
|
849
811
|
},
|
|
850
812
|
message: "Invalid Code",
|
|
851
813
|
});
|
|
852
814
|
return iModel.withPreparedSqliteStatement("SELECT Id FROM bis_Element WHERE CodeSpecId=? AND CodeScopeId=? AND CodeValue=?", (stmt) => {
|
|
853
815
|
stmt.bindId(1, code.spec);
|
|
854
|
-
stmt.bindId(2,
|
|
816
|
+
stmt.bindId(2, Id64.fromString(code.scope));
|
|
855
817
|
stmt.bindString(3, code.value);
|
|
856
818
|
return stmt.nextRow() ? stmt.getValueId(0) : undefined;
|
|
857
819
|
});
|
|
@@ -861,7 +823,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
861
823
|
*/
|
|
862
824
|
async onExportElement(sourceElement) {
|
|
863
825
|
this.markSourceEntityExists(sourceElement);
|
|
864
|
-
let targetElementId =
|
|
826
|
+
let targetElementId = Id64.invalid;
|
|
865
827
|
let targetElementProps;
|
|
866
828
|
if (this._options.wasSourceIModelCopiedToTarget) {
|
|
867
829
|
targetElementId = sourceElement.id;
|
|
@@ -873,27 +835,27 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
873
835
|
targetElementProps = await this.onTransformElement(sourceElement);
|
|
874
836
|
}
|
|
875
837
|
// if an existing remapping was not yet found, check by FederationGuid and then by Code
|
|
876
|
-
if (!
|
|
838
|
+
if (!Id64.isValid(targetElementId))
|
|
877
839
|
targetElementId = await this.findExistingTargetElement(sourceElement, targetElementProps);
|
|
878
840
|
if (!this.hasElementChanged(sourceElement)) {
|
|
879
|
-
|
|
841
|
+
Logger.logTrace(loggerCategory, `Skipping unchanged element (${sourceElement.id}, ${sourceElement.getDisplayLabel()}).`);
|
|
880
842
|
return;
|
|
881
843
|
}
|
|
882
844
|
if (!(await this.doAllReferencesExistInTarget(sourceElement))) {
|
|
883
845
|
this._partiallyCommittedElementIds.add(sourceElement.id);
|
|
884
846
|
}
|
|
885
847
|
// targetElementId will be valid (indicating update) or undefined (indicating insert)
|
|
886
|
-
targetElementProps.id =
|
|
848
|
+
targetElementProps.id = Id64.isValid(targetElementId)
|
|
887
849
|
? targetElementId
|
|
888
850
|
: undefined;
|
|
889
851
|
if (this._options.preserveElementIdsForFiltering) {
|
|
890
|
-
const isValid =
|
|
852
|
+
const isValid = Id64.isValid(targetElementId);
|
|
891
853
|
if (isValid && targetElementId !== sourceElement.id) {
|
|
892
854
|
// Element found with different id
|
|
893
|
-
|
|
855
|
+
ITwinError.throwError({
|
|
894
856
|
iTwinErrorId: {
|
|
895
|
-
scope:
|
|
896
|
-
key:
|
|
857
|
+
scope: IModelTransformerErrorScope,
|
|
858
|
+
key: IModelTransformerError.ElementIdNotPreservable,
|
|
897
859
|
},
|
|
898
860
|
message: `Element id(${sourceElement.id}) cannot be preserved. Found a different mapping(${targetElementId}) from source element`,
|
|
899
861
|
});
|
|
@@ -907,10 +869,10 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
907
869
|
// if we don't find mapping for source element in target(invalid) but another element with source id exists in target
|
|
908
870
|
if (sourceInTargetElemProps) {
|
|
909
871
|
// Element id is already taken by another element
|
|
910
|
-
|
|
872
|
+
ITwinError.throwError({
|
|
911
873
|
iTwinErrorId: {
|
|
912
|
-
scope:
|
|
913
|
-
key:
|
|
874
|
+
scope: IModelTransformerErrorScope,
|
|
875
|
+
key: IModelTransformerError.ElementIdNotPreservable,
|
|
914
876
|
},
|
|
915
877
|
message: `Element id(${sourceElement.id}) cannot be preserved. An unrelated element in the target already uses id: ${sourceElement.id}`,
|
|
916
878
|
});
|
|
@@ -929,7 +891,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
929
891
|
}
|
|
930
892
|
this.context.remapElement(sourceElement.id, targetElementProps.id);
|
|
931
893
|
if (this.sourceDb === this.targetDb) {
|
|
932
|
-
this._cloneContext.existenceCache.markExists(this.targetDb,
|
|
894
|
+
this._cloneContext.existenceCache.markExists(this.targetDb, EntityReferences.fromEntityType(targetElementProps.id, ConcreteEntityTypes.Element));
|
|
933
895
|
}
|
|
934
896
|
// the transformer does not currently 'split' or 'join' any elements, therefore, it does not
|
|
935
897
|
// insert external source aspects because federation guids are sufficient for this.
|
|
@@ -947,7 +909,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
947
909
|
: sourceElement.federationGuid;
|
|
948
910
|
if (!provenance) {
|
|
949
911
|
const aspectProps = await this.initElementProvenance(sourceElement.id, targetElementProps.id);
|
|
950
|
-
const foundEsaProps = await
|
|
912
|
+
const foundEsaProps = await ProvenanceManager.queryScopeExternalSourceAspect(provenanceDb, aspectProps);
|
|
951
913
|
if (foundEsaProps === undefined)
|
|
952
914
|
aspectProps.id = provenanceEditTxn.insertAspect(aspectProps);
|
|
953
915
|
else {
|
|
@@ -963,7 +925,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
963
925
|
const targetElementIds = new Set();
|
|
964
926
|
for (const sourceElementId of sourceElementIds) {
|
|
965
927
|
const targetElementId = this.context.findTargetElementId(sourceElementId);
|
|
966
|
-
if (
|
|
928
|
+
if (Id64.isValidId64(targetElementId) &&
|
|
967
929
|
!this._targetElementIdsRemappedByCode.has(targetElementId)) {
|
|
968
930
|
targetElementIds.add(targetElementId);
|
|
969
931
|
}
|
|
@@ -976,11 +938,11 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
976
938
|
async onExportModel(sourceModel) {
|
|
977
939
|
this.markSourceEntityExists(sourceModel);
|
|
978
940
|
if (this._options.skipPropagateChangesToRootElements &&
|
|
979
|
-
|
|
941
|
+
IModel.repositoryModelId === sourceModel.id)
|
|
980
942
|
return; // The RepositoryModel should not be directly imported
|
|
981
943
|
const targetModeledElementId = this.context.findTargetElementId(sourceModel.id);
|
|
982
944
|
// there can only be one repositoryModel per database, so ignore the repo model on remapped subjects
|
|
983
|
-
const isRemappedRootSubject = sourceModel.id ===
|
|
945
|
+
const isRemappedRootSubject = sourceModel.id === IModel.repositoryModelId &&
|
|
984
946
|
targetModeledElementId !== sourceModel.id;
|
|
985
947
|
if (isRemappedRootSubject)
|
|
986
948
|
return;
|
|
@@ -989,7 +951,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
989
951
|
if (targetModelProps.id === undefined) {
|
|
990
952
|
throw new Error("targetModelProps.id should be assigned by now");
|
|
991
953
|
}
|
|
992
|
-
this._cloneContext.existenceCache.markExists(this.targetDb,
|
|
954
|
+
this._cloneContext.existenceCache.markExists(this.targetDb, EntityReferences.fromEntityType(targetModelProps.id, ConcreteEntityTypes.Model));
|
|
993
955
|
this._targetModelsImportedInCurrentTransform.add(targetModelProps.id);
|
|
994
956
|
}
|
|
995
957
|
/** Override of [IModelExportHandler.onDeleteModel]($transformer) that is called when [IModelExporter]($transformer) detects that a [Model]($backend) has been deleted from the source iModel. */
|
|
@@ -998,13 +960,13 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
998
960
|
// - If only the model is deleted, [[initFromExternalSourceAspects]] will have already remapped the underlying element since it still exists.
|
|
999
961
|
// - If both were deleted, [[remapDeletedSourceEntities]] will find and remap the deleted element making this operation valid
|
|
1000
962
|
const targetModelId = this.context.findTargetElementId(sourceModelId);
|
|
1001
|
-
if (!
|
|
963
|
+
if (!Id64.isValidId64(targetModelId))
|
|
1002
964
|
return;
|
|
1003
965
|
// This handles cases where model with a partition element was remapped to
|
|
1004
966
|
// new element by code value after recreation.
|
|
1005
967
|
if (this._targetElementIdsRemappedByCode.has(targetModelId) &&
|
|
1006
968
|
this._targetModelsImportedInCurrentTransform.has(targetModelId)) {
|
|
1007
|
-
|
|
969
|
+
Logger.logTrace(loggerCategory, `Skipping delete operation for model (source id: ${sourceModelId}) because the target model (id: ${targetModelId}) was remapped by Code and re-imported during this transformation pass.`);
|
|
1008
970
|
return;
|
|
1009
971
|
}
|
|
1010
972
|
const sql = `
|
|
@@ -1017,7 +979,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1017
979
|
WHERE ECInstanceId=:targetModelId
|
|
1018
980
|
`;
|
|
1019
981
|
if (this.exporter.sourceDbChanges?.element.deleteIds.has(sourceModelId)) {
|
|
1020
|
-
const params = new
|
|
982
|
+
const params = new QueryBinder().bindId("targetModelId", targetModelId);
|
|
1021
983
|
const reader = this.targetDb.createQueryReader(sql, params, {
|
|
1022
984
|
usePrimaryConn: true,
|
|
1023
985
|
});
|
|
@@ -1033,9 +995,9 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1033
995
|
await this.importer.deleteModel(targetModelId);
|
|
1034
996
|
}
|
|
1035
997
|
catch (error) {
|
|
1036
|
-
const isDeletionProhibitedErr = error instanceof
|
|
1037
|
-
(error.errorNumber ===
|
|
1038
|
-
error.errorNumber ===
|
|
998
|
+
const isDeletionProhibitedErr = error instanceof IModelError &&
|
|
999
|
+
(error.errorNumber === IModelStatus.DeletionProhibited ||
|
|
1000
|
+
error.errorNumber === IModelStatus.ForeignKeyConstraint);
|
|
1039
1001
|
if (!isDeletionProhibitedErr)
|
|
1040
1002
|
throw error;
|
|
1041
1003
|
// Models are processed before elements, but a definition model cannot be deleted while it contains elements.
|
|
@@ -1067,7 +1029,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1067
1029
|
* @note This method is called from [[process]], so it only needs to be called directly when processing a subset of an iModel.
|
|
1068
1030
|
* @note After composing subset processing calls, call [[IModelImporter.finalize]] before saving target changes.
|
|
1069
1031
|
*/
|
|
1070
|
-
async processModelContents(sourceModelId, targetModelId, elementClassFullName =
|
|
1032
|
+
async processModelContents(sourceModelId, targetModelId, elementClassFullName = Element.classFullName) {
|
|
1071
1033
|
await this.initialize();
|
|
1072
1034
|
this.targetDb.models.getModel(targetModelId); // throws if Model does not exist
|
|
1073
1035
|
this.context.remapElement(sourceModelId, targetModelId); // set remapping in case importModelContents is called directly
|
|
@@ -1077,22 +1039,22 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1077
1039
|
async processSubjectSubModels(sourceSubjectId) {
|
|
1078
1040
|
await this.initialize();
|
|
1079
1041
|
// import DefinitionModels first
|
|
1080
|
-
const childDefinitionPartitionSql = `SELECT ECInstanceId FROM ${
|
|
1081
|
-
const params = new
|
|
1042
|
+
const childDefinitionPartitionSql = `SELECT ECInstanceId FROM ${DefinitionPartition.classFullName} WHERE Parent.Id=:subjectId`;
|
|
1043
|
+
const params = new QueryBinder().bindId("subjectId", sourceSubjectId);
|
|
1082
1044
|
for await (const row of this.sourceDb.createQueryReader(childDefinitionPartitionSql, params, { usePrimaryConn: true })) {
|
|
1083
1045
|
await this.processModel(row.id);
|
|
1084
1046
|
}
|
|
1085
1047
|
// import other partitions next
|
|
1086
|
-
const childPartitionSql = `SELECT ECInstanceId FROM ${
|
|
1048
|
+
const childPartitionSql = `SELECT ECInstanceId FROM ${InformationPartitionElement.classFullName} WHERE Parent.Id=:subjectId`;
|
|
1087
1049
|
for await (const row of this.sourceDb.createQueryReader(childPartitionSql, params, { usePrimaryConn: true })) {
|
|
1088
1050
|
const modelId = row.id;
|
|
1089
1051
|
const model = this.sourceDb.models.getModel(modelId);
|
|
1090
|
-
if (!(model instanceof
|
|
1052
|
+
if (!(model instanceof DefinitionModel)) {
|
|
1091
1053
|
await this.processModel(modelId);
|
|
1092
1054
|
}
|
|
1093
1055
|
}
|
|
1094
1056
|
// recurse into child Subjects
|
|
1095
|
-
const childSubjectSql = `SELECT ECInstanceId FROM ${
|
|
1057
|
+
const childSubjectSql = `SELECT ECInstanceId FROM ${Subject.classFullName} WHERE Parent.Id=:subjectId`;
|
|
1096
1058
|
for await (const row of this.sourceDb.createQueryReader(childSubjectSql, params, { usePrimaryConn: true })) {
|
|
1097
1059
|
await this.processSubjectSubModels(row.id);
|
|
1098
1060
|
}
|
|
@@ -1112,10 +1074,10 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1112
1074
|
};
|
|
1113
1075
|
targetModelProps.id = targetModeledElementId;
|
|
1114
1076
|
if (targetModelProps.parentModel === undefined) {
|
|
1115
|
-
|
|
1077
|
+
ITwinError.throwError({
|
|
1116
1078
|
iTwinErrorId: {
|
|
1117
|
-
scope:
|
|
1118
|
-
key:
|
|
1079
|
+
scope: IModelTransformerErrorScope,
|
|
1080
|
+
key: IModelTransformerError.ParentModelRequired,
|
|
1119
1081
|
},
|
|
1120
1082
|
message: "targetElementProps must have a defined parentModel",
|
|
1121
1083
|
});
|
|
@@ -1132,8 +1094,8 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1132
1094
|
});
|
|
1133
1095
|
// TODO: ignore if we remove change cache usage
|
|
1134
1096
|
if (!this._options.noDetachChangeCache) {
|
|
1135
|
-
if (
|
|
1136
|
-
|
|
1097
|
+
if (ChangeSummaryManager.isChangeCacheAttached(this.sourceDb))
|
|
1098
|
+
ChangeSummaryManager.detachChangeCache(this.sourceDb);
|
|
1137
1099
|
}
|
|
1138
1100
|
this.setCodeValueBehavior("trim-unicode-whitespace");
|
|
1139
1101
|
}
|
|
@@ -1165,7 +1127,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1165
1127
|
const targetRelationshipProps = this.onTransformRelationship(sourceRelationship);
|
|
1166
1128
|
const targetRelationshipInstanceId = await this.importer.importRelationship(targetRelationshipProps);
|
|
1167
1129
|
if (this._pendingRelationshipDeleteTargets.size > 0 &&
|
|
1168
|
-
|
|
1130
|
+
Id64.isValid(targetRelationshipInstanceId) &&
|
|
1169
1131
|
(this._pendingRelationshipDeleteTargets.has(targetRelationshipInstanceId) ||
|
|
1170
1132
|
this._pendingRelationshipDeleteTargets.has(relationshipEndpointsKey(targetRelationshipProps.sourceId, targetRelationshipProps.targetId)))) {
|
|
1171
1133
|
this._reimportedTargetRelationshipIds.add(targetRelationshipInstanceId);
|
|
@@ -1173,7 +1135,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1173
1135
|
const provenanceDb = await this.getProvenanceDb();
|
|
1174
1136
|
const provenanceEditTxn = await this._provenanceManager.getProvenanceEditTxn();
|
|
1175
1137
|
if (!this._options.noProvenance &&
|
|
1176
|
-
|
|
1138
|
+
Id64.isValid(targetRelationshipInstanceId)) {
|
|
1177
1139
|
const needsEsaProvenance = this._options.forceExternalSourceAspectProvenance ||
|
|
1178
1140
|
!this.relationshipEndpointsHaveFedGuids(sourceRelationship, endpointFedGuids);
|
|
1179
1141
|
if (needsEsaProvenance) {
|
|
@@ -1181,7 +1143,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1181
1143
|
sourceRelSourceElementId: sourceRelationship.sourceId,
|
|
1182
1144
|
targetRelSourceElementId: targetRelationshipProps.sourceId,
|
|
1183
1145
|
});
|
|
1184
|
-
const foundEsaProps = await
|
|
1146
|
+
const foundEsaProps = await ProvenanceManager.queryScopeExternalSourceAspect(provenanceDb, aspectProps);
|
|
1185
1147
|
// onExportRelationship doesn't need to call updateAspect if esaProps were found, because relationship provenance doesn't have the same concept of a version as element provenance (which uses last mod time on the elements).
|
|
1186
1148
|
if (undefined === foundEsaProps) {
|
|
1187
1149
|
aspectProps.id = provenanceEditTxn.insertAspect(aspectProps);
|
|
@@ -1201,11 +1163,11 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1201
1163
|
* This override propagates the delete to the target iModel via [IModelImporter.deleteRelationship]($transformer).
|
|
1202
1164
|
*/
|
|
1203
1165
|
async onDeleteRelationship(sourceRelInstanceId) {
|
|
1204
|
-
(
|
|
1166
|
+
nodeAssert(this._deletedSourceRelationshipData, "should be defined at initialization by now");
|
|
1205
1167
|
const deletedRelData = this._deletedSourceRelationshipData.get(sourceRelInstanceId);
|
|
1206
1168
|
if (!deletedRelData) {
|
|
1207
1169
|
// this can occur if both the source and target deleted it
|
|
1208
|
-
|
|
1170
|
+
Logger.logWarning(loggerCategory, "tried to delete a relationship that wasn't in change data");
|
|
1209
1171
|
return;
|
|
1210
1172
|
}
|
|
1211
1173
|
const id = deletedRelData.relId ??
|
|
@@ -1215,7 +1177,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1215
1177
|
})?.id;
|
|
1216
1178
|
if (id && this._reimportedTargetRelationshipIds.has(id)) {
|
|
1217
1179
|
// The source relationship was recreated with the same endpoints and already imported into this target relationship.
|
|
1218
|
-
|
|
1180
|
+
Logger.logTrace(loggerCategory, `Skipping delete of target relationship ${id} because source relationship ${sourceRelInstanceId} was recreated`);
|
|
1219
1181
|
}
|
|
1220
1182
|
else if (id) {
|
|
1221
1183
|
await this.importer.deleteRelationship({
|
|
@@ -1229,7 +1191,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1229
1191
|
}
|
|
1230
1192
|
catch (error) {
|
|
1231
1193
|
// This aspect may no longer exist if it was deleted at some other point during the transformation. This is fine.
|
|
1232
|
-
if (error.errorNumber ===
|
|
1194
|
+
if (error.errorNumber === IModelStatus.NotFound)
|
|
1233
1195
|
return;
|
|
1234
1196
|
throw error;
|
|
1235
1197
|
}
|
|
@@ -1246,12 +1208,12 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1246
1208
|
targetRelationshipProps.targetId = this.context.findTargetElementId(sourceRelationship.targetId);
|
|
1247
1209
|
// TODO: move to cloneRelationship in IModelCloneContext
|
|
1248
1210
|
const relationshipClass = sourceRelationship.iModel.schemaContext.getSchemaItemSync(sourceRelationship.schemaItemKey, ECSchemaMetaData.RelationshipClass);
|
|
1249
|
-
|
|
1211
|
+
assert(relationshipClass !== undefined, `Cannot get metadata for ${sourceRelationship.classFullName}.`);
|
|
1250
1212
|
for (const property of relationshipClass.getPropertiesSync()) {
|
|
1251
1213
|
const propertyName = property.name;
|
|
1252
1214
|
if (property.isPrimitive() && "Id" === property.extendedTypeName) {
|
|
1253
|
-
targetRelationshipProps[
|
|
1254
|
-
this.context.findTargetElementId(sourceRelationship.asAny[
|
|
1215
|
+
targetRelationshipProps[ECJsNames.toJsName(propertyName)] =
|
|
1216
|
+
this.context.findTargetElementId(sourceRelationship.asAny[ECJsNames.toJsName(propertyName)]);
|
|
1255
1217
|
}
|
|
1256
1218
|
}
|
|
1257
1219
|
return targetRelationshipProps;
|
|
@@ -1259,7 +1221,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1259
1221
|
async shouldExportElementAspect(aspect) {
|
|
1260
1222
|
// An aspect cannot be exported when its owner has no source-to-target
|
|
1261
1223
|
// mapping.
|
|
1262
|
-
return this.context.findTargetElementId(aspect.element.id) !==
|
|
1224
|
+
return this.context.findTargetElementId(aspect.element.id) !== Id64.invalid;
|
|
1263
1225
|
}
|
|
1264
1226
|
async prepareElementAspects(excludedElementAspectClassFullNames, elementIds) {
|
|
1265
1227
|
if (!this.exporter.visitElements)
|
|
@@ -1269,7 +1231,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1269
1231
|
const targetElementIds = new Set();
|
|
1270
1232
|
for (const sourceElementId of elementIds) {
|
|
1271
1233
|
const targetElementId = this.context.findTargetElementId(sourceElementId);
|
|
1272
|
-
if (
|
|
1234
|
+
if (Id64.isValid(targetElementId)) {
|
|
1273
1235
|
targetElementIds.add(targetElementId);
|
|
1274
1236
|
}
|
|
1275
1237
|
}
|
|
@@ -1299,7 +1261,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1299
1261
|
}
|
|
1300
1262
|
}
|
|
1301
1263
|
const targetIds = await this.importer.importElementMultiAspects(await Promise.all(targetAspectPropsArray), (a) => {
|
|
1302
|
-
const isExternalSourceAspectFromTransformer = a instanceof
|
|
1264
|
+
const isExternalSourceAspectFromTransformer = a instanceof ExternalSourceAspect &&
|
|
1303
1265
|
a.scope?.id === this.targetScopeElementId;
|
|
1304
1266
|
return (!this._options.includeSourceProvenance ||
|
|
1305
1267
|
!isExternalSourceAspectFromTransformer);
|
|
@@ -1318,7 +1280,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1318
1280
|
return targetElementAspectProps;
|
|
1319
1281
|
}
|
|
1320
1282
|
/** The directory where schemas will be exported, a random temporary directory */
|
|
1321
|
-
_schemaExportDir = path.join(
|
|
1283
|
+
_schemaExportDir = path.join(KnownLocations.tmpdir, Guid.createValue());
|
|
1322
1284
|
/** Override of [IModelExportHandler.shouldExportSchema]($transformer) that is called to determine if a schema should be exported
|
|
1323
1285
|
* @note the default behavior doesn't import schemas older than those already in the target
|
|
1324
1286
|
*/
|
|
@@ -1326,7 +1288,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1326
1288
|
const versionInTarget = this.targetDb.querySchemaVersion(schemaKey.name);
|
|
1327
1289
|
if (versionInTarget === undefined)
|
|
1328
1290
|
return true;
|
|
1329
|
-
return Semver.gt(`${schemaKey.version.read}.${schemaKey.version.write}.${schemaKey.version.minor}`,
|
|
1291
|
+
return Semver.gt(`${schemaKey.version.read}.${schemaKey.version.write}.${schemaKey.version.minor}`, Schema.toSemverString(versionInTarget));
|
|
1330
1292
|
}
|
|
1331
1293
|
/** Serialize a source schema to the temporary directory used by [[processSchemas]].
|
|
1332
1294
|
* @returns A path to the serialized schema file.
|
|
@@ -1342,7 +1304,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1342
1304
|
* It is more efficient to process *data* changes after the schema changes have been saved.
|
|
1343
1305
|
*/
|
|
1344
1306
|
async processSchemas(options) {
|
|
1345
|
-
return this._schemaProcessingCoordinator.process(options?.strategy ?? new
|
|
1307
|
+
return this._schemaProcessingCoordinator.process(options?.strategy ?? new NewerVersionSchemaImportStrategy());
|
|
1346
1308
|
}
|
|
1347
1309
|
/** Cause all fonts to be exported from the source iModel and imported into the target iModel.
|
|
1348
1310
|
* @note This method is called from [[process]], so it only needs to be called directly when processing a subset of an iModel.
|
|
@@ -1385,8 +1347,8 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1385
1347
|
*/
|
|
1386
1348
|
async processSubject(sourceSubjectId, targetSubjectId) {
|
|
1387
1349
|
await this.initialize();
|
|
1388
|
-
this.sourceDb.elements.getElement(sourceSubjectId,
|
|
1389
|
-
this.targetDb.elements.getElement(targetSubjectId,
|
|
1350
|
+
this.sourceDb.elements.getElement(sourceSubjectId, Subject); // throws if sourceSubjectId is not a Subject
|
|
1351
|
+
this.targetDb.elements.getElement(targetSubjectId, Subject); // throws if targetSubjectId is not a Subject
|
|
1390
1352
|
this.context.remapElement(sourceSubjectId, targetSubjectId);
|
|
1391
1353
|
await this.processScopedElementExport(async () => {
|
|
1392
1354
|
await this.processChildElements(sourceSubjectId);
|
|
@@ -1429,7 +1391,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1429
1391
|
: undefined);
|
|
1430
1392
|
if (changedInstanceIds !== undefined) {
|
|
1431
1393
|
// The caller supplied changed IDs, so only deletion metadata is read.
|
|
1432
|
-
this._deletionBatches = await
|
|
1394
|
+
this._deletionBatches = await ChangesetScanner.scan(this.sourceDb, await ChangesetScanner.download(this.sourceDb, ranges), {});
|
|
1433
1395
|
}
|
|
1434
1396
|
else {
|
|
1435
1397
|
const scanResult = await this.collectChanges(ranges);
|
|
@@ -1466,8 +1428,8 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1466
1428
|
* the changesets to find deletion records.
|
|
1467
1429
|
* @beta
|
|
1468
1430
|
*/
|
|
1469
|
-
async collectChanges(ranges, changedInstanceIds = new
|
|
1470
|
-
const deletionBatches = await
|
|
1431
|
+
async collectChanges(ranges, changedInstanceIds = new ChangedInstanceIds(this.sourceDb)) {
|
|
1432
|
+
const deletionBatches = await ChangesetScanner.scan(this.sourceDb, await ChangesetScanner.download(this.sourceDb, ranges), { changedInstanceIds });
|
|
1471
1433
|
return { changedInstanceIds, deletionBatches };
|
|
1472
1434
|
}
|
|
1473
1435
|
/**
|
|
@@ -1497,12 +1459,12 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1497
1459
|
const alreadyImportedModelInserts = new Set();
|
|
1498
1460
|
this.exporter.sourceDbChanges?.element.insertIds.forEach((insertedSourceElementId) => {
|
|
1499
1461
|
const targetElementId = this.context.findTargetElementId(insertedSourceElementId);
|
|
1500
|
-
if (
|
|
1462
|
+
if (Id64.isValid(targetElementId))
|
|
1501
1463
|
alreadyImportedElementInserts.add(targetElementId);
|
|
1502
1464
|
});
|
|
1503
1465
|
this.exporter.sourceDbChanges?.model.insertIds.forEach((insertedSourceModelId) => {
|
|
1504
1466
|
const targetModelId = this.context.findTargetElementId(insertedSourceModelId);
|
|
1505
|
-
if (
|
|
1467
|
+
if (Id64.isValid(targetModelId))
|
|
1506
1468
|
alreadyImportedModelInserts.add(targetModelId);
|
|
1507
1469
|
});
|
|
1508
1470
|
this._deletedSourceRelationshipData = new Map();
|
|
@@ -1514,7 +1476,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1514
1476
|
const deletedScopeEsaByElementId = new Map();
|
|
1515
1477
|
for (const aspect of batch.externalSourceAspects) {
|
|
1516
1478
|
if (aspect.scopeId === this.targetScopeElementId &&
|
|
1517
|
-
aspect.kind ===
|
|
1479
|
+
aspect.kind === ExternalSourceAspect.Kind.Element)
|
|
1518
1480
|
deletedScopeEsaByElementId.set(aspect.elementId, aspect);
|
|
1519
1481
|
}
|
|
1520
1482
|
const deletedFederationGuidByElementId = new Map();
|
|
@@ -1554,9 +1516,9 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1554
1516
|
if (this.sourceDb === (await this.getProvenanceDb())) {
|
|
1555
1517
|
let identifierValue;
|
|
1556
1518
|
// TODO: clarify what happens if there are multiple (e.g. elements were merged)
|
|
1557
|
-
for await (const row of this.sourceDb.createQueryReader("SELECT esa.Identifier FROM bis.ExternalSourceAspect esa WHERE Scope.Id=:scopeId AND Kind=:kind AND Element.Id=:relatedElementId LIMIT 1",
|
|
1519
|
+
for await (const row of this.sourceDb.createQueryReader("SELECT esa.Identifier FROM bis.ExternalSourceAspect esa WHERE Scope.Id=:scopeId AND Kind=:kind AND Element.Id=:relatedElementId LIMIT 1", QueryBinder.from([
|
|
1558
1520
|
this.targetScopeElementId,
|
|
1559
|
-
|
|
1521
|
+
ExternalSourceAspect.Kind.Element,
|
|
1560
1522
|
sourceId,
|
|
1561
1523
|
]), { usePrimaryConn: true })) {
|
|
1562
1524
|
identifierValue = row.Identifier;
|
|
@@ -1629,7 +1591,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1629
1591
|
if (targetId === undefined &&
|
|
1630
1592
|
this.sourceDb === (await this._provenanceManager.getProvenanceSourceDb())) {
|
|
1631
1593
|
const contextTargetId = this.context.findTargetElementId(sourceId);
|
|
1632
|
-
if (
|
|
1594
|
+
if (Id64.isValidId64(contextTargetId))
|
|
1633
1595
|
targetId = contextTargetId;
|
|
1634
1596
|
}
|
|
1635
1597
|
// Entities inserted and deleted since the last synchronization were never synced and can be safely ignored.
|
|
@@ -1666,7 +1628,7 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1666
1628
|
const endChangesetId = this.sourceDb.changeset.id;
|
|
1667
1629
|
const [startChangesetIndex, endChangesetIndex] = await Promise.all([startChangesetIndexOrId, endChangesetId].map(async (indexOrId) => typeof indexOrId === "number"
|
|
1668
1630
|
? indexOrId
|
|
1669
|
-
:
|
|
1631
|
+
: BriefcaseManager.queryChangeset({
|
|
1670
1632
|
iModelId: this.sourceDb.iModelId,
|
|
1671
1633
|
changeset: { id: indexOrId },
|
|
1672
1634
|
}).then((changeset) => changeset.index)));
|
|
@@ -1675,10 +1637,10 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1675
1637
|
?.ignoreMissingChangesetsInSynchronizations &&
|
|
1676
1638
|
startChangesetIndex !== syncVersion.index + 1 &&
|
|
1677
1639
|
syncVersion.index !== -1) {
|
|
1678
|
-
|
|
1640
|
+
ITwinError.throwError({
|
|
1679
1641
|
iTwinErrorId: {
|
|
1680
|
-
scope:
|
|
1681
|
-
key:
|
|
1642
|
+
scope: IModelTransformerErrorScope,
|
|
1643
|
+
key: IModelTransformerError.SynchronizationRangeInvalid,
|
|
1682
1644
|
},
|
|
1683
1645
|
message: `synchronization is ${missingChangesets ? "missing changesets" : ""},` +
|
|
1684
1646
|
" startChangesetId should be" +
|
|
@@ -1690,9 +1652,9 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1690
1652
|
});
|
|
1691
1653
|
}
|
|
1692
1654
|
const changesetsToSkip = await this._provenanceManager.getChangesetsToSkip();
|
|
1693
|
-
|
|
1694
|
-
this._changesetRanges =
|
|
1695
|
-
|
|
1655
|
+
Logger.logTrace(loggerCategory, `changesets to skip: ${changesetsToSkip}`);
|
|
1656
|
+
this._changesetRanges = rangesFromRangeAndSkipped(startChangesetIndex, endChangesetIndex, changesetsToSkip);
|
|
1657
|
+
Logger.logTrace(loggerCategory, `ranges: ${this._changesetRanges}`);
|
|
1696
1658
|
/** Skipping indices found in the pendingSync and pendingReverseSync arrays can leave no ranges to process. */
|
|
1697
1659
|
this._sourceChangeDataState =
|
|
1698
1660
|
this._changesetRanges.length === 0 ? "no-changes" : "has-changes";
|
|
@@ -1700,19 +1662,19 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1700
1662
|
/** Asserts that the EditTxn is active before any write operations. */
|
|
1701
1663
|
assertEditTxnActive() {
|
|
1702
1664
|
if (!this._targetEditTxn.isActive) {
|
|
1703
|
-
|
|
1665
|
+
ITwinError.throwError({
|
|
1704
1666
|
iTwinErrorId: {
|
|
1705
|
-
scope:
|
|
1706
|
-
key:
|
|
1667
|
+
scope: IModelTransformerErrorScope,
|
|
1668
|
+
key: IModelTransformerError.EditTxnNotActive,
|
|
1707
1669
|
},
|
|
1708
1670
|
message: "The target EditTxn must be started before calling process(). Call targetEditTxn.start() before invoking the transformer.",
|
|
1709
1671
|
});
|
|
1710
1672
|
}
|
|
1711
1673
|
if (this._sourceEditTxn && !this._sourceEditTxn.isActive) {
|
|
1712
|
-
|
|
1674
|
+
ITwinError.throwError({
|
|
1713
1675
|
iTwinErrorId: {
|
|
1714
|
-
scope:
|
|
1715
|
-
key:
|
|
1676
|
+
scope: IModelTransformerErrorScope,
|
|
1677
|
+
key: IModelTransformerError.EditTxnNotActive,
|
|
1716
1678
|
},
|
|
1717
1679
|
message: "The source EditTxn was provided but is not active. Call sourceEditTxn.start() before invoking the transformer.",
|
|
1718
1680
|
});
|
|
@@ -1761,20 +1723,20 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1761
1723
|
await this.exporter.elementAspectExportCoordinator.run(async () => {
|
|
1762
1724
|
if (this._options.skipPropagateChangesToRootElements) {
|
|
1763
1725
|
// The RepositoryModel and root Subject of the target iModel should not be transformed.
|
|
1764
|
-
await this.exporter.exportChildElements(
|
|
1765
|
-
await this.exporter.exportModelContents(
|
|
1766
|
-
await this.exporter.exportSubModels(
|
|
1726
|
+
await this.exporter.exportChildElements(IModel.rootSubjectId); // start below the root Subject
|
|
1727
|
+
await this.exporter.exportModelContents(IModel.repositoryModelId, Element.classFullName, true); // after the Subject hierarchy, process the other elements of the RepositoryModel
|
|
1728
|
+
await this.exporter.exportSubModels(IModel.repositoryModelId); // start below the RepositoryModel
|
|
1767
1729
|
}
|
|
1768
1730
|
else {
|
|
1769
|
-
await this.exporter.exportModel(
|
|
1731
|
+
await this.exporter.exportModel(IModel.repositoryModelId);
|
|
1770
1732
|
}
|
|
1771
1733
|
await this.completePartiallyCommittedElements();
|
|
1772
1734
|
});
|
|
1773
1735
|
await this.completePartiallyCommittedAspects();
|
|
1774
|
-
await this.exporter.exportRelationships(
|
|
1736
|
+
await this.exporter.exportRelationships(ElementRefersToElements.classFullName);
|
|
1775
1737
|
if (this._options.forceExternalSourceAspectProvenance &&
|
|
1776
1738
|
(await this.shouldDetectDeletes())) {
|
|
1777
|
-
|
|
1739
|
+
Logger.logWarning(loggerCategory, "This workflows was deprecated in v1 and is no longer supported");
|
|
1778
1740
|
}
|
|
1779
1741
|
if (this._options.optimizeGeometry)
|
|
1780
1742
|
this.importer.optimizeGeometry(this._options.optimizeGeometry);
|
|
@@ -1844,11 +1806,10 @@ class IModelTransformer extends IModelExporter_1.IModelExportHandler {
|
|
|
1844
1806
|
}
|
|
1845
1807
|
}
|
|
1846
1808
|
}
|
|
1847
|
-
exports.IModelTransformer = IModelTransformer;
|
|
1848
1809
|
/** IModelTransformer that clones the contents of a template model.
|
|
1849
1810
|
* @beta
|
|
1850
1811
|
*/
|
|
1851
|
-
class TemplateModelCloner extends IModelTransformer {
|
|
1812
|
+
export class TemplateModelCloner extends IModelTransformer {
|
|
1852
1813
|
/** The Placement to apply to the template. */
|
|
1853
1814
|
_transform3d;
|
|
1854
1815
|
/** Accumulates the mapping of sourceElementIds to targetElementIds from the elements in the template model that were cloned. */
|
|
@@ -1858,7 +1819,7 @@ class TemplateModelCloner extends IModelTransformer {
|
|
|
1858
1819
|
* @note The expectation is that the template definitions are within the same iModel where instances will be placed.
|
|
1859
1820
|
*/
|
|
1860
1821
|
constructor(editTxn) {
|
|
1861
|
-
const target = new
|
|
1822
|
+
const target = new IModelImporter(editTxn, {
|
|
1862
1823
|
autoExtendProjectExtents: false, // autoExtendProjectExtents is intended for transformation service use cases, not template --> instance cloning
|
|
1863
1824
|
});
|
|
1864
1825
|
super({ source: editTxn.iModel, target }, { noProvenance: true }); // WIP: need to decide the proper way to handle provenance
|
|
@@ -1873,7 +1834,7 @@ class TemplateModelCloner extends IModelTransformer {
|
|
|
1873
1834
|
async placeTemplate3d(sourceTemplateModelId, targetModelId, placement) {
|
|
1874
1835
|
await this.initialize();
|
|
1875
1836
|
this.context.remapElement(sourceTemplateModelId, targetModelId);
|
|
1876
|
-
this._transform3d =
|
|
1837
|
+
this._transform3d = Transform.createOriginAndMatrix(placement.origin, placement.angles.toMatrix3d());
|
|
1877
1838
|
this._sourceIdToTargetIdMap = new Map();
|
|
1878
1839
|
await this.exporter.exportModelContents(sourceTemplateModelId);
|
|
1879
1840
|
// Note: the source --> target mapping was needed during the template model cloning phase (remapping parent/child, for example), but needs to be reset afterwards
|
|
@@ -1894,7 +1855,7 @@ class TemplateModelCloner extends IModelTransformer {
|
|
|
1894
1855
|
async placeTemplate2d(sourceTemplateModelId, targetModelId, placement) {
|
|
1895
1856
|
await this.initialize();
|
|
1896
1857
|
this.context.remapElement(sourceTemplateModelId, targetModelId);
|
|
1897
|
-
this._transform3d =
|
|
1858
|
+
this._transform3d = Transform.createOriginAndMatrix(Point3d.createFrom(placement.origin), placement.rotation);
|
|
1898
1859
|
this._sourceIdToTargetIdMap = new Map();
|
|
1899
1860
|
await this.exporter.exportModelContents(sourceTemplateModelId);
|
|
1900
1861
|
// Note: the source --> target mapping was needed during the template model cloning phase (remapping parent/child, for example), but needs to be reset afterwards
|
|
@@ -1910,27 +1871,27 @@ class TemplateModelCloner extends IModelTransformer {
|
|
|
1910
1871
|
const referenceIds = sourceElement.getReferenceIds();
|
|
1911
1872
|
for (const referenceId of referenceIds) {
|
|
1912
1873
|
// TODO: consider going through all definition elements at once and remapping them to themselves
|
|
1913
|
-
if (!
|
|
1874
|
+
if (!EntityReferences.isValid(await this.context.findTargetEntityId(referenceId))) {
|
|
1914
1875
|
if (this.context.isBetweenIModels) {
|
|
1915
|
-
|
|
1876
|
+
ITwinError.throwError({
|
|
1916
1877
|
iTwinErrorId: {
|
|
1917
|
-
scope:
|
|
1918
|
-
key:
|
|
1878
|
+
scope: IModelTransformerErrorScope,
|
|
1879
|
+
key: IModelTransformerError.DependencyMappingMissing,
|
|
1919
1880
|
},
|
|
1920
1881
|
message: `Remapping for source dependency ${referenceId} not found for target iModel`,
|
|
1921
1882
|
});
|
|
1922
1883
|
}
|
|
1923
1884
|
else {
|
|
1924
|
-
const definitionElement = this.sourceDb.elements.tryGetElement(referenceId,
|
|
1885
|
+
const definitionElement = this.sourceDb.elements.tryGetElement(referenceId, DefinitionElement);
|
|
1925
1886
|
if (definitionElement &&
|
|
1926
|
-
!(definitionElement instanceof
|
|
1887
|
+
!(definitionElement instanceof RecipeDefinitionElement)) {
|
|
1927
1888
|
this.context.remapElement(referenceId, referenceId); // when in the same iModel, can use existing DefinitionElements without remapping
|
|
1928
1889
|
}
|
|
1929
1890
|
else {
|
|
1930
|
-
|
|
1891
|
+
ITwinError.throwError({
|
|
1931
1892
|
iTwinErrorId: {
|
|
1932
|
-
scope:
|
|
1933
|
-
key:
|
|
1893
|
+
scope: IModelTransformerErrorScope,
|
|
1894
|
+
key: IModelTransformerError.DependencyMappingMissing,
|
|
1934
1895
|
},
|
|
1935
1896
|
message: `Remapping for dependency ${referenceId} not found`,
|
|
1936
1897
|
});
|
|
@@ -1939,21 +1900,20 @@ class TemplateModelCloner extends IModelTransformer {
|
|
|
1939
1900
|
}
|
|
1940
1901
|
}
|
|
1941
1902
|
const targetElementProps = await super.onTransformElement(sourceElement);
|
|
1942
|
-
targetElementProps.federationGuid =
|
|
1943
|
-
targetElementProps.code =
|
|
1944
|
-
if (sourceElement instanceof
|
|
1945
|
-
const is3d = sourceElement instanceof
|
|
1946
|
-
const placementClass = is3d ?
|
|
1903
|
+
targetElementProps.federationGuid = Guid.createValue(); // clone from template should create a new federationGuid
|
|
1904
|
+
targetElementProps.code = Code.createEmpty(); // clone from template should not maintain codes
|
|
1905
|
+
if (sourceElement instanceof GeometricElement) {
|
|
1906
|
+
const is3d = sourceElement instanceof GeometricElement3d;
|
|
1907
|
+
const placementClass = is3d ? Placement3d : Placement2d;
|
|
1947
1908
|
const placement = placementClass.fromJSON(targetElementProps.placement);
|
|
1948
1909
|
if (placement.isValid) {
|
|
1949
|
-
(
|
|
1910
|
+
nodeAssert(this._transform3d);
|
|
1950
1911
|
placement.multiplyTransform(this._transform3d);
|
|
1951
1912
|
targetElementProps.placement = placement;
|
|
1952
1913
|
}
|
|
1953
1914
|
}
|
|
1954
|
-
this._sourceIdToTargetIdMap?.set(sourceElement.id,
|
|
1915
|
+
this._sourceIdToTargetIdMap?.set(sourceElement.id, Id64.invalid); // keep track of (source) elementIds from the template model, but the target hasn't been inserted yet
|
|
1955
1916
|
return targetElementProps;
|
|
1956
1917
|
}
|
|
1957
1918
|
}
|
|
1958
|
-
exports.TemplateModelCloner = TemplateModelCloner;
|
|
1959
1919
|
//# sourceMappingURL=IModelTransformer.js.map
|