UNPKG

@itwin/core-backend

Version:
746 lines • 360 kB
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) { if (value !== null && value !== void 0) { if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected."); var dispose, inner; if (async) { if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined."); dispose = value[Symbol.asyncDispose]; } if (dispose === void 0) { if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined."); dispose = value[Symbol.dispose]; if (async) inner = dispose; } if (typeof dispose !== "function") throw new TypeError("Object not disposable."); if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } }; env.stack.push({ value: value, dispose: dispose, async: async }); } else if (async) { env.stack.push({ async: true }); } return value; }; var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) { return function (env) { function fail(e) { env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e; env.hasError = true; } var r, s = 0; function next() { while (r = env.stack.pop()) { try { if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next); if (r.dispose) { var result = r.dispose.call(r.value); if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); }); } else s |= 1; } catch (e) { fail(e); } } if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve(); if (env.hasError) throw env.error; } return next(); }; })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }); /*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ import { DbResult, Id64 } from "@itwin/core-bentley"; import { Code, ColorDef, IModel, SubCategoryAppearance } from "@itwin/core-common"; import { Arc3d, IModelJson, Point3d } from "@itwin/core-geometry"; import { assert, expect } from "chai"; import { DrawingCategory } from "../../Category"; import { _nativeDb, BriefcaseDb, ChannelControl } from "../../core-backend"; import { HubMock } from "../../internal/HubMock"; import { ChangesetReader } from "../../ChangesetReader"; import * as path from "node:path"; import * as fs from "fs"; import { HubWrappers, IModelTestUtils } from "../IModelTestUtils"; import { KnownTestLocations } from "../KnownTestLocations"; import { ChangeUnifierCache, PartialChangeUnifier } from "../../PartialChangeUnifier"; import { PropertyFilter } from "../../ChangesetReaderTypes"; import { EditTxn } from "../../EditTxn"; import { DisableNativeAssertions } from "../TestUtils"; /* eslint-disable @typescript-eslint/naming-convention */ // disabling it because the property names are not in camelcase, and we want to test them as-is /** Open a txn, drive the unifier, log and return all merged instances. */ function readTxn(db, txnId, propFilter, rowOptions, invert, useInMemoryUnifierCache) { const env_1 = { stack: [], error: void 0, hasError: false }; try { const reader = __addDisposableResource(env_1, ChangesetReader.openTxn({ db, txnId, propFilter, rowOptions, invert }), false); const inMemCache = useInMemoryUnifierCache ?? true; const pcu = __addDisposableResource(env_1, new PartialChangeUnifier(inMemCache ? ChangeUnifierCache.createInMemoryCache() : ChangeUnifierCache.createSqliteBackedCache()), false); while (reader.step()) pcu.appendFrom(reader); const instances = Array.from(pcu.instances); return instances; } catch (e_1) { env_1.error = e_1; env_1.hasError = true; } finally { __disposeResources(env_1); } } function startTestTxn(iModel, description = "changeset reader") { const txn = new EditTxn(iModel, description); txn.start(); return txn; } async function importSchemaStrings(txn, schemas) { if (txn.isActive) txn.saveChanges(); await txn.iModel.importSchemaStrings(schemas); } describe("ChangesetReader insert-full", () => { let rwIModel; let fullElementId; let drawingModelId; let drawingCategoryId; let txnId; let txn; before(async () => { HubMock.startup("ECChangesetInsertFull", KnownTestLocations.outputDir); const adminToken = "super manager token"; const iTwinId = HubMock.iTwinId; const rwIModelId = await HubMock.createNewIModel({ iTwinId, iModelName: "insertFull", description: "insertFull", accessToken: adminToken }); rwIModel = await HubWrappers.downloadAndOpenBriefcase({ iTwinId, iModelId: rwIModelId, accessToken: adminToken }); txn = startTestTxn(rwIModel, "ChangesetReader insert-full setup"); // Txn 1: import schema + drawing model setup, then push const schema = `<?xml version="1.0" encoding="UTF-8"?> <ECSchema schemaName="TestDomain" alias="ts" version="01.00" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.1"> <ECSchemaReference name="BisCore" version="01.00" alias="bis"/> <!-- Rich struct: scalar fields + nested point2d/3d sub-properties --> <ECStructClass typeName="RichPoint" modifier="Sealed"> <ECProperty propertyName="X" typeName="double"/> <ECProperty propertyName="Y" typeName="double"/> <ECProperty propertyName="Z" typeName="double"/> <ECProperty propertyName="Label" typeName="string"/> <ECProperty propertyName="Pt2d" typeName="point2d"/> <ECProperty propertyName="Pt3d" typeName="point3d"/> </ECStructClass> <!-- Relationship used by the RelatedElem navigation property --> <ECRelationshipClass typeName="Test2dUsesElement" strength="referencing" modifier="None"> <Source multiplicity="(0..*)" roleLabel="uses" polymorphic="true"><Class class="Test2dElement"/></Source> <Target multiplicity="(0..1)" roleLabel="is used by" polymorphic="true"><Class class="bis:Element"/></Target> </ECRelationshipClass> <ECEntityClass typeName="Test2dElement"> <BaseClass>bis:GraphicalElement2d</BaseClass> <!-- Primitives --> <ECProperty propertyName="StrProp" typeName="string"/> <ECProperty propertyName="IntProp" typeName="int"/> <ECProperty propertyName="LongProp" typeName="long"/> <ECProperty propertyName="DblProp" typeName="double"/> <ECProperty propertyName="BoolProp" typeName="boolean"/> <ECProperty propertyName="DtProp" typeName="dateTime"/> <ECProperty propertyName="BinProp" typeName="binary"/> <!-- Geometric primitives --> <ECProperty propertyName="Pt2dProp" typeName="point2d"/> <ECProperty propertyName="Pt3dProp" typeName="point3d"/> <!-- Struct, arrays --> <ECStructProperty propertyName="StructProp" typeName="RichPoint"/> <ECArrayProperty propertyName="IntArrProp" typeName="int" minOccurs="0" maxOccurs="unbounded"/> <ECArrayProperty propertyName="StrArrProp" typeName="string" minOccurs="0" maxOccurs="unbounded"/> <ECStructArrayProperty propertyName="StructArrProp" typeName="RichPoint" minOccurs="0" maxOccurs="unbounded"/> <!-- Navigation property --> <ECNavigationProperty propertyName="RelatedElem" relationshipName="Test2dUsesElement" direction="forward"/> </ECEntityClass> </ECSchema>`; await importSchemaStrings(txn, [schema]); rwIModel.channels.addAllowedChannel(ChannelControl.sharedChannelName); await rwIModel.locks.acquireLocks({ shared: IModel.dictionaryId }); const codeProps = Code.createEmpty(); codeProps.value = "DrillDownDrawing"; [, drawingModelId] = IModelTestUtils.createAndInsertDrawingPartitionAndModel(txn, codeProps, true); const foundCat = DrawingCategory.queryCategoryIdByName(rwIModel, IModel.dictionaryId, "DrillDownCategory"); drawingCategoryId = foundCat ?? DrawingCategory.insert(txn, IModel.dictionaryId, "DrillDownCategory", new SubCategoryAppearance({ color: ColorDef.fromString("rgb(255,0,0)").toJSON() })); txn.saveChanges("setup"); // Wait so that LastMod on bis_Model gets a distinct timestamp before the insert txn await new Promise((resolve) => setTimeout(resolve, 300)); // Txn 2: insert FULL element every EC primitive type populated await rwIModel.locks.acquireLocks({ shared: drawingModelId }); const geom = [ Arc3d.createXY(Point3d.create(0, 0), 5), Arc3d.createXY(Point3d.create(5, 5), 2), Arc3d.createXY(Point3d.create(-5, -5), 20), ].map((a) => IModelJson.Writer.toIModelJson(a)); fullElementId = txn.insertElement({ classFullName: "TestDomain:Test2dElement", model: drawingModelId, category: drawingCategoryId, code: Code.createEmpty(), geom, StrProp: "hello", IntProp: 42, LongProp: 9_007_199_254_740_991, // Number.MAX_SAFE_INTEGER DblProp: 3.14159265358979, BoolProp: true, DtProp: "2024-01-15T12:00:00.000", BinProp: new Uint8Array([1, 2, 3, 4]), Pt2dProp: { x: 1.5, y: 2.5 }, Pt3dProp: { x: 3.0, y: 4.0, z: 5.0 }, StructProp: { X: 1.0, Y: 2.0, Z: 3.0, Label: "origin", Pt2d: { x: 0.5, y: 0.5 }, Pt3d: { x: 1.0, y: 2.0, z: 3.0 }, }, IntArrProp: [10, 20, 30], StrArrProp: ["alpha", "beta", "gamma"], StructArrProp: [ { X: 0.0, Y: 1.0, Z: 2.0, Label: "a", Pt2d: { x: 0.0, y: 0.0 }, Pt3d: { x: 0.0, y: 0.0, z: 0.0 } }, { X: 3.0, Y: 4.0, Z: 5.0, Label: "b", Pt2d: { x: 1.0, y: 1.0 }, Pt3d: { x: 1.0, y: 1.0, z: 1.0 } }, ], RelatedElem: { id: drawingCategoryId, relClassName: "TestDomain:Test2dUsesElement" }, }); txn.saveChanges("insert full element"); txnId = rwIModel.txns.getLastSavedTxnProps().id; }); after(() => { txn.end(); rwIModel?.close(); HubMock.shutdown(); }); it("txn1 insert-full | All_Properties | default rowOptions", () => { const instances = readTxn(rwIModel, txnId); assert.equal(instances.length, 3); // --- instances[0]: DrawingModel Updated New --- const modelNew = instances.find((i) => i.ECInstanceId === drawingModelId && i.$meta.stage === "New"); expect(modelNew).to.exist; assert.equal(modelNew.ECInstanceId, drawingModelId); assert.equal("BisCore:DrawingModel", rwIModel.getClassNameFromId(modelNew.ECClassId)); assert.isString(modelNew.LastMod); assert.isString(modelNew.GeometryGuid); // Object.keys assert.deepEqual(Object.keys(modelNew).sort(), ["ECInstanceId", "ECClassId", "LastMod", "GeometryGuid", "$meta"].sort()); // $meta keys assert.deepEqual(Object.keys(modelNew.$meta).sort(), ["op", "tables", "changeIndexes", "stage", "instanceKey", "propFilter", "changeFetchedPropNames", "isIndirectChange"].sort()); assert.equal(modelNew.$meta.op, "Updated"); assert.equal(modelNew.$meta.stage, "New"); assert.deepEqual(modelNew.$meta.tables, ["bis_Model"]); assert.deepEqual(modelNew.$meta.changeIndexes, [3]); assert.isString(modelNew.$meta.instanceKey); assert.equal(modelNew.$meta.instanceKey.split(`-`).length, 2); assert.equal(modelNew.$meta.propFilter, PropertyFilter.All); assert.deepEqual(modelNew.$meta.changeFetchedPropNames.sort(), ["ECInstanceId", "LastMod", "GeometryGuid"].sort()); assert.equal(modelNew.$meta.isIndirectChange, true); // --- instances[1]: DrawingModel Updated Old --- const modelOld = instances.find((i) => i.ECInstanceId === drawingModelId && i.$meta.stage === "Old"); expect(modelOld).to.exist; assert.equal(modelOld.ECInstanceId, drawingModelId); assert.equal("BisCore:DrawingModel", rwIModel.getClassNameFromId(modelOld.ECClassId)); // Object.keys assert.deepEqual(Object.keys(modelOld).sort(), ["ECInstanceId", "ECClassId", "$meta"].sort()); // $meta keys assert.deepEqual(Object.keys(modelOld.$meta).sort(), ["op", "tables", "changeIndexes", "stage", "instanceKey", "propFilter", "changeFetchedPropNames", "isIndirectChange"].sort()); assert.equal(modelOld.$meta.op, "Updated"); assert.equal(modelOld.$meta.stage, "Old"); assert.deepEqual(modelOld.$meta.tables, ["bis_Model"]); assert.equal(modelOld.$meta.propFilter, PropertyFilter.All); assert.deepEqual(modelOld.$meta.changeFetchedPropNames.sort(), ["ECInstanceId", "LastMod", "GeometryGuid"].sort()); assert.equal(modelOld.$meta.isIndirectChange, true); // --- instances[2]: Test2dElement Inserted New --- const elem = instances.find((i) => i.ECInstanceId === fullElementId && i.$meta.stage === "New"); expect(elem).to.exist; assert.equal(elem.ECInstanceId, fullElementId); assert.equal("TestDomain:Test2dElement", rwIModel.getClassNameFromId(elem.ECClassId)); assert.equal(elem.Model.Id, drawingModelId); assert.equal(rwIModel.getClassNameFromId(elem.Model.RelECClassId), "BisCore:ModelContainsElements"); assert.isString(elem.LastMod); assert.equal(elem.CodeSpec.Id, "0x1"); assert.equal(rwIModel.getClassNameFromId(elem.CodeSpec.RelECClassId), "BisCore:CodeSpecSpecifiesCode"); assert.equal(elem.CodeScope.Id, "0x1"); assert.equal(rwIModel.getClassNameFromId(elem.CodeScope.RelECClassId), "BisCore:ElementScopesCode"); assert.isString(elem.FederationGuid); assert.equal(elem.Category.Id, drawingCategoryId); assert.equal(rwIModel.getClassNameFromId(elem.Category.RelECClassId), "BisCore:GeometricElement2dIsInCategory"); assert.deepEqual(elem.Origin, { X: 0, Y: 0 }); assert.equal(elem.Rotation, 0); assert.deepEqual(elem.BBoxLow, { X: -25, Y: -25 }); assert.deepEqual(elem.BBoxHigh, { X: 15, Y: 15 }); assert.include(String(elem.GeometryStream), "\"bytes\""); assert.include(String(elem.BinProp), "\"bytes\""); assert.equal(elem.StrProp, "hello"); assert.equal(elem.IntProp, 42); assert.equal(elem.LongProp, 9007199254740991); assert.closeTo(elem.DblProp, 3.14159265358979, 1e-10); assert.equal(elem.BoolProp, true); assert.equal(elem.DtProp, "2024-01-15T12:00:00.000"); assert.deepEqual(elem.Pt2dProp, { X: 1.5, Y: 2.5 }); assert.deepEqual(elem.Pt3dProp, { X: 3, Y: 4, Z: 5 }); assert.deepEqual(elem.StructProp, { X: 1, Y: 2, Z: 3, Label: "origin", Pt2d: { X: 0.5, Y: 0.5 }, Pt3d: { X: 1, Y: 2, Z: 3 } }); assert.deepEqual(elem.IntArrProp, [10, 20, 30]); assert.deepEqual(elem.StrArrProp, ["alpha", "beta", "gamma"]); assert.deepEqual(elem.StructArrProp, [ { X: 0, Y: 1, Z: 2, Label: "a", Pt2d: { X: 0, Y: 0 }, Pt3d: { X: 0, Y: 0, Z: 0 } }, { X: 3, Y: 4, Z: 5, Label: "b", Pt2d: { X: 1, Y: 1 }, Pt3d: { X: 1, Y: 1, Z: 1 } }, ]); assert.equal(elem.RelatedElem.Id, drawingCategoryId); assert.equal(rwIModel.getClassNameFromId(elem.RelatedElem.RelECClassId), "TestDomain:Test2dUsesElement"); // Object.keys assert.deepEqual(Object.keys(elem).sort(), [ "ECInstanceId", "ECClassId", "Model", "LastMod", "CodeSpec", "CodeScope", "FederationGuid", "$meta", "Category", "Origin", "Rotation", "BBoxLow", "BBoxHigh", "GeometryStream", "StrProp", "IntProp", "LongProp", "DblProp", "BoolProp", "DtProp", "Pt2dProp", "Pt3dProp", "StructProp", "IntArrProp", "StrArrProp", "StructArrProp", "RelatedElem", "BinProp" ].sort()); // $meta keys assert.deepEqual(Object.keys(elem.$meta).sort(), ["op", "tables", "changeIndexes", "stage", "instanceKey", "propFilter", "changeFetchedPropNames", "isIndirectChange"].sort()); assert.equal(elem.$meta.op, "Inserted"); assert.equal(elem.$meta.stage, "New"); assert.deepEqual(elem.$meta.tables.sort(), ["bis_Element", "bis_GeometricElement2d"].sort()); assert.deepEqual(elem.$meta.changeIndexes.sort(), [1, 2].sort()); assert.isString(elem.$meta.instanceKey); assert.equal(elem.$meta.instanceKey.split(`-`).length, 2); assert.equal(elem.$meta.propFilter, PropertyFilter.All); assert.deepEqual(elem.$meta.changeFetchedPropNames.sort(), [ 'BBoxHigh', 'BBoxLow', 'BinProp', 'BoolProp', 'Category.Id', 'CodeScope.Id', 'CodeSpec.Id', 'CodeValue', 'DblProp', 'DtProp', 'ECClassId', 'ECInstanceId', 'FederationGuid', 'GeometryStream', 'IntArrProp', 'IntProp', 'JsonProperties', 'LastMod', 'LongProp', 'Model.Id', 'Origin', 'Parent', 'Pt2dProp', 'Pt3dProp', 'RelatedElem', 'Rotation', 'StrArrProp', 'StrProp', 'StructArrProp', 'StructProp.Label', 'StructProp.Pt2d', 'StructProp.Pt3d', 'StructProp.X', 'StructProp.Y', 'StructProp.Z', 'TypeDefinition', 'UserLabel' ].sort()); assert.equal(elem.$meta.isIndirectChange, false); }); it("txn1 insert-full | All_Properties | default rowOptions | invert", () => { const instances = readTxn(rwIModel, txnId, undefined, undefined, true); assert.equal(instances.length, 3); // --- instances[0]: DrawingModel Updated New --- const modelNew = instances.find((i) => i.ECInstanceId === drawingModelId && i.$meta.stage === "New"); expect(modelNew).to.exist; assert.equal(modelNew.ECInstanceId, drawingModelId); assert.equal("BisCore:DrawingModel", rwIModel.getClassNameFromId(modelNew.ECClassId)); assert.isUndefined(modelNew.LastMod); assert.isUndefined(modelNew.GeometryGuid); // Object.keys assert.deepEqual(Object.keys(modelNew).sort(), ["ECInstanceId", "ECClassId", "$meta"].sort()); // $meta keys assert.deepEqual(Object.keys(modelNew.$meta).sort(), ["op", "tables", "changeIndexes", "stage", "instanceKey", "propFilter", "changeFetchedPropNames", "isIndirectChange"].sort()); assert.equal(modelNew.$meta.op, "Updated"); assert.equal(modelNew.$meta.stage, "New"); assert.deepEqual(modelNew.$meta.tables, ["bis_Model"]); assert.deepEqual(modelNew.$meta.changeIndexes, [3]); assert.isString(modelNew.$meta.instanceKey); assert.equal(modelNew.$meta.instanceKey.split(`-`).length, 2); assert.equal(modelNew.$meta.propFilter, PropertyFilter.All); assert.deepEqual(modelNew.$meta.changeFetchedPropNames.sort(), ["ECInstanceId", "LastMod", "GeometryGuid"].sort()); assert.equal(modelNew.$meta.isIndirectChange, true); // --- instances[1]: DrawingModel Updated Old --- const modelOld = instances.find((i) => i.ECInstanceId === drawingModelId && i.$meta.stage === "Old"); expect(modelOld).to.exist; assert.equal(modelOld.ECInstanceId, drawingModelId); assert.equal("BisCore:DrawingModel", rwIModel.getClassNameFromId(modelOld.ECClassId)); assert.isString(modelOld.LastMod); assert.isString(modelOld.GeometryGuid); // Object.keys assert.deepEqual(Object.keys(modelOld).sort(), ["ECInstanceId", "ECClassId", "$meta", "LastMod", "GeometryGuid"].sort()); // $meta keys assert.deepEqual(Object.keys(modelOld.$meta).sort(), ["op", "tables", "changeIndexes", "stage", "instanceKey", "propFilter", "changeFetchedPropNames", "isIndirectChange"].sort()); assert.equal(modelOld.$meta.op, "Updated"); assert.equal(modelOld.$meta.stage, "Old"); assert.deepEqual(modelOld.$meta.tables, ["bis_Model"]); assert.equal(modelOld.$meta.propFilter, PropertyFilter.All); assert.deepEqual(modelOld.$meta.changeFetchedPropNames.sort(), ["ECInstanceId", "LastMod", "GeometryGuid"].sort()); assert.equal(modelOld.$meta.isIndirectChange, true); // --- instances[2]: Test2dElement Inserted New --- const elem = instances.find((i) => i.ECInstanceId === fullElementId && i.$meta.stage === "Old"); expect(elem).to.exist; assert.equal(elem.ECInstanceId, fullElementId); assert.equal("TestDomain:Test2dElement", rwIModel.getClassNameFromId(elem.ECClassId)); assert.equal(elem.Model.Id, drawingModelId); assert.equal(rwIModel.getClassNameFromId(elem.Model.RelECClassId), "BisCore:ModelContainsElements"); assert.isString(elem.LastMod); assert.equal(elem.CodeSpec.Id, "0x1"); assert.equal(rwIModel.getClassNameFromId(elem.CodeSpec.RelECClassId), "BisCore:CodeSpecSpecifiesCode"); assert.equal(elem.CodeScope.Id, "0x1"); assert.equal(rwIModel.getClassNameFromId(elem.CodeScope.RelECClassId), "BisCore:ElementScopesCode"); assert.isString(elem.FederationGuid); assert.equal(elem.Category.Id, drawingCategoryId); assert.equal(rwIModel.getClassNameFromId(elem.Category.RelECClassId), "BisCore:GeometricElement2dIsInCategory"); assert.deepEqual(elem.Origin, { X: 0, Y: 0 }); assert.equal(elem.Rotation, 0); assert.deepEqual(elem.BBoxLow, { X: -25, Y: -25 }); assert.deepEqual(elem.BBoxHigh, { X: 15, Y: 15 }); assert.include(String(elem.GeometryStream), "\"bytes\""); assert.include(String(elem.BinProp), "\"bytes\""); assert.equal(elem.StrProp, "hello"); assert.equal(elem.IntProp, 42); assert.equal(elem.LongProp, 9007199254740991); assert.closeTo(elem.DblProp, 3.14159265358979, 1e-10); assert.equal(elem.BoolProp, true); assert.equal(elem.DtProp, "2024-01-15T12:00:00.000"); assert.deepEqual(elem.Pt2dProp, { X: 1.5, Y: 2.5 }); assert.deepEqual(elem.Pt3dProp, { X: 3, Y: 4, Z: 5 }); assert.deepEqual(elem.StructProp, { X: 1, Y: 2, Z: 3, Label: "origin", Pt2d: { X: 0.5, Y: 0.5 }, Pt3d: { X: 1, Y: 2, Z: 3 } }); assert.deepEqual(elem.IntArrProp, [10, 20, 30]); assert.deepEqual(elem.StrArrProp, ["alpha", "beta", "gamma"]); assert.deepEqual(elem.StructArrProp, [ { X: 0, Y: 1, Z: 2, Label: "a", Pt2d: { X: 0, Y: 0 }, Pt3d: { X: 0, Y: 0, Z: 0 } }, { X: 3, Y: 4, Z: 5, Label: "b", Pt2d: { X: 1, Y: 1 }, Pt3d: { X: 1, Y: 1, Z: 1 } }, ]); assert.equal(elem.RelatedElem.Id, drawingCategoryId); assert.equal(rwIModel.getClassNameFromId(elem.RelatedElem.RelECClassId), "TestDomain:Test2dUsesElement"); // Object.keys assert.deepEqual(Object.keys(elem).sort(), [ "ECInstanceId", "ECClassId", "Model", "LastMod", "CodeSpec", "CodeScope", "FederationGuid", "$meta", "Category", "Origin", "Rotation", "BBoxLow", "BBoxHigh", "GeometryStream", "StrProp", "IntProp", "LongProp", "DblProp", "BoolProp", "DtProp", "Pt2dProp", "Pt3dProp", "StructProp", "IntArrProp", "StrArrProp", "StructArrProp", "RelatedElem", "BinProp" ].sort()); // $meta keys assert.deepEqual(Object.keys(elem.$meta).sort(), ["op", "tables", "changeIndexes", "stage", "instanceKey", "propFilter", "changeFetchedPropNames", "isIndirectChange"].sort()); assert.equal(elem.$meta.op, "Deleted"); assert.equal(elem.$meta.stage, "Old"); assert.deepEqual(elem.$meta.tables.sort(), ["bis_Element", "bis_GeometricElement2d"].sort()); assert.deepEqual(elem.$meta.changeIndexes.sort(), [1, 2].sort()); assert.isString(elem.$meta.instanceKey); assert.equal(elem.$meta.instanceKey.split(`-`).length, 2); assert.equal(elem.$meta.propFilter, PropertyFilter.All); assert.deepEqual(elem.$meta.changeFetchedPropNames.sort(), [ 'BBoxHigh', 'BBoxLow', 'BinProp', 'BoolProp', 'Category.Id', 'CodeScope.Id', 'CodeSpec.Id', 'CodeValue', 'DblProp', 'DtProp', 'ECClassId', 'ECInstanceId', 'FederationGuid', 'GeometryStream', 'IntArrProp', 'IntProp', 'JsonProperties', 'LastMod', 'LongProp', 'Model.Id', 'Origin', 'Parent', 'Pt2dProp', 'Pt3dProp', 'RelatedElem', 'Rotation', 'StrArrProp', 'StrProp', 'StructArrProp', 'StructProp.Label', 'StructProp.Pt2d', 'StructProp.Pt3d', 'StructProp.X', 'StructProp.Y', 'StructProp.Z', 'TypeDefinition', 'UserLabel' ].sort()); assert.equal(elem.$meta.isIndirectChange, false); }); it("txn1 insert-full | Bis_Element_Properties", () => { const instances = readTxn(rwIModel, txnId, PropertyFilter.BisCoreElement, { classIdsToClassNames: true }); assert.equal(instances.length, 3); // --- instances[0]: DrawingModel Updated New --- const modelNew = instances.find((i) => i.ECInstanceId === drawingModelId && i.$meta.stage === "New"); expect(modelNew).to.exist; assert.equal(modelNew.ECInstanceId, drawingModelId); assert.equal(modelNew.ECClassId, "BisCore.DrawingModel"); assert.isString(modelNew.LastMod); assert.isString(modelNew.GeometryGuid); assert.deepEqual(Object.keys(modelNew).sort(), ["ECInstanceId", "ECClassId", "LastMod", "GeometryGuid", "$meta"].sort()); assert.deepEqual(Object.keys(modelNew.$meta).sort(), ["op", "tables", "changeIndexes", "stage", "instanceKey", "propFilter", "changeFetchedPropNames", "rowOptions", "isIndirectChange"].sort()); assert.equal(modelNew.$meta.op, "Updated"); assert.equal(modelNew.$meta.stage, "New"); assert.equal(modelNew.$meta.propFilter, PropertyFilter.BisCoreElement); assert.deepEqual(modelNew.$meta.changeFetchedPropNames.sort(), ["ECInstanceId", "LastMod", "GeometryGuid"].sort()); assert.deepEqual(modelNew.$meta.rowOptions, { classIdsToClassNames: true }); assert.equal(modelNew.$meta.isIndirectChange, true); // --- instances[1]: DrawingModel Updated Old --- const modelOld = instances.find((i) => i.ECInstanceId === drawingModelId && i.$meta.stage === "Old"); expect(modelOld).to.exist; assert.equal(modelOld.ECInstanceId, drawingModelId); assert.equal(modelOld.ECClassId, "BisCore.DrawingModel"); assert.deepEqual(Object.keys(modelOld).sort(), ["ECInstanceId", "ECClassId", "$meta"].sort()); assert.deepEqual(Object.keys(modelOld.$meta).sort(), ["op", "tables", "changeIndexes", "stage", "instanceKey", "propFilter", "changeFetchedPropNames", "rowOptions", "isIndirectChange"].sort()); assert.equal(modelOld.$meta.op, "Updated"); assert.equal(modelOld.$meta.stage, "Old"); assert.equal(modelOld.$meta.propFilter, PropertyFilter.BisCoreElement); assert.deepEqual(modelOld.$meta.changeFetchedPropNames.sort(), ["ECInstanceId", "LastMod", "GeometryGuid"].sort()); assert.deepEqual(modelOld.$meta.rowOptions, { classIdsToClassNames: true }); assert.equal(modelOld.$meta.isIndirectChange, true); // --- instances[2]: Test2dElement Inserted New (Bis_Element_Properties: no custom props) --- const elem = instances.find((i) => i.ECInstanceId === fullElementId && i.$meta.stage === "New"); expect(elem).to.exist; assert.equal(elem.ECInstanceId, fullElementId); assert.equal(elem.ECClassId, "TestDomain.Test2dElement"); // No custom domain props assert.isUndefined(elem.StrProp); assert.isUndefined(elem.IntProp); assert.isUndefined(elem.LongProp); assert.isUndefined(elem.DblProp); assert.isUndefined(elem.BoolProp); assert.isUndefined(elem.DtProp); assert.isUndefined(elem.Pt2dProp); assert.isUndefined(elem.Pt3dProp); assert.isUndefined(elem.StructProp); assert.isUndefined(elem.IntArrProp); assert.isUndefined(elem.StrArrProp); assert.isUndefined(elem.StructArrProp); assert.isUndefined(elem.RelatedElem); expect(elem.Model).to.exist; expect(elem.CodeScope).to.exist; expect(elem.CodeSpec).to.exist; expect(elem.FederationGuid).to.exist; expect(elem.LastMod).to.exist; assert.deepEqual(Object.keys(elem).sort(), ["ECInstanceId", "ECClassId", "$meta", "CodeScope", "CodeSpec", "FederationGuid", "LastMod", "Model"].sort()); assert.deepEqual(Object.keys(elem.$meta).sort(), ["op", "tables", "changeIndexes", "stage", "instanceKey", "propFilter", "changeFetchedPropNames", "rowOptions", "isIndirectChange"].sort()); assert.equal(elem.$meta.op, "Inserted"); assert.equal(elem.$meta.stage, "New"); assert.deepEqual(elem.$meta.tables.sort(), ["bis_Element", "bis_GeometricElement2d"].sort()); assert.deepEqual(elem.$meta.changeIndexes.sort(), [1, 2].sort()); assert.isString(elem.$meta.instanceKey); assert.equal(elem.$meta.instanceKey.split(`-`).length, 2); assert.equal(elem.$meta.propFilter, PropertyFilter.BisCoreElement); assert.deepEqual(elem.$meta.changeFetchedPropNames.sort(), ["ECInstanceId", "ECClassId", "CodeScope.Id", "CodeSpec.Id", "CodeValue", "FederationGuid", "JsonProperties", "LastMod", "Model.Id", "Parent", "UserLabel"].sort()); assert.deepEqual(elem.$meta.rowOptions, { classIdsToClassNames: true }); assert.equal(elem.$meta.isIndirectChange, false); }); it("txn1 insert-full | Instance_Key", () => { const instances = readTxn(rwIModel, txnId, PropertyFilter.InstanceKey); assert.equal(instances.length, 3); // --- instances[0]: DrawingModel Updated New --- const modelNew = instances.find((i) => i.ECInstanceId === drawingModelId && i.$meta.stage === "New"); expect(modelNew).to.exist; assert.equal(modelNew.ECInstanceId, drawingModelId); assert.equal("BisCore:DrawingModel", rwIModel.getClassNameFromId(modelNew.ECClassId)); assert.deepEqual(Object.keys(modelNew).sort(), ["ECInstanceId", "ECClassId", "$meta"].sort()); assert.deepEqual(Object.keys(modelNew.$meta).sort(), ["op", "tables", "changeIndexes", "stage", "instanceKey", "propFilter", "changeFetchedPropNames", "isIndirectChange"].sort()); assert.equal(modelNew.$meta.op, "Updated"); assert.equal(modelNew.$meta.stage, "New"); assert.deepEqual(modelNew.$meta.tables, ["bis_Model"]); assert.deepEqual(modelNew.$meta.changeIndexes, [3]); assert.isString(modelNew.$meta.instanceKey); assert.equal(modelNew.$meta.instanceKey.split(`-`).length, 2); assert.equal(modelNew.$meta.propFilter, PropertyFilter.InstanceKey); assert.deepEqual(modelNew.$meta.changeFetchedPropNames, ["ECInstanceId"]); assert.equal(modelNew.$meta.isIndirectChange, true); // --- instances[1]: DrawingModel Updated Old --- const modelOld = instances.find((i) => i.ECInstanceId === drawingModelId && i.$meta.stage === "Old"); expect(modelOld).to.exist; assert.equal(modelOld.ECInstanceId, drawingModelId); assert.equal("BisCore:DrawingModel", rwIModel.getClassNameFromId(modelOld.ECClassId)); assert.deepEqual(Object.keys(modelOld).sort(), ["ECInstanceId", "ECClassId", "$meta"].sort()); assert.deepEqual(Object.keys(modelOld.$meta).sort(), ["op", "tables", "changeIndexes", "stage", "instanceKey", "propFilter", "changeFetchedPropNames", "isIndirectChange"].sort()); assert.equal(modelOld.$meta.op, "Updated"); assert.equal(modelOld.$meta.stage, "Old"); assert.equal(modelOld.$meta.propFilter, PropertyFilter.InstanceKey); assert.deepEqual(modelOld.$meta.changeFetchedPropNames, ["ECInstanceId"]); assert.equal(modelOld.$meta.isIndirectChange, true); // --- instances[2]: Test2dElement Inserted New (only ECInstanceId + ECClassId) --- const elem = instances.find((i) => i.ECInstanceId === fullElementId && i.$meta.stage === "New"); expect(elem).to.exist; assert.equal(elem.ECInstanceId, fullElementId); assert.equal("TestDomain:Test2dElement", rwIModel.getClassNameFromId(elem.ECClassId)); assert.isUndefined(elem.StrProp); assert.isUndefined(elem.Model); assert.isUndefined(elem.Category); assert.isUndefined(elem.LastMod); assert.deepEqual(Object.keys(elem).sort(), ["ECInstanceId", "ECClassId", "$meta"].sort()); assert.deepEqual(Object.keys(elem.$meta).sort(), ["op", "tables", "changeIndexes", "stage", "instanceKey", "propFilter", "changeFetchedPropNames", "isIndirectChange"].sort()); assert.equal(elem.$meta.op, "Inserted"); assert.equal(elem.$meta.stage, "New"); assert.deepEqual(elem.$meta.tables.sort(), ["bis_Element", "bis_GeometricElement2d"].sort()); assert.deepEqual(elem.$meta.changeIndexes.sort(), [1, 2].sort()); assert.isString(elem.$meta.instanceKey); assert.equal(elem.$meta.instanceKey.split(`-`).length, 2); assert.equal(elem.$meta.propFilter, PropertyFilter.InstanceKey); assert.deepEqual(elem.$meta.changeFetchedPropNames.sort(), ["ECInstanceId", "ECClassId"].sort()); assert.equal(elem.$meta.isIndirectChange, false); }); it("txn1 | rowOptions: classIdsToClassNames", () => { const instances = readTxn(rwIModel, txnId, undefined, { classIdsToClassNames: true }); assert.equal(instances.length, 3); // --- instances[0]: DrawingModel Updated New (ECClassId is now class name) --- const modelNew = instances.find((i) => i.ECInstanceId === drawingModelId && i.$meta.stage === "New"); expect(modelNew).to.exist; assert.equal(modelNew.ECInstanceId, drawingModelId); assert.equal(modelNew.ECClassId, "BisCore.DrawingModel"); assert.isString(modelNew.LastMod); assert.isString(modelNew.GeometryGuid); assert.deepEqual(Object.keys(modelNew).sort(), ["ECInstanceId", "ECClassId", "LastMod", "GeometryGuid", "$meta"].sort()); assert.deepEqual(Object.keys(modelNew.$meta).sort(), ["op", "tables", "changeIndexes", "stage", "instanceKey", "propFilter", "changeFetchedPropNames", "rowOptions", "isIndirectChange"].sort()); assert.equal(modelNew.$meta.op, "Updated"); assert.equal(modelNew.$meta.stage, "New"); assert.equal(modelNew.$meta.propFilter, PropertyFilter.All); assert.deepEqual(modelNew.$meta.changeFetchedPropNames.sort(), ["ECInstanceId", "LastMod", "GeometryGuid"].sort()); assert.deepEqual(modelNew.$meta.rowOptions, { classIdsToClassNames: true }); assert.equal(modelNew.$meta.isIndirectChange, true); // --- instances[1]: DrawingModel Updated Old --- const modelOld = instances.find((i) => i.ECInstanceId === drawingModelId && i.$meta.stage === "Old"); expect(modelOld).to.exist; assert.equal(modelOld.ECInstanceId, drawingModelId); assert.equal(modelOld.ECClassId, "BisCore.DrawingModel"); assert.deepEqual(Object.keys(modelOld).sort(), ["ECInstanceId", "ECClassId", "$meta"].sort()); assert.deepEqual(Object.keys(modelOld.$meta).sort(), ["op", "tables", "changeIndexes", "stage", "instanceKey", "propFilter", "changeFetchedPropNames", "rowOptions", "isIndirectChange"].sort()); assert.equal(modelOld.$meta.op, "Updated"); assert.equal(modelOld.$meta.stage, "Old"); assert.equal(modelOld.$meta.propFilter, PropertyFilter.All); assert.deepEqual(modelOld.$meta.changeFetchedPropNames.sort(), ["ECInstanceId", "LastMod", "GeometryGuid"].sort()); assert.deepEqual(modelOld.$meta.rowOptions, { classIdsToClassNames: true }); assert.equal(modelOld.$meta.isIndirectChange, true); // --- instances[2]: Test2dElement Inserted New (ECClassId + all RelECClassId = class names) --- const elem = instances.find((i) => i.ECInstanceId === fullElementId && i.$meta.stage === "New"); expect(elem).to.exist; assert.equal(elem.ECInstanceId, fullElementId); assert.equal("TestDomain.Test2dElement", elem.ECClassId); assert.deepEqual(elem.Model, { Id: drawingModelId, RelECClassId: "BisCore.ModelContainsElements" }); assert.isString(elem.LastMod); assert.deepEqual(elem.CodeSpec, { Id: "0x1", RelECClassId: "BisCore.CodeSpecSpecifiesCode" }); assert.deepEqual(elem.CodeScope, { Id: "0x1", RelECClassId: "BisCore.ElementScopesCode" }); assert.isString(elem.FederationGuid); assert.deepEqual(elem.Category, { Id: drawingCategoryId, RelECClassId: "BisCore.GeometricElement2dIsInCategory" }); assert.deepEqual(elem.Origin, { X: 0, Y: 0 }); assert.equal(elem.Rotation, 0); assert.deepEqual(elem.BBoxLow, { X: -25, Y: -25 }); assert.deepEqual(elem.BBoxHigh, { X: 15, Y: 15 }); assert.include(String(elem.GeometryStream), "\"bytes\""); assert.include(String(elem.BinProp), "\"bytes\""); assert.equal(elem.StrProp, "hello"); assert.equal(elem.IntProp, 42); assert.equal(elem.LongProp, 9007199254740991); assert.closeTo(elem.DblProp, 3.14159265358979, 1e-10); assert.equal(elem.BoolProp, true); assert.equal(elem.DtProp, "2024-01-15T12:00:00.000"); assert.deepEqual(elem.Pt2dProp, { X: 1.5, Y: 2.5 }); assert.deepEqual(elem.Pt3dProp, { X: 3, Y: 4, Z: 5 }); assert.deepEqual(elem.StructProp, { X: 1, Y: 2, Z: 3, Label: "origin", Pt2d: { X: 0.5, Y: 0.5 }, Pt3d: { X: 1, Y: 2, Z: 3 } }); assert.deepEqual(elem.IntArrProp, [10, 20, 30]); assert.deepEqual(elem.StrArrProp, ["alpha", "beta", "gamma"]); assert.equal(elem.StructArrProp.length, 2); assert.deepEqual(elem.RelatedElem, { Id: drawingCategoryId, RelECClassId: "TestDomain.Test2dUsesElement" }); assert.deepEqual(Object.keys(elem).sort(), [ "ECInstanceId", "ECClassId", "Model", "LastMod", "CodeSpec", "CodeScope", "FederationGuid", "$meta", "Category", "Origin", "Rotation", "BBoxLow", "BBoxHigh", "GeometryStream", "StrProp", "IntProp", "LongProp", "DblProp", "BoolProp", "DtProp", "Pt2dProp", "Pt3dProp", "StructProp", "IntArrProp", "StrArrProp", "StructArrProp", "RelatedElem", "BinProp" ].sort()); assert.deepEqual(Object.keys(elem.$meta).sort(), ["op", "tables", "changeIndexes", "stage", "instanceKey", "propFilter", "changeFetchedPropNames", "rowOptions", "isIndirectChange"].sort()); assert.equal(elem.$meta.op, "Inserted"); assert.equal(elem.$meta.stage, "New"); assert.equal(elem.$meta.propFilter, PropertyFilter.All); assert.deepEqual(elem.$meta.rowOptions, { classIdsToClassNames: true }); assert.deepEqual(elem.$meta.changeFetchedPropNames.sort(), ["ECInstanceId", "ECClassId", "Model.Id", "LastMod", "CodeSpec.Id", "CodeScope.Id", "CodeValue", "UserLabel", "Parent", "FederationGuid", "JsonProperties", "Category.Id", "Origin", "Rotation", "BBoxLow", "BBoxHigh", "GeometryStream", "TypeDefinition", "StrProp", "IntProp", "LongProp", "DblProp", "BoolProp", "DtProp", "BinProp", "Pt2dProp", "Pt3dProp", "StructProp.X", "StructProp.Y", "StructProp.Z", "StructProp.Label", "StructProp.Pt2d", "StructProp.Pt3d", "IntArrProp", "StrArrProp", "StructArrProp", "RelatedElem"].sort()); assert.equal(elem.$meta.isIndirectChange, false); }); it("txn1 | rowOptions: useJsName", () => { const instances = readTxn(rwIModel, txnId, undefined, { useJsName: true }); assert.equal(instances.length, 3); // --- instances[0]: DrawingModel Updated New (all keys camelCase) --- const modelNew = instances.find((i) => i.id === drawingModelId && i.$meta.stage === "New"); expect(modelNew).to.exist; assert.equal(modelNew.id, drawingModelId); assert.equal(modelNew.className, "BisCore.DrawingModel"); assert.isString(modelNew.lastMod); assert.isString(modelNew.geometryGuid); assert.isUndefined(modelNew.ECInstanceId); assert.isUndefined(modelNew.ECClassId); assert.deepEqual(Object.keys(modelNew).sort(), ["id", "className", "lastMod", "geometryGuid", "$meta"].sort()); assert.deepEqual(Object.keys(modelNew.$meta).sort(), ["op", "tables", "changeIndexes", "stage", "instanceKey", "propFilter", "changeFetchedPropNames", "rowOptions", "isIndirectChange"].sort()); assert.equal(modelNew.$meta.op, "Updated"); assert.equal(modelNew.$meta.stage, "New"); assert.equal(modelNew.$meta.propFilter, PropertyFilter.All); assert.deepEqual(modelNew.$meta.changeFetchedPropNames.sort(), ["ECInstanceId", "LastMod", "GeometryGuid"].sort()); assert.deepEqual(modelNew.$meta.rowOptions, { useJsName: true }); assert.equal(modelNew.$meta.isIndirectChange, true); // --- instances[1]: DrawingModel Updated Old --- const modelOld = instances.find((i) => i.id === drawingModelId && i.$meta.stage === "Old"); expect(modelOld).to.exist; assert.equal(modelOld.id, drawingModelId); assert.equal(modelOld.className, "BisCore.DrawingModel"); assert.isUndefined(modelOld.ECInstanceId); assert.deepEqual(Object.keys(modelOld).sort(), ["id", "className", "$meta"].sort()); assert.deepEqual(Object.keys(modelOld.$meta).sort(), ["op", "tables", "changeIndexes", "stage", "instanceKey", "propFilter", "changeFetchedPropNames", "rowOptions", "isIndirectChange"].sort()); assert.equal(modelOld.$meta.op, "Updated"); assert.equal(modelOld.$meta.stage, "Old"); assert.equal(modelOld.$meta.propFilter, PropertyFilter.All); assert.deepEqual(modelOld.$meta.changeFetchedPropNames.sort(), ["ECInstanceId", "LastMod", "GeometryGuid"].sort()); assert.deepEqual(modelOld.$meta.rowOptions, { useJsName: true }); assert.equal(modelOld.$meta.isIndirectChange, true); // --- instances[2]: Test2dElement Inserted New (camelCase keys + class names for nav) --- const elem = instances.find((i) => i.id === fullElementId && i.$meta.stage === "New"); expect(elem).to.exist; assert.equal(elem.id, fullElementId); assert.equal(elem.className, "TestDomain.Test2dElement"); assert.isUndefined(elem.ECInstanceId); assert.isUndefined(elem.ECClassId); assert.isUndefined(elem.StrProp); assert.deepEqual(elem.model, { id: drawingModelId, relClassName: "BisCore.ModelContainsElements" }); assert.isString(elem.lastMod); assert.deepEqual(elem.codeSpec, { id: "0x1", relClassName: "BisCore.CodeSpecSpecifiesCode" }); assert.deepEqual(elem.codeScope, { id: "0x1", relClassName: "BisCore.ElementScopesCode" }); assert.isString(elem.federationGuid); assert.deepEqual(elem.category, { id: drawingCategoryId, relClassName: "BisCore.GeometricElement2dIsInCategory" }); assert.deepEqual(elem.origin, { x: 0, y: 0 }); assert.equal(elem.rotation, 0); assert.deepEqual(elem.bBoxLow, { x: -25, y: -25 }); assert.deepEqual(elem.bBoxHigh, { x: 15, y: 15 }); assert.include(String(elem.geometryStream), "\"bytes\""); assert.include(String(elem.binProp), "\"bytes\""); assert.equal(elem.strProp, "hello"); assert.equal(elem.intProp, 42); assert.equal(elem.longProp, 9007199254740991); assert.closeTo(elem.dblProp, 3.14159265358979, 1e-10); assert.equal(elem.boolProp, true); assert.equal(elem.dtProp, "2024-01-15T12:00:00.000"); assert.deepEqual(elem.pt2dProp, { x: 1.5, y: 2.5 }); assert.deepEqual(elem.pt3dProp, { x: 3, y: 4, z: 5 }); assert.deepEqual(elem.structProp, { x: 1, y: 2, z: 3, label: "origin", pt2d: { x: 0.5, y: 0.5 }, pt3d: { x: 1, y: 2, z: 3 } }); assert.deepEqual(elem.intArrProp, [10, 20, 30]); assert.deepEqual(elem.strArrProp, ["alpha", "beta", "gamma"]); assert.equal(elem.structArrProp.length, 2); assert.deepEqual(elem.structArrProp[0], { x: 0, y: 1, z: 2, label: "a", pt2d: { x: 0, y: 0 }, pt3d: { x: 0, y: 0, z: 0 } }); assert.deepEqual(elem.relatedElem, { id: drawingCategoryId, relClassName: "TestDomain.Test2dUsesElement" }); assert.deepEqual(Object.keys(elem).sort(), [ "id", "className", "model", "lastMod", "codeSpec", "codeScope", "federationGuid", "$meta", "category", "origin", "rotation", "bBoxLow", "bBoxHigh", "geometryStream", "strProp", "intProp", "longProp", "dblProp", "boolProp", "dtProp", "pt2dProp", "pt3dProp", "structProp", "intArrProp", "strArrProp", "structArrProp", "relatedElem", "binProp" ].sort()); assert.deepEqual(Object.keys(elem.$meta).sort(), ["op", "tables", "changeIndexes", "stage", "instanceKey", "propFilter", "changeFetchedPropNames", "rowOptions", "isIndirectChange"].sort()); assert.equal(elem.$meta.op, "Inserted"); assert.equal(elem.$meta.stage, "New"); assert.equal(elem.$meta.propFilter, PropertyFilter.All); assert.deepEqual(elem.$meta.changeFetchedPropNames.sort(), [ 'BBoxHigh', 'BBoxLow', 'BinProp', 'BoolProp', 'Category.Id', 'CodeScope.Id', 'CodeSpec.Id', 'CodeValue', 'DblProp', 'DtProp', 'ECClassId', 'ECInstanceId', 'FederationGuid', 'GeometryStream', 'IntArrProp', 'IntProp', 'JsonProperties', 'LastMod', 'LongProp', 'Model.Id', 'Origin', 'Parent', 'Pt2dProp', 'Pt3dProp', 'RelatedElem', 'Rotation', 'StrArrProp', 'StrProp', 'StructArrProp', 'StructProp.Label', 'StructProp.Pt2d', 'StructProp.Pt3d', 'StructProp.X', 'StructProp.Y', 'StructProp.Z', 'TypeDefinition', 'UserLabel' ].sort()); assert.deepEqual(elem.$meta.rowOptions, { useJsName: true }); assert.equal(elem.$meta.isIndirectChange, false); }); it("txn1 | rowOptions: abbreviateBlobs", () => { const instances = readTxn(rwIModel, txnId, undefined, { abbreviateBlobs: true }); assert.equal(instances.length, 3); // --- instances[0]: DrawingModel Updated New --- const modelNew = instances.find((i) => i.ECInstanceId === drawingModelId && i.$meta.stage === "New"); expect(modelNew).to.exist; assert.equal(modelNew.ECInstanceId, drawingModelId); assert.equal("BisCore:DrawingModel", rwIModel.getClassNameFromId(modelNew.ECClassId)); // still raw hex assert.isString(modelNew.LastMod); assert.isString(modelNew.GeometryGuid); assert.deepEqual(Object.keys(modelNew).sort(), ["ECInstanceId", "ECClassId", "LastMod", "GeometryGuid", "$meta"].sort()); assert.deepEqual(Object.keys(modelNew.$meta).sort(), ["op", "tables", "changeIndexes", "stage", "instanceKey", "propFilter", "changeFetchedPropNames", "rowOptions", "isIndirectChange"].sort()); assert.equal(modelNew.$meta.op, "Updated"); assert.equal(modelNew.$meta.stage, "New"); assert.equal(modelNew.$meta.propFilter, PropertyFilter.All); assert.deepEqual(modelNew.$meta.changeFetchedPropNames.sort(), ["ECInstanceId", "LastMod", "GeometryGuid"].sort()); assert.deepEqual(modelNew.$meta.rowOptions, { abbreviateBlobs: true }); assert.equal(modelNew.$meta.isIndirectChange, true); // --- instances[1]: DrawingModel Updated Old --- const modelOld = instances.find((i) => i.ECInstanceId === drawingModelId && i.$meta.stage === "Old"); expect(modelOld).to.exist; assert.equal(modelOld.ECInstanceId, drawingModelId); assert.equal("BisCore:DrawingModel", rwIModel.getClassNameFromId(modelOld.ECClassId)); assert.deepEqual(Object.keys(modelOld).sort(), ["ECInstanceId", "ECClassId", "$meta"].sort()); assert.deepEqual(Object.keys(modelOld.$meta).sort(), ["op", "tables", "changeIndexes", "stage", "instanceKey", "propFilter", "changeFetchedPropNames", "rowOptions", "isIndirectChange"].sort()); assert.equal(modelOld.$meta.op, "Updated"); assert.equal(modelOld.$meta.stage, "Old"); assert.equal(modelOld.$meta.propFilter, PropertyFilter.All); assert.deepEqual(modelOld.$meta.changeFetchedPropNames.sort(), ["ECInstanceId", "LastMod", "GeometryGuid"].sort()); assert.deepEqual(modelOld.$meta.rowOptions, { abbreviateBlobs: true }); assert.equal(modelOld.$meta.isIndirectChange, true); // --- instances[2]: Test2dElement Inserted New --- const elem = instances.find((i) => i.ECInstanceId === fullElementId && i.$meta.stage === "New"); expect(elem).to.exist; assert.equal(elem.ECInstanceId, fullElementId); assert.equal