@itwin/core-backend 5.15.0-dev.1 → 5.15.0-dev.10
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 +42 -1
- package/lib/cjs/BriefcaseManager.d.ts +2 -2
- package/lib/cjs/BriefcaseManager.js.map +1 -1
- package/lib/cjs/ChangesetReaderTypes.d.ts +1 -1
- package/lib/cjs/ChangesetReaderTypes.js.map +1 -1
- package/lib/cjs/ECSqlRowExecutor.d.ts +3 -3
- package/lib/cjs/ECSqlRowExecutor.d.ts.map +1 -1
- package/lib/cjs/ECSqlRowExecutor.js +2 -2
- package/lib/cjs/ECSqlRowExecutor.js.map +1 -1
- package/lib/cjs/ECSqlStatement.d.ts +5 -0
- package/lib/cjs/ECSqlStatement.d.ts.map +1 -1
- package/lib/cjs/ECSqlStatement.js +15 -2
- package/lib/cjs/ECSqlStatement.js.map +1 -1
- package/lib/cjs/ECSqlSyncReader.d.ts.map +1 -1
- package/lib/cjs/ECSqlSyncReader.js +2 -2
- package/lib/cjs/ECSqlSyncReader.js.map +1 -1
- package/lib/cjs/Element.d.ts +29 -2
- package/lib/cjs/Element.d.ts.map +1 -1
- package/lib/cjs/Element.js +38 -2
- package/lib/cjs/Element.js.map +1 -1
- package/lib/cjs/GeographicCRSServices.d.ts +50 -2
- package/lib/cjs/GeographicCRSServices.d.ts.map +1 -1
- package/lib/cjs/GeographicCRSServices.js +11 -1
- package/lib/cjs/GeographicCRSServices.js.map +1 -1
- package/lib/cjs/ViewStore.d.ts.map +1 -1
- package/lib/cjs/ViewStore.js +62 -19
- package/lib/cjs/ViewStore.js.map +1 -1
- package/lib/esm/BriefcaseManager.d.ts +2 -2
- package/lib/esm/BriefcaseManager.js.map +1 -1
- package/lib/esm/ChangesetReaderTypes.d.ts +1 -1
- package/lib/esm/ChangesetReaderTypes.js.map +1 -1
- package/lib/esm/ECSqlRowExecutor.d.ts +3 -3
- package/lib/esm/ECSqlRowExecutor.d.ts.map +1 -1
- package/lib/esm/ECSqlRowExecutor.js +2 -2
- package/lib/esm/ECSqlRowExecutor.js.map +1 -1
- package/lib/esm/ECSqlStatement.d.ts +5 -0
- package/lib/esm/ECSqlStatement.d.ts.map +1 -1
- package/lib/esm/ECSqlStatement.js +15 -2
- package/lib/esm/ECSqlStatement.js.map +1 -1
- package/lib/esm/ECSqlSyncReader.d.ts.map +1 -1
- package/lib/esm/ECSqlSyncReader.js +3 -3
- package/lib/esm/ECSqlSyncReader.js.map +1 -1
- package/lib/esm/Element.d.ts +29 -2
- package/lib/esm/Element.d.ts.map +1 -1
- package/lib/esm/Element.js +41 -5
- package/lib/esm/Element.js.map +1 -1
- package/lib/esm/GeographicCRSServices.d.ts +50 -2
- package/lib/esm/GeographicCRSServices.d.ts.map +1 -1
- package/lib/esm/GeographicCRSServices.js +10 -1
- package/lib/esm/GeographicCRSServices.js.map +1 -1
- package/lib/esm/ViewStore.d.ts.map +1 -1
- package/lib/esm/ViewStore.js +62 -19
- package/lib/esm/ViewStore.js.map +1 -1
- package/lib/esm/test/ecdb/ECSqlQuery.test.js +17 -11
- package/lib/esm/test/ecdb/ECSqlQuery.test.js.map +1 -1
- package/lib/esm/test/ecdb/ECSqlSyncReader.test.js +140 -0
- package/lib/esm/test/ecdb/ECSqlSyncReader.test.js.map +1 -1
- package/lib/esm/test/element/ElementSubModelInsert.test.d.ts +2 -0
- package/lib/esm/test/element/ElementSubModelInsert.test.d.ts.map +1 -0
- package/lib/esm/test/element/ElementSubModelInsert.test.js +183 -0
- package/lib/esm/test/element/ElementSubModelInsert.test.js.map +1 -0
- package/lib/esm/test/hubaccess/CodeSwap.test.js +78 -0
- package/lib/esm/test/hubaccess/CodeSwap.test.js.map +1 -1
- package/lib/esm/test/hubaccess/SchemaImportOrphanColumns.test.d.ts +2 -0
- package/lib/esm/test/hubaccess/SchemaImportOrphanColumns.test.d.ts.map +1 -0
- package/lib/esm/test/hubaccess/SchemaImportOrphanColumns.test.js +142 -0
- package/lib/esm/test/hubaccess/SchemaImportOrphanColumns.test.js.map +1 -0
- package/lib/esm/test/imodel/IModelGeolocation.test.js +5 -5
- package/lib/esm/test/imodel/IModelGeolocation.test.js.map +1 -1
- package/lib/esm/test/standalone/ChangesetReader.test.js +5 -5
- package/lib/esm/test/standalone/ChangesetReader.test.js.map +1 -1
- package/lib/esm/test/standalone/SQliteChangesetReaderAndChangesetECAdaptor.test.js +2 -2
- package/lib/esm/test/standalone/SQliteChangesetReaderAndChangesetECAdaptor.test.js.map +1 -1
- package/lib/esm/test/standalone/SessionApplyIndirect.test.d.ts +2 -0
- package/lib/esm/test/standalone/SessionApplyIndirect.test.d.ts.map +1 -0
- package/lib/esm/test/standalone/SessionApplyIndirect.test.js +211 -0
- package/lib/esm/test/standalone/SessionApplyIndirect.test.js.map +1 -0
- package/lib/esm/test/standalone/ViewStoreDb.test.js +53 -0
- package/lib/esm/test/standalone/ViewStoreDb.test.js.map +1 -1
- package/package.json +15 -15
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ECSqlSyncReader.test.js","sourceRoot":"","sources":["../../../../src/test/ecdb/ECSqlSyncReader.test.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n\r\nimport { assert, expect } from \"chai\";\r\nimport * as sinon from \"sinon\";\r\nimport { QueryBinder, QueryOptionsBuilder, QueryRowFormat } from \"@itwin/core-common\";\r\nimport { SnapshotDb } from \"../../IModelDb\";\r\nimport { IModelTestUtils } from \"../IModelTestUtils\";\r\nimport { Id64 } from \"@itwin/core-bentley\";\r\nimport { ECSqlStatement } from \"../../ECSqlStatement\";\r\nimport { ECDbTestHelper } from \"./ECDbTestHelper\";\r\nimport { KnownTestLocations } from \"../KnownTestLocations\";\r\n\r\ndescribe(\"WithQueryReaderTests\", () => {\r\n let iModel: SnapshotDb;\r\n\r\n before(async () => {\r\n iModel = SnapshotDb.openFile(IModelTestUtils.resolveAssetFile(\"test.bim\"));\r\n });\r\n\r\n after(async () => {\r\n iModel.close();\r\n });\r\n it(\"check behvaiour if we call clearCaches in between\", () => {\r\n let actualRowCount = 0;\r\n const expectedInstanceIds = [\"0x1\", \"0xe\", \"0x10\", \"0x11\", \"0x12\",\r\n \"0x13\", \"0x14\", \"0x15\", \"0x16\", \"0x17\"];\r\n\r\n expect(() => iModel.withQueryReader(\"SELECT * FROM bis.Element\", (reader) => {\r\n let loopCount = 0;\r\n // First loop - read first 10 rows\r\n while (loopCount < 10) {\r\n reader.step()\r\n actualRowCount++;\r\n loopCount++;\r\n assert.isDefined(reader.current[0]);\r\n assert.equal(reader.current[0], expectedInstanceIds[actualRowCount - 1]);\r\n }\r\n assert.equal(loopCount, 10);\r\n iModel.clearCaches();\r\n\r\n reader.step(); // step should fail after clearCaches\r\n })).to.throw(\"Step failed\");\r\n });\r\n it(\"should throw error if we try to step on a closed iModelDb object\", () => {\r\n const imodelPath = iModel.pathName;\r\n expect(() => iModel.withQueryReader(\"SELECT * FROM bis.Element\", (reader) => {\r\n let loopCount = 0;\r\n while (loopCount < 10) {\r\n reader.step();\r\n assert.isDefined(reader.current[0]);\r\n loopCount++;\r\n }\r\n assert.equal(loopCount, 10);\r\n iModel.close();\r\n\r\n iModel = SnapshotDb.openFile(imodelPath);\r\n assert.isDefined(reader.current[0]);\r\n reader.step(); // step should fail after iModelDb is closed\r\n })).to.throw(\"Statement is not prepared\");\r\n });\r\n it(\"returning reader from withQueryReader callback should throw error if we try to step on it\", () => {\r\n const readerObj = iModel.withQueryReader(\"SELECT * FROM bis.Element\", (reader) => {\r\n reader.step();\r\n return reader;\r\n });\r\n expect(readerObj.current[0]).to.equal(\"0x1\"); // will not throw error as we are just accessing current row\r\n expect(() => readerObj.step()).to.throw(\"Statement is not prepared\");\r\n });\r\n it(\"checking rowFormat unspecified case - values accessed by index\", () => {\r\n // Default rowFormat is UseECSqlPropertyIndexes: columns are accessed by their SELECT-order index.\r\n iModel.withQueryReader(\"SELECT ECInstanceId, ECClassId FROM bis.Element\", (reader) => {\r\n assert.isTrue(reader.step());\r\n const id: string = reader.current[0];\r\n const classId: string = reader.current[1];\r\n assert.isTrue(Id64.isValid(classId));\r\n assert.isTrue(Id64.isValid(id));\r\n assert.equal(id, \"0x19\");\r\n });\r\n });\r\n\r\n it(\"checking rowFormat UseECSqlPropertyIndexes - values accessed by index\", () => {\r\n const config = new QueryOptionsBuilder().setRowFormat(QueryRowFormat.UseECSqlPropertyIndexes).getOptions();\r\n iModel.withQueryReader(\"SELECT ECInstanceId, ECClassId FROM bis.Element\", (reader) => {\r\n assert.isTrue(reader.step());\r\n // Index 0 → ECInstanceId, index 1 → ECClassId\r\n const id: string = reader.current[0];\r\n const classId: string = reader.current[1];\r\n assert.equal(id, \"0x19\");\r\n assert.isTrue(Id64.isValid(classId));\r\n // Swapping column order changes index, not value\r\n }, undefined, config);\r\n });\r\n\r\n it(\"checking rowFormat UseECSqlPropertyNames - values accessed by ECSQL property name\", () => {\r\n const config = new QueryOptionsBuilder().setRowFormat(QueryRowFormat.UseECSqlPropertyNames).getOptions();\r\n iModel.withQueryReader(\"SELECT ECInstanceId, ECClassId FROM bis.Element\", (reader) => {\r\n assert.isTrue(reader.step());\r\n const id: string = reader.current.ECInstanceId;\r\n const classId: string = reader.current.ECClassId;\r\n assert.equal(id, \"0x19\");\r\n assert.isTrue(Id64.isValid(classId));\r\n }, undefined, config);\r\n });\r\n\r\n it(\"checking rowFormat UseJsPropertyNames - values accessed by JavaScript property name\", () => {\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n const config = new QueryOptionsBuilder().setRowFormat(QueryRowFormat.UseJsPropertyNames).getOptions();\r\n iModel.withQueryReader(\"SELECT ECInstanceId, ECClassId FROM bis.Element\", (reader) => {\r\n assert.isTrue(reader.step());\r\n // ECInstanceId → id, ECClassId → className (resolved to a fully-qualified class name string)\r\n const id: string = reader.current.id;\r\n const className: string = reader.current.className;\r\n assert.equal(id, \"0x19\");\r\n // className should be in the form \"SchemaName.ClassName\"\r\n assert.equal(className, \"BisCore.DrawingCategory\");\r\n }, undefined, config);\r\n });\r\n\r\n it(\"checking rowFormat UseECSqlPropertyNames with convertClassIdsToClassNames - ECClassId returned as class name string\", () => {\r\n const config = new QueryOptionsBuilder()\r\n .setRowFormat(QueryRowFormat.UseECSqlPropertyNames)\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n .setConvertClassIdsToNames(true)\r\n .getOptions();\r\n iModel.withQueryReader(\"SELECT ECInstanceId, ECClassId FROM bis.Element\", (reader) => {\r\n assert.isTrue(reader.step());\r\n const id: string = reader.current.ECInstanceId;\r\n const classId: string = reader.current.ECClassId;\r\n assert.equal(id, \"0x19\");\r\n // With convertClassIdsToClassNames, ECClassId is resolved to \"SchemaName.ClassName\" instead of an Id\r\n assert.equal(classId, \"BisCore.DrawingCategory\");\r\n }, undefined, config);\r\n });\r\n\r\n describe(\"statement caching (regression)\", () => {\r\n // `withQueryReader` used to build a fresh `ECSqlStatement` and re-compile the ECSQL on every\r\n // call (via `ECSqlRowExecutor`), with no caching. Callers such as `IModelTransformer` invoke\r\n // per-element helpers (e.g. `hasSubModel`) once per element, so on large models this turned one\r\n // cached ECSQL prepare into N full native compiles - a significant performance regression. The\r\n // reader now reuses a prepared statement from the owning db's `_statementCache`.\r\n const sql = \"SELECT ECInstanceId FROM bis.Element WHERE ECInstanceId=?\";\r\n\r\n afterEach(() => sinon.restore());\r\n\r\n it(\"reuses a single prepared statement across repeated calls instead of re-preparing\", () => {\r\n iModel.clearCaches();\r\n const prepareSpy = sinon.spy(ECSqlStatement.prototype, \"prepare\"); // eslint-disable-line @typescript-eslint/no-deprecated\r\n for (let i = 0; i < 20; i++) {\r\n iModel.withQueryReader(sql, (reader) => {\r\n reader.step();\r\n }, new QueryBinder().bindId(1, \"0x1\"));\r\n }\r\n expect(prepareSpy.callCount).to.equal(1, \"queries with identical ECSQL text should re-use one cached prepared statement\");\r\n });\r\n\r\n it(\"keeps nested withQueryReader calls on the same SQL independent\", () => {\r\n iModel.clearCaches();\r\n // A nested reader on the same SQL must get its own statement (findAndRemove hands the outer\r\n // reader's statement out of the cache), so results do not corrupt each other.\r\n const outerId = iModel.withQueryReader(sql, (outer) => {\r\n assert.isTrue(outer.step());\r\n const innerId = iModel.withQueryReader(sql, (inner) => {\r\n assert.isTrue(inner.step());\r\n return inner.current[0] as string;\r\n }, new QueryBinder().bindId(1, \"0xe\"));\r\n expect(innerId).to.equal(\"0xe\");\r\n // Outer reader's cursor must be unaffected by the nested reader.\r\n return outer.current[0] as string;\r\n }, new QueryBinder().bindId(1, \"0x1\"));\r\n expect(outerId).to.equal(\"0x1\");\r\n });\r\n\r\n it(\"recovers from a prepare failure without poisoning the cache\", () => {\r\n iModel.clearCaches();\r\n const invalidSql = \"SELECT * FROM bis.ThisClassDoesNotExist\";\r\n const prepareSpy = sinon.spy(ECSqlStatement.prototype, \"prepare\"); // eslint-disable-line @typescript-eslint/no-deprecated\r\n expect(() => iModel.withQueryReader(invalidSql, (reader) => reader.step())).to.throw();\r\n expect(() => iModel.withQueryReader(invalidSql, (reader) => reader.step())).to.throw();\r\n expect(prepareSpy.callCount).to.equal(2, \"a statement that failed to prepare must not be cached\");\r\n\r\n iModel.withQueryReader(sql, (reader) => {\r\n assert.isTrue(reader.step());\r\n expect(reader.current[0]).to.equal(\"0x1\");\r\n }, new QueryBinder().bindId(1, \"0x1\"));\r\n });\r\n\r\n it(\"releases the executor and cached statement when binding fails during reader construction\", () => {\r\n iModel.clearCaches();\r\n const prepareSpy = sinon.spy(ECSqlStatement.prototype, \"prepare\"); // eslint-disable-line @typescript-eslint/no-deprecated\r\n iModel.withQueryReader(sql, (reader) => reader.step(), new QueryBinder().bindId(1, \"0x1\"));\r\n const listenerCount = iModel.onBeforeClose.numberOfListeners;\r\n\r\n const bindStub = sinon.stub(ECSqlStatement.prototype, \"bindParams\").throws(new Error(\"Expected bind failure\")); // eslint-disable-line @typescript-eslint/no-deprecated\r\n expect(() => iModel.withQueryReader(sql, () => undefined, new QueryBinder().bindId(1, \"0x1\"))).to.throw(\"Expected bind failure\");\r\n bindStub.restore();\r\n expect(iModel.onBeforeClose.numberOfListeners).to.equal(listenerCount);\r\n\r\n iModel.withQueryReader(sql, (reader) => reader.step(), new QueryBinder().bindId(1, \"0x1\"));\r\n expect(prepareSpy.callCount).to.equal(1, \"the statement checked out before the bind failure should be returned to the cache\");\r\n });\r\n\r\n it(\"also caches for ECDb.withQueryReader (shared ECSqlRowExecutor path)\", () => {\r\n using ecdb = ECDbTestHelper.createECDb(KnownTestLocations.outputDir, \"syncReaderStmtCache.ecdb\",\r\n `<ECSchema schemaName=\"Test\" alias=\"ts\" version=\"01.00.00\" xmlns=\"http://www.bentley.com/schemas/Bentley.ECXML.3.2\">\r\n <ECEntityClass typeName=\"Foo\" modifier=\"Sealed\">\r\n <ECProperty propertyName=\"n\" typeName=\"int\"/>\r\n </ECEntityClass>\r\n </ECSchema>`);\r\n ecdb.saveChanges();\r\n const ecdbSql = \"SELECT ECInstanceId FROM meta.ECClassDef WHERE ECInstanceId=?\";\r\n const prepareSpy = sinon.spy(ECSqlStatement.prototype, \"prepare\"); // eslint-disable-line @typescript-eslint/no-deprecated\r\n for (let i = 0; i < 10; i++)\r\n ecdb.withQueryReader(ecdbSql, (reader) => reader.step(), new QueryBinder().bindId(1, \"0x1\"));\r\n expect(prepareSpy.callCount).to.equal(1, \"ECDb.withQueryReader should also reuse a cached prepared statement\");\r\n });\r\n });\r\n});\r\n"]}
|
|
1
|
+
{"version":3,"file":"ECSqlSyncReader.test.js","sourceRoot":"","sources":["../../../../src/test/ecdb/ECSqlSyncReader.test.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n\r\nimport { assert, expect } from \"chai\";\r\nimport * as sinon from \"sinon\";\r\nimport * as path from \"node:path\";\r\nimport { QueryBinder, QueryOptionsBuilder, QueryPropertyMetaData, QueryRowFormat } from \"@itwin/core-common\";\r\nimport { SnapshotDb } from \"../../IModelDb\";\r\nimport { IModelTestUtils } from \"../IModelTestUtils\";\r\nimport { Id64 } from \"@itwin/core-bentley\";\r\nimport { ECSqlStatement } from \"../../ECSqlStatement\";\r\nimport { ECDbTestHelper } from \"./ECDbTestHelper\";\r\nimport { KnownTestLocations } from \"../KnownTestLocations\";\r\nimport { IModelNative } from \"../../internal/NativePlatform\";\r\nimport { IModelJsFs } from \"../../IModelJsFs\";\r\nimport { SynchronousQueryOptions } from \"../../ECSqlSyncReader\";\r\n\r\ndescribe(\"WithQueryReaderTests\", () => {\r\n let iModel: SnapshotDb;\r\n\r\n before(async () => {\r\n iModel = SnapshotDb.openFile(IModelTestUtils.resolveAssetFile(\"test.bim\"));\r\n });\r\n\r\n after(async () => {\r\n iModel.close();\r\n });\r\n it(\"check behvaiour if we call clearCaches in between\", () => {\r\n let actualRowCount = 0;\r\n const expectedInstanceIds = [\"0x1\", \"0xe\", \"0x10\", \"0x11\", \"0x12\",\r\n \"0x13\", \"0x14\", \"0x15\", \"0x16\", \"0x17\"];\r\n\r\n expect(() => iModel.withQueryReader(\"SELECT * FROM bis.Element\", (reader) => {\r\n let loopCount = 0;\r\n // First loop - read first 10 rows\r\n while (loopCount < 10) {\r\n reader.step()\r\n actualRowCount++;\r\n loopCount++;\r\n assert.isDefined(reader.current[0]);\r\n assert.equal(reader.current[0], expectedInstanceIds[actualRowCount - 1]);\r\n }\r\n assert.equal(loopCount, 10);\r\n iModel.clearCaches();\r\n\r\n reader.step(); // step should fail after clearCaches\r\n })).to.throw(\"Step failed\");\r\n });\r\n it(\"should throw error if we try to step on a closed iModelDb object\", () => {\r\n const imodelPath = iModel.pathName;\r\n expect(() => iModel.withQueryReader(\"SELECT * FROM bis.Element\", (reader) => {\r\n let loopCount = 0;\r\n while (loopCount < 10) {\r\n reader.step();\r\n assert.isDefined(reader.current[0]);\r\n loopCount++;\r\n }\r\n assert.equal(loopCount, 10);\r\n iModel.close();\r\n\r\n iModel = SnapshotDb.openFile(imodelPath);\r\n assert.isDefined(reader.current[0]);\r\n reader.step(); // step should fail after iModelDb is closed\r\n })).to.throw(\"Statement is not prepared\");\r\n });\r\n it(\"returning reader from withQueryReader callback should throw error if we try to step on it\", () => {\r\n const readerObj = iModel.withQueryReader(\"SELECT * FROM bis.Element\", (reader) => {\r\n reader.step();\r\n return reader;\r\n });\r\n expect(readerObj.current[0]).to.equal(\"0x1\"); // will not throw error as we are just accessing current row\r\n expect(() => readerObj.step()).to.throw(\"Statement is not prepared\");\r\n });\r\n it(\"checking rowFormat unspecified case - values accessed by index\", () => {\r\n // Default rowFormat is UseECSqlPropertyIndexes: columns are accessed by their SELECT-order index.\r\n iModel.withQueryReader(\"SELECT ECInstanceId, ECClassId FROM bis.Element\", (reader) => {\r\n assert.isTrue(reader.step());\r\n const id: string = reader.current[0];\r\n const classId: string = reader.current[1];\r\n assert.isTrue(Id64.isValid(classId));\r\n assert.isTrue(Id64.isValid(id));\r\n assert.equal(id, \"0x19\");\r\n });\r\n });\r\n\r\n it(\"checking rowFormat UseECSqlPropertyIndexes - values accessed by index\", () => {\r\n const config = new QueryOptionsBuilder().setRowFormat(QueryRowFormat.UseECSqlPropertyIndexes).getOptions();\r\n iModel.withQueryReader(\"SELECT ECInstanceId, ECClassId FROM bis.Element\", (reader) => {\r\n assert.isTrue(reader.step());\r\n // Index 0 → ECInstanceId, index 1 → ECClassId\r\n const id: string = reader.current[0];\r\n const classId: string = reader.current[1];\r\n assert.equal(id, \"0x19\");\r\n assert.isTrue(Id64.isValid(classId));\r\n // Swapping column order changes index, not value\r\n }, undefined, config);\r\n });\r\n\r\n it(\"checking rowFormat UseECSqlPropertyNames - values accessed by ECSQL property name\", () => {\r\n const config = new QueryOptionsBuilder().setRowFormat(QueryRowFormat.UseECSqlPropertyNames).getOptions();\r\n iModel.withQueryReader(\"SELECT ECInstanceId, ECClassId FROM bis.Element\", (reader) => {\r\n assert.isTrue(reader.step());\r\n const id: string = reader.current.ECInstanceId;\r\n const classId: string = reader.current.ECClassId;\r\n assert.equal(id, \"0x19\");\r\n assert.isTrue(Id64.isValid(classId));\r\n }, undefined, config);\r\n });\r\n\r\n it(\"checking rowFormat UseJsPropertyNames - values accessed by JavaScript property name\", () => {\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n const config = new QueryOptionsBuilder().setRowFormat(QueryRowFormat.UseJsPropertyNames).getOptions();\r\n iModel.withQueryReader(\"SELECT ECInstanceId, ECClassId FROM bis.Element\", (reader) => {\r\n assert.isTrue(reader.step());\r\n // ECInstanceId → id, ECClassId → className (resolved to a fully-qualified class name string)\r\n const id: string = reader.current.id;\r\n const className: string = reader.current.className;\r\n assert.equal(id, \"0x19\");\r\n // className should be in the form \"SchemaName.ClassName\"\r\n assert.equal(className, \"BisCore.DrawingCategory\");\r\n }, undefined, config);\r\n });\r\n\r\n it(\"checking rowFormat UseECSqlPropertyNames with convertClassIdsToClassNames - ECClassId returned as class name string\", () => {\r\n const config = new QueryOptionsBuilder()\r\n .setRowFormat(QueryRowFormat.UseECSqlPropertyNames)\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n .setConvertClassIdsToNames(true)\r\n .getOptions();\r\n iModel.withQueryReader(\"SELECT ECInstanceId, ECClassId FROM bis.Element\", (reader) => {\r\n assert.isTrue(reader.step());\r\n const id: string = reader.current.ECInstanceId;\r\n const classId: string = reader.current.ECClassId;\r\n assert.equal(id, \"0x19\");\r\n // With convertClassIdsToClassNames, ECClassId is resolved to \"SchemaName.ClassName\" instead of an Id\r\n assert.equal(classId, \"BisCore.DrawingCategory\");\r\n }, undefined, config);\r\n });\r\n\r\n describe(\"statement caching (regression)\", () => {\r\n // `withQueryReader` used to build a fresh `ECSqlStatement` and re-compile the ECSQL on every\r\n // call (via `ECSqlRowExecutor`), with no caching. Callers such as `IModelTransformer` invoke\r\n // per-element helpers (e.g. `hasSubModel`) once per element, so on large models this turned one\r\n // cached ECSQL prepare into N full native compiles - a significant performance regression. The\r\n // reader now reuses a prepared statement from the owning db's `_statementCache`.\r\n const sql = \"SELECT ECInstanceId FROM bis.Element WHERE ECInstanceId=?\";\r\n\r\n afterEach(() => sinon.restore());\r\n\r\n it(\"reuses a single prepared statement across repeated calls instead of re-preparing\", () => {\r\n iModel.clearCaches();\r\n const prepareSpy = sinon.spy(ECSqlStatement.prototype, \"prepare\"); // eslint-disable-line @typescript-eslint/no-deprecated\r\n for (let i = 0; i < 20; i++) {\r\n iModel.withQueryReader(sql, (reader) => {\r\n reader.step();\r\n }, new QueryBinder().bindId(1, \"0x1\"));\r\n }\r\n expect(prepareSpy.callCount).to.equal(1, \"queries with identical ECSQL text should re-use one cached prepared statement\");\r\n });\r\n\r\n it(\"keeps nested withQueryReader calls on the same SQL independent\", () => {\r\n iModel.clearCaches();\r\n // A nested reader on the same SQL must get its own statement (findAndRemove hands the outer\r\n // reader's statement out of the cache), so results do not corrupt each other.\r\n const outerId = iModel.withQueryReader(sql, (outer) => {\r\n assert.isTrue(outer.step());\r\n const innerId = iModel.withQueryReader(sql, (inner) => {\r\n assert.isTrue(inner.step());\r\n return inner.current[0] as string;\r\n }, new QueryBinder().bindId(1, \"0xe\"));\r\n expect(innerId).to.equal(\"0xe\");\r\n // Outer reader's cursor must be unaffected by the nested reader.\r\n return outer.current[0] as string;\r\n }, new QueryBinder().bindId(1, \"0x1\"));\r\n expect(outerId).to.equal(\"0x1\");\r\n });\r\n\r\n it(\"recovers from a prepare failure without poisoning the cache\", () => {\r\n iModel.clearCaches();\r\n const invalidSql = \"SELECT * FROM bis.ThisClassDoesNotExist\";\r\n const prepareSpy = sinon.spy(ECSqlStatement.prototype, \"prepare\"); // eslint-disable-line @typescript-eslint/no-deprecated\r\n expect(() => iModel.withQueryReader(invalidSql, (reader) => reader.step())).to.throw();\r\n expect(() => iModel.withQueryReader(invalidSql, (reader) => reader.step())).to.throw();\r\n expect(prepareSpy.callCount).to.equal(2, \"a statement that failed to prepare must not be cached\");\r\n\r\n iModel.withQueryReader(sql, (reader) => {\r\n assert.isTrue(reader.step());\r\n expect(reader.current[0]).to.equal(\"0x1\");\r\n }, new QueryBinder().bindId(1, \"0x1\"));\r\n });\r\n\r\n it(\"releases the executor and cached statement when binding fails during reader construction\", () => {\r\n iModel.clearCaches();\r\n const prepareSpy = sinon.spy(ECSqlStatement.prototype, \"prepare\"); // eslint-disable-line @typescript-eslint/no-deprecated\r\n iModel.withQueryReader(sql, (reader) => reader.step(), new QueryBinder().bindId(1, \"0x1\"));\r\n const listenerCount = iModel.onBeforeClose.numberOfListeners;\r\n\r\n const bindStub = sinon.stub(ECSqlStatement.prototype, \"bindParams\").throws(new Error(\"Expected bind failure\")); // eslint-disable-line @typescript-eslint/no-deprecated\r\n expect(() => iModel.withQueryReader(sql, () => undefined, new QueryBinder().bindId(1, \"0x1\"))).to.throw(\"Expected bind failure\");\r\n bindStub.restore();\r\n expect(iModel.onBeforeClose.numberOfListeners).to.equal(listenerCount);\r\n\r\n iModel.withQueryReader(sql, (reader) => reader.step(), new QueryBinder().bindId(1, \"0x1\"));\r\n expect(prepareSpy.callCount).to.equal(1, \"the statement checked out before the bind failure should be returned to the cache\");\r\n });\r\n\r\n it(\"also caches for ECDb.withQueryReader (shared ECSqlRowExecutor path)\", () => {\r\n using ecdb = ECDbTestHelper.createECDb(KnownTestLocations.outputDir, \"syncReaderStmtCache.ecdb\",\r\n `<ECSchema schemaName=\"Test\" alias=\"ts\" version=\"01.00.00\" xmlns=\"http://www.bentley.com/schemas/Bentley.ECXML.3.2\">\r\n <ECEntityClass typeName=\"Foo\" modifier=\"Sealed\">\r\n <ECProperty propertyName=\"n\" typeName=\"int\"/>\r\n </ECEntityClass>\r\n </ECSchema>`);\r\n ecdb.saveChanges();\r\n const ecdbSql = \"SELECT ECInstanceId FROM meta.ECClassDef WHERE ECInstanceId=?\";\r\n const prepareSpy = sinon.spy(ECSqlStatement.prototype, \"prepare\"); // eslint-disable-line @typescript-eslint/no-deprecated\r\n for (let i = 0; i < 10; i++)\r\n ecdb.withQueryReader(ecdbSql, (reader) => reader.step(), new QueryBinder().bindId(1, \"0x1\"));\r\n expect(prepareSpy.callCount).to.equal(1, \"ECDb.withQueryReader should also reuse a cached prepared statement\");\r\n });\r\n });\r\n\r\n describe(\"metadata caching\", () => {\r\n // Column metadata depends only on the prepared statement and the row-adaptor options, so it is cached\r\n // on the cached ECSqlStatement instead of being fetched from native code on every withQueryReader call.\r\n const sql = \"SELECT ECInstanceId, ECClassId, CodeValue, GeometryStream FROM bis.GeometricElement3d WHERE ECInstanceId=?\";\r\n let elementId: string;\r\n\r\n before(() => {\r\n elementId = iModel.withQueryReader(\"SELECT ECInstanceId FROM bis.GeometricElement3d WHERE GeometryStream IS NOT NULL LIMIT 1\", (reader) => {\r\n assert.isTrue(reader.step());\r\n return reader.current[0] as string;\r\n });\r\n });\r\n\r\n afterEach(() => sinon.restore());\r\n\r\n function readMetadata(options: SynchronousQueryOptions): { meta: QueryPropertyMetaData[], row: any } {\r\n return iModel.withQueryReader(sql, (reader) => {\r\n assert.isTrue(reader.step());\r\n return { meta: reader.getMetaData(), row: reader.current.toRow() };\r\n }, new QueryBinder().bindId(1, elementId), options);\r\n }\r\n\r\n it(\"returns metadata matching the row options when the same statement is reused with different options\", () => {\r\n const optionSets: SynchronousQueryOptions[] = [\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n { rowFormat: QueryRowFormat.UseJsPropertyNames },\r\n { rowFormat: QueryRowFormat.UseECSqlPropertyNames },\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n { rowFormat: QueryRowFormat.UseJsPropertyNames, abbreviateBlobs: true },\r\n { rowFormat: QueryRowFormat.UseECSqlPropertyNames, abbreviateBlobs: true },\r\n { rowFormat: QueryRowFormat.UseECSqlPropertyNames, convertClassIdsToClassNames: true },\r\n ];\r\n\r\n // Expected metadata comes from a freshly prepared statement for each option set.\r\n const expected = optionSets.map((options) => {\r\n iModel.clearCaches();\r\n return readMetadata({ ...options }).meta;\r\n });\r\n expect(expected[0].map((p) => p.jsonName)).to.deep.equal([\"id\", \"className\", \"codeValue\", \"geometryStream\"]);\r\n expect(expected[1].map((p) => p.name)).to.deep.equal([\"ECInstanceId\", \"ECClassId\", \"CodeValue\", \"GeometryStream\"]);\r\n\r\n iModel.clearCaches();\r\n for (let pass = 0; pass < 2; pass++) {\r\n optionSets.forEach((options, i) => {\r\n const { meta, row } = readMetadata({ ...options });\r\n expect(meta).to.deep.equal(expected[i]);\r\n const geometryStream = row[options.rowFormat === QueryRowFormat.UseECSqlPropertyNames ? \"GeometryStream\" : \"geometryStream\"];\r\n if (options.abbreviateBlobs)\r\n expect(geometryStream).to.be.a(\"string\").and.match(/^\\{\"bytes\":\\d+\\}$/);\r\n else\r\n expect(geometryStream).to.be.instanceOf(Uint8Array);\r\n });\r\n }\r\n });\r\n\r\n it(\"fetches native metadata once per statement and row options\", () => {\r\n // Native prototype methods cannot be spied on directly, so count calls through a subclass.\r\n const getMetadataSpy = sinon.spy();\r\n const nativeStatement = IModelNative.platform.ECSqlStatement;\r\n sinon.replace(IModelNative.platform, \"ECSqlStatement\", class extends nativeStatement {\r\n public override getMetadata(...args: Parameters<typeof nativeStatement.prototype.getMetadata>) {\r\n getMetadataSpy();\r\n return super.getMetadata(...args);\r\n }\r\n });\r\n iModel.clearCaches();\r\n const options = { rowFormat: QueryRowFormat.UseECSqlPropertyNames };\r\n for (let i = 0; i < 10; i++)\r\n readMetadata({ ...options });\r\n expect(getMetadataSpy.callCount).to.equal(1);\r\n\r\n readMetadata({ ...options, abbreviateBlobs: true });\r\n readMetadata({ ...options, abbreviateBlobs: true });\r\n expect(getMetadataSpy.callCount).to.equal(2, \"different row options need their own metadata\");\r\n\r\n iModel.clearCaches();\r\n readMetadata({ ...options });\r\n expect(getMetadataSpy.callCount).to.equal(3, \"a re-prepared statement must not reuse cached metadata\");\r\n });\r\n\r\n it(\"does not share metadata objects between calls\", () => {\r\n iModel.clearCaches();\r\n const options = { rowFormat: QueryRowFormat.UseECSqlPropertyNames };\r\n const expected = structuredClone(readMetadata({ ...options }).meta);\r\n\r\n iModel.withQueryReader(sql, (reader) => {\r\n assert.isTrue(reader.step());\r\n const readerMeta = reader.getMetaData();\r\n readerMeta[0].name = \"Changed\";\r\n readerMeta[0].index = 3;\r\n readerMeta.reverse();\r\n const proxyMeta = reader.current.getMetaData();\r\n proxyMeta.push({ ...proxyMeta[0], name: \"Extra\" });\r\n }, new QueryBinder().bindId(1, elementId), options);\r\n\r\n const { meta, row } = readMetadata({ ...options });\r\n expect(meta).to.deep.equal(expected);\r\n expect(row.ECInstanceId).to.equal(elementId);\r\n });\r\n\r\n it(\"returns metadata for queries that produce no rows\", () => {\r\n iModel.clearCaches();\r\n const options = { rowFormat: QueryRowFormat.UseECSqlPropertyNames };\r\n const expected = readMetadata({ ...options }).meta;\r\n for (let i = 0; i < 3; i++) {\r\n iModel.withQueryReader(sql, (reader) => {\r\n expect(reader.step()).to.be.false;\r\n expect(reader.getMetaData()).to.deep.equal(expected);\r\n }, new QueryBinder().bindId(1, \"0xffffff\"), options);\r\n iModel.withQueryReader(sql, (reader) => {\r\n expect(reader.getMetaData()).to.deep.equal(expected);\r\n expect(reader.toArray()).to.deep.equal([]);\r\n }, new QueryBinder().bindId(1, \"0xffffff\"), options);\r\n }\r\n });\r\n\r\n it(\"reflects a schema import between calls\", () => {\r\n const schemaXml = (version: string, extraProperty: string) => `<ECSchema schemaName=\"Test\" alias=\"ts\" version=\"${version}\" xmlns=\"http://www.bentley.com/schemas/Bentley.ECXML.3.2\">\r\n <ECEntityClass typeName=\"Foo\" modifier=\"Sealed\">\r\n <ECProperty propertyName=\"n\" typeName=\"int\"/>\r\n ${extraProperty}\r\n </ECEntityClass>\r\n </ECSchema>`;\r\n using ecdb = ECDbTestHelper.createECDb(KnownTestLocations.outputDir, \"syncReaderMetadataCache.ecdb\", schemaXml(\"01.00.00\", \"\"));\r\n ecdb.withCachedWriteStatement(\"INSERT INTO ts.Foo(n) VALUES(1)\", (stmt) => stmt.stepForInsert());\r\n ecdb.saveChanges();\r\n\r\n const fooSql = \"SELECT * FROM ts.Foo\";\r\n const options = { rowFormat: QueryRowFormat.UseECSqlPropertyNames };\r\n const readNames = () => ecdb.withQueryReader(fooSql, (reader) => {\r\n assert.isTrue(reader.step());\r\n return reader.getMetaData().map((p) => p.name);\r\n }, undefined, options);\r\n expect(readNames()).to.deep.equal([\"ECInstanceId\", \"ECClassId\", \"n\"]);\r\n expect(readNames()).to.deep.equal([\"ECInstanceId\", \"ECClassId\", \"n\"]);\r\n\r\n const schemaPath = path.join(KnownTestLocations.outputDir, \"syncReaderMetadataCache.ecschema.xml\");\r\n IModelJsFs.writeFileSync(schemaPath, schemaXml(\"01.00.01\", `<ECProperty propertyName=\"m\" typeName=\"string\"/>`));\r\n ecdb.importSchema(schemaPath);\r\n ecdb.saveChanges();\r\n\r\n expect(readNames()).to.deep.equal([\"ECInstanceId\", \"ECClassId\", \"n\", \"m\"]);\r\n });\r\n });\r\n});\r\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ElementSubModelInsert.test.d.ts","sourceRoot":"","sources":["../../../../src/test/element/ElementSubModelInsert.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/*---------------------------------------------------------------------------------------------
|
|
2
|
+
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
3
|
+
* See LICENSE.md in the repository root for full copyright notice.
|
|
4
|
+
*--------------------------------------------------------------------------------------------*/
|
|
5
|
+
import { expect } from "chai";
|
|
6
|
+
import { spy as sinonSpy } from "sinon";
|
|
7
|
+
import { Id64, IModelStatus } from "@itwin/core-bentley";
|
|
8
|
+
import { Code, IModel, IModelError } from "@itwin/core-common";
|
|
9
|
+
import { ClassRegistry } from "../../ClassRegistry";
|
|
10
|
+
import { withEditTxn } from "../../EditTxn";
|
|
11
|
+
import { Document, Drawing, SectionDrawing, Sheet, TemplateRecipe2d } from "../../Element";
|
|
12
|
+
import { GenericSchema } from "../../domains/GenericSchema";
|
|
13
|
+
import { SnapshotDb } from "../../IModelDb";
|
|
14
|
+
import { DefinitionModel, DocumentListModel, DrawingModel, SectionDrawingModel, SheetModel } from "../../Model";
|
|
15
|
+
import { Schema, Schemas } from "../../Schema";
|
|
16
|
+
import { IModelTestUtils } from "../IModelTestUtils";
|
|
17
|
+
class TestSubModelSchema extends Schema {
|
|
18
|
+
static get schemaName() { return "TestSubModel"; }
|
|
19
|
+
}
|
|
20
|
+
/** A Sheet subclass that overrides the hook and defers to the inherited validation via `super`. */
|
|
21
|
+
class TestSheetSpy extends Sheet {
|
|
22
|
+
static get className() { return "TestSheetSpy"; }
|
|
23
|
+
static onSubModelInsert(arg) {
|
|
24
|
+
super.onSubModelInsert(arg);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/** A Sheet subclass that widens the inherited rule to also permit a DrawingModel. */
|
|
28
|
+
class TestSheetWidened extends Sheet {
|
|
29
|
+
static get className() { return "TestSheetWidened"; }
|
|
30
|
+
static get allowedSubModelClasses() { return [SheetModel, DrawingModel]; }
|
|
31
|
+
}
|
|
32
|
+
/** A Sheet subclass that replaces the hook without calling `super`, opting out of validation. */
|
|
33
|
+
class TestSheetUnvalidated extends Sheet {
|
|
34
|
+
static get className() { return "TestSheetUnvalidated"; }
|
|
35
|
+
static onSubModelInsert(_arg) { }
|
|
36
|
+
}
|
|
37
|
+
/** A domain ISubModeledElement unrelated to Sheet/Drawing that opts in by overriding only the getter. */
|
|
38
|
+
class TestRestrictedDocument extends Document {
|
|
39
|
+
static get className() { return "TestRestrictedDocument"; }
|
|
40
|
+
static get allowedSubModelClasses() { return [DrawingModel]; }
|
|
41
|
+
}
|
|
42
|
+
const testSchemaXml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
43
|
+
<ECSchema schemaName="TestSubModel" alias="tsm" version="01.00.00" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.2">
|
|
44
|
+
<ECSchemaReference name="BisCore" version="01.00.04" alias="bis"/>
|
|
45
|
+
<ECCustomAttributes>
|
|
46
|
+
<SchemaHasBehavior xmlns="BisCore.01.00.00"/>
|
|
47
|
+
</ECCustomAttributes>
|
|
48
|
+
<ECEntityClass typeName="TestSheetModel">
|
|
49
|
+
<BaseClass>bis:SheetModel</BaseClass>
|
|
50
|
+
</ECEntityClass>
|
|
51
|
+
<ECEntityClass typeName="TestSheetGenerated">
|
|
52
|
+
<BaseClass>bis:Sheet</BaseClass>
|
|
53
|
+
</ECEntityClass>
|
|
54
|
+
<ECEntityClass typeName="TestSheetSpy">
|
|
55
|
+
<BaseClass>bis:Sheet</BaseClass>
|
|
56
|
+
</ECEntityClass>
|
|
57
|
+
<ECEntityClass typeName="TestSheetWidened">
|
|
58
|
+
<BaseClass>bis:Sheet</BaseClass>
|
|
59
|
+
</ECEntityClass>
|
|
60
|
+
<ECEntityClass typeName="TestSheetUnvalidated">
|
|
61
|
+
<BaseClass>bis:Sheet</BaseClass>
|
|
62
|
+
</ECEntityClass>
|
|
63
|
+
<ECEntityClass typeName="TestHostDocument">
|
|
64
|
+
<BaseClass>bis:Document</BaseClass>
|
|
65
|
+
<BaseClass>bis:ISubModeledElement</BaseClass>
|
|
66
|
+
</ECEntityClass>
|
|
67
|
+
<ECEntityClass typeName="TestRestrictedDocument">
|
|
68
|
+
<BaseClass>bis:Document</BaseClass>
|
|
69
|
+
<BaseClass>bis:ISubModeledElement</BaseClass>
|
|
70
|
+
</ECEntityClass>
|
|
71
|
+
</ECSchema>`;
|
|
72
|
+
describe("Sub-model insert validation", () => {
|
|
73
|
+
let imodel;
|
|
74
|
+
let documentListModelId;
|
|
75
|
+
before(async () => {
|
|
76
|
+
GenericSchema.registerSchema();
|
|
77
|
+
Schemas.registerSchema(TestSubModelSchema);
|
|
78
|
+
ClassRegistry.register(TestSheetSpy, TestSubModelSchema);
|
|
79
|
+
ClassRegistry.register(TestSheetWidened, TestSubModelSchema);
|
|
80
|
+
ClassRegistry.register(TestSheetUnvalidated, TestSubModelSchema);
|
|
81
|
+
ClassRegistry.register(TestRestrictedDocument, TestSubModelSchema);
|
|
82
|
+
const iModelPath = IModelTestUtils.prepareOutputFile("SubModelInsert", "SubModelInsert.bim");
|
|
83
|
+
imodel = SnapshotDb.createEmpty(iModelPath, { rootSubject: { name: "SubModelInsertTest" } });
|
|
84
|
+
await imodel.importSchemaStrings([testSchemaXml]);
|
|
85
|
+
documentListModelId = withEditTxn(imodel, (txn) => DocumentListModel.insert(txn, SnapshotDb.rootSubjectId, "DocumentList"));
|
|
86
|
+
});
|
|
87
|
+
after(() => {
|
|
88
|
+
imodel.close();
|
|
89
|
+
Schemas.unregisterSchema(TestSubModelSchema.schemaName);
|
|
90
|
+
});
|
|
91
|
+
function insertHost(classFullName, modelId = documentListModelId) {
|
|
92
|
+
const id = withEditTxn(imodel, (txn) => txn.insertElement({ classFullName, model: modelId, code: Code.createEmpty() }));
|
|
93
|
+
expect(Id64.isValidId64(id)).to.be.true;
|
|
94
|
+
return id;
|
|
95
|
+
}
|
|
96
|
+
function insertSubModel(modelClassFullName, modeledElementId) {
|
|
97
|
+
return withEditTxn(imodel, (txn) => txn.insertModel({ classFullName: modelClassFullName, modeledElement: { id: modeledElementId } }));
|
|
98
|
+
}
|
|
99
|
+
function expectAccepted(hostClassFullName, modelClassFullName, hostModelId) {
|
|
100
|
+
const hostId = insertHost(hostClassFullName, hostModelId);
|
|
101
|
+
const modelId = insertSubModel(modelClassFullName, hostId);
|
|
102
|
+
expect(modelId).to.equal(hostId);
|
|
103
|
+
expect(imodel.models.getModel(modelId).classFullName).to.equal(modelClassFullName);
|
|
104
|
+
}
|
|
105
|
+
function expectRejected(hostClassFullName, modelClassFullName, hostModelId) {
|
|
106
|
+
const hostId = insertHost(hostClassFullName, hostModelId);
|
|
107
|
+
let error;
|
|
108
|
+
try {
|
|
109
|
+
insertSubModel(modelClassFullName, hostId);
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
error = err;
|
|
113
|
+
}
|
|
114
|
+
expect(error).to.be.instanceOf(IModelError);
|
|
115
|
+
expect(error.errorNumber).to.equal(IModelStatus.WrongModel);
|
|
116
|
+
expect(error.message).to.contain("must be sub-modeled by");
|
|
117
|
+
expect(imodel.models.tryGetModel(hostId)).to.be.undefined;
|
|
118
|
+
}
|
|
119
|
+
describe("accepts", () => {
|
|
120
|
+
it("Sheet + SheetModel", () => expectAccepted(Sheet.classFullName, SheetModel.classFullName));
|
|
121
|
+
it("Drawing + DrawingModel", () => expectAccepted(Drawing.classFullName, DrawingModel.classFullName));
|
|
122
|
+
it("SectionDrawing + DrawingModel", () => expectAccepted(SectionDrawing.classFullName, DrawingModel.classFullName));
|
|
123
|
+
it("SectionDrawing + SectionDrawingModel", () => expectAccepted(SectionDrawing.classFullName, SectionDrawingModel.classFullName));
|
|
124
|
+
it("SectionDrawing + Generic:GraphicalModel3d", () => expectAccepted(SectionDrawing.classFullName, "Generic:GraphicalModel3d"));
|
|
125
|
+
it("TemplateRecipe2d + DrawingModel", () => expectAccepted(TemplateRecipe2d.classFullName, DrawingModel.classFullName, IModel.dictionaryId));
|
|
126
|
+
it("Sheet + SheetModel subclass without a JS class", () => expectAccepted(Sheet.classFullName, "TestSubModel:TestSheetModel"));
|
|
127
|
+
it("no allowedSubModelClasses → any model accepted", () => {
|
|
128
|
+
expectAccepted("TestSubModel:TestHostDocument", SheetModel.classFullName);
|
|
129
|
+
expectAccepted("TestSubModel:TestHostDocument", DrawingModel.classFullName);
|
|
130
|
+
});
|
|
131
|
+
it("Sheet subclass that widens allowedSubModelClasses + DrawingModel", () => expectAccepted(TestSheetWidened.classFullName, DrawingModel.classFullName));
|
|
132
|
+
it("Sheet subclass that overrides onSubModelInsert without super + DrawingModel", () => expectAccepted(TestSheetUnvalidated.classFullName, DrawingModel.classFullName));
|
|
133
|
+
it("Document subclass with allowedSubModelClasses + DrawingModel", () => expectAccepted(TestRestrictedDocument.classFullName, DrawingModel.classFullName));
|
|
134
|
+
});
|
|
135
|
+
describe("rejects with IModelStatus.WrongModel", () => {
|
|
136
|
+
it("Sheet + DrawingModel", () => expectRejected(Sheet.classFullName, DrawingModel.classFullName));
|
|
137
|
+
it("Drawing + SheetModel", () => expectRejected(Drawing.classFullName, SheetModel.classFullName));
|
|
138
|
+
it("SectionDrawing + SheetModel", () => expectRejected(SectionDrawing.classFullName, SheetModel.classFullName));
|
|
139
|
+
it("TemplateRecipe2d + SheetModel", () => expectRejected(TemplateRecipe2d.classFullName, SheetModel.classFullName, IModel.dictionaryId));
|
|
140
|
+
it("Sheet subclass without a JS class + DrawingModel", () => expectRejected("TestSubModel:TestSheetGenerated", DrawingModel.classFullName));
|
|
141
|
+
it("Document subclass with allowedSubModelClasses + SheetModel", () => expectRejected(TestRestrictedDocument.classFullName, SheetModel.classFullName));
|
|
142
|
+
});
|
|
143
|
+
it("invokes an overriding subclass hook that defers to the inherited validation", () => {
|
|
144
|
+
const spy = sinonSpy(TestSheetSpy, "onSubModelInsert");
|
|
145
|
+
try {
|
|
146
|
+
expectAccepted(TestSheetSpy.classFullName, SheetModel.classFullName);
|
|
147
|
+
expect(spy.calledOnce).to.be.true;
|
|
148
|
+
expect(spy.getCall(0).args[0].subModelProps.classFullName).to.equal(SheetModel.classFullName);
|
|
149
|
+
expectRejected(TestSheetSpy.classFullName, DrawingModel.classFullName);
|
|
150
|
+
expect(spy.calledTwice).to.be.true;
|
|
151
|
+
expect(spy.getCall(1).threw()).to.be.true;
|
|
152
|
+
}
|
|
153
|
+
finally {
|
|
154
|
+
spy.restore();
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
describe("missing required behavior", () => {
|
|
158
|
+
it("rejects sub-model insertion", () => {
|
|
159
|
+
const hostId = insertHost(TestRestrictedDocument.classFullName);
|
|
160
|
+
Schemas.unregisterSchema(TestSubModelSchema.schemaName);
|
|
161
|
+
try {
|
|
162
|
+
let error;
|
|
163
|
+
try {
|
|
164
|
+
insertSubModel(DefinitionModel.classFullName, hostId);
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
error = err;
|
|
168
|
+
}
|
|
169
|
+
expect(error).to.be.instanceOf(IModelError);
|
|
170
|
+
expect(error.errorNumber).to.equal(IModelStatus.WrongHandler);
|
|
171
|
+
expect(imodel.models.tryGetModel(hostId)).to.be.undefined;
|
|
172
|
+
}
|
|
173
|
+
finally {
|
|
174
|
+
Schemas.registerSchema(TestSubModelSchema);
|
|
175
|
+
ClassRegistry.register(TestSheetSpy, TestSubModelSchema);
|
|
176
|
+
ClassRegistry.register(TestSheetWidened, TestSubModelSchema);
|
|
177
|
+
ClassRegistry.register(TestSheetUnvalidated, TestSubModelSchema);
|
|
178
|
+
ClassRegistry.register(TestRestrictedDocument, TestSubModelSchema);
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
//# sourceMappingURL=ElementSubModelInsert.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ElementSubModelInsert.test.js","sourceRoot":"","sources":["../../../../src/test/element/ElementSubModelInsert.test.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the repository root for full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\nimport { expect } from \"chai\";\r\nimport { spy as sinonSpy } from \"sinon\";\r\nimport { Id64, Id64String, IModelStatus } from \"@itwin/core-bentley\";\r\nimport { Code, IModel, IModelError } from \"@itwin/core-common\";\r\nimport { ClassRegistry } from \"../../ClassRegistry\";\r\nimport { withEditTxn } from \"../../EditTxn\";\r\nimport { Document, Drawing, OnSubModelPropsArg, SectionDrawing, Sheet, TemplateRecipe2d } from \"../../Element\";\r\nimport { EntityClassType } from \"../../Entity\";\r\nimport { GenericSchema } from \"../../domains/GenericSchema\";\r\nimport { SnapshotDb } from \"../../IModelDb\";\r\nimport { DefinitionModel, DocumentListModel, DrawingModel, Model, SectionDrawingModel, SheetModel } from \"../../Model\";\r\nimport { Schema, Schemas } from \"../../Schema\";\r\nimport { IModelTestUtils } from \"../IModelTestUtils\";\r\n\r\nclass TestSubModelSchema extends Schema {\r\n public static override get schemaName(): string { return \"TestSubModel\"; }\r\n}\r\n\r\n/** A Sheet subclass that overrides the hook and defers to the inherited validation via `super`. */\r\nclass TestSheetSpy extends Sheet {\r\n public static override get className(): string { return \"TestSheetSpy\"; }\r\n public static override onSubModelInsert(arg: OnSubModelPropsArg): void {\r\n super.onSubModelInsert(arg);\r\n }\r\n}\r\n\r\n/** A Sheet subclass that widens the inherited rule to also permit a DrawingModel. */\r\nclass TestSheetWidened extends Sheet {\r\n public static override get className(): string { return \"TestSheetWidened\"; }\r\n protected static override get allowedSubModelClasses(): Array<EntityClassType<Model>> { return [SheetModel, DrawingModel]; }\r\n}\r\n\r\n/** A Sheet subclass that replaces the hook without calling `super`, opting out of validation. */\r\nclass TestSheetUnvalidated extends Sheet {\r\n public static override get className(): string { return \"TestSheetUnvalidated\"; }\r\n public static override onSubModelInsert(_arg: OnSubModelPropsArg): void { }\r\n}\r\n\r\n/** A domain ISubModeledElement unrelated to Sheet/Drawing that opts in by overriding only the getter. */\r\nclass TestRestrictedDocument extends Document {\r\n public static override get className(): string { return \"TestRestrictedDocument\"; }\r\n protected static override get allowedSubModelClasses(): Array<EntityClassType<Model>> { return [DrawingModel]; }\r\n}\r\n\r\nconst testSchemaXml = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<ECSchema schemaName=\"TestSubModel\" alias=\"tsm\" version=\"01.00.00\" xmlns=\"http://www.bentley.com/schemas/Bentley.ECXML.3.2\">\r\n <ECSchemaReference name=\"BisCore\" version=\"01.00.04\" alias=\"bis\"/>\r\n <ECCustomAttributes>\r\n <SchemaHasBehavior xmlns=\"BisCore.01.00.00\"/>\r\n </ECCustomAttributes>\r\n <ECEntityClass typeName=\"TestSheetModel\">\r\n <BaseClass>bis:SheetModel</BaseClass>\r\n </ECEntityClass>\r\n <ECEntityClass typeName=\"TestSheetGenerated\">\r\n <BaseClass>bis:Sheet</BaseClass>\r\n </ECEntityClass>\r\n <ECEntityClass typeName=\"TestSheetSpy\">\r\n <BaseClass>bis:Sheet</BaseClass>\r\n </ECEntityClass>\r\n <ECEntityClass typeName=\"TestSheetWidened\">\r\n <BaseClass>bis:Sheet</BaseClass>\r\n </ECEntityClass>\r\n <ECEntityClass typeName=\"TestSheetUnvalidated\">\r\n <BaseClass>bis:Sheet</BaseClass>\r\n </ECEntityClass>\r\n <ECEntityClass typeName=\"TestHostDocument\">\r\n <BaseClass>bis:Document</BaseClass>\r\n <BaseClass>bis:ISubModeledElement</BaseClass>\r\n </ECEntityClass>\r\n <ECEntityClass typeName=\"TestRestrictedDocument\">\r\n <BaseClass>bis:Document</BaseClass>\r\n <BaseClass>bis:ISubModeledElement</BaseClass>\r\n </ECEntityClass>\r\n</ECSchema>`;\r\n\r\ndescribe(\"Sub-model insert validation\", () => {\r\n let imodel: SnapshotDb;\r\n let documentListModelId: Id64String;\r\n\r\n before(async () => {\r\n GenericSchema.registerSchema();\r\n Schemas.registerSchema(TestSubModelSchema);\r\n ClassRegistry.register(TestSheetSpy, TestSubModelSchema);\r\n ClassRegistry.register(TestSheetWidened, TestSubModelSchema);\r\n ClassRegistry.register(TestSheetUnvalidated, TestSubModelSchema);\r\n ClassRegistry.register(TestRestrictedDocument, TestSubModelSchema);\r\n\r\n const iModelPath = IModelTestUtils.prepareOutputFile(\"SubModelInsert\", \"SubModelInsert.bim\");\r\n imodel = SnapshotDb.createEmpty(iModelPath, { rootSubject: { name: \"SubModelInsertTest\" } });\r\n await imodel.importSchemaStrings([testSchemaXml]);\r\n documentListModelId = withEditTxn(imodel, (txn) => DocumentListModel.insert(txn, SnapshotDb.rootSubjectId, \"DocumentList\"));\r\n });\r\n\r\n after(() => {\r\n imodel.close();\r\n Schemas.unregisterSchema(TestSubModelSchema.schemaName);\r\n });\r\n\r\n function insertHost(classFullName: string, modelId: Id64String = documentListModelId): Id64String {\r\n const id = withEditTxn(imodel, (txn) => txn.insertElement({ classFullName, model: modelId, code: Code.createEmpty() }));\r\n expect(Id64.isValidId64(id)).to.be.true;\r\n return id;\r\n }\r\n\r\n function insertSubModel(modelClassFullName: string, modeledElementId: Id64String): Id64String {\r\n return withEditTxn(imodel, (txn) => txn.insertModel({ classFullName: modelClassFullName, modeledElement: { id: modeledElementId } }));\r\n }\r\n\r\n function expectAccepted(hostClassFullName: string, modelClassFullName: string, hostModelId?: Id64String): void {\r\n const hostId = insertHost(hostClassFullName, hostModelId);\r\n const modelId = insertSubModel(modelClassFullName, hostId);\r\n expect(modelId).to.equal(hostId);\r\n expect(imodel.models.getModel(modelId).classFullName).to.equal(modelClassFullName);\r\n }\r\n\r\n function expectRejected(hostClassFullName: string, modelClassFullName: string, hostModelId?: Id64String): void {\r\n const hostId = insertHost(hostClassFullName, hostModelId);\r\n let error: unknown;\r\n try {\r\n insertSubModel(modelClassFullName, hostId);\r\n } catch (err) {\r\n error = err;\r\n }\r\n\r\n expect(error).to.be.instanceOf(IModelError);\r\n expect((error as IModelError).errorNumber).to.equal(IModelStatus.WrongModel);\r\n expect((error as IModelError).message).to.contain(\"must be sub-modeled by\");\r\n expect(imodel.models.tryGetModel(hostId)).to.be.undefined;\r\n }\r\n\r\n describe(\"accepts\", () => {\r\n it(\"Sheet + SheetModel\", () => expectAccepted(Sheet.classFullName, SheetModel.classFullName));\r\n it(\"Drawing + DrawingModel\", () => expectAccepted(Drawing.classFullName, DrawingModel.classFullName));\r\n it(\"SectionDrawing + DrawingModel\", () => expectAccepted(SectionDrawing.classFullName, DrawingModel.classFullName));\r\n it(\"SectionDrawing + SectionDrawingModel\", () => expectAccepted(SectionDrawing.classFullName, SectionDrawingModel.classFullName));\r\n it(\"SectionDrawing + Generic:GraphicalModel3d\", () => expectAccepted(SectionDrawing.classFullName, \"Generic:GraphicalModel3d\"));\r\n it(\"TemplateRecipe2d + DrawingModel\", () => expectAccepted(TemplateRecipe2d.classFullName, DrawingModel.classFullName, IModel.dictionaryId));\r\n it(\"Sheet + SheetModel subclass without a JS class\", () => expectAccepted(Sheet.classFullName, \"TestSubModel:TestSheetModel\"));\r\n it(\"no allowedSubModelClasses → any model accepted\", () => {\r\n expectAccepted(\"TestSubModel:TestHostDocument\", SheetModel.classFullName);\r\n expectAccepted(\"TestSubModel:TestHostDocument\", DrawingModel.classFullName);\r\n });\r\n it(\"Sheet subclass that widens allowedSubModelClasses + DrawingModel\", () => expectAccepted(TestSheetWidened.classFullName, DrawingModel.classFullName));\r\n it(\"Sheet subclass that overrides onSubModelInsert without super + DrawingModel\", () => expectAccepted(TestSheetUnvalidated.classFullName, DrawingModel.classFullName));\r\n it(\"Document subclass with allowedSubModelClasses + DrawingModel\", () => expectAccepted(TestRestrictedDocument.classFullName, DrawingModel.classFullName));\r\n });\r\n\r\n describe(\"rejects with IModelStatus.WrongModel\", () => {\r\n it(\"Sheet + DrawingModel\", () => expectRejected(Sheet.classFullName, DrawingModel.classFullName));\r\n it(\"Drawing + SheetModel\", () => expectRejected(Drawing.classFullName, SheetModel.classFullName));\r\n it(\"SectionDrawing + SheetModel\", () => expectRejected(SectionDrawing.classFullName, SheetModel.classFullName));\r\n it(\"TemplateRecipe2d + SheetModel\", () => expectRejected(TemplateRecipe2d.classFullName, SheetModel.classFullName, IModel.dictionaryId));\r\n it(\"Sheet subclass without a JS class + DrawingModel\", () => expectRejected(\"TestSubModel:TestSheetGenerated\", DrawingModel.classFullName));\r\n it(\"Document subclass with allowedSubModelClasses + SheetModel\", () => expectRejected(TestRestrictedDocument.classFullName, SheetModel.classFullName));\r\n });\r\n\r\n it(\"invokes an overriding subclass hook that defers to the inherited validation\", () => {\r\n const spy = sinonSpy(TestSheetSpy, \"onSubModelInsert\");\r\n try {\r\n expectAccepted(TestSheetSpy.classFullName, SheetModel.classFullName);\r\n expect(spy.calledOnce).to.be.true;\r\n expect(spy.getCall(0).args[0].subModelProps.classFullName).to.equal(SheetModel.classFullName);\r\n\r\n expectRejected(TestSheetSpy.classFullName, DrawingModel.classFullName);\r\n expect(spy.calledTwice).to.be.true;\r\n expect(spy.getCall(1).threw()).to.be.true;\r\n } finally {\r\n spy.restore();\r\n }\r\n });\r\n\r\n describe(\"missing required behavior\", () => {\r\n it(\"rejects sub-model insertion\", () => {\r\n const hostId = insertHost(TestRestrictedDocument.classFullName);\r\n Schemas.unregisterSchema(TestSubModelSchema.schemaName);\r\n\r\n try {\r\n let error: unknown;\r\n try {\r\n insertSubModel(DefinitionModel.classFullName, hostId);\r\n } catch (err) {\r\n error = err;\r\n }\r\n\r\n expect(error).to.be.instanceOf(IModelError);\r\n expect((error as IModelError).errorNumber).to.equal(IModelStatus.WrongHandler);\r\n expect(imodel.models.tryGetModel(hostId)).to.be.undefined;\r\n } finally {\r\n Schemas.registerSchema(TestSubModelSchema);\r\n ClassRegistry.register(TestSheetSpy, TestSubModelSchema);\r\n ClassRegistry.register(TestSheetWidened, TestSubModelSchema);\r\n ClassRegistry.register(TestSheetUnvalidated, TestSubModelSchema);\r\n ClassRegistry.register(TestRestrictedDocument, TestSubModelSchema);\r\n }\r\n });\r\n });\r\n});\r\n"]}
|
|
@@ -336,6 +336,84 @@ describe("Code value management: null, swap, undo/redo, and cross-briefcase pull
|
|
|
336
336
|
HubMock.shutdown();
|
|
337
337
|
}
|
|
338
338
|
});
|
|
339
|
+
// Regression for iTwin/itwinjs-backlog#2435: rebasing a code swap must not cascade-delete derived-class rows.
|
|
340
|
+
it("preserves both drawing graphics when rebasing a local code swap over an unrelated incoming change", async () => {
|
|
341
|
+
HubMock.startup("CodeSwapRebaseCascadeTest", KnownTestLocations.outputDir);
|
|
342
|
+
let far;
|
|
343
|
+
let local;
|
|
344
|
+
try {
|
|
345
|
+
const iModelId = await HubMock.createNewIModel({
|
|
346
|
+
accessToken: "far-user",
|
|
347
|
+
iTwinId: HubMock.iTwinId,
|
|
348
|
+
iModelName: "CodeSwapRebaseCascadeTest",
|
|
349
|
+
description: "CodeSwapRebaseCascadeTest",
|
|
350
|
+
});
|
|
351
|
+
const source = far = await HubWrappers.downloadAndOpenBriefcase({ accessToken: "far-user", iTwinId: HubMock.iTwinId, iModelId });
|
|
352
|
+
source.channels.addAllowedChannel(ChannelControl.sharedChannelName);
|
|
353
|
+
await source.locks.acquireLocks({ shared: IModel.dictionaryId });
|
|
354
|
+
const { drawingModelId, drawingCategoryId, codeSpecId } = withEditTxn(source, "setup code swap rebase", (txn) => {
|
|
355
|
+
const [, modelId] = IModelTestUtils.createAndInsertDrawingPartitionAndModel(txn, IModelTestUtils.getUniqueModelCode(source, "DrawingModel"));
|
|
356
|
+
const categoryId = DrawingCategory.insert(txn, IModel.dictionaryId, "MyDrawingCategory", new SubCategoryAppearance());
|
|
357
|
+
const specId = source.codeSpecs.insert(txn, "CodeSwapRebaseCascadeCodeSpec", CodeScopeSpec.Type.Model);
|
|
358
|
+
return { drawingModelId: modelId, drawingCategoryId: categoryId, codeSpecId: specId };
|
|
359
|
+
});
|
|
360
|
+
await source.pushChanges({ description: "setup" });
|
|
361
|
+
const target = local = await HubWrappers.downloadAndOpenBriefcase({ accessToken: "local-user", iTwinId: HubMock.iTwinId, iModelId });
|
|
362
|
+
target.channels.addAllowedChannel(ChannelControl.sharedChannelName);
|
|
363
|
+
const codeA = new Code({ spec: codeSpecId, scope: drawingModelId, value: "CODE_A" });
|
|
364
|
+
const codeB = new Code({ spec: codeSpecId, scope: drawingModelId, value: "CODE_B" });
|
|
365
|
+
await source.locks.acquireLocks({ shared: drawingModelId });
|
|
366
|
+
const { elementA, elementB, unrelatedId } = withEditTxn(source, "insert code swap elements", (txn) => {
|
|
367
|
+
const props = {
|
|
368
|
+
classFullName: "BisCore:DrawingGraphic",
|
|
369
|
+
model: drawingModelId,
|
|
370
|
+
category: drawingCategoryId,
|
|
371
|
+
code: Code.createEmpty(),
|
|
372
|
+
};
|
|
373
|
+
return {
|
|
374
|
+
elementA: txn.insertElement({ ...props, code: codeA }),
|
|
375
|
+
elementB: txn.insertElement({ ...props, code: codeB }),
|
|
376
|
+
unrelatedId: txn.insertElement(props),
|
|
377
|
+
};
|
|
378
|
+
});
|
|
379
|
+
await source.pushChanges({ description: "insert code swap elements" });
|
|
380
|
+
await target.pullChanges();
|
|
381
|
+
await target.locks.acquireLocks({ exclusive: [elementA, elementB] });
|
|
382
|
+
withEditTxn(target, "local code swap", (txn) => {
|
|
383
|
+
// The session captures only the net swap, discarding this temporary value.
|
|
384
|
+
txn.updateElement({ id: elementA, code: new Code({ spec: codeSpecId, scope: drawingModelId, value: "CODE_TEMP" }) });
|
|
385
|
+
txn.updateElement({ id: elementB, code: codeA });
|
|
386
|
+
txn.updateElement({ id: elementA, code: codeB });
|
|
387
|
+
});
|
|
388
|
+
chai.expect(target.txns.hasPendingTxns).to.be.true;
|
|
389
|
+
// Force a genuine rebase of the local swap, rather than a fast-forward pull.
|
|
390
|
+
await source.locks.acquireLocks({ exclusive: unrelatedId });
|
|
391
|
+
withEditTxn(source, "unrelated incoming change", (txn) => {
|
|
392
|
+
txn.updateElement({ id: unrelatedId, userLabel: "remote update" });
|
|
393
|
+
});
|
|
394
|
+
await source.pushChanges({ description: "unrelated incoming change" });
|
|
395
|
+
let rebaseCount = 0;
|
|
396
|
+
target.txns.rebaser.onRebaseBegin.addListener(() => { ++rebaseCount; });
|
|
397
|
+
await target.pullChanges();
|
|
398
|
+
chai.expect(rebaseCount).to.equal(1);
|
|
399
|
+
chai.expect(target.txns.hasPendingTxns).to.be.true;
|
|
400
|
+
target.clearCaches();
|
|
401
|
+
const a = target.elements.getElementProps(elementA);
|
|
402
|
+
const b = target.elements.getElementProps(elementB);
|
|
403
|
+
chai.expect(a.code).to.deep.equal(codeB.toJSON());
|
|
404
|
+
chai.expect(b.code).to.deep.equal(codeA.toJSON());
|
|
405
|
+
chai.expect(a.category).to.equal(drawingCategoryId);
|
|
406
|
+
chai.expect(b.category).to.equal(drawingCategoryId);
|
|
407
|
+
chai.expect(a.model).to.equal(drawingModelId);
|
|
408
|
+
chai.expect(b.model).to.equal(drawingModelId);
|
|
409
|
+
chai.expect(target.elements.getElementProps(unrelatedId).userLabel).to.equal("remote update");
|
|
410
|
+
}
|
|
411
|
+
finally {
|
|
412
|
+
far?.close();
|
|
413
|
+
local?.close();
|
|
414
|
+
HubMock.shutdown();
|
|
415
|
+
}
|
|
416
|
+
});
|
|
339
417
|
it("single-transaction code swap reverts to old behaviour (swap not applied) when noUpdateLoop is true", async () => {
|
|
340
418
|
HubMock.startup("CodeSwapNoUpdateLoopTest", KnownTestLocations.outputDir);
|
|
341
419
|
let b1;
|