UNPKG

@itwin/core-backend

Version:
151 lines • 7.05 kB
"use strict"; /*--------------------------------------------------------------------------------------------- * 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