@itwin/core-backend 5.10.0-dev.16 → 5.10.0-dev.19
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/lib/cjs/ChangesetReader.d.ts +84 -1
- package/lib/cjs/ChangesetReader.d.ts.map +1 -1
- package/lib/cjs/ChangesetReader.js +108 -12
- package/lib/cjs/ChangesetReader.js.map +1 -1
- package/lib/cjs/TxnManager.d.ts.map +1 -1
- package/lib/cjs/TxnManager.js +7 -0
- package/lib/cjs/TxnManager.js.map +1 -1
- package/lib/cjs/internal/ElementLRUCache.d.ts.map +1 -1
- package/lib/cjs/internal/ElementLRUCache.js +23 -4
- package/lib/cjs/internal/ElementLRUCache.js.map +1 -1
- package/lib/cjs/internal/workspace/SettingsSchemasImpl.d.ts.map +1 -1
- package/lib/cjs/internal/workspace/SettingsSchemasImpl.js +54 -9
- package/lib/cjs/internal/workspace/SettingsSchemasImpl.js.map +1 -1
- package/lib/cjs/workspace/SettingsSchemas.d.ts +15 -1
- package/lib/cjs/workspace/SettingsSchemas.d.ts.map +1 -1
- package/lib/cjs/workspace/SettingsSchemas.js.map +1 -1
- package/lib/esm/ChangesetReader.d.ts +84 -1
- package/lib/esm/ChangesetReader.d.ts.map +1 -1
- package/lib/esm/ChangesetReader.js +108 -12
- package/lib/esm/ChangesetReader.js.map +1 -1
- package/lib/esm/TxnManager.d.ts.map +1 -1
- package/lib/esm/TxnManager.js +7 -0
- package/lib/esm/TxnManager.js.map +1 -1
- package/lib/esm/internal/ElementLRUCache.d.ts.map +1 -1
- package/lib/esm/internal/ElementLRUCache.js +23 -4
- package/lib/esm/internal/ElementLRUCache.js.map +1 -1
- package/lib/esm/internal/workspace/SettingsSchemasImpl.d.ts.map +1 -1
- package/lib/esm/internal/workspace/SettingsSchemasImpl.js +54 -9
- package/lib/esm/internal/workspace/SettingsSchemasImpl.js.map +1 -1
- package/lib/esm/test/ElementLRUCache.test.js +60 -0
- package/lib/esm/test/ElementLRUCache.test.js.map +1 -1
- package/lib/esm/test/imodel/IModel.test.js +29 -0
- package/lib/esm/test/imodel/IModel.test.js.map +1 -1
- package/lib/esm/test/standalone/ChangesetReader.test.js +945 -337
- package/lib/esm/test/standalone/ChangesetReader.test.js.map +1 -1
- package/lib/esm/test/standalone/SettingsSchemas.test.js +382 -0
- package/lib/esm/test/standalone/SettingsSchemas.test.js.map +1 -1
- package/lib/esm/workspace/SettingsSchemas.d.ts +15 -1
- package/lib/esm/workspace/SettingsSchemas.d.ts.map +1 -1
- package/lib/esm/workspace/SettingsSchemas.js.map +1 -1
- package/package.json +14 -14
|
@@ -21,6 +21,7 @@ import { AnyDb, SqliteChangeOp } from "./SqliteChangesetReader";
|
|
|
21
21
|
* @beta
|
|
22
22
|
*/
|
|
23
23
|
export declare class ChangesetReader implements Disposable, ChangeSource {
|
|
24
|
+
private static readonly defaultSpillThresholdInBytes;
|
|
24
25
|
private readonly _nativeReader;
|
|
25
26
|
private _rowOptions?;
|
|
26
27
|
private _propFilter;
|
|
@@ -34,18 +35,21 @@ export declare class ChangesetReader implements Disposable, ChangeSource {
|
|
|
34
35
|
/**
|
|
35
36
|
* `true` when the current row belongs to an EC-mapped table.
|
|
36
37
|
* Valid only after a successful call to [[step]].
|
|
38
|
+
* @throws [[IModelError]] if called before a successful [[step]] call.
|
|
37
39
|
* @beta
|
|
38
40
|
*/
|
|
39
41
|
get isECTable(): boolean;
|
|
40
42
|
/**
|
|
41
43
|
* Name of the SQLite table for the current change row.
|
|
42
44
|
* Valid only after a successful call to [[step]].
|
|
45
|
+
* @throws [[IModelError]] if called before a successful [[step]] call.
|
|
43
46
|
* @beta
|
|
44
47
|
*/
|
|
45
48
|
get tableName(): string;
|
|
46
49
|
/**
|
|
47
50
|
* `true` when the current change was applied indirectly
|
|
48
51
|
* Valid only after a successful call to [[step]].
|
|
52
|
+
* @throws [[IModelError]] if called before a successful [[step]] call.
|
|
49
53
|
* @beta
|
|
50
54
|
*/
|
|
51
55
|
get isIndirectChange(): boolean;
|
|
@@ -72,6 +76,7 @@ export declare class ChangesetReader implements Disposable, ChangeSource {
|
|
|
72
76
|
* @param args.invert When `true`, invert all operations (Insert↔Delete).
|
|
73
77
|
* @param args.valueOptions Row adaptor options controlling how EC property values are formatted.
|
|
74
78
|
* @param args.propFilter Controls which properties are included. Defaults to `All`.
|
|
79
|
+
* @throws if the native layer fails to open the file.
|
|
75
80
|
* @beta
|
|
76
81
|
*/
|
|
77
82
|
static openFile(args: {
|
|
@@ -83,10 +88,17 @@ export declare class ChangesetReader implements Disposable, ChangeSource {
|
|
|
83
88
|
* @param args.db Database with schema at or ahead of the last changeset.
|
|
84
89
|
* @param args.valueOptions Row adaptor options controlling how EC property values are formatted.
|
|
85
90
|
* @param args.propFilter Controls which properties are included. Defaults to `All`.
|
|
91
|
+
* @param args.spillThresholdInBytes When the total size of the changeset data in the change group exceeds this threshold (in bytes),
|
|
92
|
+
* the reader writes the data to a temporary file on disk and streams it from there instead of buffering everything in memory.
|
|
93
|
+
* This keeps peak memory usage bounded, making the API suitable for processing large changeset groups under low-memory conditions.
|
|
94
|
+
* Defaults to 50 MiB.
|
|
95
|
+
* @throws if `changesetFiles` is empty, or if the native layer fails to open
|
|
96
|
+
* the group.
|
|
86
97
|
* @beta
|
|
87
98
|
*/
|
|
88
99
|
static openGroup(args: {
|
|
89
100
|
readonly changesetFiles: string[];
|
|
101
|
+
spillThresholdInBytes?: number;
|
|
90
102
|
} & ChangesetReaderArgs): ChangesetReader;
|
|
91
103
|
/**
|
|
92
104
|
* Read pending (not yet pushed) local changes from an open IModelDb.
|
|
@@ -94,21 +106,34 @@ export declare class ChangesetReader implements Disposable, ChangeSource {
|
|
|
94
106
|
* @param args.includeInMemoryChanges Also include in-memory (not yet saved to disk) changes.
|
|
95
107
|
* @param args.valueOptions Row adaptor options controlling how EC property values are formatted.
|
|
96
108
|
* @param args.propFilter Controls which properties are included. Defaults to `All`.
|
|
109
|
+
* @param args.spillThresholdInBytes When the total size of all local un-pushed saved changes exceeds this threshold (in bytes),
|
|
110
|
+
* the reader writes the data to a temporary file on disk and streams it from there instead of buffering everything in memory.
|
|
111
|
+
* This keeps peak memory usage bounded, making the API suitable for iModels with large local change backlogs under low-memory conditions.
|
|
112
|
+
* Defaults to 50 MiB.
|
|
113
|
+
* @throws if the native layer
|
|
114
|
+
* fails to open the local changes.
|
|
97
115
|
* @beta
|
|
98
116
|
*/
|
|
99
117
|
static openLocalChanges(args: Omit<ChangesetReaderArgs, "db"> & {
|
|
100
118
|
db: IModelDb;
|
|
101
119
|
includeInMemoryChanges?: boolean;
|
|
120
|
+
spillThresholdInBytes?: number;
|
|
102
121
|
}): ChangesetReader;
|
|
103
122
|
/**
|
|
104
123
|
* Read the in-memory (not yet saved to disk) changes of an open IModelDb.
|
|
105
124
|
* @param args.db Must be an [IModelDb]($backend).
|
|
106
125
|
* @param args.valueOptions Row adaptor options controlling how EC property values are formatted.
|
|
107
126
|
* @param args.propFilter Controls which properties are included. Defaults to `All`.
|
|
127
|
+
* @param args.spillThresholdInBytes When the total size of the in-memory (unsaved) change data exceeds this threshold (in bytes),
|
|
128
|
+
* the reader writes the data to a temporary file on disk and streams it from there instead of buffering everything in memory.
|
|
129
|
+
* This keeps peak memory usage bounded, making the API suitable for large in-memory transactions under low-memory conditions.
|
|
130
|
+
* Defaults to 50 MiB.
|
|
131
|
+
* @throws if the native layer encounters an error while opening the in-memory changes.
|
|
108
132
|
* @beta
|
|
109
133
|
*/
|
|
110
134
|
static openInMemoryChanges(args: Omit<ChangesetReaderArgs, "db"> & {
|
|
111
135
|
db: IModelDb;
|
|
136
|
+
spillThresholdInBytes?: number;
|
|
112
137
|
}): ChangesetReader;
|
|
113
138
|
/**
|
|
114
139
|
* Read a single saved transaction by its id.
|
|
@@ -116,17 +141,27 @@ export declare class ChangesetReader implements Disposable, ChangeSource {
|
|
|
116
141
|
* @param args.txnId The id of the saved transaction to read.
|
|
117
142
|
* @param args.valueOptions Row adaptor options controlling how EC property values are formatted.
|
|
118
143
|
* @param args.propFilter Controls which properties are included. Defaults to `All`.
|
|
144
|
+
* @param args.spillThresholdInBytes When the total size of the transaction's change data exceeds this threshold (in bytes),
|
|
145
|
+
* the reader writes the data to a temporary file on disk and streams it from there instead of buffering everything in memory.
|
|
146
|
+
* This keeps peak memory usage bounded, making the API suitable for large transactions under low-memory conditions.
|
|
147
|
+
* Defaults to 50 MiB.
|
|
148
|
+
* @throws if `txnId` is not found, or
|
|
149
|
+
* the native layer fails to open the transaction data.
|
|
119
150
|
* @beta
|
|
120
151
|
*/
|
|
121
152
|
static openTxn(args: Omit<ChangesetReaderArgs, "db"> & {
|
|
122
153
|
db: IModelDb;
|
|
123
154
|
txnId: Id64String;
|
|
155
|
+
spillThresholdInBytes?: number;
|
|
124
156
|
}): ChangesetReader;
|
|
157
|
+
/** Handle errors that occur while auto closing the reader if there is also an error while opening the reader */
|
|
158
|
+
private handleCloseErrorWhileOpening;
|
|
125
159
|
/**
|
|
126
160
|
* Restrict iteration to changes from the named SQLite tables.
|
|
127
161
|
* That means the rows for changes from other tables will be skipped entirely and won't be visible through the reader.
|
|
128
162
|
* @param tableNames SQLite table names to include.
|
|
129
163
|
* Note: Table names must be provided in the correct case for proper filtering.
|
|
164
|
+
* @throws if the native layer encounters an error while setting the filter.
|
|
130
165
|
* @beta
|
|
131
166
|
*/
|
|
132
167
|
setTableNameFilters(tableNames: Set<string>): void;
|
|
@@ -134,6 +169,7 @@ export declare class ChangesetReader implements Disposable, ChangeSource {
|
|
|
134
169
|
* Restrict iteration to changes with the given operation types.
|
|
135
170
|
* That means the rows for changes with other operation types will be skipped entirely and won't be visible through the reader.
|
|
136
171
|
* @param ops Operations to include.
|
|
172
|
+
* @throws if the native layer encounters an error while setting the filter.
|
|
137
173
|
* @beta
|
|
138
174
|
*/
|
|
139
175
|
setOpCodeFilters(ops: Set<SqliteChangeOp>): void;
|
|
@@ -142,43 +178,90 @@ export declare class ChangesetReader implements Disposable, ChangeSource {
|
|
|
142
178
|
* That means the rows for changes from other EC classes will be skipped entirely and won't be visible through the reader.
|
|
143
179
|
* @param classNames EC class names to include. The classNames should be in the full name format(i.e. "SchemaName:ClassName").
|
|
144
180
|
* Note: Schema names and class names must be provided in the correct case for proper filtering. Derived classes are not automatically included, so they must be specified explicitly if needed.
|
|
181
|
+
* @throws if the native layer encounters an error while setting the filter.
|
|
145
182
|
* @beta
|
|
146
183
|
*/
|
|
147
184
|
setClassNameFilters(classNames: Set<string>): void;
|
|
148
185
|
/**
|
|
149
186
|
* Remove the table-name filters
|
|
187
|
+
* @throws if the native layer encounters an error.
|
|
150
188
|
* @beta
|
|
151
189
|
*/
|
|
152
190
|
clearTableNameFilters(): void;
|
|
153
191
|
/**
|
|
154
192
|
* Remove the op-code filters
|
|
193
|
+
* @throws if the native layer encounters an error.
|
|
155
194
|
* @beta
|
|
156
195
|
*/
|
|
157
196
|
clearOpCodeFilters(): void;
|
|
158
197
|
/**
|
|
159
198
|
* Remove the class-name filters
|
|
199
|
+
* @throws if the native layer encounters an error.
|
|
160
200
|
* @beta
|
|
161
201
|
*/
|
|
162
202
|
clearClassNameFilters(): void;
|
|
203
|
+
/**
|
|
204
|
+
* Enable strict mode on the reader.
|
|
205
|
+
*
|
|
206
|
+
* Strict mode affects how the reader handles a **column-count mismatch** between a change
|
|
207
|
+
* record and the corresponding live database table. Such a mismatch can occur when columns
|
|
208
|
+
* have been added to a table after the changeset was created.
|
|
209
|
+
*
|
|
210
|
+
* When strict mode is **enabled**: if the number of columns recorded in a change row differs
|
|
211
|
+
* from the number of columns currently present in the live table, the reader throws an error
|
|
212
|
+
* instead of processing that row.
|
|
213
|
+
*
|
|
214
|
+
* Use strict mode when you need to be certain that every change row is interpreted against
|
|
215
|
+
* exactly the schema that was in effect when the changeset was written.
|
|
216
|
+
*
|
|
217
|
+
* @see [[disableStrictMode]] — the default (lenient) behaviour.
|
|
218
|
+
* @throws if the native layer encounters an error.
|
|
219
|
+
* @beta
|
|
220
|
+
*/
|
|
221
|
+
enableStrictMode(): void;
|
|
222
|
+
/**
|
|
223
|
+
* Disable strict mode on the reader (this is the default).
|
|
224
|
+
*
|
|
225
|
+
* When strict mode is **disabled**: if the number of columns recorded in a change row differs
|
|
226
|
+
* from the number of columns currently present in the live table, the reader takes the
|
|
227
|
+
* **minimum** of the two column counts and proceeds normally with that subset. This is safe
|
|
228
|
+
* because SQLite only ever appends new columns at the end of a table and never removes them —
|
|
229
|
+
* so older change records simply lack the trailing columns that were added later, and those
|
|
230
|
+
* missing columns are silently ignored.
|
|
231
|
+
*
|
|
232
|
+
* @see [[enableStrictMode]] — throw on column-count mismatches instead.
|
|
233
|
+
* @throws if the native layer encounters an error.
|
|
234
|
+
* @beta
|
|
235
|
+
*/
|
|
236
|
+
disableStrictMode(): void;
|
|
163
237
|
/**
|
|
164
238
|
* Advance to the next change and populate `inserted` and/or `deleted`.
|
|
165
239
|
* @returns `true` while positioned on a valid change; `false` when the stream is exhausted.
|
|
240
|
+
* @throws if the native layer encounters an error while reading or decoding
|
|
241
|
+
* the next change.
|
|
166
242
|
* @beta
|
|
167
243
|
*/
|
|
168
244
|
step(): boolean;
|
|
169
245
|
/**
|
|
170
246
|
* SQLite opcode of the current change.
|
|
171
247
|
* Valid only after a successful call to [[step]].
|
|
248
|
+
* @throws [[IModelError]] if called before a successful [[step]] call.
|
|
172
249
|
* @beta
|
|
173
250
|
*/
|
|
174
251
|
get op(): SqliteChangeOp;
|
|
175
252
|
/**
|
|
176
253
|
* Close the reader and release all native resources.
|
|
254
|
+
*
|
|
255
|
+
* @throws if the native layer encounters an error during cleanup. Native resources
|
|
256
|
+
* are not fully released when this throws — check the native error
|
|
257
|
+
* logs for details.
|
|
177
258
|
* @beta
|
|
178
259
|
*/
|
|
179
260
|
close(): void;
|
|
180
261
|
/**
|
|
181
|
-
* Implements the `Disposable` contract —
|
|
262
|
+
* Implements the `Disposable` contract — delegates to [[close]].
|
|
263
|
+
*
|
|
264
|
+
* @throws if the native layer fails to release its resources (re-thrown from [[close]]).
|
|
182
265
|
* @beta
|
|
183
266
|
*/
|
|
184
267
|
[Symbol.dispose](): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChangesetReader.d.ts","sourceRoot":"","sources":["../../src/ChangesetReader.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,OAAO,EAA2B,UAAU,EAAgB,MAAM,qBAAqB,CAAC;AAExF,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAItC,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,YAAY,EAAoC,MAAM,wBAAwB,CAAC;AAC7H,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAOhE;;;;;;;;;;;;;;GAcG;AACH,qBAAa,eAAgB,YAAW,UAAU,EAAE,YAAY;IAC9D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA+E;IAE7G,OAAO,CAAC,WAAW,CAAC,CAAmB;IACvC,OAAO,CAAC,WAAW,CAAsC;IACzD,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,GAAG,CAAC,CAAiB;IAC7B,OAAO,CAAC,UAAU,CAAC,CAAU;IAC7B,OAAO,CAAC,UAAU,CAAC,CAAS;IAC5B,OAAO,CAAC,iBAAiB,CAAC,CAAU;IAEpC,4CAA4C;IAC5C,SAAgB,EAAE,EAAE,KAAK,CAAC;IAE1B
|
|
1
|
+
{"version":3,"file":"ChangesetReader.d.ts","sourceRoot":"","sources":["../../src/ChangesetReader.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,OAAO,EAA2B,UAAU,EAAgB,MAAM,qBAAqB,CAAC;AAExF,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAItC,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,YAAY,EAAoC,MAAM,wBAAwB,CAAC;AAC7H,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAOhE;;;;;;;;;;;;;;GAcG;AACH,qBAAa,eAAgB,YAAW,UAAU,EAAE,YAAY;IAC9D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,4BAA4B,CAAoB;IACxE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA+E;IAE7G,OAAO,CAAC,WAAW,CAAC,CAAmB;IACvC,OAAO,CAAC,WAAW,CAAsC;IACzD,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,GAAG,CAAC,CAAiB;IAC7B,OAAO,CAAC,UAAU,CAAC,CAAU;IAC7B,OAAO,CAAC,UAAU,CAAC,CAAS;IAC5B,OAAO,CAAC,iBAAiB,CAAC,CAAU;IAEpC,4CAA4C;IAC5C,SAAgB,EAAE,EAAE,KAAK,CAAC;IAE1B;;;;;OAKG;IACH,IAAW,SAAS,IAAI,OAAO,CAI9B;IAED;;;;;OAKG;IACH,IAAW,SAAS,IAAI,MAAM,CAI7B;IAED;;;;;OAKG;IACH,IAAW,gBAAgB,IAAI,OAAO,CAIrC;IAED;;;;OAIG;IACI,QAAQ,CAAC,EAAE,cAAc,CAAC;IAEjC;;;;OAIG;IACI,OAAO,CAAC,EAAE,cAAc,CAAC;IAGhC,OAAO;IAIP;mBACe;IACf,OAAO,CAAC,kBAAkB;IAY1B;;;;;;;;;OASG;WACW,QAAQ,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,mBAAmB,GAAG,eAAe;IAelG;;;;;;;;;;;;;OAaG;WACW,SAAS,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,cAAc,EAAE,MAAM,EAAE,CAAC;QAAC,qBAAqB,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,mBAAmB,GAAG,eAAe;IAiB3I;;;;;;;;;;;;;OAaG;WACW,gBAAgB,CAC5B,IAAI,EAAE,IAAI,CAAC,mBAAmB,EAAE,IAAI,CAAC,GAAG;QAAE,EAAE,EAAE,QAAQ,CAAC;QAAC,sBAAsB,CAAC,EAAE,OAAO,CAAC;QAAC,qBAAqB,CAAC,EAAE,MAAM,CAAA;KAAE,GACzH,eAAe;IAclB;;;;;;;;;;;OAWG;WACW,mBAAmB,CAC/B,IAAI,EAAE,IAAI,CAAC,mBAAmB,EAAE,IAAI,CAAC,GAAG;QAAE,EAAE,EAAE,QAAQ,CAAC;QAAC,qBAAqB,CAAC,EAAE,MAAM,CAAA;KAAE,GACvF,eAAe;IAclB;;;;;;;;;;;;;OAaG;WACW,OAAO,CACnB,IAAI,EAAE,IAAI,CAAC,mBAAmB,EAAE,IAAI,CAAC,GAAG;QAAE,EAAE,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,UAAU,CAAC;QAAC,qBAAqB,CAAC,EAAE,MAAM,CAAA;KAAE,GAC1G,eAAe;IAclB,gHAAgH;IAChH,OAAO,CAAC,4BAA4B;IAepC;;;;;;;OAOG;IACI,mBAAmB,CAAC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI;IAIzD;;;;;;OAMG;IACI,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,cAAc,CAAC,GAAG,IAAI;IAIvD;;;;;;;OAOG;IACI,mBAAmB,CAAC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI;IAIzD;;;;OAIG;IACI,qBAAqB,IAAI,IAAI;IAIpC;;;;OAIG;IACI,kBAAkB,IAAI,IAAI;IAIjC;;;;OAIG;IACI,qBAAqB,IAAI,IAAI;IAQpC;;;;;;;;;;;;;;;;;OAiBG;IACI,gBAAgB,IAAI,IAAI;IAI/B;;;;;;;;;;;;;OAaG;IACI,iBAAiB,IAAI,IAAI;IAQhC;;;;;;OAMG;IACI,IAAI,IAAI,OAAO;IAmEtB;;;;;OAKG;IACH,IAAW,EAAE,IAAI,cAAc,CAI9B;IAMD;;;;;;;OAOG;IACI,KAAK,IAAI,IAAI;IAWpB;;;;;OAKG;IACI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI;CAGhC"}
|
|
@@ -32,6 +32,7 @@ const ChangesetReaderTypes_1 = require("./ChangesetReaderTypes");
|
|
|
32
32
|
* @beta
|
|
33
33
|
*/
|
|
34
34
|
class ChangesetReader {
|
|
35
|
+
static defaultSpillThresholdInBytes = 50 * 1024 * 1024; // 50 MiB
|
|
35
36
|
_nativeReader = new NativePlatform_1.IModelNative.platform.ChangesetReader();
|
|
36
37
|
// Internal options — keep ECClassId as raw Id so the unifier can use it as-is.
|
|
37
38
|
_rowOptions;
|
|
@@ -46,6 +47,7 @@ class ChangesetReader {
|
|
|
46
47
|
/**
|
|
47
48
|
* `true` when the current row belongs to an EC-mapped table.
|
|
48
49
|
* Valid only after a successful call to [[step]].
|
|
50
|
+
* @throws [[IModelError]] if called before a successful [[step]] call.
|
|
49
51
|
* @beta
|
|
50
52
|
*/
|
|
51
53
|
get isECTable() {
|
|
@@ -56,6 +58,7 @@ class ChangesetReader {
|
|
|
56
58
|
/**
|
|
57
59
|
* Name of the SQLite table for the current change row.
|
|
58
60
|
* Valid only after a successful call to [[step]].
|
|
61
|
+
* @throws [[IModelError]] if called before a successful [[step]] call.
|
|
59
62
|
* @beta
|
|
60
63
|
*/
|
|
61
64
|
get tableName() {
|
|
@@ -66,6 +69,7 @@ class ChangesetReader {
|
|
|
66
69
|
/**
|
|
67
70
|
* `true` when the current change was applied indirectly
|
|
68
71
|
* Valid only after a successful call to [[step]].
|
|
72
|
+
* @throws [[IModelError]] if called before a successful [[step]] call.
|
|
69
73
|
* @beta
|
|
70
74
|
*/
|
|
71
75
|
get isIndirectChange() {
|
|
@@ -108,6 +112,7 @@ class ChangesetReader {
|
|
|
108
112
|
* @param args.invert When `true`, invert all operations (Insert↔Delete).
|
|
109
113
|
* @param args.valueOptions Row adaptor options controlling how EC property values are formatted.
|
|
110
114
|
* @param args.propFilter Controls which properties are included. Defaults to `All`.
|
|
115
|
+
* @throws if the native layer fails to open the file.
|
|
111
116
|
* @beta
|
|
112
117
|
*/
|
|
113
118
|
static openFile(args) {
|
|
@@ -119,7 +124,7 @@ class ChangesetReader {
|
|
|
119
124
|
reader._nativeReader.openFile(args.db[Symbols_1._nativeDb], args.fileName, args.invert ?? false, reader._propFilter);
|
|
120
125
|
}
|
|
121
126
|
catch (e) {
|
|
122
|
-
reader.
|
|
127
|
+
reader.handleCloseErrorWhileOpening(e);
|
|
123
128
|
throw e;
|
|
124
129
|
}
|
|
125
130
|
return reader;
|
|
@@ -130,20 +135,26 @@ class ChangesetReader {
|
|
|
130
135
|
* @param args.db Database with schema at or ahead of the last changeset.
|
|
131
136
|
* @param args.valueOptions Row adaptor options controlling how EC property values are formatted.
|
|
132
137
|
* @param args.propFilter Controls which properties are included. Defaults to `All`.
|
|
138
|
+
* @param args.spillThresholdInBytes When the total size of the changeset data in the change group exceeds this threshold (in bytes),
|
|
139
|
+
* the reader writes the data to a temporary file on disk and streams it from there instead of buffering everything in memory.
|
|
140
|
+
* This keeps peak memory usage bounded, making the API suitable for processing large changeset groups under low-memory conditions.
|
|
141
|
+
* Defaults to 50 MiB.
|
|
142
|
+
* @throws if `changesetFiles` is empty, or if the native layer fails to open
|
|
143
|
+
* the group.
|
|
133
144
|
* @beta
|
|
134
145
|
*/
|
|
135
146
|
static openGroup(args) {
|
|
136
147
|
if (args.changesetFiles.length === 0)
|
|
137
|
-
throw new
|
|
148
|
+
throw new core_common_1.IModelError(core_bentley_1.IModelStatus.BadArg, "changesetFiles must contain at least one file.");
|
|
138
149
|
const reader = new ChangesetReader(args.db);
|
|
139
150
|
reader._rowOptions = args.rowOptions;
|
|
140
151
|
const propFilter = args.propFilter ?? ChangesetReaderTypes_1.PropertyFilter.All;
|
|
141
152
|
reader._propFilter = propFilter;
|
|
142
153
|
try {
|
|
143
|
-
reader._nativeReader.openGroup(args.db[Symbols_1._nativeDb], args.changesetFiles, args.invert ?? false, reader._propFilter);
|
|
154
|
+
reader._nativeReader.openGroup(args.db[Symbols_1._nativeDb], args.changesetFiles, args.invert ?? false, reader._propFilter, args.spillThresholdInBytes ?? this.defaultSpillThresholdInBytes);
|
|
144
155
|
}
|
|
145
156
|
catch (e) {
|
|
146
|
-
reader.
|
|
157
|
+
reader.handleCloseErrorWhileOpening(e);
|
|
147
158
|
throw e;
|
|
148
159
|
}
|
|
149
160
|
return reader;
|
|
@@ -154,6 +165,12 @@ class ChangesetReader {
|
|
|
154
165
|
* @param args.includeInMemoryChanges Also include in-memory (not yet saved to disk) changes.
|
|
155
166
|
* @param args.valueOptions Row adaptor options controlling how EC property values are formatted.
|
|
156
167
|
* @param args.propFilter Controls which properties are included. Defaults to `All`.
|
|
168
|
+
* @param args.spillThresholdInBytes When the total size of all local un-pushed saved changes exceeds this threshold (in bytes),
|
|
169
|
+
* the reader writes the data to a temporary file on disk and streams it from there instead of buffering everything in memory.
|
|
170
|
+
* This keeps peak memory usage bounded, making the API suitable for iModels with large local change backlogs under low-memory conditions.
|
|
171
|
+
* Defaults to 50 MiB.
|
|
172
|
+
* @throws if the native layer
|
|
173
|
+
* fails to open the local changes.
|
|
157
174
|
* @beta
|
|
158
175
|
*/
|
|
159
176
|
static openLocalChanges(args) {
|
|
@@ -162,10 +179,10 @@ class ChangesetReader {
|
|
|
162
179
|
const propFilter = args.propFilter ?? ChangesetReaderTypes_1.PropertyFilter.All;
|
|
163
180
|
reader._propFilter = propFilter;
|
|
164
181
|
try {
|
|
165
|
-
reader._nativeReader.openLocalChanges(args.db[Symbols_1._nativeDb], args.includeInMemoryChanges ?? false, args.invert ?? false, reader._propFilter);
|
|
182
|
+
reader._nativeReader.openLocalChanges(args.db[Symbols_1._nativeDb], args.includeInMemoryChanges ?? false, args.invert ?? false, reader._propFilter, args.spillThresholdInBytes ?? this.defaultSpillThresholdInBytes);
|
|
166
183
|
}
|
|
167
184
|
catch (e) {
|
|
168
|
-
reader.
|
|
185
|
+
reader.handleCloseErrorWhileOpening(e);
|
|
169
186
|
throw e;
|
|
170
187
|
}
|
|
171
188
|
return reader;
|
|
@@ -175,6 +192,11 @@ class ChangesetReader {
|
|
|
175
192
|
* @param args.db Must be an [IModelDb]($backend).
|
|
176
193
|
* @param args.valueOptions Row adaptor options controlling how EC property values are formatted.
|
|
177
194
|
* @param args.propFilter Controls which properties are included. Defaults to `All`.
|
|
195
|
+
* @param args.spillThresholdInBytes When the total size of the in-memory (unsaved) change data exceeds this threshold (in bytes),
|
|
196
|
+
* the reader writes the data to a temporary file on disk and streams it from there instead of buffering everything in memory.
|
|
197
|
+
* This keeps peak memory usage bounded, making the API suitable for large in-memory transactions under low-memory conditions.
|
|
198
|
+
* Defaults to 50 MiB.
|
|
199
|
+
* @throws if the native layer encounters an error while opening the in-memory changes.
|
|
178
200
|
* @beta
|
|
179
201
|
*/
|
|
180
202
|
static openInMemoryChanges(args) {
|
|
@@ -183,10 +205,10 @@ class ChangesetReader {
|
|
|
183
205
|
const propFilter = args.propFilter ?? ChangesetReaderTypes_1.PropertyFilter.All;
|
|
184
206
|
reader._propFilter = propFilter;
|
|
185
207
|
try {
|
|
186
|
-
reader._nativeReader.openInMemoryChanges(args.db[Symbols_1._nativeDb], args.invert ?? false, reader._propFilter);
|
|
208
|
+
reader._nativeReader.openInMemoryChanges(args.db[Symbols_1._nativeDb], args.invert ?? false, reader._propFilter, args.spillThresholdInBytes ?? this.defaultSpillThresholdInBytes);
|
|
187
209
|
}
|
|
188
210
|
catch (e) {
|
|
189
|
-
reader.
|
|
211
|
+
reader.handleCloseErrorWhileOpening(e);
|
|
190
212
|
throw e;
|
|
191
213
|
}
|
|
192
214
|
return reader;
|
|
@@ -197,22 +219,40 @@ class ChangesetReader {
|
|
|
197
219
|
* @param args.txnId The id of the saved transaction to read.
|
|
198
220
|
* @param args.valueOptions Row adaptor options controlling how EC property values are formatted.
|
|
199
221
|
* @param args.propFilter Controls which properties are included. Defaults to `All`.
|
|
222
|
+
* @param args.spillThresholdInBytes When the total size of the transaction's change data exceeds this threshold (in bytes),
|
|
223
|
+
* the reader writes the data to a temporary file on disk and streams it from there instead of buffering everything in memory.
|
|
224
|
+
* This keeps peak memory usage bounded, making the API suitable for large transactions under low-memory conditions.
|
|
225
|
+
* Defaults to 50 MiB.
|
|
226
|
+
* @throws if `txnId` is not found, or
|
|
227
|
+
* the native layer fails to open the transaction data.
|
|
200
228
|
* @beta
|
|
201
229
|
*/
|
|
202
230
|
static openTxn(args) {
|
|
203
231
|
const reader = new ChangesetReader(args.db);
|
|
204
|
-
reader._rowOptions = args.rowOptions
|
|
232
|
+
reader._rowOptions = args.rowOptions;
|
|
205
233
|
const propFilter = args.propFilter ?? ChangesetReaderTypes_1.PropertyFilter.All;
|
|
206
234
|
reader._propFilter = propFilter;
|
|
207
235
|
try {
|
|
208
|
-
reader._nativeReader.openTxn(args.db[Symbols_1._nativeDb], args.txnId, args.invert ?? false, reader._propFilter);
|
|
236
|
+
reader._nativeReader.openTxn(args.db[Symbols_1._nativeDb], args.txnId, args.invert ?? false, reader._propFilter, args.spillThresholdInBytes ?? this.defaultSpillThresholdInBytes);
|
|
209
237
|
}
|
|
210
238
|
catch (e) {
|
|
211
|
-
reader.
|
|
239
|
+
reader.handleCloseErrorWhileOpening(e);
|
|
212
240
|
throw e;
|
|
213
241
|
}
|
|
214
242
|
return reader;
|
|
215
243
|
}
|
|
244
|
+
/** Handle errors that occur while auto closing the reader if there is also an error while opening the reader */
|
|
245
|
+
handleCloseErrorWhileOpening(e) {
|
|
246
|
+
try {
|
|
247
|
+
this.close();
|
|
248
|
+
}
|
|
249
|
+
catch (closeError) {
|
|
250
|
+
throw new core_common_1.IModelError(core_bentley_1.IModelStatus.BadArg, `Failed to open ChangesetReader with error ${e instanceof Error ? e.message : String(e)}.
|
|
251
|
+
Additionally, that triggered an automatic closure of the reader
|
|
252
|
+
releasing native resources which also failed with failure ${closeError instanceof Error ? closeError.message : String(closeError)}.
|
|
253
|
+
Check native error logs for more details.`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
216
256
|
// ---------------------------------------------------------------------------
|
|
217
257
|
// Filtering
|
|
218
258
|
// ---------------------------------------------------------------------------
|
|
@@ -221,6 +261,7 @@ class ChangesetReader {
|
|
|
221
261
|
* That means the rows for changes from other tables will be skipped entirely and won't be visible through the reader.
|
|
222
262
|
* @param tableNames SQLite table names to include.
|
|
223
263
|
* Note: Table names must be provided in the correct case for proper filtering.
|
|
264
|
+
* @throws if the native layer encounters an error while setting the filter.
|
|
224
265
|
* @beta
|
|
225
266
|
*/
|
|
226
267
|
setTableNameFilters(tableNames) {
|
|
@@ -230,6 +271,7 @@ class ChangesetReader {
|
|
|
230
271
|
* Restrict iteration to changes with the given operation types.
|
|
231
272
|
* That means the rows for changes with other operation types will be skipped entirely and won't be visible through the reader.
|
|
232
273
|
* @param ops Operations to include.
|
|
274
|
+
* @throws if the native layer encounters an error while setting the filter.
|
|
233
275
|
* @beta
|
|
234
276
|
*/
|
|
235
277
|
setOpCodeFilters(ops) {
|
|
@@ -240,6 +282,7 @@ class ChangesetReader {
|
|
|
240
282
|
* That means the rows for changes from other EC classes will be skipped entirely and won't be visible through the reader.
|
|
241
283
|
* @param classNames EC class names to include. The classNames should be in the full name format(i.e. "SchemaName:ClassName").
|
|
242
284
|
* Note: Schema names and class names must be provided in the correct case for proper filtering. Derived classes are not automatically included, so they must be specified explicitly if needed.
|
|
285
|
+
* @throws if the native layer encounters an error while setting the filter.
|
|
243
286
|
* @beta
|
|
244
287
|
*/
|
|
245
288
|
setClassNameFilters(classNames) {
|
|
@@ -247,6 +290,7 @@ class ChangesetReader {
|
|
|
247
290
|
}
|
|
248
291
|
/**
|
|
249
292
|
* Remove the table-name filters
|
|
293
|
+
* @throws if the native layer encounters an error.
|
|
250
294
|
* @beta
|
|
251
295
|
*/
|
|
252
296
|
clearTableNameFilters() {
|
|
@@ -254,6 +298,7 @@ class ChangesetReader {
|
|
|
254
298
|
}
|
|
255
299
|
/**
|
|
256
300
|
* Remove the op-code filters
|
|
301
|
+
* @throws if the native layer encounters an error.
|
|
257
302
|
* @beta
|
|
258
303
|
*/
|
|
259
304
|
clearOpCodeFilters() {
|
|
@@ -261,17 +306,61 @@ class ChangesetReader {
|
|
|
261
306
|
}
|
|
262
307
|
/**
|
|
263
308
|
* Remove the class-name filters
|
|
309
|
+
* @throws if the native layer encounters an error.
|
|
264
310
|
* @beta
|
|
265
311
|
*/
|
|
266
312
|
clearClassNameFilters() {
|
|
267
313
|
this._nativeReader.clearClassNameFilters();
|
|
268
314
|
}
|
|
269
315
|
// ---------------------------------------------------------------------------
|
|
316
|
+
// Strict mode
|
|
317
|
+
// ---------------------------------------------------------------------------
|
|
318
|
+
/**
|
|
319
|
+
* Enable strict mode on the reader.
|
|
320
|
+
*
|
|
321
|
+
* Strict mode affects how the reader handles a **column-count mismatch** between a change
|
|
322
|
+
* record and the corresponding live database table. Such a mismatch can occur when columns
|
|
323
|
+
* have been added to a table after the changeset was created.
|
|
324
|
+
*
|
|
325
|
+
* When strict mode is **enabled**: if the number of columns recorded in a change row differs
|
|
326
|
+
* from the number of columns currently present in the live table, the reader throws an error
|
|
327
|
+
* instead of processing that row.
|
|
328
|
+
*
|
|
329
|
+
* Use strict mode when you need to be certain that every change row is interpreted against
|
|
330
|
+
* exactly the schema that was in effect when the changeset was written.
|
|
331
|
+
*
|
|
332
|
+
* @see [[disableStrictMode]] — the default (lenient) behaviour.
|
|
333
|
+
* @throws if the native layer encounters an error.
|
|
334
|
+
* @beta
|
|
335
|
+
*/
|
|
336
|
+
enableStrictMode() {
|
|
337
|
+
this._nativeReader.enableStrictMode();
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Disable strict mode on the reader (this is the default).
|
|
341
|
+
*
|
|
342
|
+
* When strict mode is **disabled**: if the number of columns recorded in a change row differs
|
|
343
|
+
* from the number of columns currently present in the live table, the reader takes the
|
|
344
|
+
* **minimum** of the two column counts and proceeds normally with that subset. This is safe
|
|
345
|
+
* because SQLite only ever appends new columns at the end of a table and never removes them —
|
|
346
|
+
* so older change records simply lack the trailing columns that were added later, and those
|
|
347
|
+
* missing columns are silently ignored.
|
|
348
|
+
*
|
|
349
|
+
* @see [[enableStrictMode]] — throw on column-count mismatches instead.
|
|
350
|
+
* @throws if the native layer encounters an error.
|
|
351
|
+
* @beta
|
|
352
|
+
*/
|
|
353
|
+
disableStrictMode() {
|
|
354
|
+
this._nativeReader.disableStrictMode();
|
|
355
|
+
}
|
|
356
|
+
// ---------------------------------------------------------------------------
|
|
270
357
|
// Iteration
|
|
271
358
|
// ---------------------------------------------------------------------------
|
|
272
359
|
/**
|
|
273
360
|
* Advance to the next change and populate `inserted` and/or `deleted`.
|
|
274
361
|
* @returns `true` while positioned on a valid change; `false` when the stream is exhausted.
|
|
362
|
+
* @throws if the native layer encounters an error while reading or decoding
|
|
363
|
+
* the next change.
|
|
275
364
|
* @beta
|
|
276
365
|
*/
|
|
277
366
|
step() {
|
|
@@ -336,6 +425,7 @@ class ChangesetReader {
|
|
|
336
425
|
/**
|
|
337
426
|
* SQLite opcode of the current change.
|
|
338
427
|
* Valid only after a successful call to [[step]].
|
|
428
|
+
* @throws [[IModelError]] if called before a successful [[step]] call.
|
|
339
429
|
* @beta
|
|
340
430
|
*/
|
|
341
431
|
get op() {
|
|
@@ -348,6 +438,10 @@ class ChangesetReader {
|
|
|
348
438
|
// ---------------------------------------------------------------------------
|
|
349
439
|
/**
|
|
350
440
|
* Close the reader and release all native resources.
|
|
441
|
+
*
|
|
442
|
+
* @throws if the native layer encounters an error during cleanup. Native resources
|
|
443
|
+
* are not fully released when this throws — check the native error
|
|
444
|
+
* logs for details.
|
|
351
445
|
* @beta
|
|
352
446
|
*/
|
|
353
447
|
close() {
|
|
@@ -361,7 +455,9 @@ class ChangesetReader {
|
|
|
361
455
|
this._nativeReader.close();
|
|
362
456
|
}
|
|
363
457
|
/**
|
|
364
|
-
* Implements the `Disposable` contract —
|
|
458
|
+
* Implements the `Disposable` contract — delegates to [[close]].
|
|
459
|
+
*
|
|
460
|
+
* @throws if the native layer fails to release its resources (re-thrown from [[close]]).
|
|
365
461
|
* @beta
|
|
366
462
|
*/
|
|
367
463
|
[Symbol.dispose]() {
|