@itwin/core-backend
Version:
iTwin.js backend components
151 lines • 7.05 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.SchemaSync = void 0;
/** @packageDocumentation
* @module SQLiteDb
*/
const CloudSqlite_1 = require("./CloudSqlite");
const SQLiteDb_1 = require("./SQLiteDb");
const IModelDb_1 = require("./IModelDb");
const core_bentley_1 = require("@itwin/core-bentley");
const core_common_1 = require("@itwin/core-common");
const NativePlatform_1 = require("./internal/NativePlatform");
const Symbols_1 = require("./internal/Symbols");
/** @internal */
var SchemaSync;
(function (SchemaSync) {
const lockParams = { retryDelayMs: 1000, nRetries: 30 };
/** A CloudSqlite database for synchronizing schema changes across briefcases. */
class SchemaSyncDb extends SQLiteDb_1.VersionedSqliteDb {
myVersion = "4.0.0";
createDDL() { }
}
SchemaSync.SchemaSyncDb = SchemaSyncDb;
const syncProperty = { namespace: "itwinjs", name: "SchemaSync" };
const defaultDbName = "SchemaSyncDb";
const testSyncCachePropKey = "test.schema_sync.cache_name";
// for tests only
SchemaSync.setTestCache = (iModel, cacheName) => {
if (cacheName)
iModel[Symbols_1._nativeDb].saveLocalValue(testSyncCachePropKey, cacheName);
else
iModel[Symbols_1._nativeDb].deleteLocalValue(testSyncCachePropKey);
};
const getCloudAccess = async (arg) => {
let nativeDb;
const argIsIModelDb = arg instanceof IModelDb_1.IModelDb;
if (argIsIModelDb) {
nativeDb = arg[Symbols_1._nativeDb];
}
else {
nativeDb = new NativePlatform_1.IModelNative.platform.DgnDb();
nativeDb.openIModel(arg.fileName, core_bentley_1.OpenMode.Readonly);
}
const propsString = nativeDb.queryFileProperty(syncProperty, true);
if (!propsString)
throw new Error("iModel does not have a SchemaSyncDb");
try {
const props = JSON.parse(propsString);
const accessToken = await CloudSqlite_1.CloudSqlite.requestToken(props);
const access = new CloudAccess({ ...props, accessToken });
Object.assign(access.lockParams, lockParams);
const testSyncCache = nativeDb.queryLocalValue(testSyncCachePropKey);
if (testSyncCache)
access.setCache(CloudSqlite_1.CloudSqlite.CloudCaches.getCache({ cacheName: testSyncCache }));
return access;
}
finally {
if (!argIsIModelDb) {
nativeDb.closeFile();
}
}
};
SchemaSync.withLockedAccess = async (iModel, args, operation) => {
const access = await getCloudAccess(iModel);
try {
await access.withLockedDb(args, async () => operation(access));
}
finally {
access.close();
}
};
SchemaSync.withReadonlyAccess = async (iModel, operation) => {
const access = await getCloudAccess(iModel);
access.synchronizeWithCloud();
access.openForRead();
try {
await operation(access);
}
finally {
access.close();
}
};
SchemaSync.isEnabled = (iModel) => {
return iModel[Symbols_1._nativeDb].schemaSyncEnabled();
};
/** Synchronize local briefcase schemas with cloud container */
SchemaSync.pull = async (iModel) => {
if (iModel[Symbols_1._nativeDb].schemaSyncEnabled() && !iModel.isReadonly) {
await SchemaSync.withReadonlyAccess(iModel, async (syncAccess) => {
const schemaSyncDbUri = syncAccess.getUri();
iModel.clearCaches();
iModel[Symbols_1._nativeDb].schemaSyncPull(schemaSyncDbUri);
iModel.saveChanges("schema synchronized with cloud container");
});
}
};
SchemaSync.initializeForIModel = async (arg) => {
const props = { baseUri: arg.containerProps.baseUri, containerId: arg.containerProps.containerId, storageType: arg.containerProps.storageType }; // sanitize to only known properties
const iModel = arg.iModel;
const briefcase = iModel instanceof IModelDb_1.BriefcaseDb ? iModel : undefined;
await iModel.acquireSchemaLock();
if (briefcase) {
if (briefcase.txns.hasLocalChanges) {
throw new core_common_1.IModelError(core_bentley_1.DbResult.BE_SQLITE_ERROR, "Enabling SchemaSync for iModel failed. There are unsaved or un-pushed local changes.");
}
await briefcase.pullChanges();
}
try {
iModel.saveFileProperty(syncProperty, JSON.stringify(props));
await SchemaSync.withLockedAccess(arg.iModel, { operationName: "initialize schemaSync", openMode: core_bentley_1.OpenMode.Readonly }, async (syncAccess) => {
iModel[Symbols_1._nativeDb].schemaSyncInit(syncAccess.getUri(), props.containerId, arg.overrideContainer ?? false);
iModel.saveChanges(`Enable SchemaSync (container id: ${props.containerId})`);
});
}
catch (err) {
throw err;
}
finally {
iModel.abandonChanges();
}
if (briefcase) {
if (arg.overrideContainer)
await briefcase.pushChanges({ description: `Overriding SchemaSync for iModel with container-id: ${props.containerId}` });
else
await briefcase.pushChanges({ description: `Enable SchemaSync for iModel with container-id: ${props.containerId}` });
}
};
/** Provides access to a cloud-based `SchemaSyncDb` to hold ECSchemas. */
class CloudAccess extends CloudSqlite_1.CloudSqlite.DbAccess {
constructor(props) {
super({ dbType: SchemaSyncDb, props, dbName: defaultDbName });
}
getUri() {
return `${this.getCloudDb()[Symbols_1._nativeDb].getFilePath()}?vfs=${this.container.cache?.name}&writable=${this.container.isWriteable ? 1 : 0}`;
}
/**
* Initialize a cloud container for use as a SchemaSync. The container must first be created via its storage supplier api (e.g. Azure, or AWS).
* A valid sasToken that grants write access must be supplied. This function creates and uploads an empty ChannelDb into the container.
* @note this deletes any existing content in the container.
*/
static async initializeDb(props) {
return super._initializeDb({ props, dbType: SchemaSyncDb, dbName: defaultDbName });
}
}
SchemaSync.CloudAccess = CloudAccess;
})(SchemaSync || (exports.SchemaSync = SchemaSync = {}));
//# sourceMappingURL=SchemaSync.js.map
;