@itwin/core-backend 5.6.0-dev.6 → 5.6.0-dev.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/ChannelControl.d.ts +29 -0
- package/lib/cjs/ChannelControl.d.ts.map +1 -1
- package/lib/cjs/ChannelControl.js.map +1 -1
- package/lib/cjs/IModelDb.d.ts +116 -4
- package/lib/cjs/IModelDb.d.ts.map +1 -1
- package/lib/cjs/IModelDb.js +117 -63
- package/lib/cjs/IModelDb.js.map +1 -1
- package/lib/cjs/internal/ChannelAdmin.d.ts +2 -1
- package/lib/cjs/internal/ChannelAdmin.d.ts.map +1 -1
- package/lib/cjs/internal/ChannelAdmin.js +23 -0
- package/lib/cjs/internal/ChannelAdmin.js.map +1 -1
- package/lib/esm/ChannelControl.d.ts +29 -0
- package/lib/esm/ChannelControl.d.ts.map +1 -1
- package/lib/esm/ChannelControl.js.map +1 -1
- package/lib/esm/IModelDb.d.ts +116 -4
- package/lib/esm/IModelDb.d.ts.map +1 -1
- package/lib/esm/IModelDb.js +116 -62
- package/lib/esm/IModelDb.js.map +1 -1
- package/lib/esm/internal/ChannelAdmin.d.ts +2 -1
- package/lib/esm/internal/ChannelAdmin.d.ts.map +1 -1
- package/lib/esm/internal/ChannelAdmin.js +23 -0
- package/lib/esm/internal/ChannelAdmin.js.map +1 -1
- package/lib/esm/test/schema/SchemaImportCallbacks.test.d.ts +2 -0
- package/lib/esm/test/schema/SchemaImportCallbacks.test.d.ts.map +1 -0
- package/lib/esm/test/schema/SchemaImportCallbacks.test.js +916 -0
- package/lib/esm/test/schema/SchemaImportCallbacks.test.js.map +1 -0
- package/package.json +14 -14
package/lib/esm/IModelDb.js
CHANGED
|
@@ -81,6 +81,24 @@ class IModelSettings extends SettingsImpl {
|
|
|
81
81
|
yield* IModelHost.appWorkspace.settings.getSettingEntries(name);
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Strategy for transforming data during schema import.
|
|
86
|
+
* @beta
|
|
87
|
+
*/
|
|
88
|
+
export var DataTransformationStrategy;
|
|
89
|
+
(function (DataTransformationStrategy) {
|
|
90
|
+
/** No data transformation will be performed after schema import. */
|
|
91
|
+
DataTransformationStrategy["None"] = "None";
|
|
92
|
+
/** Data transformation will be performed using a temporary snapshot created before schema import.
|
|
93
|
+
* Useful for complex transformations requiring full read access to complete pre-import state for lazy conversion.
|
|
94
|
+
* Note: Creates a complete copy of the briefcase file, which may be large.
|
|
95
|
+
*/
|
|
96
|
+
DataTransformationStrategy["Snapshot"] = "Snapshot";
|
|
97
|
+
/** Data transformation will be performed using in-memory cached data created before schema import.
|
|
98
|
+
* Useful for lightweight transformations involving limited data.
|
|
99
|
+
*/
|
|
100
|
+
DataTransformationStrategy["InMemory"] = "InMemory";
|
|
101
|
+
})(DataTransformationStrategy || (DataTransformationStrategy = {}));
|
|
84
102
|
/** An iModel database file. The database file can either be a briefcase or a snapshot.
|
|
85
103
|
* @see [Accessing iModels]($docs/learning/backend/AccessingIModels.md)
|
|
86
104
|
* @see [About IModelDb]($docs/learning/backend/IModelDb.md)
|
|
@@ -715,21 +733,68 @@ export class IModelDb extends IModel {
|
|
|
715
733
|
this.clearCaches();
|
|
716
734
|
}
|
|
717
735
|
}
|
|
718
|
-
/**
|
|
719
|
-
*
|
|
720
|
-
* You must import a schema into an iModel before you can insert instances of the classes in that schema. See [[Element]]
|
|
721
|
-
* @param schemaFileName array of Full paths to ECSchema.xml files to be imported.
|
|
722
|
-
* @param {SchemaImportOptions} options - options during schema import.
|
|
723
|
-
* @throws [[IModelError]] if the schema lock cannot be obtained or there is a problem importing the schema.
|
|
724
|
-
* @note Changes are saved if importSchemas is successful and abandoned if not successful.
|
|
725
|
-
* - You can use NativeLoggerCategory to turn on the native logs. You can also control [what exactly is logged by the loggers](https://www.itwinjs.org/learning/common/logging/#controlling-what-is-logged).
|
|
726
|
-
* - See [Schema Versioning]($docs/bis/guide/schema-evolution/schema-versioning-and-generations.md) for more information on acceptable changes to schemas.
|
|
727
|
-
* @note This method should not be called from {TxnManager.withIndirectTxnModeAsync} or {RebaseHandler.recompute}.
|
|
728
|
-
* @see querySchemaVersion
|
|
736
|
+
/** Helper to clean up snapshot resources safely
|
|
737
|
+
* @internal
|
|
729
738
|
*/
|
|
730
|
-
|
|
731
|
-
if (
|
|
732
|
-
|
|
739
|
+
cleanupSnapshot(resources) {
|
|
740
|
+
if (resources.snapshot) {
|
|
741
|
+
const pathName = resources.snapshot.pathName;
|
|
742
|
+
resources.snapshot.close();
|
|
743
|
+
if (pathName && IModelJsFs.existsSync(pathName)) {
|
|
744
|
+
IModelJsFs.removeSync(pathName);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
async preSchemaImportCallback(callback, context) {
|
|
749
|
+
const callbackResources = {
|
|
750
|
+
transformStrategy: DataTransformationStrategy.None,
|
|
751
|
+
};
|
|
752
|
+
try {
|
|
753
|
+
if (callback?.preSchemaImportCallback) {
|
|
754
|
+
const callbackResult = await callback.preSchemaImportCallback(context);
|
|
755
|
+
callbackResources.transformStrategy = callbackResult.transformStrategy;
|
|
756
|
+
if (callbackResult.transformStrategy === DataTransformationStrategy.Snapshot) {
|
|
757
|
+
// Create temporary snapshot file
|
|
758
|
+
const snapshotDb = SnapshotDb.createFrom(this, `${this.pathName}.snapshot-${Date.now()}`);
|
|
759
|
+
callbackResources.snapshot = snapshotDb;
|
|
760
|
+
}
|
|
761
|
+
else if (callbackResult.transformStrategy === DataTransformationStrategy.InMemory) {
|
|
762
|
+
if (callbackResult.cachedData === undefined) {
|
|
763
|
+
throw new IModelError(IModelStatus.BadRequest, "InMemory transform strategy requires cachedData to be provided.");
|
|
764
|
+
}
|
|
765
|
+
callbackResources.cachedData = callbackResult.cachedData;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
catch (callbackError) {
|
|
770
|
+
this.abandonChanges();
|
|
771
|
+
this.cleanupSnapshot(callbackResources);
|
|
772
|
+
throw new IModelError(callbackError.errorNumber ?? IModelStatus.BadRequest, `Failed to execute preSchemaImportCallback: ${callbackError.message}`);
|
|
773
|
+
}
|
|
774
|
+
return callbackResources;
|
|
775
|
+
}
|
|
776
|
+
async postSchemaImportCallback(callback, context) {
|
|
777
|
+
if (context.resources.transformStrategy === DataTransformationStrategy.Snapshot && (context.resources.snapshot === undefined || !IModelJsFs.existsSync(context.resources.snapshot.pathName))) {
|
|
778
|
+
throw new IModelError(IModelStatus.BadRequest, "Snapshot transform strategy requires a snapshot to be created");
|
|
779
|
+
}
|
|
780
|
+
if (context.resources.transformStrategy === DataTransformationStrategy.InMemory && context.resources.cachedData === undefined) {
|
|
781
|
+
throw new IModelError(IModelStatus.BadRequest, "InMemory transform strategy requires cachedData to be provided.");
|
|
782
|
+
}
|
|
783
|
+
try {
|
|
784
|
+
if (callback?.postSchemaImportCallback)
|
|
785
|
+
await callback.postSchemaImportCallback(context);
|
|
786
|
+
}
|
|
787
|
+
catch (callbackError) {
|
|
788
|
+
this.abandonChanges();
|
|
789
|
+
throw new IModelError(callbackError.errorNumber ?? IModelStatus.BadRequest, `Failed to execute postSchemaImportCallback: ${callbackError.message}`);
|
|
790
|
+
}
|
|
791
|
+
finally {
|
|
792
|
+
// Always clean up snapshot, whether success or error
|
|
793
|
+
this.cleanupSnapshot(context.resources);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
/** Shared implementation for importing schemas from file or string. */
|
|
797
|
+
async importSchemasInternal(schemas, options, nativeImportOp) {
|
|
733
798
|
if (this instanceof BriefcaseDb) {
|
|
734
799
|
if (this.txns.rebaser.isRebasing) {
|
|
735
800
|
throw new IModelError(IModelStatus.BadRequest, "Cannot import schemas while rebasing");
|
|
@@ -738,13 +803,25 @@ export class IModelDb extends IModel {
|
|
|
738
803
|
throw new IModelError(IModelStatus.BadRequest, "Cannot import schemas while in an indirect change scope");
|
|
739
804
|
}
|
|
740
805
|
}
|
|
806
|
+
if (options?.channelUpgrade) {
|
|
807
|
+
try {
|
|
808
|
+
await this.channels.upgradeChannel(options.channelUpgrade, this, options.data);
|
|
809
|
+
}
|
|
810
|
+
catch (error) {
|
|
811
|
+
this.abandonChanges();
|
|
812
|
+
throw error;
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
let preSchemaImportCallbackResult = { transformStrategy: DataTransformationStrategy.None };
|
|
816
|
+
if (options?.schemaImportCallbacks?.preSchemaImportCallback)
|
|
817
|
+
preSchemaImportCallbackResult = await this.preSchemaImportCallback(options.schemaImportCallbacks, { iModel: this, data: options.data, schemaData: schemas });
|
|
741
818
|
const maybeCustomNativeContext = options?.ecSchemaXmlContext?.nativeContext;
|
|
742
819
|
if (this[_nativeDb].schemaSyncEnabled()) {
|
|
743
820
|
await SchemaSync.withLockedAccess(this, { openMode: OpenMode.Readonly, operationName: "schema sync" }, async (syncAccess) => {
|
|
744
821
|
const schemaSyncDbUri = syncAccess.getUri();
|
|
745
822
|
this.saveChanges();
|
|
746
823
|
try {
|
|
747
|
-
|
|
824
|
+
nativeImportOp(schemas, { schemaLockHeld: false, ecSchemaXmlContext: maybeCustomNativeContext, schemaSyncDbUri });
|
|
748
825
|
}
|
|
749
826
|
catch (outerErr) {
|
|
750
827
|
if (DbResult.BE_SQLITE_ERROR_DataTransformRequired === outerErr.errorNumber) {
|
|
@@ -752,7 +829,7 @@ export class IModelDb extends IModel {
|
|
|
752
829
|
if (this[_nativeDb].getITwinId() !== Guid.empty)
|
|
753
830
|
await this.acquireSchemaLock();
|
|
754
831
|
try {
|
|
755
|
-
|
|
832
|
+
nativeImportOp(schemas, { schemaLockHeld: true, ecSchemaXmlContext: maybeCustomNativeContext, schemaSyncDbUri });
|
|
756
833
|
}
|
|
757
834
|
catch (innerErr) {
|
|
758
835
|
throw new IModelError(innerErr.errorNumber, innerErr.message);
|
|
@@ -772,71 +849,48 @@ export class IModelDb extends IModel {
|
|
|
772
849
|
if (this[_nativeDb].getITwinId() !== Guid.empty) // if this iModel is associated with an iTwin, importing schema requires the schema lock
|
|
773
850
|
await this.acquireSchemaLock();
|
|
774
851
|
try {
|
|
775
|
-
|
|
852
|
+
nativeImportOp(schemas, nativeImportOptions);
|
|
776
853
|
}
|
|
777
854
|
catch (err) {
|
|
778
855
|
throw new IModelError(err.errorNumber, err.message);
|
|
779
856
|
}
|
|
780
857
|
}
|
|
781
858
|
this.clearCaches();
|
|
859
|
+
if (options?.schemaImportCallbacks?.postSchemaImportCallback)
|
|
860
|
+
await this.postSchemaImportCallback(options.schemaImportCallbacks, { iModel: this, resources: preSchemaImportCallbackResult, data: options.data });
|
|
861
|
+
}
|
|
862
|
+
/** Import an ECSchema. On success, the schema definition is stored in the iModel.
|
|
863
|
+
* This method is asynchronous (must be awaited) because, in the case where this IModelDb is a briefcase, this method first obtains the schema lock from the iModel server.
|
|
864
|
+
* You must import a schema into an iModel before you can insert instances of the classes in that schema. See [[Element]]
|
|
865
|
+
* @param schemaFileName array of Full paths to ECSchema.xml files to be imported.
|
|
866
|
+
* @param {SchemaImportOptions} options - options during schema import.
|
|
867
|
+
* @throws [[IModelError]] if the schema lock cannot be obtained or there is a problem importing the schema.
|
|
868
|
+
* @note Changes are saved if importSchemas is successful and abandoned if not successful.
|
|
869
|
+
* - You can use NativeLoggerCategory to turn on the native logs. You can also control [what exactly is logged by the loggers](https://www.itwinjs.org/learning/common/logging/#controlling-what-is-logged).
|
|
870
|
+
* - See [Schema Versioning]($docs/bis/guide/schema-evolution/schema-versioning-and-generations.md) for more information on acceptable changes to schemas.
|
|
871
|
+
* @note This method should not be called from {TxnManager.withIndirectTxnModeAsync} or {RebaseHandler.recompute}.
|
|
872
|
+
* @see querySchemaVersion
|
|
873
|
+
*/
|
|
874
|
+
async importSchemas(schemaFileNames, options) {
|
|
875
|
+
if (schemaFileNames.length === 0)
|
|
876
|
+
return;
|
|
877
|
+
await this.importSchemasInternal(schemaFileNames, options, (schemas, importOptions) => this[_nativeDb].importSchemas(schemas, importOptions));
|
|
782
878
|
}
|
|
783
879
|
/** Import ECSchema(s) serialized to XML. On success, the schema definition is stored in the iModel.
|
|
784
880
|
* This method is asynchronous (must be awaited) because, in the case where this IModelDb is a briefcase, this method first obtains the schema lock from the iModel server.
|
|
785
881
|
* You must import a schema into an iModel before you can insert instances of the classes in that schema. See [[Element]]
|
|
786
882
|
* @param serializedXmlSchemas The xml string(s) created from a serialized ECSchema.
|
|
883
|
+
* @param {SchemaImportOptions} options - options during schema import.
|
|
787
884
|
* @throws [[IModelError]] if the schema lock cannot be obtained or there is a problem importing the schema.
|
|
788
885
|
* @note Changes are saved if importSchemaStrings is successful and abandoned if not successful.
|
|
789
886
|
* @note This method should not be called from {TxnManager.withIndirectTxnModeAsync} or {RebaseHandler.recompute}.
|
|
790
887
|
* @see querySchemaVersion
|
|
791
888
|
* @alpha
|
|
792
889
|
*/
|
|
793
|
-
async importSchemaStrings(serializedXmlSchemas) {
|
|
890
|
+
async importSchemaStrings(serializedXmlSchemas, options) {
|
|
794
891
|
if (serializedXmlSchemas.length === 0)
|
|
795
892
|
return;
|
|
796
|
-
|
|
797
|
-
if (this.txns.rebaser.isRebasing) {
|
|
798
|
-
throw new IModelError(IModelStatus.BadRequest, "Cannot import schemas while rebasing");
|
|
799
|
-
}
|
|
800
|
-
if (this.txns.isIndirectChanges) {
|
|
801
|
-
throw new IModelError(IModelStatus.BadRequest, "Cannot import schemas while in an indirect change scope");
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
if (this[_nativeDb].schemaSyncEnabled()) {
|
|
805
|
-
await SchemaSync.withLockedAccess(this, { openMode: OpenMode.Readonly, operationName: "schemaSync" }, async (syncAccess) => {
|
|
806
|
-
const schemaSyncDbUri = syncAccess.getUri();
|
|
807
|
-
this.saveChanges();
|
|
808
|
-
try {
|
|
809
|
-
this[_nativeDb].importXmlSchemas(serializedXmlSchemas, { schemaLockHeld: false, schemaSyncDbUri });
|
|
810
|
-
}
|
|
811
|
-
catch (outerErr) {
|
|
812
|
-
if (DbResult.BE_SQLITE_ERROR_DataTransformRequired === outerErr.errorNumber) {
|
|
813
|
-
this.abandonChanges();
|
|
814
|
-
if (this[_nativeDb].getITwinId() !== Guid.empty)
|
|
815
|
-
await this.acquireSchemaLock();
|
|
816
|
-
try {
|
|
817
|
-
this[_nativeDb].importXmlSchemas(serializedXmlSchemas, { schemaLockHeld: true, schemaSyncDbUri });
|
|
818
|
-
}
|
|
819
|
-
catch (innerErr) {
|
|
820
|
-
throw new IModelError(innerErr.errorNumber, innerErr.message);
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
else {
|
|
824
|
-
throw new IModelError(outerErr.errorNumber, outerErr.message);
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
});
|
|
828
|
-
}
|
|
829
|
-
else {
|
|
830
|
-
if (this.iTwinId && this.iTwinId !== Guid.empty) // if this iModel is associated with an iTwin, importing schema requires the schema lock
|
|
831
|
-
await this.acquireSchemaLock();
|
|
832
|
-
try {
|
|
833
|
-
this[_nativeDb].importXmlSchemas(serializedXmlSchemas, { schemaLockHeld: true });
|
|
834
|
-
}
|
|
835
|
-
catch (err) {
|
|
836
|
-
throw new IModelError(err.errorNumber, err.message);
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
this.clearCaches();
|
|
893
|
+
await this.importSchemasInternal(serializedXmlSchemas, options, (schemas, importOptions) => this[_nativeDb].importXmlSchemas(schemas, importOptions));
|
|
840
894
|
}
|
|
841
895
|
/** Find an opened instance of any subclass of IModelDb, by filename
|
|
842
896
|
* @note this method returns an IModelDb if the filename is open for *any* subclass of IModelDb
|