edinburgh 0.5.0 → 0.6.1
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/README.md +309 -246
- package/build/src/datapack.d.ts +9 -9
- package/build/src/datapack.js +9 -9
- package/build/src/edinburgh.d.ts +21 -7
- package/build/src/edinburgh.js +53 -67
- package/build/src/edinburgh.js.map +1 -1
- package/build/src/indexes.d.ts +85 -205
- package/build/src/indexes.js +150 -503
- package/build/src/indexes.js.map +1 -1
- package/build/src/migrate.js +8 -10
- package/build/src/migrate.js.map +1 -1
- package/build/src/models.d.ts +152 -107
- package/build/src/models.js +433 -144
- package/build/src/models.js.map +1 -1
- package/build/src/types.d.ts +30 -48
- package/build/src/types.js +25 -24
- package/build/src/types.js.map +1 -1
- package/build/src/utils.d.ts +4 -4
- package/build/src/utils.js +4 -4
- package/package.json +2 -2
- package/skill/AnyModelClass.md +7 -0
- package/skill/FindOptions.md +37 -0
- package/skill/Lifecycle Hooks.md +24 -0
- package/skill/{Model_delete.md → Lifecycle Hooks_delete.md } +1 -1
- package/skill/{Model_getPrimaryKeyHash.md → Lifecycle Hooks_getPrimaryKeyHash.md } +1 -1
- package/skill/{Model_isValid.md → Lifecycle Hooks_isValid.md } +1 -1
- package/skill/Lifecycle Hooks_migrate.md +26 -0
- package/skill/{Model_preCommit.md → Lifecycle Hooks_preCommit.md } +2 -2
- package/skill/{Model_preventPersist.md → Lifecycle Hooks_preventPersist.md } +1 -1
- package/skill/{Model_validate.md → Lifecycle Hooks_validate.md } +2 -2
- package/skill/ModelBase.md +7 -0
- package/skill/ModelClass.md +8 -0
- package/skill/SKILL.md +180 -132
- package/skill/Schema Evolution.md +19 -0
- package/skill/TypeWrapper_containsNull.md +11 -0
- package/skill/TypeWrapper_deserialize.md +9 -0
- package/skill/TypeWrapper_getError.md +11 -0
- package/skill/TypeWrapper_serialize.md +10 -0
- package/skill/TypeWrapper_serializeType.md +9 -0
- package/skill/array.md +2 -2
- package/skill/defineModel.md +3 -2
- package/skill/deleteEverything.md +8 -0
- package/skill/field.md +3 -3
- package/skill/link.md +3 -3
- package/skill/literal.md +1 -1
- package/skill/opt.md +1 -1
- package/skill/or.md +1 -1
- package/skill/record.md +1 -1
- package/skill/set.md +2 -2
- package/skill/setOnSaveCallback.md +5 -2
- package/skill/transact.md +1 -1
- package/src/datapack.ts +9 -9
- package/src/edinburgh.ts +68 -68
- package/src/indexes.ts +251 -599
- package/src/migrate.ts +9 -10
- package/src/models.ts +528 -231
- package/src/types.ts +36 -34
- package/src/utils.ts +4 -4
- package/skill/BaseIndex.md +0 -16
- package/skill/BaseIndex_batchProcess.md +0 -10
- package/skill/BaseIndex_find.md +0 -7
- package/skill/BaseIndex_find_2.md +0 -7
- package/skill/BaseIndex_find_3.md +0 -7
- package/skill/BaseIndex_find_4.md +0 -7
- package/skill/Model.md +0 -20
- package/skill/Model_batchProcess.md +0 -8
- package/skill/Model_migrate.md +0 -32
- package/skill/Model_replaceInto.md +0 -16
- package/skill/NonPrimaryIndex.md +0 -10
- package/skill/SecondaryIndex.md +0 -9
- package/skill/UniqueIndex.md +0 -9
- package/skill/dump.md +0 -8
package/skill/array.md
CHANGED
|
@@ -10,8 +10,8 @@ Create an array type wrapper with optional length constraints.
|
|
|
10
10
|
|
|
11
11
|
**Parameters:**
|
|
12
12
|
|
|
13
|
-
- `inner: TypeWrapper<T>` -
|
|
14
|
-
- `opts: {min?: number, max?: number}` (optional) -
|
|
13
|
+
- `inner: TypeWrapper<T>` - Type wrapper for array elements.
|
|
14
|
+
- `opts: {min?: number, max?: number}` (optional) - Optional constraints (min/max length).
|
|
15
15
|
|
|
16
16
|
**Returns:** An array type instance.
|
|
17
17
|
|
package/skill/defineModel.md
CHANGED
|
@@ -16,7 +16,8 @@ typed fields, primary key access, and optional secondary and unique indexes.
|
|
|
16
16
|
|
|
17
17
|
**Parameters:**
|
|
18
18
|
|
|
19
|
-
- `
|
|
20
|
-
- `
|
|
19
|
+
- `tableName: string` - The database table name for this model.
|
|
20
|
+
- `cls: T` - A plain class whose properties use E.field().
|
|
21
|
+
- `opts?: { pk?: PK, unique?: UNIQUE, index?: INDEX, override?: boolean }` - Registration options.
|
|
21
22
|
|
|
22
23
|
**Returns:** The enhanced model constructor.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
### deleteEverything · function
|
|
2
|
+
|
|
3
|
+
Delete every key/value entry in the database and reinitialize all registered models.
|
|
4
|
+
|
|
5
|
+
This clears rows, index metadata, and schema-version records. It is mainly useful
|
|
6
|
+
for tests, local resets, or tooling that needs a completely empty database.
|
|
7
|
+
|
|
8
|
+
**Signature:** `() => Promise<void>`
|
package/skill/field.md
CHANGED
|
@@ -14,15 +14,15 @@ This allows for both runtime introspection and compile-time type safety.
|
|
|
14
14
|
|
|
15
15
|
**Parameters:**
|
|
16
16
|
|
|
17
|
-
- `type: TypeWrapper<T>` -
|
|
18
|
-
- `options: Partial<FieldConfig<T>>` (optional) -
|
|
17
|
+
- `type: TypeWrapper<T>` - The type wrapper for this field.
|
|
18
|
+
- `options: Partial<FieldConfig<T>>` (optional) - Additional field configuration options.
|
|
19
19
|
|
|
20
20
|
**Returns:** The field value (typed as T, but actually returns FieldConfig<T>).
|
|
21
21
|
|
|
22
22
|
**Examples:**
|
|
23
23
|
|
|
24
24
|
```typescript
|
|
25
|
-
const User = E.defineModel(class {
|
|
25
|
+
const User = E.defineModel("User", class {
|
|
26
26
|
name = E.field(E.string, {description: "User's full name"});
|
|
27
27
|
age = E.field(E.opt(E.number), {description: "User's age", default: 25});
|
|
28
28
|
});
|
package/skill/link.md
CHANGED
|
@@ -10,19 +10,19 @@ Create a link type wrapper for model relationships.
|
|
|
10
10
|
|
|
11
11
|
**Parameters:**
|
|
12
12
|
|
|
13
|
-
- `TargetModel: T` -
|
|
13
|
+
- `TargetModel: T` - The model class this link points to.
|
|
14
14
|
|
|
15
15
|
**Returns:** A link type instance.
|
|
16
16
|
|
|
17
17
|
**Examples:**
|
|
18
18
|
|
|
19
19
|
```typescript
|
|
20
|
-
const Author = E.defineModel(class {
|
|
20
|
+
const Author = E.defineModel("Author", class {
|
|
21
21
|
id = E.field(E.identifier);
|
|
22
22
|
posts = E.field(E.array(E.link(() => Book)));
|
|
23
23
|
}, { pk: "id" });
|
|
24
24
|
|
|
25
|
-
const Book = E.defineModel(class {
|
|
25
|
+
const Book = E.defineModel("Book", class {
|
|
26
26
|
id = E.field(E.identifier);
|
|
27
27
|
author = E.field(E.link(Author));
|
|
28
28
|
}, { pk: "id" });
|
package/skill/literal.md
CHANGED
package/skill/opt.md
CHANGED
package/skill/or.md
CHANGED
package/skill/record.md
CHANGED
|
@@ -10,7 +10,7 @@ Create a Record type wrapper for key-value objects with string or number keys.
|
|
|
10
10
|
|
|
11
11
|
**Parameters:**
|
|
12
12
|
|
|
13
|
-
- `inner: TypeWrapper<T>` -
|
|
13
|
+
- `inner: TypeWrapper<T>` - Type wrapper for record values.
|
|
14
14
|
|
|
15
15
|
**Returns:** A record type instance.
|
|
16
16
|
|
package/skill/set.md
CHANGED
|
@@ -10,8 +10,8 @@ Create a Set type wrapper with optional length constraints.
|
|
|
10
10
|
|
|
11
11
|
**Parameters:**
|
|
12
12
|
|
|
13
|
-
- `inner: TypeWrapper<T>` -
|
|
14
|
-
- `opts: {min?: number, max?: number}` (optional) -
|
|
13
|
+
- `inner: TypeWrapper<T>` - Type wrapper for set elements.
|
|
14
|
+
- `opts: {min?: number, max?: number}` (optional) - Optional constraints (min/max length).
|
|
15
15
|
|
|
16
16
|
**Returns:** A set type instance.
|
|
17
17
|
|
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
Set a callback function to be called after a model is saved and committed.
|
|
4
4
|
|
|
5
|
-
**Signature:** `(callback: (commitId: number, items: Map<
|
|
5
|
+
**Signature:** `(callback: (commitId: number, items: Map<ModelBase, Change>) => void) => void`
|
|
6
6
|
|
|
7
7
|
**Parameters:**
|
|
8
8
|
|
|
9
|
-
- `callback: ((commitId: number, items: Map<Model<
|
|
9
|
+
- `callback: ((commitId: number, items: Map<Model<unknown>, Change>) => void) | undefined` - The callback function to set. It gets called after each successful
|
|
10
10
|
`transact()` commit that has changes, with the following arguments:
|
|
11
11
|
- A sequential number. Higher numbers have been committed after lower numbers.
|
|
12
12
|
- A map of model instances to their changes. The change can be "created", "deleted", or an object containing the old values.
|
|
13
|
+
|
|
14
|
+
The callback is called within a new transaction context, allowing lazy-loads to happen. However, any
|
|
15
|
+
changes made to Edinburgh models will not be saved.
|
package/skill/transact.md
CHANGED
|
@@ -18,7 +18,7 @@ times.
|
|
|
18
18
|
|
|
19
19
|
**Parameters:**
|
|
20
20
|
|
|
21
|
-
- `fn: () => T` -
|
|
21
|
+
- `fn: () => T` - The function to execute within the transaction context. Receives a Transaction instance.
|
|
22
22
|
|
|
23
23
|
**Returns:** A promise that resolves with the function's return value.
|
|
24
24
|
|
package/src/datapack.ts
CHANGED
|
@@ -46,7 +46,7 @@ export default class DataPack {
|
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
48
|
* Create a new DataPack instance.
|
|
49
|
-
* @param data
|
|
49
|
+
* @param data Optional initial data as Uint8Array or buffer size as number.
|
|
50
50
|
*/
|
|
51
51
|
constructor(data: Uint8Array | number = 1900) {
|
|
52
52
|
if (data instanceof Uint8Array) {
|
|
@@ -59,10 +59,10 @@ export default class DataPack {
|
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
61
|
* Helper function to write a multi-byte integer with length prefix
|
|
62
|
-
* @param value
|
|
63
|
-
* @param headerType
|
|
64
|
-
* @param invertBytes
|
|
65
|
-
* @param invertByteCount
|
|
62
|
+
* @param value The value to write
|
|
63
|
+
* @param headerType The type bits (0-7) for the header
|
|
64
|
+
* @param invertBytes Whether to invert bytes (for negative numbers)
|
|
65
|
+
* @param invertByteCount Whether to invert the byte count (for type 0)
|
|
66
66
|
*/
|
|
67
67
|
private writeMultiByteNumber(value: number, headerType: number, invertBytes: boolean = false, invertByteCount: boolean = false): void {
|
|
68
68
|
let byteCount = 0;
|
|
@@ -87,8 +87,8 @@ export default class DataPack {
|
|
|
87
87
|
|
|
88
88
|
/**
|
|
89
89
|
* Helper function to read a multi-byte integer with length prefix
|
|
90
|
-
* @param byteCount
|
|
91
|
-
* @param invertBytes
|
|
90
|
+
* @param byteCount Number of bytes to read
|
|
91
|
+
* @param invertBytes Whether to invert bytes (for negative numbers)
|
|
92
92
|
* @returns The read value
|
|
93
93
|
*/
|
|
94
94
|
private readMultiByteNumber(byteCount: number, invertBytes: boolean = false): number {
|
|
@@ -383,7 +383,7 @@ export default class DataPack {
|
|
|
383
383
|
|
|
384
384
|
/**
|
|
385
385
|
* Ensure the buffer has capacity for additional bytes.
|
|
386
|
-
* @param bytesNeeded
|
|
386
|
+
* @param bytesNeeded Number of additional bytes needed.
|
|
387
387
|
*/
|
|
388
388
|
private ensureCapacity(bytesNeeded: number): void {
|
|
389
389
|
const needed = this.writePos + bytesNeeded;
|
|
@@ -511,7 +511,7 @@ export default class DataPack {
|
|
|
511
511
|
/**
|
|
512
512
|
* Like writeString but writes without a length prefix and with a null terminator, for ordered storage.
|
|
513
513
|
* Can be read with {@link read} or {@link readString} just like any other string.
|
|
514
|
-
* @param str
|
|
514
|
+
* @param str The string to write. May not contain null characters.
|
|
515
515
|
*/
|
|
516
516
|
writeOrderedString(str: string): DataPack {
|
|
517
517
|
const utf8Bytes = new TextEncoder().encode(str);
|
package/src/edinburgh.ts
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
import * as lowlevel from "olmdb/lowlevel";
|
|
2
2
|
import { init as olmdbInit, DatabaseError } from "olmdb/lowlevel";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
let initNeeded = true;
|
|
6
|
-
export function scheduleInit() { initNeeded = true; }
|
|
3
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
4
|
+
import { pendingModelInits } from "./models.js";
|
|
7
5
|
|
|
8
6
|
|
|
9
7
|
// Re-export public API from models
|
|
10
8
|
export {
|
|
11
9
|
Model,
|
|
10
|
+
type ModelClass,
|
|
11
|
+
type AnyModelClass,
|
|
12
|
+
type ModelBase,
|
|
12
13
|
defineModel,
|
|
14
|
+
deleteEverything,
|
|
13
15
|
field,
|
|
14
|
-
currentTxn,
|
|
15
16
|
} from "./models.js";
|
|
16
17
|
|
|
17
|
-
import type {
|
|
18
|
+
import type { Change, Model } from "./models.js";
|
|
18
19
|
|
|
19
20
|
// Re-export public API from types (only factory functions and instances)
|
|
20
21
|
export {
|
|
@@ -41,14 +42,33 @@ export {
|
|
|
41
42
|
dump,
|
|
42
43
|
} from "./indexes.js";
|
|
43
44
|
|
|
44
|
-
export {
|
|
45
|
+
export type { FindOptions, IndexRangeIterator } from './indexes.js';
|
|
45
46
|
|
|
46
47
|
export { type Change } from './models.js';
|
|
47
|
-
export type {
|
|
48
|
+
export type { FieldConfig } from './models.js';
|
|
49
|
+
export { TypeWrapper } from './types.js';
|
|
48
50
|
export { DatabaseError } from "olmdb/lowlevel";
|
|
49
51
|
export { runMigration } from './migrate.js';
|
|
50
52
|
export type { MigrationOptions, MigrationResult } from './migrate.js';
|
|
51
53
|
|
|
54
|
+
export interface Transaction {
|
|
55
|
+
id: number;
|
|
56
|
+
instances: Map<number, Model<unknown>>; // pkHash => instance
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const txnStorage = new AsyncLocalStorage<Transaction>();
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Returns the current transaction from AsyncLocalStorage.
|
|
63
|
+
* Throws if called outside a transact() callback.
|
|
64
|
+
* @internal
|
|
65
|
+
*/
|
|
66
|
+
export function currentTxn(): Transaction {
|
|
67
|
+
const txn = txnStorage.getStore();
|
|
68
|
+
if (!txn) throw new DatabaseError("No active transaction. Operations must be performed within a transact() callback.", 'NO_TRANSACTION');
|
|
69
|
+
return txn;
|
|
70
|
+
}
|
|
71
|
+
|
|
52
72
|
let olmdbReady = false;
|
|
53
73
|
let maxRetryCount = 6;
|
|
54
74
|
|
|
@@ -88,7 +108,7 @@ const STALE_INSTANCE_DESCRIPTOR = {
|
|
|
88
108
|
* times.
|
|
89
109
|
*
|
|
90
110
|
* @template T - The return type of the transaction function.
|
|
91
|
-
* @param fn
|
|
111
|
+
* @param fn The function to execute within the transaction context. Receives a Transaction instance.
|
|
92
112
|
* @returns A promise that resolves with the function's return value.
|
|
93
113
|
* @throws {DatabaseError} With code "RACING_TRANSACTION" if the transaction fails after retries due to conflicts.
|
|
94
114
|
* @throws {DatabaseError} With code "TXN_LIMIT" if maximum number of transactions is reached.
|
|
@@ -114,17 +134,17 @@ const STALE_INSTANCE_DESCRIPTOR = {
|
|
|
114
134
|
* ```
|
|
115
135
|
*/
|
|
116
136
|
export async function transact<T>(fn: () => T): Promise<T> {
|
|
117
|
-
while (
|
|
118
|
-
// Make sure only one async task is doing the inits, the rest should wait for it
|
|
137
|
+
while (pendingModelInits.size || pendingInit) {
|
|
119
138
|
if (pendingInit) {
|
|
120
139
|
await pendingInit;
|
|
121
140
|
} else {
|
|
122
141
|
pendingInit = (async () => {
|
|
123
142
|
if (!olmdbReady) olmdbInit('.edinburgh');
|
|
124
143
|
olmdbReady = true;
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
144
|
+
const models = [...pendingModelInits];
|
|
145
|
+
pendingModelInits.clear();
|
|
146
|
+
for (const model of models) {
|
|
147
|
+
await model._initialize();
|
|
128
148
|
}
|
|
129
149
|
})();
|
|
130
150
|
await pendingInit;
|
|
@@ -135,7 +155,7 @@ export async function transact<T>(fn: () => T): Promise<T> {
|
|
|
135
155
|
// try {
|
|
136
156
|
for (let retryCount = 0; retryCount < maxRetryCount; retryCount++) {
|
|
137
157
|
const txnId = lowlevel.startTransaction();
|
|
138
|
-
const txn: Transaction = { id: txnId, instances: new
|
|
158
|
+
const txn: Transaction = { id: txnId, instances: new Map() };
|
|
139
159
|
const onSaveItems: Map<Model<unknown>, Change> | undefined = onSaveCallback ? new Map() : undefined;
|
|
140
160
|
|
|
141
161
|
let result: T | undefined;
|
|
@@ -144,16 +164,16 @@ export async function transact<T>(fn: () => T): Promise<T> {
|
|
|
144
164
|
result = await fn();
|
|
145
165
|
|
|
146
166
|
// Call preCommit() on all instances before writing.
|
|
147
|
-
// Note:
|
|
167
|
+
// Note: Map iteration visits newly added items, so preCommit() creating
|
|
148
168
|
// new instances is handled correctly.
|
|
149
|
-
for (const instance of txn.instances) {
|
|
150
|
-
instance.preCommit?.();
|
|
169
|
+
for (const instance of txn.instances.values()) {
|
|
170
|
+
if (instance._oldValues !== false) instance.preCommit?.();
|
|
151
171
|
}
|
|
152
172
|
|
|
153
173
|
// Save all modified instances before committing
|
|
154
174
|
// This needs to happen inside txnStorage.run, because resolving default values
|
|
155
175
|
// for identifiers requires database access.
|
|
156
|
-
for (const instance of txn.instances) {
|
|
176
|
+
for (const instance of txn.instances.values()) {
|
|
157
177
|
const change = instance._write(txn);
|
|
158
178
|
if (onSaveItems && change) {
|
|
159
179
|
onSaveItems.set(instance, change);
|
|
@@ -163,30 +183,36 @@ export async function transact<T>(fn: () => T): Promise<T> {
|
|
|
163
183
|
} catch (e: any) {
|
|
164
184
|
try { lowlevel.abortTransaction(txnId); } catch {}
|
|
165
185
|
throw e;
|
|
166
|
-
} finally {
|
|
167
|
-
// Make the instances read-only to make it clear that their transaction has ended.
|
|
168
|
-
for (const instance of txn.instances) {
|
|
169
|
-
delete instance._oldValues;
|
|
170
|
-
Object.defineProperty(instance, "_txn", STALE_INSTANCE_DESCRIPTOR);
|
|
171
|
-
Object.freeze(instance);
|
|
172
|
-
}
|
|
173
|
-
// Destroy the transaction object, to make sure things crash if they are used after
|
|
174
|
-
// this point, and to help the GC reclaim memory.
|
|
175
|
-
txn.id = txn.instances = txn.instancesByPk = undefined as any;
|
|
176
186
|
}
|
|
177
187
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
188
|
+
if (onSaveItems?.size) {
|
|
189
|
+
// Perform writes, and start a new transaction at or past the point-in-time of our commit
|
|
190
|
+
const commitResult = lowlevel.commitTransaction(txnId, true);
|
|
191
|
+
if (typeof commitResult === 'object') {
|
|
192
|
+
const commitSeq = await commitResult;
|
|
193
|
+
if (commitSeq <= 0) continue; // Race condition - retry
|
|
194
|
+
// Run the callback within our new transaction context, so it can fetch linked lazy fields if needed
|
|
184
195
|
onSaveCallback!(commitSeq, onSaveItems);
|
|
185
196
|
}
|
|
186
|
-
|
|
197
|
+
// else: only reads
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Make the instances read-only to make it clear that their transaction has ended.
|
|
201
|
+
for (const instance of txn.instances.values()) {
|
|
202
|
+
delete instance._oldValues;
|
|
203
|
+
Object.defineProperty(instance, "_txn", STALE_INSTANCE_DESCRIPTOR);
|
|
204
|
+
Object.freeze(instance);
|
|
187
205
|
}
|
|
188
206
|
|
|
189
|
-
//
|
|
207
|
+
// Destroy the transaction object, to make sure things crash if they are used after
|
|
208
|
+
// this point, and to help the GC reclaim memory.
|
|
209
|
+
txn.id = txn.instances = undefined as any;
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
// Commit the transaction and actually end it
|
|
213
|
+
if ((await lowlevel.commitTransaction(txnId)) <= 0) continue; // Race condition - retry
|
|
214
|
+
|
|
215
|
+
return result as T;
|
|
190
216
|
}
|
|
191
217
|
throw new DatabaseError("Transaction keeps getting raced", "RACING_TRANSACTION");
|
|
192
218
|
// } catch (e: Error | any) {
|
|
@@ -207,7 +233,7 @@ export function setMaxRetryCount(count: number) {
|
|
|
207
233
|
maxRetryCount = count;
|
|
208
234
|
}
|
|
209
235
|
|
|
210
|
-
let onSaveCallback: ((commitId: number, items: Map<Model<
|
|
236
|
+
let onSaveCallback: ((commitId: number, items: Map<Model<unknown>, Change>) => void) | undefined;
|
|
211
237
|
|
|
212
238
|
/**
|
|
213
239
|
* Set a callback function to be called after a model is saved and committed.
|
|
@@ -216,36 +242,10 @@ let onSaveCallback: ((commitId: number, items: Map<Model<any>, Change>) => void)
|
|
|
216
242
|
* `transact()` commit that has changes, with the following arguments:
|
|
217
243
|
* - A sequential number. Higher numbers have been committed after lower numbers.
|
|
218
244
|
* - A map of model instances to their changes. The change can be "created", "deleted", or an object containing the old values.
|
|
245
|
+
*
|
|
246
|
+
* The callback is called within a new transaction context, allowing lazy-loads to happen. However, any
|
|
247
|
+
* changes made to Edinburgh models will not be saved.
|
|
219
248
|
*/
|
|
220
|
-
export function setOnSaveCallback(callback: ((commitId: number, items: Map<Model<
|
|
249
|
+
export function setOnSaveCallback(callback: ((commitId: number, items: Map<Model<unknown>, Change>) => void) | undefined) {
|
|
221
250
|
onSaveCallback = callback;
|
|
222
251
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
export async function deleteEverything(): Promise<void> {
|
|
226
|
-
let done = false;
|
|
227
|
-
while (!done) {
|
|
228
|
-
await transact(() => {
|
|
229
|
-
const txn = currentTxn();
|
|
230
|
-
const iteratorId = lowlevel.createIterator(txn.id, undefined, undefined, false);
|
|
231
|
-
const deadline = Date.now() + 150;
|
|
232
|
-
let count = 0;
|
|
233
|
-
try {
|
|
234
|
-
while (true) {
|
|
235
|
-
const raw = lowlevel.readIterator(iteratorId);
|
|
236
|
-
if (!raw) { done = true; break; }
|
|
237
|
-
lowlevel.del(txn.id, raw.key);
|
|
238
|
-
if (++count >= 4096 || Date.now() >= deadline) break;
|
|
239
|
-
}
|
|
240
|
-
} finally {
|
|
241
|
-
lowlevel.closeIterator(iteratorId);
|
|
242
|
-
}
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
// Re-init indexes since metadata was deleted
|
|
246
|
-
for (const model of Object.values(modelRegistry)) {
|
|
247
|
-
if (!model.fields) continue;
|
|
248
|
-
model._resetIndexes();
|
|
249
|
-
await model._loadCreateIndexes();
|
|
250
|
-
}
|
|
251
|
-
}
|