@itwin/core-backend 5.5.0-dev.1 → 5.5.0-dev.4
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/CHANGELOG.md +19 -1
- package/lib/esm/test/assets/IncrementalSchemaLocater/configs/simple.config.js +5 -5
- package/lib/esm/test/assets/IncrementalSchemaLocater/configs/simple.config.js.map +1 -1
- package/lib/esm/test/incrementalSchemaLocater/ECSqlQueries.test.js +432 -198
- package/lib/esm/test/incrementalSchemaLocater/ECSqlQueries.test.js.map +1 -1
- package/lib/esm/test/incrementalSchemaLocater/IncrementalLoading.test.js +272 -190
- package/lib/esm/test/incrementalSchemaLocater/IncrementalLoading.test.js.map +1 -1
- package/lib/esm/test/incrementalSchemaLocater/TestContext.d.ts +27 -0
- package/lib/esm/test/incrementalSchemaLocater/TestContext.d.ts.map +1 -0
- package/lib/esm/test/incrementalSchemaLocater/TestContext.js +136 -0
- package/lib/esm/test/incrementalSchemaLocater/TestContext.js.map +1 -0
- package/lib/esm/test/standalone/ChangesetReader.test.js +222 -3
- package/lib/esm/test/standalone/ChangesetReader.test.js.map +1 -1
- package/package.json +14 -14
- package/lib/esm/test/incrementalSchemaLocater/utils/IModelSchemaLocater.d.ts +0 -11
- package/lib/esm/test/incrementalSchemaLocater/utils/IModelSchemaLocater.d.ts.map +0 -1
- package/lib/esm/test/incrementalSchemaLocater/utils/IModelSchemaLocater.js +0 -36
- package/lib/esm/test/incrementalSchemaLocater/utils/IModelSchemaLocater.js.map +0 -1
- package/lib/esm/test/incrementalSchemaLocater/utils/IncrementalTestHelper.d.ts +0 -20
- package/lib/esm/test/incrementalSchemaLocater/utils/IncrementalTestHelper.d.ts.map +0 -1
- package/lib/esm/test/incrementalSchemaLocater/utils/IncrementalTestHelper.js +0 -126
- package/lib/esm/test/incrementalSchemaLocater/utils/IncrementalTestHelper.js.map +0 -1
- package/lib/esm/test/incrementalSchemaLocater/utils/TestSqlSchemaLocater.d.ts +0 -24
- package/lib/esm/test/incrementalSchemaLocater/utils/TestSqlSchemaLocater.d.ts.map +0 -1
- package/lib/esm/test/incrementalSchemaLocater/utils/TestSqlSchemaLocater.js +0 -67
- package/lib/esm/test/incrementalSchemaLocater/utils/TestSqlSchemaLocater.js.map +0 -1
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Schema, SchemaContext, SchemaKey } from "@itwin/ecschema-metadata";
|
|
2
|
+
import { IModelIncrementalSchemaLocater } from "../../IModelIncrementalSchemaLocater";
|
|
3
|
+
import { IModelDb } from "../../IModelDb";
|
|
4
|
+
interface Options {
|
|
5
|
+
readonly bimFile?: string;
|
|
6
|
+
readonly incrementalSchemaLoading?: "enabled" | "disabled" | undefined;
|
|
7
|
+
}
|
|
8
|
+
type SchemaLocaterType<TOptions> = TOptions extends {
|
|
9
|
+
incrementalSchemaLoading: "disabled";
|
|
10
|
+
} ? never : IModelIncrementalSchemaLocater;
|
|
11
|
+
export declare class TestContext<TLocater = never> implements AsyncDisposable {
|
|
12
|
+
private readonly _iModel;
|
|
13
|
+
private readonly _schemaLocater;
|
|
14
|
+
private readonly _assetContext;
|
|
15
|
+
private constructor();
|
|
16
|
+
get iModel(): IModelDb;
|
|
17
|
+
get schemaLocater(): TLocater;
|
|
18
|
+
get schemaContext(): SchemaContext;
|
|
19
|
+
static create<TOptions extends Options>(options?: TOptions): Promise<TestContext<SchemaLocaterType<TOptions>>>;
|
|
20
|
+
private static loadIModelFile;
|
|
21
|
+
private static createIModel;
|
|
22
|
+
getSchemaNames(): Promise<string[]>;
|
|
23
|
+
importAssetSchema(schemaKey: SchemaKey): Promise<Schema>;
|
|
24
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
export {};
|
|
27
|
+
//# sourceMappingURL=TestContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TestContext.d.ts","sourceRoot":"","sources":["../../../../src/test/incrementalSchemaLocater/TestContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,aAAa,EAAsC,SAAS,EAAmB,MAAM,0BAA0B,CAAC;AACjI,OAAO,EAAE,8BAA8B,EAAE,MAAM,sCAAsC,CAAC;AACtF,OAAO,EAAe,QAAQ,EAAgB,MAAM,gBAAgB,CAAC;AAUrE,UAAU,OAAO;IACf,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,wBAAwB,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;CACxE;AAED,KAAK,iBAAiB,CAAC,QAAQ,IAAI,QAAQ,SAAS;IAAE,wBAAwB,EAAE,UAAU,CAAA;CAAE,GAAG,KAAK,GAAG,8BAA8B,CAAC;AAEtI,qBAAa,WAAW,CAAC,QAAQ,GAAG,KAAK,CAAE,YAAW,eAAe;IACnE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAW;IACnC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAW;IAC1C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAE9C,OAAO;IAoBP,IAAW,MAAM,IAAI,QAAQ,CAE5B;IAED,IAAW,aAAa,IAAI,QAAQ,CAEnC;IAED,IAAW,aAAa,IAAI,aAAa,CAExC;WAEmB,MAAM,CAAC,QAAQ,SAAS,OAAO,EAAE,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,WAAW,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC;mBAqBtG,cAAc;mBASd,YAAY;IAuBpB,cAAc,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAenC,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC;IA6BxD,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC;CAGpD"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { SchemaContext, SchemaGraphUtil, SchemaJsonLocater, SchemaMatchType } from "@itwin/ecschema-metadata";
|
|
2
|
+
import { IModelIncrementalSchemaLocater } from "../../IModelIncrementalSchemaLocater";
|
|
3
|
+
import { BriefcaseDb, IModelDb, StandaloneDb } from "../../IModelDb";
|
|
4
|
+
import { IModelHost } from "../../IModelHost";
|
|
5
|
+
import { KnownTestLocations } from "../KnownTestLocations";
|
|
6
|
+
import { OpenMode } from "@itwin/core-bentley";
|
|
7
|
+
import { IModelJsFs } from "../../IModelJsFs";
|
|
8
|
+
import { ProfileOptions } from "@itwin/core-common";
|
|
9
|
+
import { SchemaXmlFileLocater } from "@itwin/ecschema-locaters";
|
|
10
|
+
import { DOMParser, XMLSerializer } from "@xmldom/xmldom";
|
|
11
|
+
import * as path from "path";
|
|
12
|
+
export class TestContext {
|
|
13
|
+
_iModel;
|
|
14
|
+
_schemaLocater;
|
|
15
|
+
_assetContext;
|
|
16
|
+
constructor(iModel) {
|
|
17
|
+
this._iModel = iModel;
|
|
18
|
+
this._schemaLocater = this._iModel.schemaContext.locaters.find((locater) => {
|
|
19
|
+
return locater instanceof IModelIncrementalSchemaLocater;
|
|
20
|
+
});
|
|
21
|
+
// Ideally we should not need a seperate context here to locate and locate the bisschemas from the
|
|
22
|
+
// parent imodel context, but due to a bug in the incremental schema logic, we have to do this for now.
|
|
23
|
+
// TODO: remove this when issue #1763 is fixed.
|
|
24
|
+
this._assetContext = new SchemaContext();
|
|
25
|
+
this._assetContext.addLocater(new SchemaJsonLocater((schemaName) => {
|
|
26
|
+
return iModel.getSchemaProps(schemaName);
|
|
27
|
+
}));
|
|
28
|
+
const xmlAssetSchemaLocater = new SchemaXmlFileLocater();
|
|
29
|
+
xmlAssetSchemaLocater.addSchemaSearchPath(path.join(KnownTestLocations.assetsDir, "IncrementalSchemaLocater"));
|
|
30
|
+
this._assetContext.addLocater(xmlAssetSchemaLocater);
|
|
31
|
+
iModel.schemaContext.addLocater(this._assetContext);
|
|
32
|
+
}
|
|
33
|
+
get iModel() {
|
|
34
|
+
return this._iModel;
|
|
35
|
+
}
|
|
36
|
+
get schemaLocater() {
|
|
37
|
+
return this._schemaLocater;
|
|
38
|
+
}
|
|
39
|
+
get schemaContext() {
|
|
40
|
+
return this._iModel.schemaContext;
|
|
41
|
+
}
|
|
42
|
+
static async create(options) {
|
|
43
|
+
if (!IModelHost.isValid) {
|
|
44
|
+
await IModelHost.startup();
|
|
45
|
+
}
|
|
46
|
+
const iModel = options?.bimFile ?
|
|
47
|
+
await this.loadIModelFile(options.bimFile) :
|
|
48
|
+
await this.createIModel();
|
|
49
|
+
const configuration = IModelHost.configuration;
|
|
50
|
+
if (configuration) {
|
|
51
|
+
const previousSetting = configuration.incrementalSchemaLoading;
|
|
52
|
+
configuration.incrementalSchemaLoading = options ? options.incrementalSchemaLoading : "enabled";
|
|
53
|
+
iModel.onBeforeClose.addOnce(() => {
|
|
54
|
+
configuration.incrementalSchemaLoading = previousSetting;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
return new TestContext(iModel);
|
|
58
|
+
}
|
|
59
|
+
static async loadIModelFile(bimFile) {
|
|
60
|
+
const pathToBriefCase = path.join(KnownTestLocations.assetsDir, bimFile);
|
|
61
|
+
return BriefcaseDb.open({
|
|
62
|
+
fileName: pathToBriefCase,
|
|
63
|
+
readonly: true,
|
|
64
|
+
key: "test-iModel",
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
static async createIModel() {
|
|
68
|
+
const testBimPath = path.join(KnownTestLocations.assetsDir, "IncrementalSchemaLocater", "test-bim.bim");
|
|
69
|
+
if (IModelJsFs.existsSync(testBimPath)) {
|
|
70
|
+
~IModelJsFs.removeSync(testBimPath);
|
|
71
|
+
}
|
|
72
|
+
const localBim = StandaloneDb.createEmpty(testBimPath, {
|
|
73
|
+
allowEdit: "true",
|
|
74
|
+
rootSubject: {
|
|
75
|
+
name: "IncrementalSchemaTestingDb"
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
localBim.close();
|
|
79
|
+
const nativeDb = IModelDb.openDgnDb({ path: testBimPath }, OpenMode.ReadWrite, { profile: ProfileOptions.Upgrade });
|
|
80
|
+
nativeDb.saveChanges();
|
|
81
|
+
nativeDb.closeFile();
|
|
82
|
+
return StandaloneDb.openFile(testBimPath, OpenMode.ReadWrite);
|
|
83
|
+
}
|
|
84
|
+
async getSchemaNames() {
|
|
85
|
+
const result = new Array();
|
|
86
|
+
const sqlQuery = "SELECT Name, VersionMajor, VersionWrite, VersionMinor FROM meta.ECSchemaDef ORDER BY Name";
|
|
87
|
+
const reader = this._iModel.createQueryReader(sqlQuery);
|
|
88
|
+
while (await reader.step()) {
|
|
89
|
+
const name = reader.current[0];
|
|
90
|
+
const versionMajor = reader.current[1];
|
|
91
|
+
const versionWrite = reader.current[2];
|
|
92
|
+
const versionMinor = reader.current[3];
|
|
93
|
+
result.push(`${name}.${versionMajor}.${versionWrite}.${versionMinor}`);
|
|
94
|
+
}
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
async importAssetSchema(schemaKey) {
|
|
98
|
+
// If schema is already in the iModel, return it.
|
|
99
|
+
if (undefined !== this.iModel.querySchemaVersion(schemaKey.name))
|
|
100
|
+
return await this.schemaContext.getSchema(schemaKey);
|
|
101
|
+
// Locate the schema from the assets using the schema contexts asset locaters.
|
|
102
|
+
const testSchema = await this._assetContext.getSchema(schemaKey, SchemaMatchType.Exact);
|
|
103
|
+
if (undefined === testSchema)
|
|
104
|
+
throw new Error(`The schema '${schemaKey.name}' could not be found in the assets folder.`);
|
|
105
|
+
const schemaXml = await getOrderedSchemaStrings(testSchema);
|
|
106
|
+
await this._iModel.importSchemaStrings(schemaXml);
|
|
107
|
+
this._iModel.saveChanges();
|
|
108
|
+
if (this.iModel.isBriefcaseDb() && !this.iModel.isReadonly) {
|
|
109
|
+
await this.iModel.pushChanges({ description: "import test schema" });
|
|
110
|
+
}
|
|
111
|
+
const schema = await this.schemaContext.getSchema(schemaKey);
|
|
112
|
+
if (undefined === schema)
|
|
113
|
+
throw new Error(`The schema '${schemaKey.name}' could not be found after import.`);
|
|
114
|
+
if (schema.loadingController && !schema.loadingController.isComplete) {
|
|
115
|
+
await schema.loadingController.wait();
|
|
116
|
+
}
|
|
117
|
+
return schema;
|
|
118
|
+
}
|
|
119
|
+
async [Symbol.asyncDispose]() {
|
|
120
|
+
return this._iModel.close();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
async function getOrderedSchemaStrings(insertSchema) {
|
|
124
|
+
const schemas = SchemaGraphUtil.buildDependencyOrderedSchemaList(insertSchema);
|
|
125
|
+
const schemaStrings = await Promise.all(schemas.map(async (schema) => getSchemaString(schema)));
|
|
126
|
+
return schemaStrings;
|
|
127
|
+
}
|
|
128
|
+
async function getSchemaString(schema) {
|
|
129
|
+
// Serialize schema to the document object
|
|
130
|
+
const xmlDocument = new DOMParser().parseFromString(`<?xml version="1.0" encoding="UTF-8"?>`, "application/xml");
|
|
131
|
+
await schema.toXml(xmlDocument);
|
|
132
|
+
const serializer = new XMLSerializer();
|
|
133
|
+
const xml = serializer.serializeToString(xmlDocument);
|
|
134
|
+
return xml;
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=TestContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TestContext.js","sourceRoot":"","sources":["../../../../src/test/incrementalSchemaLocater/TestContext.ts"],"names":[],"mappings":"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","sourcesContent":["import { Schema, SchemaContext, SchemaGraphUtil, SchemaJsonLocater, SchemaKey, SchemaMatchType } from \"@itwin/ecschema-metadata\";\r\nimport { IModelIncrementalSchemaLocater } from \"../../IModelIncrementalSchemaLocater\";\r\nimport { BriefcaseDb, IModelDb, StandaloneDb } from \"../../IModelDb\";\r\nimport { IModelHost } from \"../../IModelHost\";\r\nimport { KnownTestLocations } from \"../KnownTestLocations\";\r\nimport { OpenMode } from \"@itwin/core-bentley\";\r\nimport { IModelJsFs } from \"../../IModelJsFs\";\r\nimport { ProfileOptions } from \"@itwin/core-common\";\r\nimport { SchemaXmlFileLocater } from \"@itwin/ecschema-locaters\";\r\nimport { DOMParser, XMLSerializer } from \"@xmldom/xmldom\";\r\nimport * as path from \"path\";\r\n\r\ninterface Options {\r\n readonly bimFile?: string;\r\n readonly incrementalSchemaLoading?: \"enabled\" | \"disabled\" | undefined;\r\n}\r\n\r\ntype SchemaLocaterType<TOptions> = TOptions extends { incrementalSchemaLoading: \"disabled\" } ? never : IModelIncrementalSchemaLocater;\r\n\r\nexport class TestContext<TLocater = never> implements AsyncDisposable {\r\n private readonly _iModel: IModelDb;\r\n private readonly _schemaLocater: TLocater;\r\n private readonly _assetContext: SchemaContext;\r\n\r\n private constructor(iModel: IModelDb) {\r\n this._iModel = iModel;\r\n this._schemaLocater = this._iModel.schemaContext.locaters.find((locater) => {\r\n return locater instanceof IModelIncrementalSchemaLocater;\r\n }) as TLocater;\r\n\r\n // Ideally we should not need a seperate context here to locate and locate the bisschemas from the\r\n // parent imodel context, but due to a bug in the incremental schema logic, we have to do this for now.\r\n // TODO: remove this when issue #1763 is fixed.\r\n this._assetContext = new SchemaContext();\r\n this._assetContext.addLocater(new SchemaJsonLocater((schemaName) => {\r\n return iModel.getSchemaProps(schemaName);\r\n }))\r\n const xmlAssetSchemaLocater = new SchemaXmlFileLocater();\r\n xmlAssetSchemaLocater.addSchemaSearchPath(path.join(KnownTestLocations.assetsDir, \"IncrementalSchemaLocater\"));\r\n this._assetContext.addLocater(xmlAssetSchemaLocater);\r\n\r\n iModel.schemaContext.addLocater(this._assetContext);\r\n }\r\n\r\n public get iModel(): IModelDb {\r\n return this._iModel;\r\n }\r\n\r\n public get schemaLocater(): TLocater {\r\n return this._schemaLocater;\r\n }\r\n\r\n public get schemaContext(): SchemaContext {\r\n return this._iModel.schemaContext;\r\n }\r\n\r\n public static async create<TOptions extends Options>(options?: TOptions): Promise<TestContext<SchemaLocaterType<TOptions>>> {\r\n if(!IModelHost.isValid) {\r\n await IModelHost.startup()\r\n }\r\n\r\n const iModel = options?.bimFile ?\r\n await this.loadIModelFile(options.bimFile) :\r\n await this.createIModel();\r\n\r\n const configuration = IModelHost.configuration;\r\n if(configuration) {\r\n const previousSetting = configuration.incrementalSchemaLoading;\r\n configuration.incrementalSchemaLoading = options ?options.incrementalSchemaLoading : \"enabled\";\r\n iModel.onBeforeClose.addOnce(() => {\r\n configuration.incrementalSchemaLoading = previousSetting;\r\n });\r\n }\r\n\r\n return new TestContext(iModel);\r\n }\r\n\r\n private static async loadIModelFile(bimFile: string): Promise<IModelDb> {\r\n const pathToBriefCase = path.join(KnownTestLocations.assetsDir, bimFile);\r\n return BriefcaseDb.open({\r\n fileName: pathToBriefCase,\r\n readonly: true,\r\n key: \"test-iModel\",\r\n });\r\n }\r\n\r\n private static async createIModel(): Promise<IModelDb> {\r\n const testBimPath = path.join(KnownTestLocations.assetsDir, \"IncrementalSchemaLocater\", \"test-bim.bim\");\r\n\r\n if (IModelJsFs.existsSync(testBimPath)) {~\r\n IModelJsFs.removeSync(testBimPath);\r\n }\r\n\r\n const localBim = StandaloneDb.createEmpty(testBimPath, {\r\n allowEdit: \"true\",\r\n rootSubject: {\r\n name: \"IncrementalSchemaTestingDb\"\r\n },\r\n });\r\n\r\n localBim.close();\r\n\r\n const nativeDb = IModelDb.openDgnDb({ path: testBimPath }, OpenMode.ReadWrite, { profile: ProfileOptions.Upgrade });\r\n nativeDb.saveChanges();\r\n nativeDb.closeFile();\r\n\r\n return StandaloneDb.openFile(testBimPath, OpenMode.ReadWrite);\r\n }\r\n\r\n public async getSchemaNames(): Promise<string[]> {\r\n const result = new Array<string>();\r\n const sqlQuery = \"SELECT Name, VersionMajor, VersionWrite, VersionMinor FROM meta.ECSchemaDef ORDER BY Name\";\r\n const reader = this._iModel.createQueryReader(sqlQuery);\r\n while (await reader.step()) {\r\n const name = reader.current[0];\r\n const versionMajor = reader.current[1];\r\n const versionWrite = reader.current[2];\r\n const versionMinor = reader.current[3];\r\n\r\n result.push(`${name}.${versionMajor}.${versionWrite}.${versionMinor}`);\r\n }\r\n return result;\r\n }\r\n\r\n public async importAssetSchema(schemaKey: SchemaKey): Promise<Schema> {\r\n // If schema is already in the iModel, return it.\r\n if (undefined !== this.iModel.querySchemaVersion(schemaKey.name))\r\n return await this.schemaContext.getSchema(schemaKey) as Schema;\r\n\r\n // Locate the schema from the assets using the schema contexts asset locaters.\r\n const testSchema = await this._assetContext.getSchema(schemaKey, SchemaMatchType.Exact);\r\n if (undefined === testSchema)\r\n throw new Error(`The schema '${schemaKey.name}' could not be found in the assets folder.`);\r\n\r\n const schemaXml = await getOrderedSchemaStrings(testSchema);\r\n await this._iModel.importSchemaStrings(schemaXml);\r\n this._iModel.saveChanges();\r\n\r\n if (this.iModel.isBriefcaseDb() && !this.iModel.isReadonly) {\r\n await this.iModel.pushChanges({ description: \"import test schema\" });\r\n }\r\n\r\n const schema = await this.schemaContext.getSchema(schemaKey);\r\n if (undefined === schema)\r\n throw new Error(`The schema '${schemaKey.name}' could not be found after import.`);\r\n\r\n if(schema.loadingController && !schema.loadingController.isComplete) {\r\n await schema.loadingController.wait();\r\n }\r\n\r\n return schema;\r\n }\r\n\r\n public async [Symbol.asyncDispose](): Promise<void> {\r\n return this._iModel.close();\r\n }\r\n}\r\n\r\nasync function getOrderedSchemaStrings(insertSchema: Schema): Promise<string[]> {\r\n const schemas = SchemaGraphUtil.buildDependencyOrderedSchemaList(insertSchema);\r\n const schemaStrings = await Promise.all(schemas.map(async (schema) => getSchemaString(schema)));\r\n return schemaStrings;\r\n}\r\n\r\nasync function getSchemaString(schema: Schema): Promise<string> {\r\n // Serialize schema to the document object\r\n const xmlDocument = new DOMParser().parseFromString(`<?xml version=\"1.0\" encoding=\"UTF-8\"?>`, \"application/xml\");\r\n await schema.toXml(xmlDocument);\r\n\r\n const serializer = new XMLSerializer();\r\n const xml = serializer.serializeToString(xmlDocument);\r\n\r\n return xml;\r\n}\r\n"]}
|
|
@@ -55,18 +55,19 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
55
55
|
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
56
56
|
*--------------------------------------------------------------------------------------------*/
|
|
57
57
|
import { DbResult, Id64 } from "@itwin/core-bentley";
|
|
58
|
-
import { Code, ColorDef, IModel, SubCategoryAppearance } from "@itwin/core-common";
|
|
58
|
+
import { Code, ColorDef, IModel, QueryBinder, SubCategoryAppearance } from "@itwin/core-common";
|
|
59
59
|
import { Arc3d, IModelJson, Point3d } from "@itwin/core-geometry";
|
|
60
|
+
import * as chai from "chai";
|
|
60
61
|
import { assert, expect } from "chai";
|
|
61
62
|
import * as path from "node:path";
|
|
62
63
|
import { DrawingCategory } from "../../Category";
|
|
63
64
|
import { ChangesetECAdaptor, ChangesetECAdaptor as ECChangesetAdaptor, ECChangeUnifierCache, PartialECChangeUnifier } from "../../ChangesetECAdaptor";
|
|
65
|
+
import { _nativeDb, ChannelControl, GraphicalElement2d } from "../../core-backend";
|
|
66
|
+
import { BriefcaseDb, SnapshotDb } from "../../IModelDb";
|
|
64
67
|
import { HubMock } from "../../internal/HubMock";
|
|
65
|
-
import { SnapshotDb } from "../../IModelDb";
|
|
66
68
|
import { SqliteChangesetReader } from "../../SqliteChangesetReader";
|
|
67
69
|
import { HubWrappers, IModelTestUtils } from "../IModelTestUtils";
|
|
68
70
|
import { KnownTestLocations } from "../KnownTestLocations";
|
|
69
|
-
import { _nativeDb, ChannelControl } from "../../core-backend";
|
|
70
71
|
describe("Changeset Reader API", async () => {
|
|
71
72
|
let iTwinId;
|
|
72
73
|
before(() => {
|
|
@@ -1434,5 +1435,223 @@ describe("Changeset Reader API", async () => {
|
|
|
1434
1435
|
}
|
|
1435
1436
|
await rwIModel.pushChanges({ description: "insert element", accessToken: adminToken });
|
|
1436
1437
|
});
|
|
1438
|
+
it("Instance update to a different class (bug)", async () => {
|
|
1439
|
+
/**
|
|
1440
|
+
* Test scenario: Verifies changeset reader behavior when an instance ID is reused with a different class.
|
|
1441
|
+
*
|
|
1442
|
+
* Steps:
|
|
1443
|
+
* 1. Import schema with two classes (T1 and T2) that inherit from GraphicalElement2d.
|
|
1444
|
+
* - T1 has property 'p' of type string
|
|
1445
|
+
* - T2 has property 'p' of type long
|
|
1446
|
+
* 2. Insert an element of type T1 with id=elId and property p="wwww"
|
|
1447
|
+
* 3. Push changeset #1: "insert element"
|
|
1448
|
+
* 4. Delete the T1 element
|
|
1449
|
+
* 5. Manipulate the element ID sequence to force reuse of the same ID
|
|
1450
|
+
* 6. Insert a new element of type T2 with the same id=elId but property p=1111
|
|
1451
|
+
* 7. Push changeset #2: "buggy changeset"
|
|
1452
|
+
*
|
|
1453
|
+
* Verification:
|
|
1454
|
+
* - Changeset #2 should show an "Updated" operation (not Delete+Insert)
|
|
1455
|
+
* - In bis_Element table: ECClassId changes from T1 to T2
|
|
1456
|
+
* - In bis_GeometricElement2d table: ECClassId changes from T1 to T2
|
|
1457
|
+
* - Property 'p' changes from string "wwww" to integer 1111
|
|
1458
|
+
*
|
|
1459
|
+
* This tests the changeset reader's ability to handle instance class changes,
|
|
1460
|
+
* which can occur in edge cases where IDs are reused with different types.
|
|
1461
|
+
*/
|
|
1462
|
+
const adminToken = "super manager token";
|
|
1463
|
+
const iModelName = "test";
|
|
1464
|
+
const modelId = await HubMock.createNewIModel({ iTwinId, iModelName, description: "TestSubject", accessToken: adminToken });
|
|
1465
|
+
assert.isNotEmpty(modelId);
|
|
1466
|
+
let b1 = await HubWrappers.downloadAndOpenBriefcase({ iTwinId, iModelId: modelId, accessToken: adminToken });
|
|
1467
|
+
// 1. Import schema with classes that span overflow table.
|
|
1468
|
+
const schema = `<?xml version="1.0" encoding="UTF-8"?>
|
|
1469
|
+
<ECSchema schemaName="TestDomain" alias="ts" version="01.00" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.1">
|
|
1470
|
+
<ECSchemaReference name="BisCore" version="01.00" alias="bis"/>
|
|
1471
|
+
<ECEntityClass typeName="T1">
|
|
1472
|
+
<BaseClass>bis:GraphicalElement2d</BaseClass>
|
|
1473
|
+
<ECProperty propertyName="p" typeName="string"/>
|
|
1474
|
+
</ECEntityClass>
|
|
1475
|
+
<ECEntityClass typeName="T2">
|
|
1476
|
+
<BaseClass>bis:GraphicalElement2d</BaseClass>
|
|
1477
|
+
<ECProperty propertyName="p" typeName="long"/>
|
|
1478
|
+
</ECEntityClass>
|
|
1479
|
+
</ECSchema>`;
|
|
1480
|
+
await b1.importSchemaStrings([schema]);
|
|
1481
|
+
b1.channels.addAllowedChannel(ChannelControl.sharedChannelName);
|
|
1482
|
+
// Create drawing model and category
|
|
1483
|
+
await b1.locks.acquireLocks({ shared: IModel.dictionaryId });
|
|
1484
|
+
const codeProps = Code.createEmpty();
|
|
1485
|
+
codeProps.value = "DrawingModel";
|
|
1486
|
+
const [, drawingModelId] = IModelTestUtils.createAndInsertDrawingPartitionAndModel(b1, codeProps, true);
|
|
1487
|
+
let drawingCategoryId = DrawingCategory.queryCategoryIdByName(b1, IModel.dictionaryId, "MyDrawingCategory");
|
|
1488
|
+
if (undefined === drawingCategoryId)
|
|
1489
|
+
drawingCategoryId = DrawingCategory.insert(b1, IModel.dictionaryId, "MyDrawingCategory", new SubCategoryAppearance({ color: ColorDef.fromString("rgb(255,0,0)").toJSON() }));
|
|
1490
|
+
const geomArray = [
|
|
1491
|
+
Arc3d.createXY(Point3d.create(0, 0), 5),
|
|
1492
|
+
Arc3d.createXY(Point3d.create(5, 5), 2),
|
|
1493
|
+
Arc3d.createXY(Point3d.create(-5, -5), 20),
|
|
1494
|
+
];
|
|
1495
|
+
const geometryStream = [];
|
|
1496
|
+
for (const geom of geomArray) {
|
|
1497
|
+
const arcData = IModelJson.Writer.toIModelJson(geom);
|
|
1498
|
+
geometryStream.push(arcData);
|
|
1499
|
+
}
|
|
1500
|
+
const geomElementT1 = {
|
|
1501
|
+
classFullName: `TestDomain:T1`,
|
|
1502
|
+
model: drawingModelId,
|
|
1503
|
+
category: drawingCategoryId,
|
|
1504
|
+
code: Code.createEmpty(),
|
|
1505
|
+
geom: geometryStream,
|
|
1506
|
+
p: "wwww",
|
|
1507
|
+
};
|
|
1508
|
+
const elId = b1.elements.insertElement(geomElementT1);
|
|
1509
|
+
assert.isTrue(Id64.isValidId64(elId), "insert worked");
|
|
1510
|
+
b1.saveChanges();
|
|
1511
|
+
await b1.pushChanges({ description: "insert element" });
|
|
1512
|
+
await b1.locks.acquireLocks({ shared: drawingModelId, exclusive: elId });
|
|
1513
|
+
await b1.locks.acquireLocks({ shared: IModel.dictionaryId });
|
|
1514
|
+
b1.elements.deleteElement(elId);
|
|
1515
|
+
b1.saveChanges();
|
|
1516
|
+
// Force id set to reproduce same instance with different classid
|
|
1517
|
+
const bid = BigInt(elId) - 1n;
|
|
1518
|
+
b1[_nativeDb].saveLocalValue("bis_elementidsequence", bid.toString());
|
|
1519
|
+
b1.saveChanges();
|
|
1520
|
+
const fileName = b1[_nativeDb].getFilePath();
|
|
1521
|
+
b1.close();
|
|
1522
|
+
b1 = await BriefcaseDb.open({ fileName });
|
|
1523
|
+
b1.channels.addAllowedChannel(ChannelControl.sharedChannelName);
|
|
1524
|
+
const geomElementT2 = {
|
|
1525
|
+
classFullName: `TestDomain:T2`,
|
|
1526
|
+
model: drawingModelId,
|
|
1527
|
+
category: drawingCategoryId,
|
|
1528
|
+
code: Code.createEmpty(),
|
|
1529
|
+
geom: geometryStream,
|
|
1530
|
+
p: 1111,
|
|
1531
|
+
};
|
|
1532
|
+
const elId2 = b1.elements.insertElement(geomElementT2);
|
|
1533
|
+
chai.expect(elId).equals(elId2);
|
|
1534
|
+
b1.saveChanges();
|
|
1535
|
+
await b1.pushChanges({ description: "buggy changeset" });
|
|
1536
|
+
const getChanges = async () => {
|
|
1537
|
+
return HubMock.downloadChangesets({ iModelId: modelId, targetDir: path.join(KnownTestLocations.outputDir, modelId, "changesets") });
|
|
1538
|
+
};
|
|
1539
|
+
const changesets = await getChanges();
|
|
1540
|
+
chai.expect(changesets.length).equals(2);
|
|
1541
|
+
chai.expect(changesets[0].description).equals("insert element");
|
|
1542
|
+
chai.expect(changesets[1].description).equals("buggy changeset");
|
|
1543
|
+
const getClassId = async (name) => {
|
|
1544
|
+
const r = b1.createQueryReader("SELECT FORMAT('0x%x', ec_classid(?))", QueryBinder.from([name]));
|
|
1545
|
+
if (await r.step()) {
|
|
1546
|
+
return r.current[0];
|
|
1547
|
+
}
|
|
1548
|
+
};
|
|
1549
|
+
const t1ClassId = await getClassId("TestDomain:T1");
|
|
1550
|
+
const t2ClassId = await getClassId("TestDomain:T2");
|
|
1551
|
+
const reader = SqliteChangesetReader.openFile({ fileName: changesets[1].pathname, disableSchemaCheck: true, db: b1 });
|
|
1552
|
+
let bisElementAsserted = false;
|
|
1553
|
+
let bisGeometricElement2dAsserted = false;
|
|
1554
|
+
while (reader.step()) {
|
|
1555
|
+
if (reader.tableName === "bis_Element" && reader.op === "Updated") {
|
|
1556
|
+
bisElementAsserted = true;
|
|
1557
|
+
chai.expect(reader.getColumnNames(reader.tableName)).deep.equals([
|
|
1558
|
+
"Id",
|
|
1559
|
+
"ECClassId",
|
|
1560
|
+
"ModelId",
|
|
1561
|
+
"LastMod",
|
|
1562
|
+
"CodeSpecId",
|
|
1563
|
+
"CodeScopeId",
|
|
1564
|
+
"CodeValue",
|
|
1565
|
+
"UserLabel",
|
|
1566
|
+
"ParentId",
|
|
1567
|
+
"ParentRelECClassId",
|
|
1568
|
+
"FederationGuid",
|
|
1569
|
+
"JsonProperties",
|
|
1570
|
+
]);
|
|
1571
|
+
const oldId = reader.getChangeValueId(0, "Old");
|
|
1572
|
+
const newId = reader.getChangeValueId(0, "New");
|
|
1573
|
+
chai.expect(oldId).equals(elId);
|
|
1574
|
+
chai.expect(newId).to.be.undefined;
|
|
1575
|
+
const oldClassId = reader.getChangeValueId(1, "Old");
|
|
1576
|
+
const newClassId = reader.getChangeValueId(1, "New");
|
|
1577
|
+
chai.expect(oldClassId).equals(t1ClassId);
|
|
1578
|
+
chai.expect(newClassId).equals(t2ClassId);
|
|
1579
|
+
chai.expect(oldClassId).is.not.equal(newClassId);
|
|
1580
|
+
}
|
|
1581
|
+
if (reader.tableName === "bis_GeometricElement2d" && reader.op === "Updated") {
|
|
1582
|
+
bisGeometricElement2dAsserted = true;
|
|
1583
|
+
chai.expect(reader.getColumnNames(reader.tableName)).deep.equals([
|
|
1584
|
+
"ElementId",
|
|
1585
|
+
"ECClassId",
|
|
1586
|
+
"CategoryId",
|
|
1587
|
+
"Origin_X",
|
|
1588
|
+
"Origin_Y",
|
|
1589
|
+
"Rotation",
|
|
1590
|
+
"BBoxLow_X",
|
|
1591
|
+
"BBoxLow_Y",
|
|
1592
|
+
"BBoxHigh_X",
|
|
1593
|
+
"BBoxHigh_Y",
|
|
1594
|
+
"GeometryStream",
|
|
1595
|
+
"TypeDefinitionId",
|
|
1596
|
+
"TypeDefinitionRelECClassId",
|
|
1597
|
+
"js1",
|
|
1598
|
+
"js2",
|
|
1599
|
+
]);
|
|
1600
|
+
// ECInstanceId
|
|
1601
|
+
const oldId = reader.getChangeValueId(0, "Old");
|
|
1602
|
+
const newId = reader.getChangeValueId(0, "New");
|
|
1603
|
+
chai.expect(oldId).equals(elId);
|
|
1604
|
+
chai.expect(newId).to.be.undefined;
|
|
1605
|
+
// ECClassId (changed)
|
|
1606
|
+
const oldClassId = reader.getChangeValueId(1, "Old");
|
|
1607
|
+
const newClassId = reader.getChangeValueId(1, "New");
|
|
1608
|
+
chai.expect(oldClassId).equals(t1ClassId);
|
|
1609
|
+
chai.expect(newClassId).equals(t2ClassId);
|
|
1610
|
+
chai.expect(oldClassId).is.not.equal(newClassId);
|
|
1611
|
+
// Property 'p' changed type and value.
|
|
1612
|
+
const oldP = reader.getChangeValueText(13, "Old");
|
|
1613
|
+
const newP = reader.getChangeValueInteger(13, "New");
|
|
1614
|
+
chai.expect(oldP).equals("wwww");
|
|
1615
|
+
chai.expect(newP).equals(1111);
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
chai.expect(bisElementAsserted).to.be.true;
|
|
1619
|
+
chai.expect(bisGeometricElement2dAsserted).to.be.true;
|
|
1620
|
+
reader.close();
|
|
1621
|
+
// ChangesetECAdaptor works incorrectly as it does not expect ECClassId to change in an update.
|
|
1622
|
+
const adaptor = new ChangesetECAdaptor(SqliteChangesetReader.openFile({ fileName: changesets[1].pathname, disableSchemaCheck: true, db: b1 }));
|
|
1623
|
+
adaptor.acceptClass(GraphicalElement2d.classFullName);
|
|
1624
|
+
adaptor.acceptOp("Updated");
|
|
1625
|
+
let ecChangeForElementAsserted = false;
|
|
1626
|
+
let ecChangeForGeometricElement2dAsserted = false;
|
|
1627
|
+
while (adaptor.step()) {
|
|
1628
|
+
if (adaptor.reader.tableName === "bis_Element") {
|
|
1629
|
+
ecChangeForElementAsserted = true;
|
|
1630
|
+
chai.expect(adaptor.inserted?.$meta?.classFullName).equals("TestDomain:T1"); // WRONG should be TestDomain:T2
|
|
1631
|
+
chai.expect(adaptor.deleted?.$meta?.classFullName).equals("TestDomain:T1"); // WRONG should be TestDomain:T2
|
|
1632
|
+
}
|
|
1633
|
+
if (adaptor.reader.tableName === "bis_GeometricElement2d") {
|
|
1634
|
+
ecChangeForGeometricElement2dAsserted = true;
|
|
1635
|
+
chai.expect(adaptor.inserted?.$meta?.classFullName).equals("TestDomain:T1"); // WRONG should be TestDomain:T2
|
|
1636
|
+
chai.expect(adaptor.deleted?.$meta?.classFullName).equals("TestDomain:T1"); // WRONG should be TestDomain:T2
|
|
1637
|
+
chai.expect(adaptor.inserted?.p).equals("0x457"); // CORRECT p in T2 is integer
|
|
1638
|
+
chai.expect(adaptor.deleted?.p).equals("wwww"); // CORRECT p in T1 is string
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
chai.expect(ecChangeForElementAsserted).to.be.true;
|
|
1642
|
+
chai.expect(ecChangeForGeometricElement2dAsserted).to.be.true;
|
|
1643
|
+
adaptor.close();
|
|
1644
|
+
// PartialECChangeUnifier fail to combine changes correctly when ECClassId is updated.
|
|
1645
|
+
const adaptor2 = new ChangesetECAdaptor(SqliteChangesetReader.openFile({ fileName: changesets[1].pathname, disableSchemaCheck: true, db: b1 }));
|
|
1646
|
+
const unifier = new PartialECChangeUnifier(b1);
|
|
1647
|
+
adaptor2.acceptClass(GraphicalElement2d.classFullName);
|
|
1648
|
+
adaptor2.acceptOp("Updated");
|
|
1649
|
+
while (adaptor2.step()) {
|
|
1650
|
+
unifier.appendFrom(adaptor2);
|
|
1651
|
+
}
|
|
1652
|
+
chai.expect(unifier.getInstanceCount()).to.be.equals(2); // WRONG should be 1
|
|
1653
|
+
b1.saveChanges();
|
|
1654
|
+
b1.close();
|
|
1655
|
+
});
|
|
1437
1656
|
});
|
|
1438
1657
|
//# sourceMappingURL=ChangesetReader.test.js.map
|