@itwin/core-backend
Version:
iTwin.js backend components
136 lines • 6.34 kB
JavaScript
import { SchemaContext, SchemaGraphUtil, SchemaJsonLocater, SchemaMatchType } from "@itwin/ecschema-metadata";
import { IModelIncrementalSchemaLocater } from "../../IModelIncrementalSchemaLocater";
import { BriefcaseDb, IModelDb, StandaloneDb } from "../../IModelDb";
import { IModelHost } from "../../IModelHost";
import { KnownTestLocations } from "../KnownTestLocations";
import { OpenMode } from "@itwin/core-bentley";
import { IModelJsFs } from "../../IModelJsFs";
import { ProfileOptions } from "@itwin/core-common";
import { SchemaXmlFileLocater } from "@itwin/ecschema-locaters";
import { DOMParser, XMLSerializer } from "@xmldom/xmldom";
import * as path from "path";
export class TestContext {
_iModel;
_schemaLocater;
_assetContext;
constructor(iModel) {
this._iModel = iModel;
this._schemaLocater = this._iModel.schemaContext.locaters.find((locater) => {
return locater instanceof IModelIncrementalSchemaLocater;
});
// Ideally we should not need a seperate context here to locate and locate the bisschemas from the
// parent imodel context, but due to a bug in the incremental schema logic, we have to do this for now.
// TODO: remove this when issue #1763 is fixed.
this._assetContext = new SchemaContext();
this._assetContext.addLocater(new SchemaJsonLocater((schemaName) => {
return iModel.getSchemaProps(schemaName);
}));
const xmlAssetSchemaLocater = new SchemaXmlFileLocater();
xmlAssetSchemaLocater.addSchemaSearchPath(path.join(KnownTestLocations.assetsDir, "IncrementalSchemaLocater"));
this._assetContext.addLocater(xmlAssetSchemaLocater);
iModel.schemaContext.addLocater(this._assetContext);
}
get iModel() {
return this._iModel;
}
get schemaLocater() {
return this._schemaLocater;
}
get schemaContext() {
return this._iModel.schemaContext;
}
static async create(options) {
if (!IModelHost.isValid) {
await IModelHost.startup();
}
const iModel = options?.bimFile ?
await this.loadIModelFile(options.bimFile) :
await this.createIModel();
const configuration = IModelHost.configuration;
if (configuration) {
const previousSetting = configuration.incrementalSchemaLoading;
configuration.incrementalSchemaLoading = options ? options.incrementalSchemaLoading : "enabled";
iModel.onBeforeClose.addOnce(() => {
configuration.incrementalSchemaLoading = previousSetting;
});
}
return new TestContext(iModel);
}
static async loadIModelFile(bimFile) {
const pathToBriefCase = path.join(KnownTestLocations.assetsDir, bimFile);
return BriefcaseDb.open({
fileName: pathToBriefCase,
readonly: true,
key: "test-iModel",
});
}
static async createIModel() {
const testBimPath = path.join(KnownTestLocations.assetsDir, "IncrementalSchemaLocater", "test-bim.bim");
if (IModelJsFs.existsSync(testBimPath)) {
~IModelJsFs.removeSync(testBimPath);
}
const localBim = StandaloneDb.createEmpty(testBimPath, {
enableTransactions: true,
rootSubject: {
name: "IncrementalSchemaTestingDb"
},
});
localBim.close();
const nativeDb = IModelDb.openDgnDb({ path: testBimPath }, OpenMode.ReadWrite, { profile: ProfileOptions.Upgrade });
nativeDb.saveChanges();
nativeDb.closeFile();
return StandaloneDb.openFile(testBimPath, OpenMode.ReadWrite);
}
async getSchemaNames() {
const result = new Array();
const sqlQuery = "SELECT Name, VersionMajor, VersionWrite, VersionMinor FROM meta.ECSchemaDef ORDER BY Name";
const reader = this._iModel.createQueryReader(sqlQuery);
while (await reader.step()) {
const name = reader.current[0];
const versionMajor = reader.current[1];
const versionWrite = reader.current[2];
const versionMinor = reader.current[3];
result.push(`${name}.${versionMajor}.${versionWrite}.${versionMinor}`);
}
return result;
}
async importAssetSchema(schemaKey) {
// If schema is already in the iModel, return it.
if (undefined !== this.iModel.querySchemaVersion(schemaKey.name))
return await this.schemaContext.getSchema(schemaKey);
// Locate the schema from the assets using the schema contexts asset locaters.
const testSchema = await this._assetContext.getSchema(schemaKey, SchemaMatchType.Exact);
if (undefined === testSchema)
throw new Error(`The schema '${schemaKey.name}' could not be found in the assets folder.`);
const schemaXml = await getOrderedSchemaStrings(testSchema);
await this._iModel.importSchemaStrings(schemaXml);
this._iModel.saveChanges();
if (this.iModel.isBriefcaseDb() && !this.iModel.isReadonly) {
await this.iModel.pushChanges({ description: "import test schema" });
}
const schema = await this.schemaContext.getSchema(schemaKey);
if (undefined === schema)
throw new Error(`The schema '${schemaKey.name}' could not be found after import.`);
if (schema.loadingController && !schema.loadingController.isComplete) {
await schema.loadingController.wait();
}
return schema;
}
async [Symbol.asyncDispose]() {
return this._iModel.close();
}
}
async function getOrderedSchemaStrings(insertSchema) {
const schemas = SchemaGraphUtil.buildDependencyOrderedSchemaList(insertSchema);
const schemaStrings = await Promise.all(schemas.map(async (schema) => getSchemaString(schema)));
return schemaStrings;
}
async function getSchemaString(schema) {
// Serialize schema to the document object
const xmlDocument = new DOMParser().parseFromString(`<?xml version="1.0" encoding="UTF-8"?>`, "application/xml");
await schema.toXml(xmlDocument);
const serializer = new XMLSerializer();
const xml = serializer.serializeToString(xmlDocument);
return xml;
}
//# sourceMappingURL=TestContext.js.map