@itwin/core-backend 5.1.0-dev.34 → 5.1.0-dev.36

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.
@@ -2,7 +2,7 @@
2
2
  * @module ECDb
3
3
  */
4
4
  import { Id64String } from "@itwin/core-bentley";
5
- import { SqliteChangeOp, SqliteChangesetReader, SqliteValueStage } from "./SqliteChangesetReader";
5
+ import { AnyDb, SqliteChangeOp, SqliteChangesetReader, SqliteValueStage } from "./SqliteChangesetReader";
6
6
  /**
7
7
  * Record meta data for the change.
8
8
  * @beta
@@ -31,33 +31,83 @@ export interface ChangedECInstance {
31
31
  $meta?: ChangeMetaData;
32
32
  [key: string]: any;
33
33
  }
34
+ /**
35
+ * Represents a cache for unifying EC changes.
36
+ * @beta
37
+ */
38
+ export interface ECChangeUnifierCache extends Disposable {
39
+ /**
40
+ * Retrieves the value associated with the specified key from the cache.
41
+ * @param key - The key to retrieve the value for.
42
+ * @returns The value associated with the key, or undefined if the key is not found.
43
+ */
44
+ get(key: string): ChangedECInstance | undefined;
45
+ /**
46
+ * Sets the value associated with the specified key in the cache.
47
+ * @param key - The key to set the value for.
48
+ * @param value - The value to be associated with the key.
49
+ */
50
+ set(key: string, value: ChangedECInstance): void;
51
+ /**
52
+ * Returns an iterator for all the values in the cache.
53
+ * @returns An iterator for all the values in the cache.
54
+ */
55
+ all(): IterableIterator<ChangedECInstance>;
56
+ /**
57
+ * Returns the number of entries in the cache.
58
+ * @returns The number of entries in the cache.
59
+ */
60
+ count(): number;
61
+ }
62
+ export declare namespace ECChangeUnifierCache {
63
+ function createInMemory(): ECChangeUnifierCache;
64
+ function createSqliteBacked(db: AnyDb, bufferedReadInstanceSizeInBytes?: number): ECChangeUnifierCache;
65
+ }
34
66
  /**
35
67
  * Combine partial changed instance into single instance.
36
68
  * Partial changes is per table and a single instance can
37
69
  * span multiple tables.
38
70
  * @beta
39
71
  */
40
- export declare class PartialECChangeUnifier {
72
+ export declare class PartialECChangeUnifier implements Disposable {
73
+ private _db;
41
74
  private _cache;
42
75
  private _readonly;
76
+ constructor(_db: AnyDb, _cache?: ECChangeUnifierCache);
77
+ /**
78
+ * Dispose the instance.
79
+ */
80
+ [Symbol.dispose](): void;
43
81
  /**
44
82
  * Get root class id for a given class
45
83
  * @param classId given class id
46
84
  * @param db use to find root class
47
85
  * @returns return root class id
48
86
  */
49
- private static getRootClassId;
87
+ private getRootClassId;
88
+ /**
89
+ * Checks if the given `rhsClassId` is an instance of the `lhsClassId`.
90
+ * @param rhsClassId The ID of the right-hand side class.
91
+ * @param lhsClassId The ID of the left-hand side class.
92
+ * @returns `true` if `rhsClassId` is an instance of `lhsClassId`, `false` otherwise.
93
+ */
94
+ private instanceOf;
50
95
  /**
51
96
  * Combine partial instance with instance with same key if already exists.
52
97
  * @param rhs partial instance
53
98
  */
54
99
  private combine;
100
+ /**
101
+ * Returns the number of instances in the cache.
102
+ * @returns The number of instances in the cache.
103
+ */
104
+ getInstanceCount(): number;
55
105
  /**
56
106
  * Build key from EC change.
57
107
  * @param change EC change
58
108
  * @returns key created from EC change.
59
109
  */
60
- private static buildKey;
110
+ private buildKey;
61
111
  /**
62
112
  * Append partial changes which will be combine using there instance key.
63
113
  * @note $meta property must be present on partial change as information
@@ -66,10 +116,6 @@ export declare class PartialECChangeUnifier {
66
116
  * @beta
67
117
  */
68
118
  appendFrom(adaptor: ChangesetECAdaptor): void;
69
- /**
70
- * Delete $meta from all the instances.
71
- */
72
- stripMetaData(): void;
73
119
  /**
74
120
  * Returns complete EC change instances.
75
121
  * @beta
@@ -1 +1 @@
1
- {"version":3,"file":"ChangesetECAdaptor.d.ts","sourceRoot":"","sources":["../../src/ChangesetECAdaptor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ChangesetECAdaptor.d.ts","sourceRoot":"","sources":["../../src/ChangesetECAdaptor.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ChangesetECAdaptor = exports.PartialECChangeUnifier = void 0;
3
+ exports.ChangesetECAdaptor = exports.PartialECChangeUnifier = exports.ECChangeUnifierCache = void 0;
4
4
  /*---------------------------------------------------------------------------------------------
5
5
  * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
6
6
  * See LICENSE.md in the project root for license terms and full copyright notice.
@@ -9,6 +9,9 @@ exports.ChangesetECAdaptor = exports.PartialECChangeUnifier = void 0;
9
9
  * @module ECDb
10
10
  */
11
11
  const core_bentley_1 = require("@itwin/core-bentley");
12
+ const core_common_1 = require("@itwin/core-common");
13
+ const ECDb_1 = require("./ECDb");
14
+ const Symbols_1 = require("./internal/Symbols");
12
15
  class ECDbMap {
13
16
  db;
14
17
  _cachedClassMaps = new Map();
@@ -321,6 +324,186 @@ var DateTime;
321
324
  }
322
325
  DateTime.fromJulianDay = fromJulianDay;
323
326
  })(DateTime || (DateTime = {}));
