@itwin/core-backend
Version:
iTwin.js backend components
746 lines • 360 kB
JavaScript
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