@itwin/core-backend 5.12.0-dev.6 → 5.12.0-dev.8
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 +9 -1
- package/lib/cjs/ChangesetReader.d.ts +65 -23
- package/lib/cjs/ChangesetReader.d.ts.map +1 -1
- package/lib/cjs/ChangesetReader.js +162 -102
- package/lib/cjs/ChangesetReader.js.map +1 -1
- package/lib/cjs/ECDb.js +2 -2
- package/lib/cjs/ECDb.js.map +1 -1
- package/lib/cjs/IModelDb.js +2 -2
- package/lib/cjs/IModelDb.js.map +1 -1
- package/lib/esm/ChangesetReader.d.ts +65 -23
- package/lib/esm/ChangesetReader.d.ts.map +1 -1
- package/lib/esm/ChangesetReader.js +163 -103
- package/lib/esm/ChangesetReader.js.map +1 -1
- package/lib/esm/ECDb.js +2 -2
- package/lib/esm/ECDb.js.map +1 -1
- package/lib/esm/IModelDb.js +2 -2
- package/lib/esm/IModelDb.js.map +1 -1
- package/lib/esm/test/hubaccess/BriefcaseManager.test.js +1 -1
- package/lib/esm/test/hubaccess/BriefcaseManager.test.js.map +1 -1
- package/lib/esm/test/imodel/IModel.test.js +4 -4
- package/lib/esm/test/imodel/IModel.test.js.map +1 -1
- package/lib/esm/test/standalone/ChangesetReader.test.js +725 -110
- package/lib/esm/test/standalone/ChangesetReader.test.js.map +1 -1
- package/package.json +14 -14
|
@@ -3279,6 +3279,61 @@ describe("ChangesetReader — openFile + openGroup", () => {
|
|
|
3279
3279
|
}
|
|
3280
3280
|
}
|
|
3281
3281
|
});
|
|
3282
|
+
it("openGroup: insert in one changeset then delete in another yields no instances for the element (net no-op)", async () => {
|
|
3283
|
+
const adminToken = "super manager token";
|
|
3284
|
+
const targetDir = path.join(KnownTestLocations.outputDir, rwIModelId, "changesets");
|
|
3285
|
+
// Record how many changesets already exist so we can identify the new ones by index
|
|
3286
|
+
let changesets = await HubMock.downloadChangesets({ iModelId: rwIModelId, targetDir });
|
|
3287
|
+
const baseCount = changesets.length;
|
|
3288
|
+
// Wait so that LastMod on bis_Model gets a distinct timestamp before the insert txn
|
|
3289
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
3290
|
+
// --- Push baseCount+1: insert a brand-new element ---
|
|
3291
|
+
await rwIModel.locks.acquireLocks({ shared: drawingModelId });
|
|
3292
|
+
const noOpElementId = txn.insertElement({
|
|
3293
|
+
classFullName: "TestDomain:SimpleElement",
|
|
3294
|
+
model: drawingModelId,
|
|
3295
|
+
category: drawingCategoryId,
|
|
3296
|
+
code: Code.createEmpty(),
|
|
3297
|
+
BinProp: new Uint8Array([0xde, 0xad, 0xbe, 0xef]),
|
|
3298
|
+
});
|
|
3299
|
+
txn.saveChanges("insert no-op element");
|
|
3300
|
+
await rwIModel.pushChanges({ description: "insert no-op element", accessToken: adminToken });
|
|
3301
|
+
changesets = await HubMock.downloadChangesets({ iModelId: rwIModelId, targetDir });
|
|
3302
|
+
expect(changesets.length).to.equal(baseCount + 1);
|
|
3303
|
+
const insertCs = changesets[baseCount];
|
|
3304
|
+
// Wait so that LastMod on bis_Model gets a distinct timestamp before the delete txn
|
|
3305
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
3306
|
+
// --- Push baseCount+2: delete the same element ---
|
|
3307
|
+
await rwIModel.locks.acquireLocks({ exclusive: noOpElementId });
|
|
3308
|
+
txn.deleteElement(noOpElementId);
|
|
3309
|
+
txn.saveChanges("delete no-op element");
|
|
3310
|
+
await rwIModel.pushChanges({ description: "delete no-op element", accessToken: adminToken });
|
|
3311
|
+
changesets = await HubMock.downloadChangesets({ iModelId: rwIModelId, targetDir });
|
|
3312
|
+
expect(changesets.length).to.equal(baseCount + 2);
|
|
3313
|
+
const deleteCs = changesets[baseCount + 1];
|
|
3314
|
+
// === openGroup: insert + delete streamed together — element never existed net, so no instances ===
|
|
3315
|
+
{
|
|
3316
|
+
const env_18 = { stack: [], error: void 0, hasError: false };
|
|
3317
|
+
try {
|
|
3318
|
+
const reader = __addDisposableResource(env_18, ChangesetReader.openGroup({ db: rwIModel, changesetFiles: [insertCs.pathname, deleteCs.pathname] }), false);
|
|
3319
|
+
const pcu = __addDisposableResource(env_18, new PartialChangeUnifier(ChangeUnifierCache.createInMemoryCache()), false);
|
|
3320
|
+
while (reader.step())
|
|
3321
|
+
pcu.appendFrom(reader);
|
|
3322
|
+
const instances = Array.from(pcu.instances);
|
|
3323
|
+
// Insert followed immediately by delete cancels out: the unifier must produce zero instances
|
|
3324
|
+
// for this element because the net effect on the database is nothing changed.
|
|
3325
|
+
const elemInstances = instances.filter((i) => i.ECInstanceId === noOpElementId);
|
|
3326
|
+
expect(elemInstances).to.have.length(0, `expected no-op for element ${noOpElementId} but got ${elemInstances.length} instance(s)`);
|
|
3327
|
+
}
|
|
3328
|
+
catch (e_18) {
|
|
3329
|
+
env_18.error = e_18;
|
|
3330
|
+
env_18.hasError = true;
|
|
3331
|
+
}
|
|
3332
|
+
finally {
|
|
3333
|
+
__disposeResources(env_18);
|
|
3334
|
+
}
|
|
3335
|
+
}
|
|
3336
|
+
});
|
|
3282
3337
|
});
|
|
3283
3338
|
describe("ChangesetReader — openLocalChanges + openInmemoryChanges", () => {
|
|
3284
3339
|
let rwIModel;
|
|
@@ -3341,10 +3396,10 @@ describe("ChangesetReader — openLocalChanges + openInmemoryChanges", () => {
|
|
|
3341
3396
|
});
|
|
3342
3397
|
txn.saveChanges("insert element");
|
|
3343
3398
|
{
|
|
3344
|
-
const
|
|
3399
|
+
const env_19 = { stack: [], error: void 0, hasError: false };
|
|
3345
3400
|
try {
|
|
3346
|
-
const reader = __addDisposableResource(
|
|
3347
|
-
const pcu = __addDisposableResource(
|
|
3401
|
+
const reader = __addDisposableResource(env_19, ChangesetReader.openLocalChanges({ db: rwIModel, rowOptions: { abbreviateBlobs: false } }), false);
|
|
3402
|
+
const pcu = __addDisposableResource(env_19, new PartialChangeUnifier(ChangeUnifierCache.createSqliteBackedCache()), false);
|
|
3348
3403
|
while (reader.step())
|
|
3349
3404
|
pcu.appendFrom(reader);
|
|
3350
3405
|
const instances = Array.from(pcu.instances);
|
|
@@ -3380,12 +3435,12 @@ describe("ChangesetReader — openLocalChanges + openInmemoryChanges", () => {
|
|
|
3380
3435
|
'JsonProperties', 'LastMod', 'Model.Id', 'Origin', 'Parent', 'Pt3dProp', 'Rotation',
|
|
3381
3436
|
'TypeDefinition', 'UserLabel'].sort());
|
|
3382
3437
|
}
|
|
3383
|
-
catch (
|
|
3384
|
-
|
|
3385
|
-
|
|
3438
|
+
catch (e_19) {
|
|
3439
|
+
env_19.error = e_19;
|
|
3440
|
+
env_19.hasError = true;
|
|
3386
3441
|
}
|
|
3387
3442
|
finally {
|
|
3388
|
-
__disposeResources(
|
|
3443
|
+
__disposeResources(env_19);
|
|
3389
3444
|
}
|
|
3390
3445
|
}
|
|
3391
3446
|
// Wait so that LastMod on bis_Model gets a distinct timestamp before the update txn
|
|
@@ -3400,10 +3455,10 @@ describe("ChangesetReader — openLocalChanges + openInmemoryChanges", () => {
|
|
|
3400
3455
|
],
|
|
3401
3456
|
});
|
|
3402
3457
|
{
|
|
3403
|
-
const
|
|
3458
|
+
const env_20 = { stack: [], error: void 0, hasError: false };
|
|
3404
3459
|
try {
|
|
3405
|
-
const reader = __addDisposableResource(
|
|
3406
|
-
const pcu = __addDisposableResource(
|
|
3460
|
+
const reader = __addDisposableResource(env_20, ChangesetReader.openInMemoryChanges({ db: rwIModel, rowOptions: { abbreviateBlobs: false } }), false);
|
|
3461
|
+
const pcu = __addDisposableResource(env_20, new PartialChangeUnifier(ChangeUnifierCache.createSqliteBackedCache()), false);
|
|
3407
3462
|
while (reader.step())
|
|
3408
3463
|
pcu.appendFrom(reader);
|
|
3409
3464
|
const instances = Array.from(pcu.instances);
|
|
@@ -3441,20 +3496,20 @@ describe("ChangesetReader — openLocalChanges + openInmemoryChanges", () => {
|
|
|
3441
3496
|
assert.equal(elemOld.$meta.isIndirectChange, false);
|
|
3442
3497
|
assert.deepEqual(elemOld.$meta.changeFetchedPropNames.sort(), ['BBoxHigh', 'BBoxLow', 'BinProp', 'ECInstanceId', 'GuidArrProp', 'LastMod', 'Origin', 'Pt3dProp', 'Rotation'].sort());
|
|
3443
3498
|
}
|
|
3444
|
-
catch (
|
|
3445
|
-
|
|
3446
|
-
|
|
3499
|
+
catch (e_20) {
|
|
3500
|
+
env_20.error = e_20;
|
|
3501
|
+
env_20.hasError = true;
|
|
3447
3502
|
}
|
|
3448
3503
|
finally {
|
|
3449
|
-
__disposeResources(
|
|
3504
|
+
__disposeResources(env_20);
|
|
3450
3505
|
}
|
|
3451
3506
|
}
|
|
3452
3507
|
// === openLocalChanges: insert + update as a single stream so becomes insert ===
|
|
3453
3508
|
{
|
|
3454
|
-
const
|
|
3509
|
+
const env_21 = { stack: [], error: void 0, hasError: false };
|
|
3455
3510
|
try {
|
|
3456
|
-
const reader = __addDisposableResource(
|
|
3457
|
-
const pcu = __addDisposableResource(
|
|
3511
|
+
const reader = __addDisposableResource(env_21, ChangesetReader.openLocalChanges({ db: rwIModel, includeInMemoryChanges: true, rowOptions: { abbreviateBlobs: false } }), false);
|
|
3512
|
+
const pcu = __addDisposableResource(env_21, new PartialChangeUnifier(ChangeUnifierCache.createSqliteBackedCache()), false);
|
|
3458
3513
|
while (reader.step())
|
|
3459
3514
|
pcu.appendFrom(reader);
|
|
3460
3515
|
const instances = Array.from(pcu.instances);
|
|
@@ -3494,12 +3549,12 @@ describe("ChangesetReader — openLocalChanges + openInmemoryChanges", () => {
|
|
|
3494
3549
|
'Rotation', 'TypeDefinition', 'UserLabel'].sort());
|
|
3495
3550
|
assert.equal(elemNew.$meta.isIndirectChange, false);
|
|
3496
3551
|
}
|
|
3497
|
-
catch (
|
|
3498
|
-
|
|
3499
|
-
|
|
3552
|
+
catch (e_21) {
|
|
3553
|
+
env_21.error = e_21;
|
|
3554
|
+
env_21.hasError = true;
|
|
3500
3555
|
}
|
|
3501
3556
|
finally {
|
|
3502
|
-
__disposeResources(
|
|
3557
|
+
__disposeResources(env_21);
|
|
3503
3558
|
}
|
|
3504
3559
|
}
|
|
3505
3560
|
});
|
|
@@ -3548,7 +3603,7 @@ describe("ChangesetReader: behaviour in case imodel is not in sync with changese
|
|
|
3548
3603
|
HubMock.shutdown();
|
|
3549
3604
|
});
|
|
3550
3605
|
it("openFile() reads the middle changeset of an insert → update → delete lifecycle", async () => {
|
|
3551
|
-
const
|
|
3606
|
+
const env_22 = { stack: [], error: void 0, hasError: false };
|
|
3552
3607
|
try {
|
|
3553
3608
|
const adminToken = "super manager token";
|
|
3554
3609
|
// Push 2 (insert): insert element with category1
|
|
@@ -3596,8 +3651,8 @@ describe("ChangesetReader: behaviour in case imodel is not in sync with changese
|
|
|
3596
3651
|
const changesets = await HubMock.downloadChangesets({ iModelId: rwIModelId, targetDir });
|
|
3597
3652
|
expect(changesets.length).to.equal(4);
|
|
3598
3653
|
const middleChangeset = changesets[Math.floor(changesets.length / 2)]; // index 2 = update
|
|
3599
|
-
const reader = __addDisposableResource(
|
|
3600
|
-
const pcu = __addDisposableResource(
|
|
3654
|
+
const reader = __addDisposableResource(env_22, ChangesetReader.openFile({ db: rwIModel, fileName: middleChangeset.pathname, propFilter: PropertyFilter.InstanceKey, rowOptions: { classIdsToClassNames: true } }), false);
|
|
3655
|
+
const pcu = __addDisposableResource(env_22, new PartialChangeUnifier(ChangeUnifierCache.createInMemoryCache()), false);
|
|
3601
3656
|
while (reader.step())
|
|
3602
3657
|
pcu.appendFrom(reader);
|
|
3603
3658
|
const instances = Array.from(pcu.instances);
|
|
@@ -3616,16 +3671,16 @@ describe("ChangesetReader: behaviour in case imodel is not in sync with changese
|
|
|
3616
3671
|
expect(bisElementNew.map((i => i.ECClassId)).sort()).to.deep.equal(["BisCore.GeometricElement2d", "BisCore.Element"].sort());
|
|
3617
3672
|
expect(bisElementOld.map((i => i.ECClassId)).sort()).to.deep.equal(["BisCore.GeometricElement2d", "BisCore.Element"].sort());
|
|
3618
3673
|
}
|
|
3619
|
-
catch (
|
|
3620
|
-
|
|
3621
|
-
|
|
3674
|
+
catch (e_22) {
|
|
3675
|
+
env_22.error = e_22;
|
|
3676
|
+
env_22.hasError = true;
|
|
3622
3677
|
}
|
|
3623
3678
|
finally {
|
|
3624
|
-
__disposeResources(
|
|
3679
|
+
__disposeResources(env_22);
|
|
3625
3680
|
}
|
|
3626
3681
|
});
|
|
3627
3682
|
it("openTxn() reads the middle txn of an insert → update → update lifecycle", async () => {
|
|
3628
|
-
const
|
|
3683
|
+
const env_23 = { stack: [], error: void 0, hasError: false };
|
|
3629
3684
|
try {
|
|
3630
3685
|
// Push 2 (insert): insert element with category1
|
|
3631
3686
|
const geomArray = [
|
|
@@ -3667,8 +3722,8 @@ describe("ChangesetReader: behaviour in case imodel is not in sync with changese
|
|
|
3667
3722
|
s: { x: 100.0, y: 200.0 },
|
|
3668
3723
|
});
|
|
3669
3724
|
txn.saveChanges("update element");
|
|
3670
|
-
const reader = __addDisposableResource(
|
|
3671
|
-
const pcu = __addDisposableResource(
|
|
3725
|
+
const reader = __addDisposableResource(env_23, ChangesetReader.openTxn({ db: rwIModel, txnId }), false);
|
|
3726
|
+
const pcu = __addDisposableResource(env_23, new PartialChangeUnifier(ChangeUnifierCache.createInMemoryCache()), false);
|
|
3672
3727
|
while (reader.step())
|
|
3673
3728
|
pcu.appendFrom(reader);
|
|
3674
3729
|
const instances = Array.from(pcu.instances);
|
|
@@ -3690,12 +3745,12 @@ describe("ChangesetReader: behaviour in case imodel is not in sync with changese
|
|
|
3690
3745
|
expect(elementOld.$meta.changeFetchedPropNames).to.include("s.X");
|
|
3691
3746
|
expect(elementOld.$meta.changeFetchedPropNames).to.not.include("s.Y");
|
|
3692
3747
|
}
|
|
3693
|
-
catch (
|
|
3694
|
-
|
|
3695
|
-
|
|
3748
|
+
catch (e_23) {
|
|
3749
|
+
env_23.error = e_23;
|
|
3750
|
+
env_23.hasError = true;
|
|
3696
3751
|
}
|
|
3697
3752
|
finally {
|
|
3698
|
-
__disposeResources(
|
|
3753
|
+
__disposeResources(env_23);
|
|
3699
3754
|
}
|
|
3700
3755
|
});
|
|
3701
3756
|
});
|
|
@@ -3778,7 +3833,7 @@ describe("ChangesetReader: overflow table graceful recovery when ExclusiveRootCl
|
|
|
3778
3833
|
HubMock.shutdown();
|
|
3779
3834
|
});
|
|
3780
3835
|
it("openFile() recovers gracefully when ExclusiveRootClassId is NULL for overflow table", () => {
|
|
3781
|
-
const
|
|
3836
|
+
const env_24 = { stack: [], error: void 0, hasError: false };
|
|
3782
3837
|
try {
|
|
3783
3838
|
/**
|
|
3784
3839
|
* Simulate the broken state: clear ExclusiveRootClassId so the reader cannot
|
|
@@ -3788,7 +3843,7 @@ describe("ChangesetReader: overflow table graceful recovery when ExclusiveRootCl
|
|
|
3788
3843
|
*/
|
|
3789
3844
|
expect(rwIModel[_nativeDb].executeSql("UPDATE ec_Table SET ExclusiveRootClassId=NULL WHERE Name='bis_GeometricElement2d_Overflow'")).to.equal(DbResult.BE_SQLITE_OK);
|
|
3790
3845
|
let assertedOnOverflowTable = false;
|
|
3791
|
-
const reader = __addDisposableResource(
|
|
3846
|
+
const reader = __addDisposableResource(env_24, ChangesetReader.openFile({ db: rwIModel, fileName: updateChangesetPathname }), false);
|
|
3792
3847
|
while (reader.step()) {
|
|
3793
3848
|
if (reader.tableName !== "bis_GeometricElement2d_Overflow")
|
|
3794
3849
|
continue;
|
|
@@ -3811,21 +3866,21 @@ describe("ChangesetReader: overflow table graceful recovery when ExclusiveRootCl
|
|
|
3811
3866
|
}
|
|
3812
3867
|
assert.isTrue(assertedOnOverflowTable, "Expected at least one row from the overflow table");
|
|
3813
3868
|
}
|
|
3814
|
-
catch (
|
|
3815
|
-
|
|
3816
|
-
|
|
3869
|
+
catch (e_24) {
|
|
3870
|
+
env_24.error = e_24;
|
|
3871
|
+
env_24.hasError = true;
|
|
3817
3872
|
}
|
|
3818
3873
|
finally {
|
|
3819
|
-
__disposeResources(
|
|
3874
|
+
__disposeResources(env_24);
|
|
3820
3875
|
}
|
|
3821
3876
|
});
|
|
3822
3877
|
});
|
|
3823
3878
|
describe("ChangesetReader: instance reused with a different class (class change in Updated row)", () => {
|
|
3824
3879
|
it("openFile() correctly identifies ECClassId change from T1 to T2 in a buggy changeset", async () => {
|
|
3825
|
-
const
|
|
3880
|
+
const env_25 = { stack: [], error: void 0, hasError: false };
|
|
3826
3881
|
try {
|
|
3827
3882
|
/**
|
|
3828
|
-
* Same scenario as
|
|
3883
|
+
* Same scenario as SQliteChangesetReaderAndChangesetECAdaptor.test.ts: "Instance update to a different class (bug)".
|
|
3829
3884
|
* Verifies ChangesetReader behaviour when an instance ID is reused with a different class.
|
|
3830
3885
|
*
|
|
3831
3886
|
* Steps:
|
|
@@ -3927,7 +3982,7 @@ describe("ChangesetReader: instance reused with a different class (class change
|
|
|
3927
3982
|
// so it correctly sees T2 for the new (inserted) side and T1 for the old (deleted) side.
|
|
3928
3983
|
let bisElementAsserted = false;
|
|
3929
3984
|
let bisGeomElement2dAsserted = false;
|
|
3930
|
-
const reader = __addDisposableResource(
|
|
3985
|
+
const reader = __addDisposableResource(env_25, ChangesetReader.openFile({ db: b1, fileName: changesets[1].pathname }), false);
|
|
3931
3986
|
while (reader.step()) {
|
|
3932
3987
|
if (reader.tableName === "bis_Element" && reader.op === "Updated") {
|
|
3933
3988
|
bisElementAsserted = true;
|
|
@@ -3957,12 +4012,12 @@ describe("ChangesetReader: instance reused with a different class (class change
|
|
|
3957
4012
|
b1.close();
|
|
3958
4013
|
HubMock.shutdown();
|
|
3959
4014
|
}
|
|
3960
|
-
catch (
|
|
3961
|
-
|
|
3962
|
-
|
|
4015
|
+
catch (e_25) {
|
|
4016
|
+
env_25.error = e_25;
|
|
4017
|
+
env_25.hasError = true;
|
|
3963
4018
|
}
|
|
3964
4019
|
finally {
|
|
3965
|
-
__disposeResources(
|
|
4020
|
+
__disposeResources(env_25);
|
|
3966
4021
|
}
|
|
3967
4022
|
});
|
|
3968
4023
|
});
|
|
@@ -4256,7 +4311,7 @@ describe("ChangesetReader: invalid inputs", () => {
|
|
|
4256
4311
|
expect(() => ChangesetReader.openFile({ db: iModel, fileName: KnownTestLocations.outputDir })).to.throw();
|
|
4257
4312
|
});
|
|
4258
4313
|
it("openFile: path points to a plain text file (not .changeset) throws", () => {
|
|
4259
|
-
const
|
|
4314
|
+
const env_26 = { stack: [], error: void 0, hasError: false };
|
|
4260
4315
|
try {
|
|
4261
4316
|
const txtFile = path.join(KnownTestLocations.outputDir, "not_a_changeset.txt");
|
|
4262
4317
|
if (fs.existsSync(txtFile))
|
|
@@ -4264,19 +4319,19 @@ describe("ChangesetReader: invalid inputs", () => {
|
|
|
4264
4319
|
// Write a small non-changeset file and expect the reader to reject it.
|
|
4265
4320
|
fs.writeFileSync(txtFile, "this is not a changeset");
|
|
4266
4321
|
// The native code asserts on an invalid changeset file. Suppress this.
|
|
4267
|
-
const _disableAssertions = __addDisposableResource(
|
|
4268
|
-
const reader = __addDisposableResource(
|
|
4322
|
+
const _disableAssertions = __addDisposableResource(env_26, new DisableNativeAssertions(), false);
|
|
4323
|
+
const reader = __addDisposableResource(env_26, ChangesetReader.openFile({ db: iModel, fileName: txtFile }), false);
|
|
4269
4324
|
assert.equal(reader.step(), false, "Expected step() to return false for an invalid changeset file");
|
|
4270
4325
|
assert.equal(reader.step(), false, "Expected step() to return false for an invalid changeset file");
|
|
4271
4326
|
assert.equal(reader.step(), false, "Expected step() to return false for an invalid changeset file");
|
|
4272
4327
|
assert.equal(reader.step(), false, "Expected step() to return false for an invalid changeset file");
|
|
4273
4328
|
}
|
|
4274
|
-
catch (
|
|
4275
|
-
|
|
4276
|
-
|
|
4329
|
+
catch (e_26) {
|
|
4330
|
+
env_26.error = e_26;
|
|
4331
|
+
env_26.hasError = true;
|
|
4277
4332
|
}
|
|
4278
4333
|
finally {
|
|
4279
|
-
__disposeResources(
|
|
4334
|
+
__disposeResources(env_26);
|
|
4280
4335
|
}
|
|
4281
4336
|
});
|
|
4282
4337
|
// --- openGroup ---
|
|
@@ -4296,17 +4351,17 @@ describe("ChangesetReader: invalid inputs", () => {
|
|
|
4296
4351
|
// Passing the same changeset file twice is unusual but not necessarily an error at open time.
|
|
4297
4352
|
// The reader should open and step without throwing; the caller is responsible for any semantic issues.
|
|
4298
4353
|
expect(() => {
|
|
4299
|
-
const
|
|
4354
|
+
const env_27 = { stack: [], error: void 0, hasError: false };
|
|
4300
4355
|
try {
|
|
4301
|
-
const reader = __addDisposableResource(
|
|
4356
|
+
const reader = __addDisposableResource(env_27, ChangesetReader.openGroup({ db: iModel, changesetFiles: [validChangesetPath, validChangesetPath] }), false);
|
|
4302
4357
|
while (reader.step()) { /* drain */ }
|
|
4303
4358
|
}
|
|
4304
|
-
catch (
|
|
4305
|
-
|
|
4306
|
-
|
|
4359
|
+
catch (e_27) {
|
|
4360
|
+
env_27.error = e_27;
|
|
4361
|
+
env_27.hasError = true;
|
|
4307
4362
|
}
|
|
4308
4363
|
finally {
|
|
4309
|
-
__disposeResources(
|
|
4364
|
+
__disposeResources(env_27);
|
|
4310
4365
|
}
|
|
4311
4366
|
}).to.not.throw();
|
|
4312
4367
|
});
|
|
@@ -4319,24 +4374,10 @@ describe("ChangesetReader: invalid inputs", () => {
|
|
|
4319
4374
|
});
|
|
4320
4375
|
// --- property accessors before step() ---
|
|
4321
4376
|
it("accessing tableName before step() throws", () => {
|
|
4322
|
-
const env_27 = { stack: [], error: void 0, hasError: false };
|
|
4323
|
-
try {
|
|
4324
|
-
const reader = __addDisposableResource(env_27, ChangesetReader.openFile({ db: iModel, fileName: validChangesetPath }), false);
|
|
4325
|
-
expect(() => reader.tableName).to.throw();
|
|
4326
|
-
}
|
|
4327
|
-
catch (e_27) {
|
|
4328
|
-
env_27.error = e_27;
|
|
4329
|
-
env_27.hasError = true;
|
|
4330
|
-
}
|
|
4331
|
-
finally {
|
|
4332
|
-
__disposeResources(env_27);
|
|
4333
|
-
}
|
|
4334
|
-
});
|
|
4335
|
-
it("accessing isECTable before step() throws", () => {
|
|
4336
4377
|
const env_28 = { stack: [], error: void 0, hasError: false };
|
|
4337
4378
|
try {
|
|
4338
4379
|
const reader = __addDisposableResource(env_28, ChangesetReader.openFile({ db: iModel, fileName: validChangesetPath }), false);
|
|
4339
|
-
expect(() => reader.
|
|
4380
|
+
expect(() => reader.tableName).to.throw();
|
|
4340
4381
|
}
|
|
4341
4382
|
catch (e_28) {
|
|
4342
4383
|
env_28.error = e_28;
|
|
@@ -4346,11 +4387,11 @@ describe("ChangesetReader: invalid inputs", () => {
|
|
|
4346
4387
|
__disposeResources(env_28);
|
|
4347
4388
|
}
|
|
4348
4389
|
});
|
|
4349
|
-
it("accessing
|
|
4390
|
+
it("accessing isECTable before step() throws", () => {
|
|
4350
4391
|
const env_29 = { stack: [], error: void 0, hasError: false };
|
|
4351
4392
|
try {
|
|
4352
4393
|
const reader = __addDisposableResource(env_29, ChangesetReader.openFile({ db: iModel, fileName: validChangesetPath }), false);
|
|
4353
|
-
expect(() => reader.
|
|
4394
|
+
expect(() => reader.isECTable).to.throw();
|
|
4354
4395
|
}
|
|
4355
4396
|
catch (e_29) {
|
|
4356
4397
|
env_29.error = e_29;
|
|
@@ -4360,6 +4401,20 @@ describe("ChangesetReader: invalid inputs", () => {
|
|
|
4360
4401
|
__disposeResources(env_29);
|
|
4361
4402
|
}
|
|
4362
4403
|
});
|
|
4404
|
+
it("accessing isIndirectChange before step() throws", () => {
|
|
4405
|
+
const env_30 = { stack: [], error: void 0, hasError: false };
|
|
4406
|
+
try {
|
|
4407
|
+
const reader = __addDisposableResource(env_30, ChangesetReader.openFile({ db: iModel, fileName: validChangesetPath }), false);
|
|
4408
|
+
expect(() => reader.isIndirectChange).to.throw();
|
|
4409
|
+
}
|
|
4410
|
+
catch (e_30) {
|
|
4411
|
+
env_30.error = e_30;
|
|
4412
|
+
env_30.hasError = true;
|
|
4413
|
+
}
|
|
4414
|
+
finally {
|
|
4415
|
+
__disposeResources(env_30);
|
|
4416
|
+
}
|
|
4417
|
+
});
|
|
4363
4418
|
it("openGroup: should throw if spillThresholdInBytes is negative", () => {
|
|
4364
4419
|
expect(() => {
|
|
4365
4420
|
ChangesetReader.openGroup({ db: iModel, changesetFiles: [validChangesetPath, validChangesetPath], spillThresholdInBytes: -1 });
|
|
@@ -4471,19 +4526,19 @@ describe("ChangesetReader — spillThresholdInBytes (spill-to-disk)", () => {
|
|
|
4471
4526
|
}
|
|
4472
4527
|
/** Reads all instances from a reader using an in-memory unifier cache. */
|
|
4473
4528
|
function drainReader(reader) {
|
|
4474
|
-
const
|
|
4529
|
+
const env_31 = { stack: [], error: void 0, hasError: false };
|
|
4475
4530
|
try {
|
|
4476
|
-
const pcu = __addDisposableResource(
|
|
4531
|
+
const pcu = __addDisposableResource(env_31, new PartialChangeUnifier(ChangeUnifierCache.createInMemoryCache()), false);
|
|
4477
4532
|
while (reader.step())
|
|
4478
4533
|
pcu.appendFrom(reader);
|
|
4479
4534
|
return Array.from(pcu.instances);
|
|
4480
4535
|
}
|
|
4481
|
-
catch (
|
|
4482
|
-
|
|
4483
|
-
|
|
4536
|
+
catch (e_31) {
|
|
4537
|
+
env_31.error = e_31;
|
|
4538
|
+
env_31.hasError = true;
|
|
4484
4539
|
}
|
|
4485
4540
|
finally {
|
|
4486
|
-
__disposeResources(
|
|
4541
|
+
__disposeResources(env_31);
|
|
4487
4542
|
}
|
|
4488
4543
|
}
|
|
4489
4544
|
/** Sorts instances by a stable key for deterministic deep-equality comparisons. */
|
|
@@ -4711,26 +4766,26 @@ describe("ChangesetReader: strict mode (column-count mismatch)", () => {
|
|
|
4711
4766
|
await importSchemaStrings(txn, [STRICT_MODE_SCHEMA_V2]);
|
|
4712
4767
|
// Strict mode ON: binary has one column less than the live table.
|
|
4713
4768
|
{
|
|
4714
|
-
const
|
|
4769
|
+
const env_32 = { stack: [], error: void 0, hasError: false };
|
|
4715
4770
|
try {
|
|
4716
|
-
const reader = __addDisposableResource(
|
|
4771
|
+
const reader = __addDisposableResource(env_32, ChangesetReader.openTxn({ db, txnId }), false);
|
|
4717
4772
|
reader.enableStrictMode();
|
|
4718
4773
|
expect(() => { while (reader.step()) { /* drain */ } }).to.throw();
|
|
4719
4774
|
}
|
|
4720
|
-
catch (
|
|
4721
|
-
|
|
4722
|
-
|
|
4775
|
+
catch (e_32) {
|
|
4776
|
+
env_32.error = e_32;
|
|
4777
|
+
env_32.hasError = true;
|
|
4723
4778
|
}
|
|
4724
4779
|
finally {
|
|
4725
|
-
__disposeResources(
|
|
4780
|
+
__disposeResources(env_32);
|
|
4726
4781
|
}
|
|
4727
4782
|
}
|
|
4728
4783
|
{
|
|
4729
|
-
const
|
|
4784
|
+
const env_33 = { stack: [], error: void 0, hasError: false };
|
|
4730
4785
|
try {
|
|
4731
|
-
const reader = __addDisposableResource(
|
|
4786
|
+
const reader = __addDisposableResource(env_33, ChangesetReader.openTxn({ db, txnId }), false);
|
|
4732
4787
|
reader.disableStrictMode(); // no-op when already off — verifies the API does not throw
|
|
4733
|
-
const pcu = __addDisposableResource(
|
|
4788
|
+
const pcu = __addDisposableResource(env_33, new PartialChangeUnifier(ChangeUnifierCache.createInMemoryCache()), false);
|
|
4734
4789
|
while (reader.step())
|
|
4735
4790
|
pcu.appendFrom(reader);
|
|
4736
4791
|
const instances = Array.from(pcu.instances);
|
|
@@ -4816,12 +4871,12 @@ describe("ChangesetReader: strict mode (column-count mismatch)", () => {
|
|
|
4816
4871
|
].sort());
|
|
4817
4872
|
assert.equal(elemNew.$meta.isIndirectChange, false);
|
|
4818
4873
|
}
|
|
4819
|
-
catch (
|
|
4820
|
-
|
|
4821
|
-
|
|
4874
|
+
catch (e_33) {
|
|
4875
|
+
env_33.error = e_33;
|
|
4876
|
+
env_33.hasError = true;
|
|
4822
4877
|
}
|
|
4823
4878
|
finally {
|
|
4824
|
-
__disposeResources(
|
|
4879
|
+
__disposeResources(env_33);
|
|
4825
4880
|
}
|
|
4826
4881
|
}
|
|
4827
4882
|
}
|
|
@@ -4877,26 +4932,26 @@ describe("ChangesetReader: strict mode (column-count mismatch)", () => {
|
|
|
4877
4932
|
const newCs = changesets[changesets.length - 1];
|
|
4878
4933
|
// Strict mode ON: binary has more cols, throws.
|
|
4879
4934
|
{
|
|
4880
|
-
const
|
|
4935
|
+
const env_34 = { stack: [], error: void 0, hasError: false };
|
|
4881
4936
|
try {
|
|
4882
|
-
const reader = __addDisposableResource(
|
|
4937
|
+
const reader = __addDisposableResource(env_34, ChangesetReader.openFile({ db: b1, fileName: newCs.pathname }), false);
|
|
4883
4938
|
reader.enableStrictMode();
|
|
4884
4939
|
expect(() => { while (reader.step()) { /* drain */ } }).to.throw();
|
|
4885
4940
|
}
|
|
4886
|
-
catch (
|
|
4887
|
-
|
|
4888
|
-
|
|
4941
|
+
catch (e_34) {
|
|
4942
|
+
env_34.error = e_34;
|
|
4943
|
+
env_34.hasError = true;
|
|
4889
4944
|
}
|
|
4890
4945
|
finally {
|
|
4891
|
-
__disposeResources(
|
|
4946
|
+
__disposeResources(env_34);
|
|
4892
4947
|
}
|
|
4893
4948
|
}
|
|
4894
4949
|
// Strict mode OFF: binary has more cols, does not throw.
|
|
4895
4950
|
{
|
|
4896
|
-
const
|
|
4951
|
+
const env_35 = { stack: [], error: void 0, hasError: false };
|
|
4897
4952
|
try {
|
|
4898
|
-
const reader = __addDisposableResource(
|
|
4899
|
-
const pcu = __addDisposableResource(
|
|
4953
|
+
const reader = __addDisposableResource(env_35, ChangesetReader.openFile({ db: b1, fileName: newCs.pathname }), false);
|
|
4954
|
+
const pcu = __addDisposableResource(env_35, new PartialChangeUnifier(ChangeUnifierCache.createInMemoryCache()), false);
|
|
4900
4955
|
while (reader.step())
|
|
4901
4956
|
pcu.appendFrom(reader);
|
|
4902
4957
|
const instances = Array.from(pcu.instances);
|
|
@@ -4982,12 +5037,12 @@ describe("ChangesetReader: strict mode (column-count mismatch)", () => {
|
|
|
4982
5037
|
].sort());
|
|
4983
5038
|
assert.equal(elemNew.$meta.isIndirectChange, false);
|
|
4984
5039
|
}
|
|
4985
|
-
catch (
|
|
4986
|
-
|
|
4987
|
-
|
|
5040
|
+
catch (e_35) {
|
|
5041
|
+
env_35.error = e_35;
|
|
5042
|
+
env_35.hasError = true;
|
|
4988
5043
|
}
|
|
4989
5044
|
finally {
|
|
4990
|
-
__disposeResources(
|
|
5045
|
+
__disposeResources(env_35);
|
|
4991
5046
|
}
|
|
4992
5047
|
}
|
|
4993
5048
|
}
|
|
@@ -4998,4 +5053,564 @@ describe("ChangesetReader: strict mode (column-count mismatch)", () => {
|
|
|
4998
5053
|
}
|
|
4999
5054
|
});
|
|
5000
5055
|
});
|
|
5056
|
+
describe("ChangesetReader: throwIfAlreadyStepped guard", () => {
|
|
5057
|
+
let iModel;
|
|
5058
|
+
let txn;
|
|
5059
|
+
let txnId;
|
|
5060
|
+
before(async () => {
|
|
5061
|
+
HubMock.startup("ChangesetReaderThrowGuard", KnownTestLocations.outputDir);
|
|
5062
|
+
const adminToken = "super manager token";
|
|
5063
|
+
const iTwinId = HubMock.iTwinId;
|
|
5064
|
+
const iModelId = await HubMock.createNewIModel({ iTwinId, iModelName: "throwGuard", accessToken: adminToken });
|
|
5065
|
+
iModel = await HubWrappers.downloadAndOpenBriefcase({ iTwinId, iModelId, accessToken: adminToken });
|
|
5066
|
+
txn = startTestTxn(iModel, "throwGuard setup");
|
|
5067
|
+
iModel.channels.addAllowedChannel(ChannelControl.sharedChannelName);
|
|
5068
|
+
await iModel.locks.acquireLocks({ shared: IModel.dictionaryId });
|
|
5069
|
+
IModelTestUtils.createAndInsertDrawingPartitionAndModel(txn, Code.createEmpty(), true);
|
|
5070
|
+
txn.saveChanges("setup");
|
|
5071
|
+
txnId = iModel.txns.getLastSavedTxnProps().id;
|
|
5072
|
+
});
|
|
5073
|
+
after(() => {
|
|
5074
|
+
txn.end();
|
|
5075
|
+
iModel?.close();
|
|
5076
|
+
HubMock.shutdown();
|
|
5077
|
+
});
|
|
5078
|
+
it("setTableNameFilters throws after step()", () => {
|
|
5079
|
+
const env_36 = { stack: [], error: void 0, hasError: false };
|
|
5080
|
+
try {
|
|
5081
|
+
const reader = __addDisposableResource(env_36, ChangesetReader.openTxn({ db: iModel, txnId }), false);
|
|
5082
|
+
assert.isTrue(reader.step());
|
|
5083
|
+
expect(() => reader.setTableNameFilters(new Set(["bis_Element"]))).to.throw("filters and strict mode and batch size must be configured before the first call to step()");
|
|
5084
|
+
}
|
|
5085
|
+
catch (e_36) {
|
|
5086
|
+
env_36.error = e_36;
|
|
5087
|
+
env_36.hasError = true;
|
|
5088
|
+
}
|
|
5089
|
+
finally {
|
|
5090
|
+
__disposeResources(env_36);
|
|
5091
|
+
}
|
|
5092
|
+
});
|
|
5093
|
+
it("setOpCodeFilters throws after step()", () => {
|
|
5094
|
+
const env_37 = { stack: [], error: void 0, hasError: false };
|
|
5095
|
+
try {
|
|
5096
|
+
const reader = __addDisposableResource(env_37, ChangesetReader.openTxn({ db: iModel, txnId }), false);
|
|
5097
|
+
assert.isTrue(reader.step());
|
|
5098
|
+
expect(() => reader.setOpCodeFilters(new Set(["Inserted"]))).to.throw("filters and strict mode and batch size must be configured before the first call to step()");
|
|
5099
|
+
}
|
|
5100
|
+
catch (e_37) {
|
|
5101
|
+
env_37.error = e_37;
|
|
5102
|
+
env_37.hasError = true;
|
|
5103
|
+
}
|
|
5104
|
+
finally {
|
|
5105
|
+
__disposeResources(env_37);
|
|
5106
|
+
}
|
|
5107
|
+
});
|
|
5108
|
+
it("setClassNameFilters throws after step()", () => {
|
|
5109
|
+
const env_38 = { stack: [], error: void 0, hasError: false };
|
|
5110
|
+
try {
|
|
5111
|
+
const reader = __addDisposableResource(env_38, ChangesetReader.openTxn({ db: iModel, txnId }), false);
|
|
5112
|
+
assert.isTrue(reader.step());
|
|
5113
|
+
expect(() => reader.setClassNameFilters(new Set(["BisCore:Element"]))).to.throw("filters and strict mode and batch size must be configured before the first call to step()");
|
|
5114
|
+
}
|
|
5115
|
+
catch (e_38) {
|
|
5116
|
+
env_38.error = e_38;
|
|
5117
|
+
env_38.hasError = true;
|
|
5118
|
+
}
|
|
5119
|
+
finally {
|
|
5120
|
+
__disposeResources(env_38);
|
|
5121
|
+
}
|
|
5122
|
+
});
|
|
5123
|
+
it("clearTableNameFilters throws after step()", () => {
|
|
5124
|
+
const env_39 = { stack: [], error: void 0, hasError: false };
|
|
5125
|
+
try {
|
|
5126
|
+
const reader = __addDisposableResource(env_39, ChangesetReader.openTxn({ db: iModel, txnId }), false);
|
|
5127
|
+
assert.isTrue(reader.step());
|
|
5128
|
+
expect(() => reader.clearTableNameFilters()).to.throw("filters and strict mode and batch size must be configured before the first call to step()");
|
|
5129
|
+
}
|
|
5130
|
+
catch (e_39) {
|
|
5131
|
+
env_39.error = e_39;
|
|
5132
|
+
env_39.hasError = true;
|
|
5133
|
+
}
|
|
5134
|
+
finally {
|
|
5135
|
+
__disposeResources(env_39);
|
|
5136
|
+
}
|
|
5137
|
+
});
|
|
5138
|
+
it("clearOpCodeFilters throws after step()", () => {
|
|
5139
|
+
const env_40 = { stack: [], error: void 0, hasError: false };
|
|
5140
|
+
try {
|
|
5141
|
+
const reader = __addDisposableResource(env_40, ChangesetReader.openTxn({ db: iModel, txnId }), false);
|
|
5142
|
+
assert.isTrue(reader.step());
|
|
5143
|
+
expect(() => reader.clearOpCodeFilters()).to.throw("filters and strict mode and batch size must be configured before the first call to step()");
|
|
5144
|
+
}
|
|
5145
|
+
catch (e_40) {
|
|
5146
|
+
env_40.error = e_40;
|
|
5147
|
+
env_40.hasError = true;
|
|
5148
|
+
}
|
|
5149
|
+
finally {
|
|
5150
|
+
__disposeResources(env_40);
|
|
5151
|
+
}
|
|
5152
|
+
});
|
|
5153
|
+
it("clearClassNameFilters throws after step()", () => {
|
|
5154
|
+
const env_41 = { stack: [], error: void 0, hasError: false };
|
|
5155
|
+
try {
|
|
5156
|
+
const reader = __addDisposableResource(env_41, ChangesetReader.openTxn({ db: iModel, txnId }), false);
|
|
5157
|
+
assert.isTrue(reader.step());
|
|
5158
|
+
expect(() => reader.clearClassNameFilters()).to.throw("filters and strict mode and batch size must be configured before the first call to step()");
|
|
5159
|
+
}
|
|
5160
|
+
catch (e_41) {
|
|
5161
|
+
env_41.error = e_41;
|
|
5162
|
+
env_41.hasError = true;
|
|
5163
|
+
}
|
|
5164
|
+
finally {
|
|
5165
|
+
__disposeResources(env_41);
|
|
5166
|
+
}
|
|
5167
|
+
});
|
|
5168
|
+
it("enableStrictMode throws after step()", () => {
|
|
5169
|
+
const env_42 = { stack: [], error: void 0, hasError: false };
|
|
5170
|
+
try {
|
|
5171
|
+
const reader = __addDisposableResource(env_42, ChangesetReader.openTxn({ db: iModel, txnId }), false);
|
|
5172
|
+
assert.isTrue(reader.step());
|
|
5173
|
+
expect(() => reader.enableStrictMode()).to.throw("filters and strict mode and batch size must be configured before the first call to step()");
|
|
5174
|
+
}
|
|
5175
|
+
catch (e_42) {
|
|
5176
|
+
env_42.error = e_42;
|
|
5177
|
+
env_42.hasError = true;
|
|
5178
|
+
}
|
|
5179
|
+
finally {
|
|
5180
|
+
__disposeResources(env_42);
|
|
5181
|
+
}
|
|
5182
|
+
});
|
|
5183
|
+
it("disableStrictMode throws after step()", () => {
|
|
5184
|
+
const env_43 = { stack: [], error: void 0, hasError: false };
|
|
5185
|
+
try {
|
|
5186
|
+
const reader = __addDisposableResource(env_43, ChangesetReader.openTxn({ db: iModel, txnId }), false);
|
|
5187
|
+
assert.isTrue(reader.step());
|
|
5188
|
+
expect(() => reader.disableStrictMode()).to.throw("filters and strict mode and batch size must be configured before the first call to step()");
|
|
5189
|
+
}
|
|
5190
|
+
catch (e_43) {
|
|
5191
|
+
env_43.error = e_43;
|
|
5192
|
+
env_43.hasError = true;
|
|
5193
|
+
}
|
|
5194
|
+
finally {
|
|
5195
|
+
__disposeResources(env_43);
|
|
5196
|
+
}
|
|
5197
|
+
});
|
|
5198
|
+
it("setBatchSize throws after step()", () => {
|
|
5199
|
+
const env_44 = { stack: [], error: void 0, hasError: false };
|
|
5200
|
+
try {
|
|
5201
|
+
const reader = __addDisposableResource(env_44, ChangesetReader.openTxn({ db: iModel, txnId }), false);
|
|
5202
|
+
assert.isTrue(reader.step());
|
|
5203
|
+
expect(() => reader.setBatchSize(10)).to.throw("filters and strict mode and batch size must be configured before the first call to step()");
|
|
5204
|
+
}
|
|
5205
|
+
catch (e_44) {
|
|
5206
|
+
env_44.error = e_44;
|
|
5207
|
+
env_44.hasError = true;
|
|
5208
|
+
}
|
|
5209
|
+
finally {
|
|
5210
|
+
__disposeResources(env_44);
|
|
5211
|
+
}
|
|
5212
|
+
});
|
|
5213
|
+
it("setBatchSize throws with zero or negative value", () => {
|
|
5214
|
+
const env_45 = { stack: [], error: void 0, hasError: false };
|
|
5215
|
+
try {
|
|
5216
|
+
const reader = __addDisposableResource(env_45, ChangesetReader.openTxn({ db: iModel, txnId }), false);
|
|
5217
|
+
expect(() => reader.setBatchSize(0)).to.throw("batchSize must be a positive integer");
|
|
5218
|
+
expect(() => reader.setBatchSize(-1)).to.throw("batchSize must be a positive integer");
|
|
5219
|
+
}
|
|
5220
|
+
catch (e_45) {
|
|
5221
|
+
env_45.error = e_45;
|
|
5222
|
+
env_45.hasError = true;
|
|
5223
|
+
}
|
|
5224
|
+
finally {
|
|
5225
|
+
__disposeResources(env_45);
|
|
5226
|
+
}
|
|
5227
|
+
});
|
|
5228
|
+
it("filters can be set before any step()", () => {
|
|
5229
|
+
const env_46 = { stack: [], error: void 0, hasError: false };
|
|
5230
|
+
try {
|
|
5231
|
+
const reader = __addDisposableResource(env_46, ChangesetReader.openTxn({ db: iModel, txnId }), false);
|
|
5232
|
+
// None of these should throw before step() is called
|
|
5233
|
+
expect(() => reader.setTableNameFilters(new Set(["bis_Element"]))).to.not.throw();
|
|
5234
|
+
expect(() => reader.setOpCodeFilters(new Set(["Inserted"]))).to.not.throw();
|
|
5235
|
+
expect(() => reader.setClassNameFilters(new Set(["BisCore:Element"]))).to.not.throw();
|
|
5236
|
+
expect(() => reader.clearTableNameFilters()).to.not.throw();
|
|
5237
|
+
expect(() => reader.clearOpCodeFilters()).to.not.throw();
|
|
5238
|
+
expect(() => reader.clearClassNameFilters()).to.not.throw();
|
|
5239
|
+
expect(() => reader.enableStrictMode()).to.not.throw();
|
|
5240
|
+
expect(() => reader.disableStrictMode()).to.not.throw();
|
|
5241
|
+
expect(() => reader.setBatchSize(5)).to.not.throw();
|
|
5242
|
+
}
|
|
5243
|
+
catch (e_46) {
|
|
5244
|
+
env_46.error = e_46;
|
|
5245
|
+
env_46.hasError = true;
|
|
5246
|
+
}
|
|
5247
|
+
finally {
|
|
5248
|
+
__disposeResources(env_46);
|
|
5249
|
+
}
|
|
5250
|
+
});
|
|
5251
|
+
});
|
|
5252
|
+
describe("ChangesetReader: batched stepping behavior", () => {
|
|
5253
|
+
let iModel;
|
|
5254
|
+
let txn;
|
|
5255
|
+
let txnId;
|
|
5256
|
+
before(async () => {
|
|
5257
|
+
HubMock.startup("ChangesetReaderBatchStep", KnownTestLocations.outputDir);
|
|
5258
|
+
const adminToken = "super manager token";
|
|
5259
|
+
const iTwinId = HubMock.iTwinId;
|
|
5260
|
+
const iModelId = await HubMock.createNewIModel({ iTwinId, iModelName: "batchStep", accessToken: adminToken });
|
|
5261
|
+
iModel = await HubWrappers.downloadAndOpenBriefcase({ iTwinId, iModelId, accessToken: adminToken });
|
|
5262
|
+
txn = startTestTxn(iModel, "batchStep setup");
|
|
5263
|
+
iModel.channels.addAllowedChannel(ChannelControl.sharedChannelName);
|
|
5264
|
+
await iModel.locks.acquireLocks({ shared: IModel.dictionaryId });
|
|
5265
|
+
IModelTestUtils.createAndInsertDrawingPartitionAndModel(txn, Code.createEmpty(), true);
|
|
5266
|
+
txn.saveChanges("setup");
|
|
5267
|
+
txnId = iModel.txns.getLastSavedTxnProps().id;
|
|
5268
|
+
});
|
|
5269
|
+
after(() => {
|
|
5270
|
+
txn.end();
|
|
5271
|
+
iModel?.close();
|
|
5272
|
+
HubMock.shutdown();
|
|
5273
|
+
});
|
|
5274
|
+
it("step() returns false when no rows remain", () => {
|
|
5275
|
+
const env_47 = { stack: [], error: void 0, hasError: false };
|
|
5276
|
+
try {
|
|
5277
|
+
const reader = __addDisposableResource(env_47, ChangesetReader.openTxn({ db: iModel, txnId }), false);
|
|
5278
|
+
// Drain all rows
|
|
5279
|
+
while (reader.step()) { /* consume */ }
|
|
5280
|
+
// The next call must also return false
|
|
5281
|
+
assert.isFalse(reader.step());
|
|
5282
|
+
}
|
|
5283
|
+
catch (e_47) {
|
|
5284
|
+
env_47.error = e_47;
|
|
5285
|
+
env_47.hasError = true;
|
|
5286
|
+
}
|
|
5287
|
+
finally {
|
|
5288
|
+
__disposeResources(env_47);
|
|
5289
|
+
}
|
|
5290
|
+
});
|
|
5291
|
+
it("step() returns false repeatedly after exhaustion", () => {
|
|
5292
|
+
const env_48 = { stack: [], error: void 0, hasError: false };
|
|
5293
|
+
try {
|
|
5294
|
+
const reader = __addDisposableResource(env_48, ChangesetReader.openTxn({ db: iModel, txnId }), false);
|
|
5295
|
+
while (reader.step()) { /* consume */ }
|
|
5296
|
+
assert.isFalse(reader.step());
|
|
5297
|
+
assert.isFalse(reader.step());
|
|
5298
|
+
assert.isFalse(reader.step());
|
|
5299
|
+
}
|
|
5300
|
+
catch (e_48) {
|
|
5301
|
+
env_48.error = e_48;
|
|
5302
|
+
env_48.hasError = true;
|
|
5303
|
+
}
|
|
5304
|
+
finally {
|
|
5305
|
+
__disposeResources(env_48);
|
|
5306
|
+
}
|
|
5307
|
+
});
|
|
5308
|
+
it("inserted/deleted are undefined after exhaustion", () => {
|
|
5309
|
+
const env_49 = { stack: [], error: void 0, hasError: false };
|
|
5310
|
+
try {
|
|
5311
|
+
const reader = __addDisposableResource(env_49, ChangesetReader.openTxn({ db: iModel, txnId }), false);
|
|
5312
|
+
while (reader.step()) { /* consume */ }
|
|
5313
|
+
assert.isUndefined(reader.inserted);
|
|
5314
|
+
assert.isUndefined(reader.deleted);
|
|
5315
|
+
}
|
|
5316
|
+
catch (e_49) {
|
|
5317
|
+
env_49.error = e_49;
|
|
5318
|
+
env_49.hasError = true;
|
|
5319
|
+
}
|
|
5320
|
+
finally {
|
|
5321
|
+
__disposeResources(env_49);
|
|
5322
|
+
}
|
|
5323
|
+
});
|
|
5324
|
+
it("op throws after exhaustion", () => {
|
|
5325
|
+
const env_50 = { stack: [], error: void 0, hasError: false };
|
|
5326
|
+
try {
|
|
5327
|
+
const reader = __addDisposableResource(env_50, ChangesetReader.openTxn({ db: iModel, txnId }), false);
|
|
5328
|
+
while (reader.step()) { /* consume */ }
|
|
5329
|
+
expect(() => reader.op).to.throw("no current row");
|
|
5330
|
+
}
|
|
5331
|
+
catch (e_50) {
|
|
5332
|
+
env_50.error = e_50;
|
|
5333
|
+
env_50.hasError = true;
|
|
5334
|
+
}
|
|
5335
|
+
finally {
|
|
5336
|
+
__disposeResources(env_50);
|
|
5337
|
+
}
|
|
5338
|
+
});
|
|
5339
|
+
it("setBatchSize(1) produces same instances as default batch size", () => {
|
|
5340
|
+
const defaultInstances = [];
|
|
5341
|
+
{
|
|
5342
|
+
const env_51 = { stack: [], error: void 0, hasError: false };
|
|
5343
|
+
try {
|
|
5344
|
+
const reader = __addDisposableResource(env_51, ChangesetReader.openTxn({ db: iModel, txnId }), false);
|
|
5345
|
+
const pcu = __addDisposableResource(env_51, new PartialChangeUnifier(ChangeUnifierCache.createInMemoryCache()), false);
|
|
5346
|
+
while (reader.step())
|
|
5347
|
+
pcu.appendFrom(reader);
|
|
5348
|
+
for (const inst of pcu.instances)
|
|
5349
|
+
defaultInstances.push(inst.ECInstanceId);
|
|
5350
|
+
}
|
|
5351
|
+
catch (e_51) {
|
|
5352
|
+
env_51.error = e_51;
|
|
5353
|
+
env_51.hasError = true;
|
|
5354
|
+
}
|
|
5355
|
+
finally {
|
|
5356
|
+
__disposeResources(env_51);
|
|
5357
|
+
}
|
|
5358
|
+
}
|
|
5359
|
+
defaultInstances.sort();
|
|
5360
|
+
const batchOneInstances = [];
|
|
5361
|
+
{
|
|
5362
|
+
const env_52 = { stack: [], error: void 0, hasError: false };
|
|
5363
|
+
try {
|
|
5364
|
+
const reader = __addDisposableResource(env_52, ChangesetReader.openTxn({ db: iModel, txnId }), false);
|
|
5365
|
+
reader.setBatchSize(1);
|
|
5366
|
+
const pcu = __addDisposableResource(env_52, new PartialChangeUnifier(ChangeUnifierCache.createInMemoryCache()), false);
|
|
5367
|
+
while (reader.step())
|
|
5368
|
+
pcu.appendFrom(reader);
|
|
5369
|
+
for (const inst of pcu.instances)
|
|
5370
|
+
batchOneInstances.push(inst.ECInstanceId);
|
|
5371
|
+
}
|
|
5372
|
+
catch (e_52) {
|
|
5373
|
+
env_52.error = e_52;
|
|
5374
|
+
env_52.hasError = true;
|
|
5375
|
+
}
|
|
5376
|
+
finally {
|
|
5377
|
+
__disposeResources(env_52);
|
|
5378
|
+
}
|
|
5379
|
+
}
|
|
5380
|
+
batchOneInstances.sort();
|
|
5381
|
+
assert.deepEqual(batchOneInstances, defaultInstances);
|
|
5382
|
+
});
|
|
5383
|
+
});
|
|
5384
|
+
describe("ChangesetReader: lazy inserted/deleted getters", () => {
|
|
5385
|
+
let iModel;
|
|
5386
|
+
let txn;
|
|
5387
|
+
let txnId;
|
|
5388
|
+
before(async () => {
|
|
5389
|
+
HubMock.startup("ChangesetReaderLazyGetters", KnownTestLocations.outputDir);
|
|
5390
|
+
const adminToken = "super manager token";
|
|
5391
|
+
const iTwinId = HubMock.iTwinId;
|
|
5392
|
+
const iModelId = await HubMock.createNewIModel({ iTwinId, iModelName: "lazyGetters", accessToken: adminToken });
|
|
5393
|
+
iModel = await HubWrappers.downloadAndOpenBriefcase({ iTwinId, iModelId, accessToken: adminToken });
|
|
5394
|
+
txn = startTestTxn(iModel, "lazyGetters setup");
|
|
5395
|
+
iModel.channels.addAllowedChannel(ChannelControl.sharedChannelName);
|
|
5396
|
+
await iModel.locks.acquireLocks({ shared: IModel.dictionaryId });
|
|
5397
|
+
IModelTestUtils.createAndInsertDrawingPartitionAndModel(txn, Code.createEmpty(), true);
|
|
5398
|
+
txn.saveChanges("setup");
|
|
5399
|
+
txnId = iModel.txns.getLastSavedTxnProps().id;
|
|
5400
|
+
});
|
|
5401
|
+
after(() => {
|
|
5402
|
+
txn.end();
|
|
5403
|
+
iModel?.close();
|
|
5404
|
+
HubMock.shutdown();
|
|
5405
|
+
});
|
|
5406
|
+
it("inserted is undefined before step()", () => {
|
|
5407
|
+
const env_53 = { stack: [], error: void 0, hasError: false };
|
|
5408
|
+
try {
|
|
5409
|
+
const reader = __addDisposableResource(env_53, ChangesetReader.openTxn({ db: iModel, txnId }), false);
|
|
5410
|
+
assert.isUndefined(reader.inserted);
|
|
5411
|
+
}
|
|
5412
|
+
catch (e_53) {
|
|
5413
|
+
env_53.error = e_53;
|
|
5414
|
+
env_53.hasError = true;
|
|
5415
|
+
}
|
|
5416
|
+
finally {
|
|
5417
|
+
__disposeResources(env_53);
|
|
5418
|
+
}
|
|
5419
|
+
});
|
|
5420
|
+
it("deleted is undefined before step()", () => {
|
|
5421
|
+
const env_54 = { stack: [], error: void 0, hasError: false };
|
|
5422
|
+
try {
|
|
5423
|
+
const reader = __addDisposableResource(env_54, ChangesetReader.openTxn({ db: iModel, txnId }), false);
|
|
5424
|
+
assert.isUndefined(reader.deleted);
|
|
5425
|
+
}
|
|
5426
|
+
catch (e_54) {
|
|
5427
|
+
env_54.error = e_54;
|
|
5428
|
+
env_54.hasError = true;
|
|
5429
|
+
}
|
|
5430
|
+
finally {
|
|
5431
|
+
__disposeResources(env_54);
|
|
5432
|
+
}
|
|
5433
|
+
});
|
|
5434
|
+
it("inserted returns a fresh object on first access, cached object on subsequent access", () => {
|
|
5435
|
+
const env_55 = { stack: [], error: void 0, hasError: false };
|
|
5436
|
+
try {
|
|
5437
|
+
const reader = __addDisposableResource(env_55, ChangesetReader.openTxn({ db: iModel, txnId }), false);
|
|
5438
|
+
// Find an Inserted row
|
|
5439
|
+
let found = false;
|
|
5440
|
+
while (reader.step()) {
|
|
5441
|
+
if (reader.inserted) {
|
|
5442
|
+
const first = reader.inserted;
|
|
5443
|
+
const second = reader.inserted;
|
|
5444
|
+
assert.strictEqual(first, second);
|
|
5445
|
+
assert.deepEqual(first, second);
|
|
5446
|
+
found = true;
|
|
5447
|
+
break;
|
|
5448
|
+
}
|
|
5449
|
+
}
|
|
5450
|
+
assert.isTrue(found, "Expected at least one row with an inserted value");
|
|
5451
|
+
}
|
|
5452
|
+
catch (e_55) {
|
|
5453
|
+
env_55.error = e_55;
|
|
5454
|
+
env_55.hasError = true;
|
|
5455
|
+
}
|
|
5456
|
+
finally {
|
|
5457
|
+
__disposeResources(env_55);
|
|
5458
|
+
}
|
|
5459
|
+
});
|
|
5460
|
+
});
|
|
5461
|
+
describe("ChangesetReader insert-many (53 elements)", () => {
|
|
5462
|
+
let rwIModel;
|
|
5463
|
+
const elementIds = [];
|
|
5464
|
+
let drawingModelId;
|
|
5465
|
+
let drawingCategoryId;
|
|
5466
|
+
let txnId;
|
|
5467
|
+
let txn;
|
|
5468
|
+
const ELEMENT_COUNT = 53;
|
|
5469
|
+
before(async () => {
|
|
5470
|
+
HubMock.startup("ECChangesetInsertMany", KnownTestLocations.outputDir);
|
|
5471
|
+
const adminToken = "super manager token";
|
|
5472
|
+
const iTwinId = HubMock.iTwinId;
|
|
5473
|
+
const rwIModelId = await HubMock.createNewIModel({ iTwinId, iModelName: "insertMany", description: "insertMany", accessToken: adminToken });
|
|
5474
|
+
rwIModel = await HubWrappers.downloadAndOpenBriefcase({ iTwinId, iModelId: rwIModelId, accessToken: adminToken });
|
|
5475
|
+
txn = startTestTxn(rwIModel, "ChangesetReader insert-many setup");
|
|
5476
|
+
const schema = `<?xml version="1.0" encoding="UTF-8"?>
|
|
5477
|
+
<ECSchema schemaName="TestDomain" alias="ts" version="01.00" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.1">
|
|
5478
|
+
<ECSchemaReference name="BisCore" version="01.00" alias="bis"/>
|
|
5479
|
+
<ECStructClass typeName="RichPoint" modifier="Sealed">
|
|
5480
|
+
<ECProperty propertyName="X" typeName="double"/>
|
|
5481
|
+
<ECProperty propertyName="Y" typeName="double"/>
|
|
5482
|
+
<ECProperty propertyName="Z" typeName="double"/>
|
|
5483
|
+
<ECProperty propertyName="Label" typeName="string"/>
|
|
5484
|
+
</ECStructClass>
|
|
5485
|
+
<ECEntityClass typeName="Test2dElement">
|
|
5486
|
+
<BaseClass>bis:GraphicalElement2d</BaseClass>
|
|
5487
|
+
<ECProperty propertyName="StrProp" typeName="string"/>
|
|
5488
|
+
<ECProperty propertyName="IntProp" typeName="int"/>
|
|
5489
|
+
<ECProperty propertyName="DblProp" typeName="double"/>
|
|
5490
|
+
<ECStructProperty propertyName="StructProp" typeName="RichPoint"/>
|
|
5491
|
+
<ECArrayProperty propertyName="IntArrProp" typeName="int" minOccurs="0" maxOccurs="unbounded"/>
|
|
5492
|
+
</ECEntityClass>
|
|
5493
|
+
</ECSchema>`;
|
|
5494
|
+
await importSchemaStrings(txn, [schema]);
|
|
5495
|
+
rwIModel.channels.addAllowedChannel(ChannelControl.sharedChannelName);
|
|
5496
|
+
await rwIModel.locks.acquireLocks({ shared: IModel.dictionaryId });
|
|
5497
|
+
const codeProps = Code.createEmpty();
|
|
5498
|
+
codeProps.value = "DrillDownDrawing";
|
|
5499
|
+
[, drawingModelId] = IModelTestUtils.createAndInsertDrawingPartitionAndModel(txn, codeProps, true);
|
|
5500
|
+
const foundCat = DrawingCategory.queryCategoryIdByName(rwIModel, IModel.dictionaryId, "DrillDownCategory");
|
|
5501
|
+
drawingCategoryId = foundCat ?? DrawingCategory.insert(txn, IModel.dictionaryId, "DrillDownCategory", new SubCategoryAppearance({ color: ColorDef.fromString("rgb(255,0,0)").toJSON() }));
|
|
5502
|
+
txn.saveChanges("setup");
|
|
5503
|
+
// Wait so that LastMod on bis_Model gets a distinct timestamp before the insert txn
|
|
5504
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
5505
|
+
// Txn 2: insert 53 elements
|
|
5506
|
+
await rwIModel.locks.acquireLocks({ shared: drawingModelId });
|
|
5507
|
+
for (let i = 0; i < ELEMENT_COUNT; i++) {
|
|
5508
|
+
const id = txn.insertElement({
|
|
5509
|
+
classFullName: "TestDomain:Test2dElement",
|
|
5510
|
+
model: drawingModelId,
|
|
5511
|
+
category: drawingCategoryId,
|
|
5512
|
+
code: Code.createEmpty(),
|
|
5513
|
+
StrProp: `element_${i}`,
|
|
5514
|
+
IntProp: i,
|
|
5515
|
+
DblProp: i * 1.5,
|
|
5516
|
+
StructProp: { X: i, Y: i + 1, Z: i + 2, Label: `pt_${i}` },
|
|
5517
|
+
IntArrProp: [i, i * 10, i * 100],
|
|
5518
|
+
});
|
|
5519
|
+
elementIds.push(id);
|
|
5520
|
+
}
|
|
5521
|
+
txn.saveChanges("insert 53 elements");
|
|
5522
|
+
txnId = rwIModel.txns.getLastSavedTxnProps().id;
|
|
5523
|
+
});
|
|
5524
|
+
after(() => {
|
|
5525
|
+
txn.end();
|
|
5526
|
+
rwIModel?.close();
|
|
5527
|
+
HubMock.shutdown();
|
|
5528
|
+
});
|
|
5529
|
+
it("All_Properties: returns all 53 inserted elements", () => {
|
|
5530
|
+
const instances = readTxn(rwIModel, txnId);
|
|
5531
|
+
// 53 inserted elements (New) + 1 model update (New + Old) = 55
|
|
5532
|
+
const elemInstances = instances.filter((i) => i.$meta.op === "Inserted" && i.$meta.stage === "New");
|
|
5533
|
+
assert.equal(elemInstances.length, ELEMENT_COUNT);
|
|
5534
|
+
// Verify the model indirect change is present
|
|
5535
|
+
const modelNew = instances.find((i) => i.ECInstanceId === drawingModelId && i.$meta.stage === "New");
|
|
5536
|
+
const modelOld = instances.find((i) => i.ECInstanceId === drawingModelId && i.$meta.stage === "Old");
|
|
5537
|
+
expect(modelNew).to.exist;
|
|
5538
|
+
expect(modelOld).to.exist;
|
|
5539
|
+
assert.equal(modelNew.$meta.op, "Updated");
|
|
5540
|
+
assert.equal(modelOld.$meta.op, "Updated");
|
|
5541
|
+
assert.equal(modelNew.$meta.isIndirectChange, true);
|
|
5542
|
+
assert.equal(modelOld.$meta.isIndirectChange, true);
|
|
5543
|
+
// Total: 53 elements + 2 model entries
|
|
5544
|
+
assert.equal(instances.length, ELEMENT_COUNT + 2);
|
|
5545
|
+
// Verify each element is present and has the correct props
|
|
5546
|
+
for (let i = 0; i < ELEMENT_COUNT; i++) {
|
|
5547
|
+
const elem = elemInstances.find((inst) => inst.ECInstanceId === elementIds[i]);
|
|
5548
|
+
expect(elem, `element ${i} not found`).to.exist;
|
|
5549
|
+
assert.equal(elem.$meta.op, "Inserted");
|
|
5550
|
+
assert.equal(elem.$meta.stage, "New");
|
|
5551
|
+
assert.equal(elem.$meta.propFilter, PropertyFilter.All);
|
|
5552
|
+
assert.equal(elem.$meta.isIndirectChange, false);
|
|
5553
|
+
assert.equal(elem.StrProp, `element_${i}`);
|
|
5554
|
+
assert.equal(elem.IntProp, i);
|
|
5555
|
+
assert.closeTo(elem.DblProp, i * 1.5, 1e-10);
|
|
5556
|
+
assert.deepEqual(elem.StructProp, { X: i, Y: i + 1, Z: i + 2, Label: `pt_${i}` });
|
|
5557
|
+
assert.deepEqual(elem.IntArrProp, [i, i * 10, i * 100]);
|
|
5558
|
+
assert.equal(elem.Model.Id, drawingModelId);
|
|
5559
|
+
assert.equal(elem.Category.Id, drawingCategoryId);
|
|
5560
|
+
}
|
|
5561
|
+
});
|
|
5562
|
+
it("BisCoreElement: returns all 53 elements without custom props", () => {
|
|
5563
|
+
const instances = readTxn(rwIModel, txnId, PropertyFilter.BisCoreElement, { classIdsToClassNames: true });
|
|
5564
|
+
const elemInstances = instances.filter((i) => i.$meta.op === "Inserted" && i.$meta.stage === "New");
|
|
5565
|
+
assert.equal(elemInstances.length, ELEMENT_COUNT);
|
|
5566
|
+
assert.equal(instances.length, ELEMENT_COUNT + 2);
|
|
5567
|
+
for (let i = 0; i < ELEMENT_COUNT; i++) {
|
|
5568
|
+
const elem = elemInstances.find((inst) => inst.ECInstanceId === elementIds[i]);
|
|
5569
|
+
expect(elem, `element ${i} not found`).to.exist;
|
|
5570
|
+
assert.equal(elem.$meta.op, "Inserted");
|
|
5571
|
+
assert.equal(elem.$meta.stage, "New");
|
|
5572
|
+
assert.equal(elem.$meta.propFilter, PropertyFilter.BisCoreElement);
|
|
5573
|
+
assert.equal(elem.$meta.isIndirectChange, false);
|
|
5574
|
+
assert.equal(elem.ECClassId, "TestDomain.Test2dElement");
|
|
5575
|
+
assert.equal(elem.Model.Id, drawingModelId);
|
|
5576
|
+
// BisCoreElement filter: no custom domain props
|
|
5577
|
+
assert.isUndefined(elem.StrProp);
|
|
5578
|
+
assert.isUndefined(elem.IntProp);
|
|
5579
|
+
assert.isUndefined(elem.DblProp);
|
|
5580
|
+
assert.isUndefined(elem.StructProp);
|
|
5581
|
+
assert.isUndefined(elem.IntArrProp);
|
|
5582
|
+
// BIS core element props are present
|
|
5583
|
+
expect(elem.Model).to.exist;
|
|
5584
|
+
expect(elem.LastMod).to.exist;
|
|
5585
|
+
expect(elem.CodeSpec).to.exist;
|
|
5586
|
+
expect(elem.CodeScope).to.exist;
|
|
5587
|
+
expect(elem.FederationGuid).to.exist;
|
|
5588
|
+
}
|
|
5589
|
+
});
|
|
5590
|
+
it("InstanceKey: returns all 53 elements with only ECInstanceId and ECClassId", () => {
|
|
5591
|
+
const instances = readTxn(rwIModel, txnId, PropertyFilter.InstanceKey);
|
|
5592
|
+
const elemInstances = instances.filter((i) => i.$meta.op === "Inserted" && i.$meta.stage === "New");
|
|
5593
|
+
assert.equal(elemInstances.length, ELEMENT_COUNT);
|
|
5594
|
+
assert.equal(instances.length, ELEMENT_COUNT + 2);
|
|
5595
|
+
for (let i = 0; i < ELEMENT_COUNT; i++) {
|
|
5596
|
+
const elem = elemInstances.find((inst) => inst.ECInstanceId === elementIds[i]);
|
|
5597
|
+
expect(elem, `element ${i} not found`).to.exist;
|
|
5598
|
+
assert.equal(elem.$meta.op, "Inserted");
|
|
5599
|
+
assert.equal(elem.$meta.stage, "New");
|
|
5600
|
+
assert.equal(elem.$meta.propFilter, PropertyFilter.InstanceKey);
|
|
5601
|
+
assert.equal(elem.$meta.isIndirectChange, false);
|
|
5602
|
+
assert.equal("TestDomain:Test2dElement", rwIModel.getClassNameFromId(elem.ECClassId));
|
|
5603
|
+
// InstanceKey: only ECInstanceId + ECClassId, no other props
|
|
5604
|
+
assert.isUndefined(elem.StrProp);
|
|
5605
|
+
assert.isUndefined(elem.IntProp);
|
|
5606
|
+
assert.isUndefined(elem.DblProp);
|
|
5607
|
+
assert.isUndefined(elem.StructProp);
|
|
5608
|
+
assert.isUndefined(elem.IntArrProp);
|
|
5609
|
+
assert.isUndefined(elem.Model);
|
|
5610
|
+
assert.isUndefined(elem.Category);
|
|
5611
|
+
assert.isUndefined(elem.LastMod);
|
|
5612
|
+
assert.deepEqual(Object.keys(elem).sort(), ["ECInstanceId", "ECClassId", "$meta"].sort());
|
|
5613
|
+
}
|
|
5614
|
+
});
|
|
5615
|
+
});
|
|
5001
5616
|
//# sourceMappingURL=ChangesetReader.test.js.map
|