327
+ var ECChangeUnifierCache;
328
+ (function (ECChangeUnifierCache) {
329
+ function createInMemory() {
330
+ return new InMemoryInstanceCache();
331
+ }
332
+ ECChangeUnifierCache.createInMemory = createInMemory;
333
+ function createSqliteBacked(db, bufferedReadInstanceSizeInBytes = 1024 * 1024 * 10) {
334
+ return new SqliteBackedInstanceCache(db, bufferedReadInstanceSizeInBytes);
335
+ }
336
+ ECChangeUnifierCache.createSqliteBacked = createSqliteBacked;
337
+ })(ECChangeUnifierCache || (exports.ECChangeUnifierCache = ECChangeUnifierCache = {}));
338
+ /**
339
+ * In-memory cache for storing changed EC instances.
340
+ */
341
+ class InMemoryInstanceCache {
342
+ _cache = new Map();
343
+ /**
344
+ * Retrieves the changed EC instance associated with the specified key.
345
+ * @param key - The key used to retrieve the instance.
346
+ * @returns The changed EC instance, or undefined if not found.
347
+ */
348
+ get(key) {
349
+ return this._cache.get(key);
350
+ }
351
+ /**
352
+ * Sets the changed EC instance associated with the specified key.
353
+ * @param key - The key used to store the instance.
354
+ * @param value - The changed EC instance to be stored.
355
+ */
356
+ set(key, value) {
357
+ const meta = value.$meta;
358
+ // Remove undefined keys
359
+ if (meta) {
360
+ Object.keys(meta).forEach((k) => meta[k] === undefined && delete meta[k]);
361
+ }
362
+ this._cache.set(key, value);
363
+ }
364
+ /**
365
+ * Returns an iterator over all the changed EC instances in the cache.
366
+ * @returns An iterator over all the changed EC instances.
367
+ */
368
+ *all() {
369
+ for (const key of Array.from(this._cache.keys()).sort()) {
370
+ const instance = this._cache.get(key);
371
+ if (instance) {
372
+ yield instance;
373
+ }
374
+ }
375
+ }
376
+ /**
377
+ * Returns the number of changed EC instances in the cache.
378
+ * @returns The number of changed EC instances.
379
+ */
380
+ count() {
381
+ return this._cache.size;
382
+ }
383
+ /**
384
+ * Disposes the cache.
385
+ */
386
+ [Symbol.dispose]() {
387
+ // Implementation details
388
+ }
389
+ }
390
+ /**
391
+ * Represents a cache for unifying EC changes in a SQLite-backed instance cache.
392
+ */
393
+ class SqliteBackedInstanceCache {
394
+ _db;
395
+ bufferedReadInstanceSizeInBytes;
396
+ _cacheTable = `[temp].[${core_bentley_1.Guid.createValue()}]`;
397
+ static defaultBufferSize = 1024 * 1024 * 10; // 10MB
398
+ /**
399
+ * Creates an instance of SqliteBackedInstanceCache.
400
+ * @param _db The underlying database connection.
401
+ * @param bufferedReadInstanceSizeInBytes The size of read instance buffer defaults to 10Mb.
402
+ * @throws Error if bufferedReadInstanceSizeInBytes is less than or equal to 0.
403
+ */
404
+ constructor(_db, bufferedReadInstanceSizeInBytes = SqliteBackedInstanceCache.defaultBufferSize) {
405
+ this._db = _db;
406
+ this.bufferedReadInstanceSizeInBytes = bufferedReadInstanceSizeInBytes;
407
+ if (bufferedReadInstanceSizeInBytes <= 0)
408
+ throw new Error("bufferedReadInstanceCount must be greater than 0");
409
+ this.createTempTable();
410
+ }
411
+ /**
412
+ * Creates a temporary table in the database for caching instances.
413
+ * @throws Error if unable to create the temporary table.
414
+ */
415
+ createTempTable() {
416
+ this._db.withSqliteStatement(`CREATE TABLE ${this._cacheTable} ([key] text primary key, [value] text)`, (stmt) => {
417
+ if (core_bentley_1.DbResult.BE_SQLITE_DONE !== stmt.step())
418
+ throw new Error("unable to create temp table");
419
+ });
420
+ }
421
+ /**
422
+ * Drops the temporary table from the database.
423
+ * @throws Error if unable to drop the temporary table.
424
+ */
425
+ dropTempTable() {
426
+ this._db.saveChanges();
427
+ if (this._db instanceof ECDb_1.ECDb)
428
+ this._db.clearStatementCache();
429
+ else {
430
+ this._db.clearCaches();
431
+ this._db[Symbols_1._nativeDb].clearECDbCache();
432
+ }
433
+ this._db.withSqliteStatement(`DROP TABLE IF EXISTS ${this._cacheTable}`, (stmt) => {
434
+ if (core_bentley_1.DbResult.BE_SQLITE_DONE !== stmt.step())
435
+ throw new Error("unable to drop temp table");
436
+ });
437
+ }
438
+ /**
439
+ * Retrieves the changed EC instance from the cache based on the specified key.
440
+ * @param key The key of the instance.
441
+ * @returns The changed EC instance if found, otherwise undefined.
442
+ */
443
+ get(key) {
444
+ return this._db.withPreparedSqliteStatement(`SELECT [value] FROM ${this._cacheTable} WHERE [key]=?`, (stmt) => {
445
+ stmt.bindString(1, key);
446
+ if (stmt.step() === core_bentley_1.DbResult.BE_SQLITE_ROW) {
447
+ const out = JSON.parse(stmt.getValueString(0), core_common_1.Base64EncodedString.reviver);
448
+ return out;
449
+ }
450
+ return undefined;
451
+ });
452
+ }
453
+ /**
454
+ * Sets the changed EC instance in the cache with the specified key.
455
+ * @param key The key of the instance.
456
+ * @param value The changed EC instance to be set.
457
+ */
458
+ set(key, value) {
459
+ const shallowCopy = Object.assign({}, value);
460
+ this._db.withPreparedSqliteStatement(`INSERT INTO ${this._cacheTable} ([key], [value]) VALUES (?, ?) ON CONFLICT ([key]) DO UPDATE SET [value] = [excluded].[value]`, (stmt) => {
461
+ stmt.bindString(1, key);
462
+ stmt.bindString(2, JSON.stringify(shallowCopy, core_common_1.Base64EncodedString.replacer));
463
+ stmt.step();
464
+ });
465
+ }
466
+ /**
467
+ * Returns an iterator for all the changed EC instances in the cache.
468
+ * @returns An iterator for all the changed EC instances.
469
+ */
470
+ *all() {
471
+ const sql = `
472
+ SELECT JSON_GROUP_ARRAY (JSON([value]))
473
+ FROM (SELECT
474
+ [value],
475
+ SUM (LENGTH ([value])) OVER (ORDER BY [key] ROWS UNBOUNDED PRECEDING) / ${this.bufferedReadInstanceSizeInBytes} AS [bucket]
476
+ FROM ${this._cacheTable})
477
+ GROUP BY [bucket]`;
478
+ const stmt = this._db.prepareSqliteStatement(sql);
479
+ while (stmt.step() === core_bentley_1.DbResult.BE_SQLITE_ROW) {
480
+ const instanceBucket = JSON.parse(stmt.getValueString(0), core_common_1.Base64EncodedString.reviver);
481
+ for (const value of instanceBucket) {
482
+ yield value;
483
+ }
484
+ }
485
+ stmt[Symbol.dispose]();
486
+ }
487
+ /**
488
+ * Returns the number of instances in the cache.
489
+ * @returns The number of instances in the cache.
490
+ */
491
+ count() {
492
+ return this._db.withPreparedSqliteStatement(`SELECT COUNT(*) FROM ${this._cacheTable}`, (stmt) => {
493
+ if (stmt.step() === core_bentley_1.DbResult.BE_SQLITE_ROW)
494
+ return stmt.getValue(0).getInteger();
495
+ return 0;
496
+ });
497
+ }
498
+ /**
499
+ * Disposes the cache by dropping the temporary table.
500
+ */
501
+ [Symbol.dispose]() {
502
+ if (this._db.isOpen) {
503
+ this.dropTempTable();
504
+ }
505
+ }
506
+ }
324
507
  /**
325
508
  * Combine partial changed instance into single instance.
326
509
  * Partial changes is per table and a single instance can
@@ -328,15 +511,26 @@ var DateTime;
328
511
  * @beta
329
512
  */
