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/README.md
CHANGED
|
@@ -22,7 +22,7 @@ import * as E from "edinburgh";
|
|
|
22
22
|
// Initialize the database (optional, defaults to ".edinburgh")
|
|
23
23
|
E.init("./my-database");
|
|
24
24
|
|
|
25
|
-
const User = E.defineModel(class {
|
|
25
|
+
const User = E.defineModel("User", class {
|
|
26
26
|
id = E.field(E.identifier);
|
|
27
27
|
name = E.field(E.string);
|
|
28
28
|
age = E.field(E.number);
|
|
@@ -42,9 +42,8 @@ const User = E.defineModel(class {
|
|
|
42
42
|
}, {
|
|
43
43
|
pk: "id",
|
|
44
44
|
unique: {
|
|
45
|
-
|
|
45
|
+
email: "email",
|
|
46
46
|
},
|
|
47
|
-
tableName: "User",
|
|
48
47
|
});
|
|
49
48
|
|
|
50
49
|
await E.transact(() => {
|
|
@@ -61,7 +60,7 @@ await E.transact(() => {
|
|
|
61
60
|
|
|
62
61
|
await E.transact(() => {
|
|
63
62
|
// Query by unique index
|
|
64
|
-
|
|
63
|
+
const john = User.getBy("email", "john@example.com")!;
|
|
65
64
|
|
|
66
65
|
// The transaction will retry if there's a conflict, such as another transaction
|
|
67
66
|
// modifying the same user (from another async function or another process)
|
|
@@ -77,12 +76,15 @@ await E.transact(() => {
|
|
|
77
76
|
|
|
78
77
|
### Defining Models
|
|
79
78
|
|
|
80
|
-
|
|
79
|
+
A model is defined using the `E.defineModel()` function by passing it..
|
|
80
|
+
- a consistent table name,
|
|
81
|
+
- an (anonymous) class containing `E.field` database properties and optionally regular properties/methods, and
|
|
82
|
+
- optional key/index configuration.
|
|
81
83
|
|
|
82
84
|
```typescript
|
|
83
85
|
import * as E from "edinburgh";
|
|
84
86
|
|
|
85
|
-
const User = E.defineModel(class {
|
|
87
|
+
const User = E.defineModel("User", class {
|
|
86
88
|
id = E.field(E.identifier);
|
|
87
89
|
name = E.field(E.string);
|
|
88
90
|
email = E.field(E.string);
|
|
@@ -90,9 +92,12 @@ const User = E.defineModel(class {
|
|
|
90
92
|
}, {
|
|
91
93
|
pk: "id",
|
|
92
94
|
unique: {
|
|
93
|
-
|
|
95
|
+
email: "email",
|
|
94
96
|
},
|
|
95
97
|
});
|
|
98
|
+
// Add this if you want to use User as a type annotation (e.g. `let u: User`).
|
|
99
|
+
// Not needed just to call User.get(), User.find(), new User(), etc.
|
|
100
|
+
type User = InstanceType<typeof User>;
|
|
96
101
|
```
|
|
97
102
|
|
|
98
103
|
Instance fields are declared with `E.field(type, options?)`. Available types:
|
|
@@ -116,7 +121,7 @@ Instance fields are declared with `E.field(type, options?)`. Available types:
|
|
|
116
121
|
#### Defaults
|
|
117
122
|
|
|
118
123
|
```typescript
|
|
119
|
-
const Post = E.defineModel(class {
|
|
124
|
+
const Post = E.defineModel("Post", class {
|
|
120
125
|
id = E.field(E.identifier); // auto-generated
|
|
121
126
|
title = E.field(E.string);
|
|
122
127
|
status = E.field(E.or("draft", "published"), {default: "draft"});
|
|
@@ -141,13 +146,13 @@ await E.transact(() => {
|
|
|
141
146
|
|
|
142
147
|
// Read + Update
|
|
143
148
|
await E.transact(() => {
|
|
144
|
-
const user = User.
|
|
149
|
+
const user = User.getBy("email", "alice@example.com");
|
|
145
150
|
if (user) user.age++;
|
|
146
151
|
});
|
|
147
152
|
|
|
148
153
|
// Return values from transactions
|
|
149
154
|
const name = await E.transact(() => {
|
|
150
|
-
const user = User.
|
|
155
|
+
const user = User.getBy("email", "alice@example.com");
|
|
151
156
|
return user?.name;
|
|
152
157
|
});
|
|
153
158
|
```
|
|
@@ -159,15 +164,15 @@ Transactions auto-retry on conflict (up to 6 times by default). Keep transaction
|
|
|
159
164
|
Edinburgh supports three index types:
|
|
160
165
|
|
|
161
166
|
```typescript
|
|
162
|
-
const Product = E.defineModel(class {
|
|
167
|
+
const Product = E.defineModel("Product", class {
|
|
163
168
|
sku = E.field(E.string);
|
|
164
169
|
name = E.field(E.string);
|
|
165
170
|
category = E.field(E.string);
|
|
166
171
|
price = E.field(E.number);
|
|
167
172
|
}, {
|
|
168
173
|
pk: "sku",
|
|
169
|
-
unique: {
|
|
170
|
-
index: {
|
|
174
|
+
unique: { name: "name" },
|
|
175
|
+
index: { category: "category" },
|
|
171
176
|
});
|
|
172
177
|
```
|
|
173
178
|
|
|
@@ -181,7 +186,7 @@ await E.transact(() => {
|
|
|
181
186
|
const p1 = Product.get("SKU-001");
|
|
182
187
|
|
|
183
188
|
// Unique index lookup
|
|
184
|
-
const p2 = Product.
|
|
189
|
+
const p2 = Product.getBy("name", "Widget");
|
|
185
190
|
|
|
186
191
|
// All return undefined if not found
|
|
187
192
|
});
|
|
@@ -189,12 +194,12 @@ await E.transact(() => {
|
|
|
189
194
|
|
|
190
195
|
#### Range Queries
|
|
191
196
|
|
|
192
|
-
|
|
197
|
+
Primary-key queries use `.find()`. Named unique and secondary indexes use `.findBy(name, ...)`:
|
|
193
198
|
|
|
194
199
|
```typescript
|
|
195
200
|
await E.transact(() => {
|
|
196
201
|
// Exact match
|
|
197
|
-
for (const p of Product.
|
|
202
|
+
for (const p of Product.findBy("category", {is: "electronics"})) {
|
|
198
203
|
console.log(p.name);
|
|
199
204
|
}
|
|
200
205
|
|
|
@@ -213,15 +218,15 @@ await E.transact(() => {
|
|
|
213
218
|
for (const p of Product.find({reverse: true})) { ... }
|
|
214
219
|
|
|
215
220
|
// Count and fetch helpers
|
|
216
|
-
const count = Product.
|
|
217
|
-
const first = Product.
|
|
221
|
+
const count = Product.findBy("category", {is: "electronics"}).count();
|
|
222
|
+
const first = Product.findBy("category", {is: "electronics"}).fetch(); // first match or undefined
|
|
218
223
|
});
|
|
219
224
|
```
|
|
220
225
|
|
|
221
226
|
#### Composite Primary Keys
|
|
222
227
|
|
|
223
228
|
```typescript
|
|
224
|
-
const Event = E.defineModel(class {
|
|
229
|
+
const Event = E.defineModel("Event", class {
|
|
225
230
|
year = E.field(E.number);
|
|
226
231
|
month = E.field(E.number);
|
|
227
232
|
id = E.field(E.identifier);
|
|
@@ -244,7 +249,7 @@ await E.transact(() => {
|
|
|
244
249
|
You can freely add regular methods, getters, and other non-persistent properties to model classes. These work normally in JavaScript but are **not stored in the database** and **not synchronized** across transactions or processes.
|
|
245
250
|
|
|
246
251
|
```typescript
|
|
247
|
-
const User = E.defineModel(class {
|
|
252
|
+
const User = E.defineModel("User", class {
|
|
248
253
|
firstName = E.field(E.string);
|
|
249
254
|
lastName = E.field(E.string);
|
|
250
255
|
|
|
@@ -267,7 +272,7 @@ const User = E.defineModel(class {
|
|
|
267
272
|
Instead of naming fields, you can pass a function as an index specification. The function receives a model instance and returns an **array** of index key values. Each element creates a separate index entry, enabling multi-value indexes. Return `[]` to skip indexing for that instance (partial index).
|
|
268
273
|
|
|
269
274
|
```typescript
|
|
270
|
-
const Article = E.defineModel(class {
|
|
275
|
+
const Article = E.defineModel("Article", class {
|
|
271
276
|
id = E.field(E.identifier);
|
|
272
277
|
firstName = E.field(E.string);
|
|
273
278
|
lastName = E.field(E.string);
|
|
@@ -276,11 +281,11 @@ const Article = E.defineModel(class {
|
|
|
276
281
|
}, {
|
|
277
282
|
pk: "id",
|
|
278
283
|
unique: {
|
|
279
|
-
|
|
284
|
+
fullName: (a: any) => [`${a.firstName} ${a.lastName}`], // computed covering unique index
|
|
280
285
|
},
|
|
281
286
|
index: {
|
|
282
|
-
|
|
283
|
-
|
|
287
|
+
domain: (a: any) => a.email ? [a.email.split("@")[1]] : [], // computed partial index
|
|
288
|
+
word: (a: any) => a.title.toLowerCase().split(" "), // computed multi-index
|
|
284
289
|
},
|
|
285
290
|
});
|
|
286
291
|
|
|
@@ -288,13 +293,13 @@ await E.transact(() => {
|
|
|
288
293
|
new Article({ firstName: "Jane", lastName: "Doe", title: "Hello World", email: "jane@acme.com" });
|
|
289
294
|
|
|
290
295
|
// Lookup via computed unique index
|
|
291
|
-
const jane = Article.
|
|
296
|
+
const jane = Article.getBy("fullName", "Jane Doe");
|
|
292
297
|
|
|
293
298
|
// Multi-value: each word in the title is indexed separately
|
|
294
|
-
for (const a of Article.
|
|
299
|
+
for (const a of Article.findBy("word", {is: "hello"})) { ... }
|
|
295
300
|
|
|
296
301
|
// Partial index: articles without email are skipped
|
|
297
|
-
for (const a of Article.
|
|
302
|
+
for (const a of Article.findBy("domain", {is: "acme.com"})) { ... }
|
|
298
303
|
});
|
|
299
304
|
```
|
|
300
305
|
|
|
@@ -303,12 +308,12 @@ await E.transact(() => {
|
|
|
303
308
|
Use `E.link(Model)` for foreign keys. Use a thunk (a function that just returns a value) for forward references when needed:
|
|
304
309
|
|
|
305
310
|
```typescript
|
|
306
|
-
const Author = E.defineModel(class {
|
|
311
|
+
const Author = E.defineModel("Author", class {
|
|
307
312
|
id = E.field(E.identifier);
|
|
308
313
|
name = E.field(E.string);
|
|
309
314
|
}, { pk: "id" });
|
|
310
315
|
|
|
311
|
-
const Book = E.defineModel(class {
|
|
316
|
+
const Book = E.defineModel("Book", class {
|
|
312
317
|
id = E.field(E.identifier);
|
|
313
318
|
title = E.field(E.string);
|
|
314
319
|
author = E.field(E.link(Author));
|
|
@@ -381,7 +386,7 @@ await Product.batchProcess({ limitRows: 1000 }, (product) => {
|
|
|
381
386
|
When you change a model's schema, Edinburgh lazily migrates old records on access. You can provide a `static migrate(record)` function to transform old rows:
|
|
382
387
|
|
|
383
388
|
```typescript
|
|
384
|
-
const UserV2 = E.defineModel(class {
|
|
389
|
+
const UserV2 = E.defineModel("User", class {
|
|
385
390
|
id = E.field(E.identifier);
|
|
386
391
|
name = E.field(E.string);
|
|
387
392
|
role = E.field(E.string); // newly added field
|
|
@@ -389,7 +394,7 @@ const UserV2 = E.defineModel(class {
|
|
|
389
394
|
static migrate(record: Record<string, any>) {
|
|
390
395
|
record.role ??= record.name.indexOf("admin") >= 0 ? "admin" : "user"; // set role based on name for old records
|
|
391
396
|
}
|
|
392
|
-
}
|
|
397
|
+
})
|
|
393
398
|
```
|
|
394
399
|
|
|
395
400
|
Edinburgh will lazily (re)run the `migrate` function on an instance whenever its implementation (the literal function code) has changed. For robustness, make sure that your `migrate` function...
|
|
@@ -424,7 +429,7 @@ console.log(result.secondaries); // { User: 1500 }
|
|
|
424
429
|
Compute derived fields before data is written:
|
|
425
430
|
|
|
426
431
|
```typescript
|
|
427
|
-
const Article = E.defineModel(class {
|
|
432
|
+
const Article = E.defineModel("Article", class {
|
|
428
433
|
id = E.field(E.identifier);
|
|
429
434
|
title = E.field(E.string);
|
|
430
435
|
slug = E.field(E.string);
|
|
@@ -432,7 +437,7 @@ const Article = E.defineModel(class {
|
|
|
432
437
|
preCommit() {
|
|
433
438
|
this.slug = this.title.toLowerCase().replace(/\s+/g, "-");
|
|
434
439
|
}
|
|
435
|
-
}
|
|
440
|
+
});
|
|
436
441
|
```
|
|
437
442
|
|
|
438
443
|
### Change Tracking
|
|
@@ -473,11 +478,14 @@ ln -s ../../node_modules/edinburgh/skill .claude/skills/edinburgh
|
|
|
473
478
|
|
|
474
479
|
The following is auto-generated from `src/edinburgh.ts`:
|
|
475
480
|
|
|
476
|
-
###
|
|
481
|
+
### currentTxn · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L66)
|
|
477
482
|
|
|
478
|
-
|
|
483
|
+
Returns the current transaction from AsyncLocalStorage.
|
|
484
|
+
Throws if called outside a transact() callback.
|
|
485
|
+
|
|
486
|
+
**Signature:** `() => Transaction`
|
|
479
487
|
|
|
480
|
-
### init · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
488
|
+
### init · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L85)
|
|
481
489
|
|
|
482
490
|
Initialize the database with the specified directory path.
|
|
483
491
|
This function may be called multiple times with the same parameters. If it is not called before the first transact(),
|
|
@@ -495,7 +503,7 @@ the database will be automatically initialized with the default directory.
|
|
|
495
503
|
init("./my-database");
|
|
496
504
|
```
|
|
497
505
|
|
|
498
|
-
### transact · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
506
|
+
### transact · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L136)
|
|
499
507
|
|
|
500
508
|
Executes a function within a database transaction context.
|
|
501
509
|
|
|
@@ -515,7 +523,7 @@ times.
|
|
|
515
523
|
|
|
516
524
|
**Parameters:**
|
|
517
525
|
|
|
518
|
-
- `fn: () => T` -
|
|
526
|
+
- `fn: () => T` - The function to execute within the transaction context. Receives a Transaction instance.
|
|
519
527
|
|
|
520
528
|
**Returns:** A promise that resolves with the function's return value.
|
|
521
529
|
|
|
@@ -545,7 +553,7 @@ await E.transact(() => {
|
|
|
545
553
|
});
|
|
546
554
|
```
|
|
547
555
|
|
|
548
|
-
### setMaxRetryCount · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
556
|
+
### setMaxRetryCount · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L232)
|
|
549
557
|
|
|
550
558
|
Set the maximum number of retries for a transaction in case of conflicts.
|
|
551
559
|
The default value is 6. Setting it to 0 will disable retries and cause transactions to fail immediately on conflict.
|
|
@@ -556,146 +564,124 @@ The default value is 6. Setting it to 0 will disable retries and cause transacti
|
|
|
556
564
|
|
|
557
565
|
- `count: number` - The maximum number of retries for a transaction.
|
|
558
566
|
|
|
559
|
-
### setOnSaveCallback · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
567
|
+
### setOnSaveCallback · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L249)
|
|
560
568
|
|
|
561
569
|
Set a callback function to be called after a model is saved and committed.
|
|
562
570
|
|
|
563
|
-
**Signature:** `(callback: (commitId: number, items: Map<
|
|
571
|
+
**Signature:** `(callback: (commitId: number, items: Map<ModelBase, Change>) => void) => void`
|
|
564
572
|
|
|
565
573
|
**Parameters:**
|
|
566
574
|
|
|
567
|
-
- `callback: ((commitId: number, items: Map<Model<
|
|
575
|
+
- `callback: ((commitId: number, items: Map<Model<unknown>, Change>) => void) | undefined` - The callback function to set. It gets called after each successful
|
|
568
576
|
`transact()` commit that has changes, with the following arguments:
|
|
569
577
|
- A sequential number. Higher numbers have been committed after lower numbers.
|
|
570
578
|
- A map of model instances to their changes. The change can be "created", "deleted", or an object containing the old values.
|
|
571
579
|
|
|
572
|
-
|
|
580
|
+
The callback is called within a new transaction context, allowing lazy-loads to happen. However, any
|
|
581
|
+
changes made to Edinburgh models will not be saved.
|
|
573
582
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
### Model · [abstract class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
583
|
+
### Model · [class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
577
584
|
|
|
578
|
-
|
|
585
|
+
**Type:** `typeof ModelBase`
|
|
579
586
|
|
|
580
|
-
|
|
587
|
+
### ModelClass · [class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
581
588
|
|
|
582
|
-
|
|
589
|
+
Runtime base constructor for model classes returned by `defineModel()`.
|
|
583
590
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
```typescript
|
|
587
|
-
const User = E.defineModel(class {
|
|
588
|
-
id = E.field(E.identifier);
|
|
589
|
-
name = E.field(E.string);
|
|
590
|
-
email = E.field(E.string);
|
|
591
|
-
}, {
|
|
592
|
-
pk: "id",
|
|
593
|
-
unique: { byEmail: "email" },
|
|
594
|
-
});
|
|
595
|
-
```
|
|
591
|
+
Prefer the `ModelClass` type alias for annotations and the result of
|
|
592
|
+
`defineModel()` for concrete model classes.
|
|
596
593
|
|
|
597
|
-
|
|
594
|
+
**Type:** `typeof ModelClassRuntime`
|
|
598
595
|
|
|
599
|
-
|
|
596
|
+
### AnyModelClass · [type](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L111)
|
|
600
597
|
|
|
601
|
-
|
|
598
|
+
A model constructor with its generic information erased.
|
|
602
599
|
|
|
603
|
-
|
|
600
|
+
Useful when accepting or storing arbitrary registered model classes.
|
|
604
601
|
|
|
605
|
-
|
|
602
|
+
**Type:** `ModelClass<new () => any, readonly any[], any, any>`
|
|
606
603
|
|
|
607
|
-
|
|
604
|
+
### ModelBase · [abstract class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
608
605
|
|
|
609
|
-
|
|
606
|
+
Base class for all database models in the Edinburgh ORM.
|
|
610
607
|
|
|
611
|
-
|
|
608
|
+
Models represent database entities with typed fields, automatic serialization,
|
|
609
|
+
change tracking, and relationship management. Model classes are created using
|
|
610
|
+
`E.defineModel()`.
|
|
612
611
|
|
|
613
|
-
|
|
612
|
+
### Schema Evolution
|
|
614
613
|
|
|
615
|
-
|
|
614
|
+
Edinburgh tracks the schema version of each model automatically. When you add, remove, or
|
|
615
|
+
change the types of fields, or add/remove indexes, Edinburgh detects the new schema version.
|
|
616
616
|
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
617
|
+
**Lazy migration:** Changes to non-key field values are migrated lazily, when a row with an
|
|
618
|
+
old schema version is read from disk, it is deserialized using the old schema and optionally
|
|
619
|
+
transformed by the static `migrate()` function. This happens transparently on every read
|
|
620
|
+
and requires no downtime or batch processing.
|
|
620
621
|
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
622
|
+
**Batch migration (via `npx migrate-edinburgh` or `runMigration()`):** Certain schema changes
|
|
623
|
+
require an explicit migration run:
|
|
624
|
+
- Adding or removing secondary/unique indexes
|
|
625
|
+
- Changing the fields or types of an existing index
|
|
626
|
+
- A `migrate()` function that changes values used in secondary index fields
|
|
624
627
|
|
|
625
|
-
|
|
626
|
-
|
|
628
|
+
The batch migration tool populates new indexes, deletes orphaned ones, and updates index
|
|
629
|
+
entries whose values were changed by `migrate()`. It does *not* rewrite primary data rows
|
|
630
|
+
(lazy migration handles that).
|
|
627
631
|
|
|
628
|
-
|
|
632
|
+
### Lifecycle Hooks
|
|
629
633
|
|
|
630
|
-
|
|
634
|
+
- **`static migrate(record)`**: Called when deserializing rows written with an older schema
|
|
635
|
+
version. Receives a plain record object; mutate it in-place to match the current schema.
|
|
631
636
|
|
|
632
|
-
-
|
|
637
|
+
- **`preCommit()`**: Called on each modified instance right before the transaction commits.
|
|
638
|
+
Useful for computing derived fields, enforcing cross-field invariants, or creating related
|
|
639
|
+
instances.
|
|
633
640
|
|
|
634
641
|
**Examples:**
|
|
635
642
|
|
|
636
643
|
```typescript
|
|
637
|
-
const User = E.defineModel(class {
|
|
644
|
+
const User = E.defineModel("User", class {
|
|
638
645
|
id = E.field(E.identifier);
|
|
639
646
|
name = E.field(E.string);
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
647
|
+
email = E.field(E.string);
|
|
648
|
+
}, {
|
|
649
|
+
pk: "id",
|
|
650
|
+
unique: { email: "email" },
|
|
651
|
+
});
|
|
652
|
+
// Optional: declare a companion type so `let u: User` works.
|
|
653
|
+
// Not needed if you only use `new User()`, `User.find()`, etc.
|
|
654
|
+
type User = InstanceType<typeof User>;
|
|
646
655
|
```
|
|
647
656
|
|
|
648
|
-
####
|
|
649
|
-
|
|
650
|
-
**Signature:** `(...args: any[]) => any`
|
|
651
|
-
|
|
652
|
-
**Parameters:**
|
|
653
|
-
|
|
654
|
-
- `args: any[]`
|
|
655
|
-
|
|
656
|
-
#### Model.getLazy · [static method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
657
|
-
|
|
658
|
-
**Signature:** `(...args: any[]) => any`
|
|
659
|
-
|
|
660
|
-
**Parameters:**
|
|
661
|
-
|
|
662
|
-
- `args: any[]`
|
|
663
|
-
|
|
664
|
-
#### Model.find · [static method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
665
|
-
|
|
666
|
-
**Signature:** `(opts?: any) => any`
|
|
657
|
+
#### ModelBase.migrate · [static method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
667
658
|
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
#### Model.batchProcess · [static method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
659
|
+
Optional migration function called when deserializing rows written with an older schema version.
|
|
660
|
+
Receives a plain record with all fields and should mutate it in-place to match the current schema.
|
|
661
|
+
It runs during lazy loading and during `runMigration()`. Changing this method creates a new schema version.
|
|
662
|
+
If it updates values used by secondary or unique indexes, those index entries are refreshed only by `runMigration()`.
|
|
673
663
|
|
|
674
|
-
**Signature:** `(
|
|
664
|
+
**Signature:** `(record: Record<string, any>) => void`
|
|
675
665
|
|
|
676
666
|
**Parameters:**
|
|
677
667
|
|
|
678
|
-
- `
|
|
679
|
-
- `callback?: any`
|
|
680
|
-
|
|
681
|
-
#### Model.replaceInto · [static method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
682
|
-
|
|
683
|
-
Load an existing instance by primary key and update it, or create a new one.
|
|
684
|
-
|
|
685
|
-
The provided object must contain all primary key fields. If a matching row exists,
|
|
686
|
-
the remaining properties from `obj` are set on the loaded instance. Otherwise a
|
|
687
|
-
new instance is created with `obj` as its initial properties.
|
|
668
|
+
- `record: Record<string, any>` - A plain object containing the row's field values from the older schema version.
|
|
688
669
|
|
|
689
|
-
**
|
|
690
|
-
|
|
691
|
-
**Parameters:**
|
|
670
|
+
**Examples:**
|
|
692
671
|
|
|
693
|
-
|
|
694
|
-
|
|
672
|
+
```typescript
|
|
673
|
+
const User = E.defineModel("User", class {
|
|
674
|
+
id = E.field(E.identifier);
|
|
675
|
+
name = E.field(E.string);
|
|
676
|
+
role = E.field(E.string);
|
|
695
677
|
|
|
696
|
-
|
|
678
|
+
static migrate(record: Record<string, any>) {
|
|
679
|
+
record.role ??= "user";
|
|
680
|
+
}
|
|
681
|
+
}, { pk: "id" });
|
|
682
|
+
```
|
|
697
683
|
|
|
698
|
-
####
|
|
684
|
+
#### modelBase.preCommit · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
699
685
|
|
|
700
686
|
Optional hook called on each modified instance right before the transaction commits.
|
|
701
687
|
Runs before data is written to disk, so changes made here are included in the commit.
|
|
@@ -711,7 +697,7 @@ Common use cases:
|
|
|
711
697
|
**Examples:**
|
|
712
698
|
|
|
713
699
|
```typescript
|
|
714
|
-
const Post = E.defineModel(class {
|
|
700
|
+
const Post = E.defineModel("Post", class {
|
|
715
701
|
id = E.field(E.identifier);
|
|
716
702
|
title = E.field(E.string);
|
|
717
703
|
slug = E.field(E.string);
|
|
@@ -722,19 +708,19 @@ const Post = E.defineModel(class {
|
|
|
722
708
|
}, { pk: "id" });
|
|
723
709
|
```
|
|
724
710
|
|
|
725
|
-
####
|
|
711
|
+
#### modelBase.getPrimaryKey · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
726
712
|
|
|
727
713
|
**Signature:** `() => Uint8Array<ArrayBufferLike>`
|
|
728
714
|
|
|
729
715
|
**Returns:** The primary key for this instance.
|
|
730
716
|
|
|
731
|
-
####
|
|
717
|
+
#### modelBase.getPrimaryKeyHash · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
732
718
|
|
|
733
719
|
**Signature:** `() => number`
|
|
734
720
|
|
|
735
721
|
**Returns:** A 53-bit positive integer non-cryptographic hash of the primary key, or undefined if not yet saved.
|
|
736
722
|
|
|
737
|
-
####
|
|
723
|
+
#### modelBase.isLazyField · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
738
724
|
|
|
739
725
|
**Signature:** `(field: keyof this) => boolean`
|
|
740
726
|
|
|
@@ -742,7 +728,7 @@ const Post = E.defineModel(class {
|
|
|
742
728
|
|
|
743
729
|
- `field: keyof this`
|
|
744
730
|
|
|
745
|
-
####
|
|
731
|
+
#### modelBase.preventPersist · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
746
732
|
|
|
747
733
|
Prevent this instance from being persisted to the database.
|
|
748
734
|
|
|
@@ -758,7 +744,7 @@ user.name = "New Name";
|
|
|
758
744
|
user.preventPersist(); // Changes won't be saved
|
|
759
745
|
```
|
|
760
746
|
|
|
761
|
-
####
|
|
747
|
+
#### modelBase.delete · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
762
748
|
|
|
763
749
|
Delete this model instance from the database.
|
|
764
750
|
|
|
@@ -773,7 +759,7 @@ const user = User.get("user123");
|
|
|
773
759
|
user.delete(); // Removes from database
|
|
774
760
|
```
|
|
775
761
|
|
|
776
|
-
####
|
|
762
|
+
#### modelBase.validate · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
777
763
|
|
|
778
764
|
Validate all fields in this model instance.
|
|
779
765
|
|
|
@@ -781,7 +767,7 @@ Validate all fields in this model instance.
|
|
|
781
767
|
|
|
782
768
|
**Parameters:**
|
|
783
769
|
|
|
784
|
-
- `raise: boolean` (optional) -
|
|
770
|
+
- `raise: boolean` (optional) - If true, throw on first validation error.
|
|
785
771
|
|
|
786
772
|
**Returns:** Array of validation errors (empty if valid).
|
|
787
773
|
|
|
@@ -795,7 +781,7 @@ if (errors.length > 0) {
|
|
|
795
781
|
}
|
|
796
782
|
```
|
|
797
783
|
|
|
798
|
-
####
|
|
784
|
+
#### modelBase.isValid · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
799
785
|
|
|
800
786
|
Check if this model instance is valid.
|
|
801
787
|
|
|
@@ -810,19 +796,19 @@ const user = new User({name: "John"});
|
|
|
810
796
|
if (!user.isValid()) shoutAtTheUser();
|
|
811
797
|
```
|
|
812
798
|
|
|
813
|
-
####
|
|
799
|
+
#### modelBase.getState · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
814
800
|
|
|
815
801
|
**Signature:** `() => "created" | "deleted" | "loaded" | "lazy"`
|
|
816
802
|
|
|
817
|
-
####
|
|
803
|
+
#### modelBase.toString · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
818
804
|
|
|
819
805
|
**Signature:** `() => string`
|
|
820
806
|
|
|
821
|
-
####
|
|
807
|
+
#### modelBase.[Symbol.for('nodejs.util.inspect.custom')] · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
822
808
|
|
|
823
809
|
**Signature:** `() => string`
|
|
824
810
|
|
|
825
|
-
### defineModel · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
811
|
+
### defineModel · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
826
812
|
|
|
827
813
|
Register a model class with the Edinburgh ORM system.
|
|
828
814
|
|
|
@@ -840,12 +826,22 @@ typed fields, primary key access, and optional secondary and unique indexes.
|
|
|
840
826
|
|
|
841
827
|
**Parameters:**
|
|
842
828
|
|
|
843
|
-
- `
|
|
844
|
-
- `
|
|
829
|
+
- `tableName: string` - The database table name for this model.
|
|
830
|
+
- `cls: T` - A plain class whose properties use E.field().
|
|
831
|
+
- `opts?: { pk?: PK, unique?: UNIQUE, index?: INDEX, override?: boolean }` - Registration options.
|
|
845
832
|
|
|
846
833
|
**Returns:** The enhanced model constructor.
|
|
847
834
|
|
|
848
|
-
###
|
|
835
|
+
### deleteEverything · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
836
|
+
|
|
837
|
+
Delete every key/value entry in the database and reinitialize all registered models.
|
|
838
|
+
|
|
839
|
+
This clears rows, index metadata, and schema-version records. It is mainly useful
|
|
840
|
+
for tests, local resets, or tooling that needs a completely empty database.
|
|
841
|
+
|
|
842
|
+
**Signature:** `() => Promise<void>`
|
|
843
|
+
|
|
844
|
+
### field · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L76)
|
|
849
845
|
|
|
850
846
|
Create a field definition for a model property.
|
|
851
847
|
|
|
@@ -861,27 +857,20 @@ This allows for both runtime introspection and compile-time type safety.
|
|
|
861
857
|
|
|
862
858
|
**Parameters:**
|
|
863
859
|
|
|
864
|
-
- `type: TypeWrapper<T>` -
|
|
865
|
-
- `options: Partial<FieldConfig<T>>` (optional) -
|
|
860
|
+
- `type: TypeWrapper<T>` - The type wrapper for this field.
|
|
861
|
+
- `options: Partial<FieldConfig<T>>` (optional) - Additional field configuration options.
|
|
866
862
|
|
|
867
863
|
**Returns:** The field value (typed as T, but actually returns FieldConfig<T>).
|
|
868
864
|
|
|
869
865
|
**Examples:**
|
|
870
866
|
|
|
871
867
|
```typescript
|
|
872
|
-
const User = E.defineModel(class {
|
|
868
|
+
const User = E.defineModel("User", class {
|
|
873
869
|
name = E.field(E.string, {description: "User's full name"});
|
|
874
870
|
age = E.field(E.opt(E.number), {description: "User's age", default: 25});
|
|
875
871
|
});
|
|
876
872
|
```
|
|
877
873
|
|
|
878
|
-
### currentTxn · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L21)
|
|
879
|
-
|
|
880
|
-
Returns the current transaction from AsyncLocalStorage.
|
|
881
|
-
Throws if called outside a transact() callback.
|
|
882
|
-
|
|
883
|
-
**Signature:** `() => Transaction`
|
|
884
|
-
|
|
885
874
|
### string · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
886
875
|
|
|
887
876
|
Type wrapper instance for the string type.
|
|
@@ -940,7 +929,7 @@ Create an optional type wrapper (allows undefined).
|
|
|
940
929
|
|
|
941
930
|
**Parameters:**
|
|
942
931
|
|
|
943
|
-
- `inner: T` -
|
|
932
|
+
- `inner: T` - The inner type to make optional.
|
|
944
933
|
|
|
945
934
|
**Returns:** A union type that accepts the inner type or undefined.
|
|
946
935
|
|
|
@@ -963,7 +952,7 @@ Create a union type wrapper from multiple type choices.
|
|
|
963
952
|
|
|
964
953
|
**Parameters:**
|
|
965
954
|
|
|
966
|
-
- `choices: T` -
|
|
955
|
+
- `choices: T` - The type choices for the union.
|
|
967
956
|
|
|
968
957
|
**Returns:** A union type instance.
|
|
969
958
|
|
|
@@ -986,8 +975,8 @@ Create an array type wrapper with optional length constraints.
|
|
|
986
975
|
|
|
987
976
|
**Parameters:**
|
|
988
977
|
|
|
989
|
-
- `inner: TypeWrapper<T>` -
|
|
990
|
-
- `opts: {min?: number, max?: number}` (optional) -
|
|
978
|
+
- `inner: TypeWrapper<T>` - Type wrapper for array elements.
|
|
979
|
+
- `opts: {min?: number, max?: number}` (optional) - Optional constraints (min/max length).
|
|
991
980
|
|
|
992
981
|
**Returns:** An array type instance.
|
|
993
982
|
|
|
@@ -1010,8 +999,8 @@ Create a Set type wrapper with optional length constraints.
|
|
|
1010
999
|
|
|
1011
1000
|
**Parameters:**
|
|
1012
1001
|
|
|
1013
|
-
- `inner: TypeWrapper<T>` -
|
|
1014
|
-
- `opts: {min?: number, max?: number}` (optional) -
|
|
1002
|
+
- `inner: TypeWrapper<T>` - Type wrapper for set elements.
|
|
1003
|
+
- `opts: {min?: number, max?: number}` (optional) - Optional constraints (min/max length).
|
|
1015
1004
|
|
|
1016
1005
|
**Returns:** A set type instance.
|
|
1017
1006
|
|
|
@@ -1034,7 +1023,7 @@ Create a Record type wrapper for key-value objects with string or number keys.
|
|
|
1034
1023
|
|
|
1035
1024
|
**Parameters:**
|
|
1036
1025
|
|
|
1037
|
-
- `inner: TypeWrapper<T>` -
|
|
1026
|
+
- `inner: TypeWrapper<T>` - Type wrapper for record values.
|
|
1038
1027
|
|
|
1039
1028
|
**Returns:** A record type instance.
|
|
1040
1029
|
|
|
@@ -1056,7 +1045,7 @@ Create a literal type wrapper for a constant value.
|
|
|
1056
1045
|
|
|
1057
1046
|
**Parameters:**
|
|
1058
1047
|
|
|
1059
|
-
- `value: T` -
|
|
1048
|
+
- `value: T` - The literal value.
|
|
1060
1049
|
|
|
1061
1050
|
**Returns:** A literal type instance.
|
|
1062
1051
|
|
|
@@ -1079,19 +1068,19 @@ Create a link type wrapper for model relationships.
|
|
|
1079
1068
|
|
|
1080
1069
|
**Parameters:**
|
|
1081
1070
|
|
|
1082
|
-
- `TargetModel: T` -
|
|
1071
|
+
- `TargetModel: T` - The model class this link points to.
|
|
1083
1072
|
|
|
1084
1073
|
**Returns:** A link type instance.
|
|
1085
1074
|
|
|
1086
1075
|
**Examples:**
|
|
1087
1076
|
|
|
1088
1077
|
```typescript
|
|
1089
|
-
const Author = E.defineModel(class {
|
|
1078
|
+
const Author = E.defineModel("Author", class {
|
|
1090
1079
|
id = E.field(E.identifier);
|
|
1091
1080
|
posts = E.field(E.array(E.link(() => Book)));
|
|
1092
1081
|
}, { pk: "id" });
|
|
1093
1082
|
|
|
1094
|
-
const Book = E.defineModel(class {
|
|
1083
|
+
const Book = E.defineModel("Book", class {
|
|
1095
1084
|
id = E.field(E.identifier);
|
|
1096
1085
|
author = E.field(E.link(Author));
|
|
1097
1086
|
}, { pk: "id" });
|
|
@@ -1099,135 +1088,195 @@ const Book = E.defineModel(class {
|
|
|
1099
1088
|
|
|
1100
1089
|
### dump · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
1101
1090
|
|
|
1102
|
-
|
|
1091
|
+
**Signature:** `() => void`
|
|
1092
|
+
|
|
1093
|
+
### FindOptions · [type](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L115)
|
|
1094
|
+
|
|
1095
|
+
Range-query options accepted by `find()`, `findBy()`, `batchProcess()`, and `batchProcessBy()`.
|
|
1096
|
+
|
|
1097
|
+
Supports exact-match lookups via `is`, inclusive bounds via `from` / `to`,
|
|
1098
|
+
exclusive bounds via `after` / `before`, and reverse scans.
|
|
1099
|
+
|
|
1100
|
+
For single-field indexes, values can be passed directly. For composite indexes,
|
|
1101
|
+
pass tuples or partial tuples for prefix matching.
|
|
1102
|
+
|
|
1103
|
+
**Type:** `(
|
|
1104
|
+
(
|
|
1105
|
+
{is: ArrayOrOnlyItem<ARG_TYPES>;} // Shortcut for setting `from` and `to` to the same value
|
|
1106
|
+
|
|
|
1107
|
+
(
|
|
1108
|
+
(
|
|
1109
|
+
{from: ArrayOrOnlyItem<ARG_TYPES>;}
|
|
1110
|
+
|
|
|
1111
|
+
{after: ArrayOrOnlyItem<ARG_TYPES>;}
|
|
1112
|
+
|
|
|
1113
|
+
{}
|
|
1114
|
+
)
|
|
1115
|
+
&
|
|
1116
|
+
(
|
|
1117
|
+
{to: ArrayOrOnlyItem<ARG_TYPES>;}
|
|
1118
|
+
|
|
|
1119
|
+
{before: ArrayOrOnlyItem<ARG_TYPES>;}
|
|
1120
|
+
|
|
|
1121
|
+
{}
|
|
1122
|
+
)
|
|
1123
|
+
)
|
|
1124
|
+
) &
|
|
1125
|
+
{
|
|
1126
|
+
reverse?: boolean;
|
|
1127
|
+
}
|
|
1128
|
+
& (FETCH extends undefined ? { fetch?: undefined } : { fetch: FETCH })
|
|
1129
|
+
)`
|
|
1130
|
+
|
|
1131
|
+
### IndexRangeIterator · [class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L73)
|
|
1132
|
+
|
|
1133
|
+
Iterator for range queries on indexes.
|
|
1134
|
+
Handles common iteration logic for both primary and unique indexes.
|
|
1135
|
+
Extends built-in Iterator to provide map/filter/reduce/toArray/etc.
|
|
1136
|
+
|
|
1137
|
+
**Type Parameters:**
|
|
1103
1138
|
|
|
1104
|
-
|
|
1105
|
-
This is primarily useful for development and debugging purposes.
|
|
1139
|
+
- `ITEM`
|
|
1106
1140
|
|
|
1107
|
-
|
|
1141
|
+
#### indexRangeIterator.[Symbol.iterator] · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L78)
|
|
1142
|
+
|
|
1143
|
+
**Signature:** `() => this`
|
|
1144
|
+
|
|
1145
|
+
#### indexRangeIterator.next · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L80)
|
|
1146
|
+
|
|
1147
|
+
**Signature:** `() => IteratorResult<ITEM, any>`
|
|
1108
1148
|
|
|
1109
|
-
|
|
1149
|
+
#### indexRangeIterator.count · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L102)
|
|
1150
|
+
|
|
1151
|
+
**Signature:** `() => number`
|
|
1152
|
+
|
|
1153
|
+
#### indexRangeIterator.fetch · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L105)
|
|
1154
|
+
|
|
1155
|
+
**Signature:** `() => ITEM`
|
|
1156
|
+
|
|
1157
|
+
### Change · [type](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L85)
|
|
1158
|
+
|
|
1159
|
+
**Type:** `Record<any, any> | "created" | "deleted"`
|
|
1110
1160
|
|
|
1111
|
-
|
|
1161
|
+
### FieldConfig · [interface](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L37)
|
|
1112
1162
|
|
|
1113
|
-
|
|
1163
|
+
Configuration interface for model fields.
|
|
1114
1164
|
|
|
1115
1165
|
**Type Parameters:**
|
|
1116
1166
|
|
|
1117
|
-
- `
|
|
1118
|
-
- `F extends readonly (keyof InstanceType<M> & string)[]` - The field names that make up this index.
|
|
1119
|
-
- `ARGS extends readonly any[] = IndexArgTypes<M, F>`
|
|
1167
|
+
- `T` - The field type.
|
|
1120
1168
|
|
|
1121
|
-
|
|
1169
|
+
#### fieldConfig.type · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L45)
|
|
1122
1170
|
|
|
1123
|
-
|
|
1124
|
-
- `_fieldNames`: - Array of field names that make up this index.
|
|
1171
|
+
The type wrapper that defines how this field is serialized/validated.
|
|
1125
1172
|
|
|
1126
|
-
|
|
1173
|
+
**Type:** `TypeWrapper<T>`
|
|
1127
1174
|
|
|
1128
|
-
|
|
1175
|
+
#### fieldConfig.description · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L47)
|
|
1129
1176
|
|
|
1130
|
-
|
|
1177
|
+
Optional human-readable description of the field.
|
|
1131
1178
|
|
|
1132
|
-
|
|
1179
|
+
**Type:** `string`
|
|
1133
1180
|
|
|
1134
|
-
####
|
|
1181
|
+
#### fieldConfig.default · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L49)
|
|
1135
1182
|
|
|
1136
|
-
|
|
1183
|
+
Optional default value or function that generates default values.
|
|
1137
1184
|
|
|
1138
|
-
**
|
|
1185
|
+
**Type:** `T | ((model: Record<string, any>) => T)`
|
|
1139
1186
|
|
|
1140
|
-
|
|
1187
|
+
### TypeWrapper · [abstract class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L33)
|
|
1141
1188
|
|
|
1142
|
-
|
|
1189
|
+
**Type Parameters:**
|
|
1143
1190
|
|
|
1144
|
-
|
|
1191
|
+
- `T` - The TypeScript type this wrapper represents.
|
|
1145
1192
|
|
|
1146
|
-
|
|
1193
|
+
#### typeWrapper.kind · [abstract property](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L47)
|
|
1147
1194
|
|
|
1148
|
-
|
|
1195
|
+
A string identifier for this type, used during serialization
|
|
1196
|
+
|
|
1197
|
+
**Type:** `string`
|
|
1149
1198
|
|
|
1150
|
-
####
|
|
1199
|
+
#### typeWrapper.serialize · [abstract method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L52)
|
|
1151
1200
|
|
|
1152
|
-
|
|
1201
|
+
Serialize a value from an object property to a Pack.
|
|
1202
|
+
|
|
1203
|
+
**Signature:** `(value: T, pack: DataPack) => void`
|
|
1153
1204
|
|
|
1154
1205
|
**Parameters:**
|
|
1155
1206
|
|
|
1156
|
-
- `
|
|
1207
|
+
- `value: T` - The value to serialize.
|
|
1208
|
+
- `pack: DataPack` - The Pack instance to write to.
|
|
1157
1209
|
|
|
1158
|
-
####
|
|
1210
|
+
#### typeWrapper.deserialize · [abstract method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L59)
|
|
1159
1211
|
|
|
1160
|
-
|
|
1212
|
+
Deserialize a value from a Pack into an object property.
|
|
1161
1213
|
|
|
1162
|
-
**Signature:** `(
|
|
1214
|
+
**Signature:** `(pack: DataPack) => T`
|
|
1163
1215
|
|
|
1164
1216
|
**Parameters:**
|
|
1165
1217
|
|
|
1166
|
-
- `
|
|
1167
|
-
- `callback: (row: InstanceType<M>) => void | Promise<void>` - - Called for each matching row within a transaction
|
|
1218
|
+
- `pack: DataPack` - The Pack instance to read from.
|
|
1168
1219
|
|
|
1169
|
-
####
|
|
1220
|
+
#### typeWrapper.getError · [abstract method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L64)
|
|
1170
1221
|
|
|
1171
|
-
|
|
1222
|
+
Validate a value.
|
|
1172
1223
|
|
|
1173
|
-
|
|
1224
|
+
**Signature:** `(value: T) => void | DatabaseError`
|
|
1174
1225
|
|
|
1175
|
-
|
|
1176
|
-
Provides shared key serialization, write/delete/update logic.
|
|
1226
|
+
**Parameters:**
|
|
1177
1227
|
|
|
1178
|
-
|
|
1228
|
+
- `value: T` - The value to validate.
|
|
1179
1229
|
|
|
1180
|
-
-
|
|
1181
|
-
- `F extends readonly (keyof InstanceType<M> & string)[]`
|
|
1182
|
-
- `ARGS extends readonly any[] = IndexArgTypes<M, F>`
|
|
1230
|
+
**Returns:** - A DatabaseError if validation fails.
|
|
1183
1231
|
|
|
1184
|
-
|
|
1232
|
+
#### typeWrapper.serializeType · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L68)
|
|
1185
1233
|
|
|
1186
|
-
|
|
1234
|
+
Serialize type metadata to a Pack (for schema serialization).
|
|
1187
1235
|
|
|
1188
|
-
**
|
|
1236
|
+
**Signature:** `(pack: DataPack) => void`
|
|
1237
|
+
|
|
1238
|
+
**Parameters:**
|
|
1189
1239
|
|
|
1190
|
-
- `
|
|
1191
|
-
- `F extends readonly (keyof InstanceType<M> & string)[]`
|
|
1192
|
-
- `ARGS extends readonly any[] = IndexArgTypes<M, F>`
|
|
1240
|
+
- `pack: DataPack` - The Pack instance to write to.
|
|
1193
1241
|
|
|
1194
|
-
####
|
|
1242
|
+
#### typeWrapper.containsNull · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L77)
|
|
1195
1243
|
|
|
1196
|
-
|
|
1244
|
+
Check if indexing should be skipped for this field value.
|
|
1245
|
+
|
|
1246
|
+
**Signature:** `(value: T) => boolean`
|
|
1197
1247
|
|
|
1198
1248
|
**Parameters:**
|
|
1199
1249
|
|
|
1200
|
-
- `
|
|
1250
|
+
- `value: T`
|
|
1201
1251
|
|
|
1202
|
-
|
|
1252
|
+
**Returns:** true if indexing should be skipped.
|
|
1203
1253
|
|
|
1204
|
-
|
|
1254
|
+
#### typeWrapper.toString · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L78)
|
|
1205
1255
|
|
|
1206
|
-
**
|
|
1256
|
+
**Signature:** `() => string`
|
|
1207
1257
|
|
|
1208
|
-
|
|
1209
|
-
- `F extends readonly (keyof InstanceType<M> & string)[]`
|
|
1210
|
-
- `ARGS extends readonly any[] = IndexArgTypes<M, F>`
|
|
1258
|
+
#### typeWrapper.clone · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L81)
|
|
1211
1259
|
|
|
1212
|
-
|
|
1260
|
+
**Signature:** `(value: T) => T`
|
|
1213
1261
|
|
|
1214
|
-
**
|
|
1262
|
+
**Parameters:**
|
|
1215
1263
|
|
|
1216
|
-
|
|
1264
|
+
- `value: T`
|
|
1217
1265
|
|
|
1218
|
-
####
|
|
1266
|
+
#### typeWrapper.equals · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L85)
|
|
1219
1267
|
|
|
1220
|
-
**
|
|
1268
|
+
**Signature:** `(value1: T, value2: T) => boolean`
|
|
1221
1269
|
|
|
1222
|
-
|
|
1270
|
+
**Parameters:**
|
|
1223
1271
|
|
|
1224
|
-
|
|
1272
|
+
- `value1: T`
|
|
1273
|
+
- `value2: T`
|
|
1225
1274
|
|
|
1226
|
-
####
|
|
1275
|
+
#### typeWrapper.getLinkedModel · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L90)
|
|
1227
1276
|
|
|
1228
|
-
**
|
|
1277
|
+
**Signature:** `() => AnyModelClass`
|
|
1229
1278
|
|
|
1230
|
-
### DatabaseError · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1279
|
+
### DatabaseError · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L174)
|
|
1231
1280
|
|
|
1232
1281
|
The DatabaseError class is used to represent errors that occur during database operations.
|
|
1233
1282
|
It extends the built-in Error class and has a machine readable error code string property.
|
|
@@ -1237,7 +1286,7 @@ Invalid function arguments will throw TypeError.
|
|
|
1237
1286
|
|
|
1238
1287
|
**Value:** `DatabaseErrorConstructor`
|
|
1239
1288
|
|
|
1240
|
-
### runMigration · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1289
|
+
### runMigration · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L121)
|
|
1241
1290
|
|
|
1242
1291
|
Run database migration: populate secondary indexes for old-version rows,
|
|
1243
1292
|
convert old primary indices, rewrite row data, and clean up orphaned indices.
|
|
@@ -1250,13 +1299,13 @@ convert old primary indices, rewrite row data, and clean up orphaned indices.
|
|
|
1250
1299
|
|
|
1251
1300
|
### MigrationOptions · [interface](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L13)
|
|
1252
1301
|
|
|
1253
|
-
#### migrationOptions.tables · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1302
|
+
#### migrationOptions.tables · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L18)
|
|
1254
1303
|
|
|
1255
1304
|
Limit migration to specific table names.
|
|
1256
1305
|
|
|
1257
1306
|
**Type:** `string[]`
|
|
1258
1307
|
|
|
1259
|
-
#### migrationOptions.populateSecondaries · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1308
|
+
#### migrationOptions.populateSecondaries · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L22)
|
|
1260
1309
|
|
|
1261
1310
|
Populate secondary indexes for rows at old schema versions (default: true).
|
|
1262
1311
|
|
|
@@ -1268,27 +1317,27 @@ Convert old primary indices when primary key fields changed (default: true).
|
|
|
1268
1317
|
|
|
1269
1318
|
**Type:** `boolean`
|
|
1270
1319
|
|
|
1271
|
-
#### migrationOptions.rewriteData · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1320
|
+
#### migrationOptions.rewriteData · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L38)
|
|
1272
1321
|
|
|
1273
1322
|
Rewrite all row data to the latest schema version (default: false).
|
|
1274
1323
|
|
|
1275
1324
|
**Type:** `boolean`
|
|
1276
1325
|
|
|
1277
|
-
#### migrationOptions.removeOrphans · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1326
|
+
#### migrationOptions.removeOrphans · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L45)
|
|
1278
1327
|
|
|
1279
1328
|
Delete orphaned secondary/unique index entries (default: true).
|
|
1280
1329
|
|
|
1281
1330
|
**Type:** `boolean`
|
|
1282
1331
|
|
|
1283
|
-
#### migrationOptions.onProgress · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1332
|
+
#### migrationOptions.onProgress · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L45)
|
|
1284
1333
|
|
|
1285
1334
|
Progress callback.
|
|
1286
1335
|
|
|
1287
1336
|
**Type:** `(info: ProgressInfo) => void`
|
|
1288
1337
|
|
|
1289
|
-
### MigrationResult · [interface](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1338
|
+
### MigrationResult · [interface](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L50)
|
|
1290
1339
|
|
|
1291
|
-
#### migrationResult.secondaries · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1340
|
+
#### migrationResult.secondaries · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L52)
|
|
1292
1341
|
|
|
1293
1342
|
Per-table counts of secondary index entries populated.
|
|
1294
1343
|
|
|
@@ -1300,21 +1349,35 @@ Per-table counts of old primary rows migrated.
|
|
|
1300
1349
|
|
|
1301
1350
|
**Type:** `Record<string, number>`
|
|
1302
1351
|
|
|
1303
|
-
#### migrationResult.conversionFailures · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1352
|
+
#### migrationResult.conversionFailures · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L59)
|
|
1304
1353
|
|
|
1305
1354
|
Per-table conversion failure counts by reason.
|
|
1306
1355
|
|
|
1307
1356
|
**Type:** `Record<string, Record<string, number>>`
|
|
1308
1357
|
|
|
1309
|
-
#### migrationResult.rewritten · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1358
|
+
#### migrationResult.rewritten · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L63)
|
|
1310
1359
|
|
|
1311
1360
|
Per-table counts of rows rewritten to latest version.
|
|
1312
1361
|
|
|
1313
1362
|
**Type:** `Record<string, number>`
|
|
1314
1363
|
|
|
1315
|
-
#### migrationResult.orphans · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1364
|
+
#### migrationResult.orphans · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L67)
|
|
1316
1365
|
|
|
1317
1366
|
Number of orphaned index entries deleted.
|
|
1318
1367
|
|
|
1319
1368
|
**Type:** `number`
|
|
1320
1369
|
|
|
1370
|
+
### Transaction · [interface](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L54)
|
|
1371
|
+
|
|
1372
|
+
#### transaction.id · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L55)
|
|
1373
|
+
|
|
1374
|
+
**Type:** `number`
|
|
1375
|
+
|
|
1376
|
+
#### transaction.instances · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L56)
|
|
1377
|
+
|
|
1378
|
+
**Type:** `Map<number, ModelBase>`
|
|
1379
|
+
|
|
1380
|
+
### txnStorage · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L59)
|
|
1381
|
+
|
|
1382
|
+
**Value:** `AsyncLocalStorage<Transaction>`
|
|
1383
|
+
|