diff --git a/common/api/ecschema-locaters.api.md b/common/api/ecschema-locaters.api.md index 8d68fc90f023..e2bc69a8af68 100644 --- a/common/api/ecschema-locaters.api.md +++ b/common/api/ecschema-locaters.api.md @@ -18,6 +18,13 @@ export class BackendSchemasXmlFileLocater extends SchemaXmlFileLocater implement addSchemaSearchPaths(schemaPaths: string[]): void; } +// @beta +export class BackendSchemaXmlStringLocater extends SchemaXmlStringLocater implements ISchemaLocater { + constructor(assetsDir: string); + addSchemaString(schemaString: string): void; + addSchemaStrings(schemaStrings: string[]): void; +} + // @beta export class FileSchemaKey extends SchemaKey { constructor(key: SchemaKey, fileName: string, schemaJson?: string); diff --git a/common/api/summary/ecschema-locaters.exports.csv b/common/api/summary/ecschema-locaters.exports.csv index 059019de01d2..da83c79c235d 100644 --- a/common/api/summary/ecschema-locaters.exports.csv +++ b/common/api/summary/ecschema-locaters.exports.csv @@ -1,6 +1,7 @@ sep=; Release Tag;API Item Type;API Item Name beta;class;BackendSchemasXmlFileLocater +beta;class;BackendSchemaXmlStringLocater beta;class;FileSchemaKey beta;class;SchemaFileLocater beta;class;SchemaJsonFileLocater diff --git a/core/ecschema-locaters/src/SchemaStringLocater.ts b/core/ecschema-locaters/src/SchemaStringLocater.ts index 6c3409e90158..01e3fc33fbf8 100644 --- a/core/ecschema-locaters/src/SchemaStringLocater.ts +++ b/core/ecschema-locaters/src/SchemaStringLocater.ts @@ -35,6 +35,7 @@ export class StringSchemaKey extends SchemaKey { */ export abstract class SchemaStringLocater { public schemaStrings: string[]; + protected searchPathPrecedence = new Map(); constructor() { this.schemaStrings = []; diff --git a/core/ecschema-locaters/src/SchemaXmlStringLocater.ts b/core/ecschema-locaters/src/SchemaXmlStringLocater.ts index 762926b8ca4d..af60d34fc06d 100644 --- a/core/ecschema-locaters/src/SchemaXmlStringLocater.ts +++ b/core/ecschema-locaters/src/SchemaXmlStringLocater.ts @@ -6,6 +6,8 @@ * @module Locaters */ +import * as path from "path"; +import * as fs from "fs"; import { DOMParser } from "@xmldom/xmldom"; import { ECObjectsError, ECObjectsStatus, ECVersion, ISchemaLocater, Schema, SchemaContext, SchemaInfo, SchemaKey, SchemaMatchType, SchemaReadHelper, XmlParser, @@ -65,8 +67,8 @@ export class SchemaXmlStringLocater extends SchemaStringLocater implements ISche if (!candidates || candidates.length === 0) return undefined; - const maxCandidate = candidates.sort(this.compareSchemaKeyByVersion)[candidates.length - 1]; - const schemaText = maxCandidate.schemaText; + const preferredCandidate = candidates.find((candidate) => this.searchPathPrecedence.get(candidate.toString()) === 0); + const schemaText = preferredCandidate ? preferredCandidate.schemaText : candidates.sort(this.compareSchemaKeyByVersion)[candidates.length - 1].schemaText; const parser = new DOMParser(); const document = parser.parseFromString(schemaText); @@ -90,8 +92,8 @@ export class SchemaXmlStringLocater extends SchemaStringLocater implements ISche if (!candidates || candidates.length === 0) return undefined; - const maxCandidate = candidates.sort(this.compareSchemaKeyByVersion)[candidates.length - 1]; - const schemaText = maxCandidate.schemaText; + const preferredCandidate = candidates.find((candidate) => this.searchPathPrecedence.get(candidate.toString()) === 0); + const schemaText = preferredCandidate ? preferredCandidate.schemaText : candidates.sort(this.compareSchemaKeyByVersion)[candidates.length - 1].schemaText; const parser = new DOMParser(); const document = parser.parseFromString(schemaText); @@ -121,3 +123,89 @@ export class SchemaXmlStringLocater extends SchemaStringLocater implements ISche } } + +/** + * A SchemaLocator implementation for locating and deserializing EC Schemas from XML strings + * loaded in memory. + * This locater is responsible for locating standard schema files + * that are released in the core-backend package and loading the schemas. + * @beta This is a workaround the current lack of a full xml parser. + */ +export class BackendSchemaXmlStringLocater extends SchemaXmlStringLocater implements ISchemaLocater { + private _standardSchemaSearchPaths: Set; + private _schemasToIgnore: Set; + + public constructor(assetsDir: string) { + super(); + + // Few standard schemas are still using ECXml version 2.0.0 which is not supported by the current implementation. + // Set the locater to ignore those schemas. + this._schemasToIgnore = new Set([ + path.join(assetsDir, "ECSchemas", "Standard", "Bentley_Common_Classes.01.01.ecschema.xml"), + path.join(assetsDir, "ECSchemas", "Standard", "Bentley_ECSchemaMap.01.00.ecschema.xml"), + path.join(assetsDir, "ECSchemas", "Standard", "Bentley_Standard_Classes.01.01.ecschema.xml"), + path.join(assetsDir, "ECSchemas", "Standard", "Bentley_Standard_CustomAttributes.01.14.ecschema.xml"), + path.join(assetsDir, "ECSchemas", "Standard", "Dimension_Schema.01.00.ecschema.xml"), + path.join(assetsDir, "ECSchemas", "Standard", "ECDbMap.01.00.ecschema.xml"), + path.join(assetsDir, "ECSchemas", "Standard", "ECv3ConversionAttributes.01.01.ecschema.xml"), + path.join(assetsDir, "ECSchemas", "Standard", "EditorCustomAttributes.01.03.ecschema.xml"), + path.join(assetsDir, "ECSchemas", "Standard", "iip_mdb_customAttributes.01.00.ecschema.xml"), + path.join(assetsDir, "ECSchemas", "Standard", "KindOfQuantity_Schema.01.01.ecschema.xml"), + path.join(assetsDir, "ECSchemas", "Standard", "rdl_customAttributes.01.00.ecschema.xml"), + path.join(assetsDir, "ECSchemas", "Standard", "SIUnitSystemDefaults.01.00.ecschema.xml"), + path.join(assetsDir, "ECSchemas", "Standard", "Units_Schema.01.00.ecschema.xml"), + path.join(assetsDir, "ECSchemas", "Standard", "Unit_Attributes.01.00.ecschema.xml"), + path.join(assetsDir, "ECSchemas", "Standard", "USCustomaryUnitSystemDefaults.01.00.ecschema.xml"), + ]); + + this._standardSchemaSearchPaths = new Set([ + path.join(assetsDir, "ECSchemas", "Dgn"), + path.join(assetsDir, "ECSchemas", "Domain"), + path.join(assetsDir, "ECSchemas", "ECDb"), + path.join(assetsDir, "ECSchemas", "Standard"), + ]); + + // Load all the standard schemas + this._standardSchemaSearchPaths.forEach((searchPath) => { + if (!fs.existsSync(searchPath)) return; + + fs.readdirSync(searchPath) + .map((file) => path.join(searchPath, file)) + .filter((filePath) => !this._schemasToIgnore.has(filePath) && fs.statSync(filePath).isFile()) + .forEach((filePath) => { + this.schemaStrings.push(fs.readFileSync(filePath).toString()); + }); + }); + + // Set all default schemas to have a lower precedence value of 1 + this.schemaStrings.forEach((schema) => { + this.searchPathPrecedence.set(this.getSchemaKey(schema).toString(), 1); + }); + } + + /** + * Adds schema strings used by this locator to find the + * Schemas. + * @param schemaStrings An array of Schema strings to add + */ + public override addSchemaStrings(schemaStrings: string[]) { + schemaStrings.forEach((schemaString) => this.addSchemaString(schemaString)); + } + + /** + * Adds a schema string used by this locator to locate and load Schemas. + * @param schemaString The text of the Schema + */ + public override addSchemaString(schemaString: string) { + const schemaKey = this.getSchemaKey(schemaString); + + // Check if an entry for the same schema and version already exists. If so, remove it as the user-defined latest schema should take precedence + const existingIndex = this.schemaStrings.findIndex((entry) => this.getSchemaKey(entry).matches(schemaKey, SchemaMatchType.LatestWriteCompatible)); + if (existingIndex !== -1) { + this.schemaStrings.splice(existingIndex, 1); + } + + this.schemaStrings.push(schemaString); + this.searchPathPrecedence.set(schemaKey.toString(), 0); + } +} \ No newline at end of file diff --git a/example-code/snippets/src/backend/SchemaXmlFileLocater.test.ts b/example-code/snippets/src/backend/SchemaXmlFileLocater.test.ts index 2942181ad55a..38b6426ae787 100644 --- a/example-code/snippets/src/backend/SchemaXmlFileLocater.test.ts +++ b/example-code/snippets/src/backend/SchemaXmlFileLocater.test.ts @@ -3,7 +3,7 @@ * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ -import { Schema, SchemaContext, SchemaKey, SchemaMatchType } from "@itwin/ecschema-metadata"; +import { ECVersion, Schema, SchemaContext, SchemaKey, SchemaMatchType } from "@itwin/ecschema-metadata"; import { BackendSchemasXmlFileLocater, SchemaXmlFileLocater } from "@itwin/ecschema-locaters"; import { KnownLocations } from "@itwin/core-backend"; import path from "path"; @@ -55,25 +55,23 @@ describe("SchemaXmlFileLocater - locate standard schema", () => { }); describe("BackendSchemasXmlFileLocater - locate standard schemas", () => { - it("BackendSchemasXmlFileLocater general use", async () => { + const lrSchemaKey = new SchemaKey("LinearReferencing"); + const unitsSchemaKey = new SchemaKey("Units"); + + async function checkSchema(context: SchemaContext, schemaKey: SchemaKey) { + const schema = await context.getSchema(schemaKey); + assert.isDefined(schema); + assert.strictEqual(schema?.name, schemaKey.name); + } + + it("BackendSchemasXmlFileLocater - check default schema paths", async () => { const context = new SchemaContext(); - const loc = new BackendSchemasXmlFileLocater(KnownLocations.nativeAssetsDir); - context.addLocater(loc); - - // Get a Dgn schema - const dgnSchema = await context.getSchema(new SchemaKey("Generic", 1, 0, 5), SchemaMatchType.Latest); - assert.isDefined(dgnSchema); - assert.strictEqual(dgnSchema?.name, "Generic"); - - // Get a Domain schema - const domainSchema = await context.getSchema(new SchemaKey("LinearReferencing", 2, 0, 3), SchemaMatchType.Latest); - assert.isDefined(domainSchema); - assert.strictEqual(domainSchema?.name, "LinearReferencing"); - - // Get a Standard schema - const standardSchema = await context.getSchema(new SchemaKey("Units", 1, 0, 8), SchemaMatchType.Latest); - assert.isDefined(standardSchema); - assert.strictEqual(standardSchema?.name, "Units"); + context.addLocater(new BackendSchemasXmlFileLocater(KnownLocations.nativeAssetsDir)); + + await checkSchema(context, new SchemaKey("BisCore")); // Get BisCore + await checkSchema(context, new SchemaKey("Generic")); // Get a Dgn schema + await checkSchema(context, lrSchemaKey); // Get a Domain schema + await checkSchema(context, unitsSchemaKey); // Get a Standard schema }); function testLocatedSchema(locatedSchema: Schema | undefined, schemaName: string, schemaItemName: string, isSchemaItemDefined: boolean) { @@ -82,18 +80,18 @@ describe("BackendSchemasXmlFileLocater - locate standard schemas", () => { assert.equal(locatedSchema?.getItemSync(schemaItemName) !== undefined, isSchemaItemDefined); } - it("BackendSchemasXmlFileLocater search path precedence check - sync", () => { + it("BackendSchemasXmlFileLocater - check search path precedence - sync", () => { let context = new SchemaContext(); const locater = new BackendSchemasXmlFileLocater(KnownLocations.nativeAssetsDir); // The locater has been setup to use the default standard schemas released by core-backend package. context.addLocater(locater); - let linearReferencingSchema = context.getSchemaSync(new SchemaKey("LinearReferencing", 2, 0, 3)); + let linearReferencingSchema = context.getSchemaSync(lrSchemaKey); testLocatedSchema(linearReferencingSchema, "LinearReferencing", "DummyTestClass", false); // should not be loaded testLocatedSchema(linearReferencingSchema, "LinearReferencing", "LinearLocationElement", true); // should be loaded - let unitsSchema = context.getSchemaSync(new SchemaKey("Units", 1, 0, 8)); + let unitsSchema = context.getSchemaSync(unitsSchemaKey); testLocatedSchema(unitsSchema, "Units", "DummyUnit", false); // should not be loaded testLocatedSchema(unitsSchema, "Units", "FAHRENHEIT", true); // should be loaded @@ -102,46 +100,47 @@ describe("BackendSchemasXmlFileLocater - locate standard schemas", () => { context.addLocater(locater); // Now give the locater specific search paths to the dummy "LinearReferencing" and "Units" schemas + locater.addSchemaSearchPath(path.join(__dirname, "assets", "DummyTestSchemas", "Dgn")); locater.addSchemaSearchPath(path.join(__dirname, "assets", "DummyTestSchemas", "Domain")); locater.addSchemaSearchPath(path.join(__dirname, "assets", "DummyTestSchemas", "Standard")); - linearReferencingSchema = context.getSchemaSync(new SchemaKey("LinearReferencing", 2, 0, 3)); + linearReferencingSchema = context.getSchemaSync(lrSchemaKey); testLocatedSchema(linearReferencingSchema, "LinearReferencing", "DummyTestClass", true); // should be loaded testLocatedSchema(linearReferencingSchema, "LinearReferencing", "LinearLocationElement", true); // should be loaded - unitsSchema = context.getSchemaSync(new SchemaKey("Units", 1, 0, 8)); + unitsSchema = context.getSchemaSync(unitsSchemaKey); testLocatedSchema(unitsSchema, "Units", "DummyUnit", true); // should be loaded testLocatedSchema(unitsSchema, "Units", "FAHRENHEIT", true); // should be loaded - // Test case 2: Register multiple search path at a time + // Test case 2: Register multiple search paths at a time context = new SchemaContext(); const newLocater = new BackendSchemasXmlFileLocater(KnownLocations.nativeAssetsDir); context.addLocater(newLocater); // Now give the locater specific search paths to the dummy "LinearReferencing" and "Units" schemas - newLocater.addSchemaSearchPaths([path.join(__dirname, "assets", "DummyTestSchemas", "Domain"), path.join(__dirname, "assets", "DummyTestSchemas", "Standard")]); + newLocater.addSchemaSearchPaths([path.join(__dirname, "assets", "DummyTestSchemas", "Dgn"), path.join(__dirname, "assets", "DummyTestSchemas", "Domain"), path.join(__dirname, "assets", "DummyTestSchemas", "Standard")]); - linearReferencingSchema = context.getSchemaSync(new SchemaKey("LinearReferencing", 2, 0, 3)); + linearReferencingSchema = context.getSchemaSync(lrSchemaKey); testLocatedSchema(linearReferencingSchema, "LinearReferencing", "DummyTestClass", true); // should be loaded testLocatedSchema(linearReferencingSchema, "LinearReferencing", "LinearLocationElement", true); // should be loaded - unitsSchema = context.getSchemaSync(new SchemaKey("Units", 1, 0, 8)); + unitsSchema = context.getSchemaSync(unitsSchemaKey); testLocatedSchema(unitsSchema, "Units", "DummyUnit", true); // should be loaded testLocatedSchema(unitsSchema, "Units", "FAHRENHEIT", true); // should be loaded }); - it("BackendSchemasXmlFileLocater search path precedence check - async", async () => { + it("BackendSchemasXmlFileLocater - check search path precedence - async", async () => { let context = new SchemaContext(); const locater = new BackendSchemasXmlFileLocater(KnownLocations.nativeAssetsDir); // The locater has been setup to use the default standard schemas released by core-backend package. context.addLocater(locater); - let linearReferencingSchema = await context.getSchema(new SchemaKey("LinearReferencing", 2, 0, 3)); + let linearReferencingSchema = await context.getSchema(lrSchemaKey); testLocatedSchema(linearReferencingSchema, "LinearReferencing", "DummyTestClass", false); // should not be loaded testLocatedSchema(linearReferencingSchema, "LinearReferencing", "LinearLocationElement", true); // should be loaded - let unitsSchema = await context.getSchema(new SchemaKey("Units", 1, 0, 8)); + let unitsSchema = await context.getSchema(unitsSchemaKey); testLocatedSchema(unitsSchema, "Units", "DummyUnit", false); // should not be loaded testLocatedSchema(unitsSchema, "Units", "FAHRENHEIT", true); // should be loaded @@ -150,31 +149,47 @@ describe("BackendSchemasXmlFileLocater - locate standard schemas", () => { context.addLocater(locater); // Now give the locater specific search paths to the dummy "LinearReferencing" and "Units" schemas + locater.addSchemaSearchPath(path.join(__dirname, "assets", "DummyTestSchemas", "Dgn")); locater.addSchemaSearchPath(path.join(__dirname, "assets", "DummyTestSchemas", "Domain")); locater.addSchemaSearchPath(path.join(__dirname, "assets", "DummyTestSchemas", "Standard")); - linearReferencingSchema = await context.getSchema(new SchemaKey("LinearReferencing", 2, 0, 3)); + linearReferencingSchema = await context.getSchema(lrSchemaKey); testLocatedSchema(linearReferencingSchema, "LinearReferencing", "DummyTestClass", true); // should be loaded testLocatedSchema(linearReferencingSchema, "LinearReferencing", "LinearLocationElement", true); // should be loaded - unitsSchema = await context.getSchema(new SchemaKey("Units", 1, 0, 8)); + unitsSchema = await context.getSchema(unitsSchemaKey); testLocatedSchema(unitsSchema, "Units", "DummyUnit", true); // should be loaded testLocatedSchema(unitsSchema, "Units", "FAHRENHEIT", true); // should be loaded - // Test case 2: Register multiple search path at a time + // Test case 2: Register multiple search paths at a time context = new SchemaContext(); const newLocater = new BackendSchemasXmlFileLocater(KnownLocations.nativeAssetsDir); context.addLocater(newLocater); // Now give the locater specific search paths to the dummy "LinearReferencing" and "Units" schemas - newLocater.addSchemaSearchPaths([path.join(__dirname, "assets", "DummyTestSchemas", "Domain"), path.join(__dirname, "assets", "DummyTestSchemas", "Standard")]); + newLocater.addSchemaSearchPaths([path.join(__dirname, "assets", "DummyTestSchemas", "Dgn"), path.join(__dirname, "assets", "DummyTestSchemas", "Domain"), path.join(__dirname, "assets", "DummyTestSchemas", "Standard")]); - linearReferencingSchema = await context.getSchema(new SchemaKey("LinearReferencing", 2, 0, 3)); + linearReferencingSchema = await context.getSchema(lrSchemaKey); testLocatedSchema(linearReferencingSchema, "LinearReferencing", "DummyTestClass", true); // should be loaded testLocatedSchema(linearReferencingSchema, "LinearReferencing", "LinearLocationElement", true); // should be loaded - unitsSchema = await context.getSchema(new SchemaKey("Units", 1, 0, 8)); + unitsSchema = await context.getSchema(unitsSchemaKey); testLocatedSchema(unitsSchema, "Units", "DummyUnit", true); // should be loaded testLocatedSchema(unitsSchema, "Units", "FAHRENHEIT", true); // should be loaded }); + + it("BackendSchemasXmlFileLocater - schema version check", () => { + for (const schemaVersion of [new ECVersion(2, 0, 0), new ECVersion(2, 5, 0), new ECVersion(5, 0, 0)]) { + const context = new SchemaContext(); + // The locater has been setup to use the default standard schemas released by core-backend package. + context.addLocater(new BackendSchemasXmlFileLocater(KnownLocations.nativeAssetsDir)); + + const linearReferencingSchema = context.getSchemaSync(new SchemaKey("LinearReferencing", schemaVersion)); + assert.isDefined(linearReferencingSchema); + assert.strictEqual(linearReferencingSchema?.name, "LinearReferencing"); + assert.strictEqual(linearReferencingSchema?.schemaKey.version.read, 2); + assert.strictEqual(linearReferencingSchema?.schemaKey.version.write, 0); + assert.isAbove(linearReferencingSchema?.schemaKey.version?.minor ?? -1, 0); + } + }); }); diff --git a/example-code/snippets/src/backend/SchemaXmlStringLocater.test.ts b/example-code/snippets/src/backend/SchemaXmlStringLocater.test.ts new file mode 100644 index 000000000000..fe77d38bbff2 --- /dev/null +++ b/example-code/snippets/src/backend/SchemaXmlStringLocater.test.ts @@ -0,0 +1,154 @@ +/*--------------------------------------------------------------------------------------------- +* Copyright (c) Bentley Systems, Incorporated. All rights reserved. +* See LICENSE.md in the project root for license terms and full copyright notice. +*--------------------------------------------------------------------------------------------*/ + +import * as fs from "fs-extra"; +import { KnownLocations } from "@itwin/core-backend"; +import { BackendSchemaXmlStringLocater } from "@itwin/ecschema-locaters"; +import { ECVersion, Schema, SchemaContext, SchemaKey } from "@itwin/ecschema-metadata"; +import { assert } from "chai"; +import path from "path"; + + +describe("BackendSchemaXmlStringLocater - locate standard schemas", () => { + const lrSchemaKey = new SchemaKey("LinearReferencing"); + const unitsSchemaKey = new SchemaKey("Units"); + + const lrSchemaText = fs.readFileSync(path.join(__dirname, "assets", "DummyTestSchemas", "Domain", "LinearReferencing.ecschema.xml")); + const unitsSchemaText = fs.readFileSync(path.join(__dirname, "assets", "DummyTestSchemas", "Standard", "Units.ecschema.xml")); + + async function checkSchema(context: SchemaContext, schemaKey: SchemaKey) { + const schema = await context.getSchema(schemaKey); + assert.isDefined(schema); + assert.strictEqual(schema?.name, schemaKey.name); + } + + it("BackendSchemaXmlStringLocater - check default schema paths", async () => { + const context = new SchemaContext(); + context.addLocater(new BackendSchemaXmlStringLocater(KnownLocations.nativeAssetsDir)); + + await checkSchema(context, new SchemaKey("BisCore")); // Get BisCore + await checkSchema(context, new SchemaKey("Generic")); // Get a Dgn schema + await checkSchema(context, lrSchemaKey); // Get a Domain schema + await checkSchema(context, unitsSchemaKey); // Get a Standard schema + }); + + function testLocatedSchema(locatedSchema: Schema | undefined, schemaName: string, schemaItemName: string, isSchemaItemDefined: boolean) { + assert.isDefined(locatedSchema); + assert.strictEqual(locatedSchema?.name, schemaName); + assert.equal(locatedSchema?.getItemSync(schemaItemName) !== undefined, isSchemaItemDefined); + } + + it("BackendSchemaXmlStringLocater - check search path precedence - sync", () => { + let context = new SchemaContext(); + const locater = new BackendSchemaXmlStringLocater(KnownLocations.nativeAssetsDir); + + // The locater has been setup to use the default standard schemas released by core-backend package. + context.addLocater(locater); + + let linearReferencingSchema = context.getSchemaSync(lrSchemaKey); + testLocatedSchema(linearReferencingSchema, "LinearReferencing", "DummyTestClass", false); // should not be loaded + testLocatedSchema(linearReferencingSchema, "LinearReferencing", "LinearLocationElement", true); // should be loaded + + let unitsSchema = context.getSchemaSync(unitsSchemaKey); + testLocatedSchema(unitsSchema, "Units", "DummyUnit", false); // should not be loaded + testLocatedSchema(unitsSchema, "Units", "FAHRENHEIT", true); // should be loaded + + // Test case 1: Register single search path at a time + context = new SchemaContext(); + context.addLocater(locater); + + locater.addSchemaString(lrSchemaText.toString()); + locater.addSchemaString(unitsSchemaText.toString()); + + linearReferencingSchema = context.getSchemaSync(lrSchemaKey); + testLocatedSchema(linearReferencingSchema, "LinearReferencing", "DummyTestClass", true); // should be loaded + testLocatedSchema(linearReferencingSchema, "LinearReferencing", "LinearLocationElement", true); // should be loaded + + unitsSchema = context.getSchemaSync(unitsSchemaKey); + testLocatedSchema(unitsSchema, "Units", "DummyUnit", true); // should be loaded + testLocatedSchema(unitsSchema, "Units", "FAHRENHEIT", true); // should be loaded + + // Test case 2: Register multiple search paths at a time + context = new SchemaContext(); + const newLocater = new BackendSchemaXmlStringLocater(KnownLocations.nativeAssetsDir); + context.addLocater(newLocater); + + // Now give the locater specific search paths to the dummy "LinearReferencing" and "Units" schemas + newLocater.addSchemaString(lrSchemaText.toString()); + newLocater.addSchemaString(unitsSchemaText.toString()); + + linearReferencingSchema = context.getSchemaSync(lrSchemaKey); + testLocatedSchema(linearReferencingSchema, "LinearReferencing", "DummyTestClass", true); // should be loaded + testLocatedSchema(linearReferencingSchema, "LinearReferencing", "LinearLocationElement", true); // should be loaded + + unitsSchema = context.getSchemaSync(unitsSchemaKey); + testLocatedSchema(unitsSchema, "Units", "DummyUnit", true); // should be loaded + testLocatedSchema(unitsSchema, "Units", "FAHRENHEIT", true); // should be loaded + }); + + it("BackendSchemaXmlStringLocater - check search path precedence - async", async () => { + let context = new SchemaContext(); + const locater = new BackendSchemaXmlStringLocater(KnownLocations.nativeAssetsDir); + + // The locater has been setup to use the default standard schemas released by core-backend package. + context.addLocater(locater); + + let linearReferencingSchema = await context.getSchema(lrSchemaKey); + testLocatedSchema(linearReferencingSchema, "LinearReferencing", "DummyTestClass", false); // should not be loaded + testLocatedSchema(linearReferencingSchema, "LinearReferencing", "LinearLocationElement", true); // should be loaded + + let unitsSchema = await context.getSchema(unitsSchemaKey); + testLocatedSchema(unitsSchema, "Units", "DummyUnit", false); // should not be loaded + testLocatedSchema(unitsSchema, "Units", "FAHRENHEIT", true); // should be loaded + + // Test case 1: Register single search path at a time + context = new SchemaContext(); + context.addLocater(locater); + + // Now give the locater specific search paths to the dummy "LinearReferencing" and "Units" schemas + locater.addSchemaString(lrSchemaText.toString()); + locater.addSchemaString(unitsSchemaText.toString()); + + linearReferencingSchema = await context.getSchema(lrSchemaKey); + testLocatedSchema(linearReferencingSchema, "LinearReferencing", "DummyTestClass", true); // should be loaded + testLocatedSchema(linearReferencingSchema, "LinearReferencing", "LinearLocationElement", true); // should be loaded + + unitsSchema = await context.getSchema(unitsSchemaKey); + testLocatedSchema(unitsSchema, "Units", "DummyUnit", true); // should be loaded + testLocatedSchema(unitsSchema, "Units", "FAHRENHEIT", true); // should be loaded + + // Test case 2: Register multiple search paths at a time + context = new SchemaContext(); + const newLocater = new BackendSchemaXmlStringLocater(KnownLocations.nativeAssetsDir); + context.addLocater(newLocater); + + // Now give the locater specific search paths to the dummy "LinearReferencing" and "Units" schemas + newLocater.addSchemaString(lrSchemaText.toString()); + newLocater.addSchemaString(unitsSchemaText.toString()); + + linearReferencingSchema = await context.getSchema(lrSchemaKey); + testLocatedSchema(linearReferencingSchema, "LinearReferencing", "DummyTestClass", true); // should be loaded + testLocatedSchema(linearReferencingSchema, "LinearReferencing", "LinearLocationElement", true); // should be loaded + + unitsSchema = await context.getSchema(unitsSchemaKey); + testLocatedSchema(unitsSchema, "Units", "DummyUnit", true); // should be loaded + testLocatedSchema(unitsSchema, "Units", "FAHRENHEIT", true); // should be loaded + }); + + it("BackendSchemaXmlStringLocater - schema version check", () => { + for (const schemaVersion of [new ECVersion(2, 0, 0), new ECVersion(2, 5, 0), new ECVersion(5, 0, 0)]) { + const context = new SchemaContext(); + // The locater has been setup to use the default standard schemas released by core-backend package. + context.addLocater(new BackendSchemaXmlStringLocater(KnownLocations.nativeAssetsDir)); + + const linearReferencingSchema = context.getSchemaSync(new SchemaKey("LinearReferencing", schemaVersion)); + assert.isDefined(linearReferencingSchema); + assert.strictEqual(linearReferencingSchema?.name, "LinearReferencing"); + assert.strictEqual(linearReferencingSchema?.schemaKey.version.read, 2); + assert.strictEqual(linearReferencingSchema?.schemaKey.version.write, 0); + assert.isAbove(linearReferencingSchema?.schemaKey.version.minor ?? -1, 0); + } + }); +}); \ No newline at end of file diff --git a/example-code/snippets/src/backend/assets/DummyTestSchemas/Domain/LinearReferencing.ecschema.xml b/example-code/snippets/src/backend/assets/DummyTestSchemas/Domain/LinearReferencing.ecschema.xml index eeb240226a9c..0a687bfb7d04 100644 --- a/example-code/snippets/src/backend/assets/DummyTestSchemas/Domain/LinearReferencing.ecschema.xml +++ b/example-code/snippets/src/backend/assets/DummyTestSchemas/Domain/LinearReferencing.ecschema.xml @@ -3,7 +3,7 @@ | * Copyright (c) Bentley Systems, Incorporated. All rights reserved. | * See LICENSE.md in the project root for license terms and full copyright notice. ======================================================================================= --> - + diff --git a/example-code/snippets/src/backend/assets/DummyTestSchemas/Standard/Units.01.00.08.ecschema.xml b/example-code/snippets/src/backend/assets/DummyTestSchemas/Standard/Units.ecschema.xml similarity index 99% rename from example-code/snippets/src/backend/assets/DummyTestSchemas/Standard/Units.01.00.08.ecschema.xml rename to example-code/snippets/src/backend/assets/DummyTestSchemas/Standard/Units.ecschema.xml index 9ef9c5a86e9e..106c1a924711 100644 --- a/example-code/snippets/src/backend/assets/DummyTestSchemas/Standard/Units.01.00.08.ecschema.xml +++ b/example-code/snippets/src/backend/assets/DummyTestSchemas/Standard/Units.ecschema.xml @@ -3,7 +3,7 @@ | * Copyright (c) Bentley Systems, Incorporated. All rights reserved. | * See LICENSE.md in the project root for license terms and full copyright notice. ======================================================================================= --> -