330
513
  class PartialECChangeUnifier {
331
- _cache = new Map();
514
+ _db;
515
+ _cache;
332
516
  _readonly = false;
517
+ constructor(_db, _cache = new InMemoryInstanceCache()) {
518
+ this._db = _db;
519
+ this._cache = _cache;
520
+ }
521
+ /**
522
+ * Dispose the instance.
523
+ */
524
+ [Symbol.dispose]() {
525
+ this._cache[Symbol.dispose]();
526
+ }
333
527
  /**
334
528
  * Get root class id for a given class
335
529
  * @param classId given class id
336
530
  * @param db use to find root class
337
531
  * @returns return root class id
338
532
  */
339
- static getRootClassId(classId, db) {
533
+ getRootClassId(classId) {
340
534
  const sql = `
341
535
  WITH
342
536
  [base_class]([classId], [baseClassId], [Level]) AS(
@@ -359,7 +553,7 @@ class PartialECChangeUnifier {
359
553
  WHERE [cc].[Name] = 'IsMixIn'
360
554
  AND [ss].[Name] = 'CoreCustomAttributes'))
361
555
  ORDER BY [Level] DESC`;
362
- return db.withSqliteStatement(sql, (stmt) => {
556
+ return this._db.withSqliteStatement(sql, (stmt) => {
363
557
  stmt.bindId(1, classId);
364
558
  if (stmt.step() === core_bentley_1.DbResult.BE_SQLITE_ROW && !stmt.isValueNull(0)) {
365
559
  return stmt.getValueString(0);
@@ -367,15 +561,30 @@ class PartialECChangeUnifier {
367
561
  return classId;
368
562
  });
369
563
  }
564
+ /**
565
+ * Checks if the given `rhsClassId` is an instance of the `lhsClassId`.
566
+ * @param rhsClassId The ID of the right-hand side class.
567
+ * @param lhsClassId The ID of the left-hand side class.
568
+ * @returns `true` if `rhsClassId` is an instance of `lhsClassId`, `false` otherwise.
569
+ */
570
+ instanceOf(rhsClassId, lhsClassId) {
571
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
572
+ return this._db.withPreparedStatement("SELECT ec_instanceof(?,?)", (stmt) => {
573
+ stmt.bindId(1, rhsClassId);
574
+ stmt.bindId(2, lhsClassId);
575
+ stmt.step();
576
+ return stmt.getValue(0).getInteger() === 1;
577
+ });
578
+ }
370
579
  /**
371
580
  * Combine partial instance with instance with same key if already exists.
372
581
  * @param rhs partial instance
373
582
  */
374
- combine(rhs, db) {
583
+ combine(rhs) {
375
584
  if (!rhs.$meta) {
376
585
  throw new Error("PartialECChange being combine must have '$meta' property");
377
586
  }
378
- const key = PartialECChangeUnifier.buildKey(rhs, db);
587
+ const key = this.buildKey(rhs);
379
588
  const lhs = this._cache.get(key);
380
589
  if (lhs) {
381
590
  const { $meta: _, ...restOfRhs } = rhs;
@@ -384,37 +593,39 @@ class PartialECChangeUnifier {
384
593
  lhs.$meta.tables = [...rhs.$meta?.tables, ...lhs.$meta?.tables];
385
594
  lhs.$meta.changeIndexes = [...rhs.$meta?.changeIndexes, ...lhs.$meta?.changeIndexes];
386
595
  // we preserve child class name & id when merging instance.
387
- if (rhs.$meta.fallbackClassId && lhs.$meta.fallbackClassId && db && rhs.$meta.fallbackClassId !== lhs.$meta.fallbackClassId) {
596
+ if (rhs.$meta.fallbackClassId && lhs.$meta.fallbackClassId && rhs.$meta.fallbackClassId !== lhs.$meta.fallbackClassId) {
388
597
  const lhsClassId = lhs.$meta.fallbackClassId;
389
598
  const rhsClassId = rhs.$meta.fallbackClassId;
390
- // eslint-disable-next-line @typescript-eslint/no-deprecated
391
- const isRhsIsSubClassOfLhs = db.withPreparedStatement("SELECT ec_instanceof(?,?)", (stmt) => {
392
- stmt.bindId(1, rhsClassId);
393
- stmt.bindId(2, lhsClassId);
394
- stmt.step();
395
- return stmt.getValue(0).getInteger() === 1;
396
- });
599
+ const isRhsIsSubClassOfLhs = this.instanceOf(rhsClassId, lhsClassId);
397
600
  if (isRhsIsSubClassOfLhs) {
398
601
  lhs.$meta.fallbackClassId = rhs.$meta.fallbackClassId;
399
602
  lhs.$meta.classFullName = rhs.$meta.classFullName;
400
603
  }
401
604
  }
402
605
  }
606
+ this._cache.set(key, lhs);
403
607
  }
404
608
  else {
405
609
  this._cache.set(key, rhs);
406
610
  }
407
611
  }
612
+ /**
613
+ * Returns the number of instances in the cache.
614
+ * @returns The number of instances in the cache.
615
+ */
616
+ getInstanceCount() {
617
+ return this._cache.count();
618
+ }
408
619
  /**
409
620
  * Build key from EC change.
410
621
  * @param change EC change
411
622
  * @returns key created from EC change.
412
623
  */
413
- static buildKey(change, db) {
624
+ buildKey(change) {
414
625
  let classId = change.ECClassId;
415
626
  if (typeof classId === "undefined") {
416
- if (db && change.$meta?.fallbackClassId) {
417
- classId = this.getRootClassId(change.$meta.fallbackClassId, db);
627
+ if (change.$meta?.fallbackClassId) {
628
+ classId = this.getRootClassId(change.$meta.fallbackClassId);
418
629
  }
419
630
  if (typeof classId === "undefined") {
420
631
  throw new Error(`unable to resolve ECClassId to root class id.`);
@@ -437,32 +648,23 @@ class PartialECChangeUnifier {
437
648
  throw new Error("this instance is marked as readonly.");
438
649
  }
439
650
  if (adaptor.op === "Updated" && adaptor.inserted && adaptor.deleted) {
440
- this.combine(adaptor.inserted, adaptor.reader.db);
441
- this.combine(adaptor.deleted, adaptor.reader.db);
651
+ this.combine(adaptor.inserted);
652
+ this.combine(adaptor.deleted);
442
653
  }
443
654
  else if (adaptor.op === "Inserted" && adaptor.inserted) {
444
- this.combine(adaptor.inserted, adaptor.reader.db);
655
+ this.combine(adaptor.inserted);
445
656
  }
446
657
  else if (adaptor.op === "Deleted" && adaptor.deleted) {
447
- this.combine(adaptor.deleted, adaptor.reader.db);
448
- }
449
- }
450
- /**
451
- * Delete $meta from all the instances.
452
- */
453
- stripMetaData() {
454
- for (const inst of this._cache.values()) {
455
- if ("$meta" in inst) {
456
- delete inst.$meta;
457
- }
658
+ this.combine(adaptor.deleted);
458
659
  }
459
- this._readonly = true;
460
660
  }
461
661
  /**
462
662
  * Returns complete EC change instances.
463
663
  * @beta
464
664
  */
465
- get instances() { return this._cache.values(); }
665
+ get instances() {
666
+ return this._cache.all();
667
+ }
466
668
  }
467
669
  exports.PartialECChangeUnifier = PartialECChangeUnifier;
468
670
  /**