edinburgh 0.5.0 → 0.6.0
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 +322 -262
- package/build/src/datapack.d.ts +9 -9
- package/build/src/datapack.js +9 -9
- package/build/src/edinburgh.d.ts +18 -7
- package/build/src/edinburgh.js +30 -51
- 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 +1 -1
- 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 +2 -2
- package/skill/transact.md +1 -1
- package/src/datapack.ts +9 -9
- package/src/edinburgh.ts +43 -52
- 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#L226)
|
|
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,121 @@ 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#L240)
|
|
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
|
+
### Model · [class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
573
581
|
|
|
574
|
-
**
|
|
582
|
+
**Type:** `typeof ModelBase`
|
|
575
583
|
|
|
576
|
-
###
|
|
584
|
+
### ModelClass · [class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
577
585
|
|
|
578
|
-
|
|
586
|
+
Runtime base constructor for model classes returned by `defineModel()`.
|
|
579
587
|
|
|
580
|
-
|
|
588
|
+
Prefer the `ModelClass` type alias for annotations and the result of
|
|
589
|
+
`defineModel()` for concrete model classes.
|
|
581
590
|
|
|
582
|
-
|
|
591
|
+
**Type:** `typeof ModelClassRuntime`
|
|
583
592
|
|
|
584
|
-
|
|
593
|
+
### AnyModelClass · [type](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L111)
|
|
585
594
|
|
|
586
|
-
|
|
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
|
-
```
|
|
596
|
-
|
|
597
|
-
#### Model.tableName · [static property](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
595
|
+
A model constructor with its generic information erased.
|
|
598
596
|
|
|
599
|
-
|
|
597
|
+
Useful when accepting or storing arbitrary registered model classes.
|
|
600
598
|
|
|
601
|
-
**Type:** `
|
|
599
|
+
**Type:** `ModelClass<new () => any, readonly any[], any, any>`
|
|
602
600
|
|
|
603
|
-
|
|
601
|
+
### ModelBase · [abstract class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
604
602
|
|
|
605
|
-
|
|
603
|
+
Base class for all database models in the Edinburgh ORM.
|
|
606
604
|
|
|
607
|
-
|
|
605
|
+
Models represent database entities with typed fields, automatic serialization,
|
|
606
|
+
change tracking, and relationship management. Model classes are created using
|
|
607
|
+
`E.defineModel()`.
|
|
608
608
|
|
|
609
|
-
|
|
609
|
+
### Schema Evolution
|
|
610
610
|
|
|
611
|
-
|
|
611
|
+
Edinburgh tracks the schema version of each model automatically. When you add, remove, or
|
|
612
|
+
change the types of fields, or add/remove indexes, Edinburgh detects the new schema version.
|
|
612
613
|
|
|
613
|
-
**
|
|
614
|
+
**Lazy migration:** Changes to non-key field values are migrated lazily, when a row with an
|
|
615
|
+
old schema version is read from disk, it is deserialized using the old schema and optionally
|
|
616
|
+
transformed by the static `migrate()` function. This happens transparently on every read
|
|
617
|
+
and requires no downtime or batch processing.
|
|
614
618
|
|
|
615
|
-
|
|
619
|
+
**Batch migration (via `npx migrate-edinburgh` or `runMigration()`):** Certain schema changes
|
|
620
|
+
require an explicit migration run:
|
|
621
|
+
- Adding or removing secondary/unique indexes
|
|
622
|
+
- Changing the fields or types of an existing index
|
|
623
|
+
- A `migrate()` function that changes values used in secondary index fields
|
|
616
624
|
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
625
|
+
The batch migration tool populates new indexes, deletes orphaned ones, and updates index
|
|
626
|
+
entries whose values were changed by `migrate()`. It does *not* rewrite primary data rows
|
|
627
|
+
(lazy migration handles that).
|
|
620
628
|
|
|
621
|
-
|
|
622
|
-
migration (via `runMigration()` / `npx migrate-edinburgh`). The function's source code is hashed
|
|
623
|
-
to detect changes. Modifying `migrate()` triggers a new schema version.
|
|
629
|
+
### Lifecycle Hooks
|
|
624
630
|
|
|
625
|
-
|
|
626
|
-
|
|
631
|
+
- **`static migrate(record)`**: Called when deserializing rows written with an older schema
|
|
632
|
+
version. Receives a plain record object; mutate it in-place to match the current schema.
|
|
627
633
|
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
- `record: Record<string, any>` - - A plain object with all field values from the old schema version.
|
|
634
|
+
- **`preCommit()`**: Called on each modified instance right before the transaction commits.
|
|
635
|
+
Useful for computing derived fields, enforcing cross-field invariants, or creating related
|
|
636
|
+
instances.
|
|
633
637
|
|
|
634
638
|
**Examples:**
|
|
635
639
|
|
|
636
640
|
```typescript
|
|
637
|
-
const User = E.defineModel(class {
|
|
641
|
+
const User = E.defineModel("User", class {
|
|
638
642
|
id = E.field(E.identifier);
|
|
639
643
|
name = E.field(E.string);
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
644
|
+
email = E.field(E.string);
|
|
645
|
+
}, {
|
|
646
|
+
pk: "id",
|
|
647
|
+
unique: { email: "email" },
|
|
648
|
+
});
|
|
649
|
+
// Optional: declare a companion type so `let u: User` works.
|
|
650
|
+
// Not needed if you only use `new User()`, `User.find()`, etc.
|
|
651
|
+
type User = InstanceType<typeof User>;
|
|
646
652
|
```
|
|
647
653
|
|
|
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`
|
|
654
|
+
#### ModelBase.migrate · [static method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
667
655
|
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
#### Model.batchProcess · [static method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
656
|
+
Optional migration function called when deserializing rows written with an older schema version.
|
|
657
|
+
Receives a plain record with all fields and should mutate it in-place to match the current schema.
|
|
658
|
+
It runs during lazy loading and during `runMigration()`. Changing this method creates a new schema version.
|
|
659
|
+
If it updates values used by secondary or unique indexes, those index entries are refreshed only by `runMigration()`.
|
|
673
660
|
|
|
674
|
-
**Signature:** `(
|
|
661
|
+
**Signature:** `(record: Record<string, any>) => void`
|
|
675
662
|
|
|
676
663
|
**Parameters:**
|
|
677
664
|
|
|
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.
|
|
665
|
+
- `record: Record<string, any>` - A plain object containing the row's field values from the older schema version.
|
|
688
666
|
|
|
689
|
-
**
|
|
690
|
-
|
|
691
|
-
**Parameters:**
|
|
667
|
+
**Examples:**
|
|
692
668
|
|
|
693
|
-
|
|
694
|
-
|
|
669
|
+
```typescript
|
|
670
|
+
const User = E.defineModel("User", class {
|
|
671
|
+
id = E.field(E.identifier);
|
|
672
|
+
name = E.field(E.string);
|
|
673
|
+
role = E.field(E.string);
|
|
695
674
|
|
|
696
|
-
|
|
675
|
+
static migrate(record: Record<string, any>) {
|
|
676
|
+
record.role ??= "user";
|
|
677
|
+
}
|
|
678
|
+
}, { pk: "id" });
|
|
679
|
+
```
|
|
697
680
|
|
|
698
|
-
####
|
|
681
|
+
#### modelBase.preCommit · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
699
682
|
|
|
700
683
|
Optional hook called on each modified instance right before the transaction commits.
|
|
701
684
|
Runs before data is written to disk, so changes made here are included in the commit.
|
|
@@ -711,7 +694,7 @@ Common use cases:
|
|
|
711
694
|
**Examples:**
|
|
712
695
|
|
|
713
696
|
```typescript
|
|
714
|
-
const Post = E.defineModel(class {
|
|
697
|
+
const Post = E.defineModel("Post", class {
|
|
715
698
|
id = E.field(E.identifier);
|
|
716
699
|
title = E.field(E.string);
|
|
717
700
|
slug = E.field(E.string);
|
|
@@ -722,19 +705,19 @@ const Post = E.defineModel(class {
|
|
|
722
705
|
}, { pk: "id" });
|
|
723
706
|
```
|
|
724
707
|
|
|
725
|
-
####
|
|
708
|
+
#### modelBase.getPrimaryKey · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
726
709
|
|
|
727
710
|
**Signature:** `() => Uint8Array<ArrayBufferLike>`
|
|
728
711
|
|
|
729
712
|
**Returns:** The primary key for this instance.
|
|
730
713
|
|
|
731
|
-
####
|
|
714
|
+
#### modelBase.getPrimaryKeyHash · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
732
715
|
|
|
733
716
|
**Signature:** `() => number`
|
|
734
717
|
|
|
735
718
|
**Returns:** A 53-bit positive integer non-cryptographic hash of the primary key, or undefined if not yet saved.
|
|
736
719
|
|
|
737
|
-
####
|
|
720
|
+
#### modelBase.isLazyField · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
738
721
|
|
|
739
722
|
**Signature:** `(field: keyof this) => boolean`
|
|
740
723
|
|
|
@@ -742,7 +725,7 @@ const Post = E.defineModel(class {
|
|
|
742
725
|
|
|
743
726
|
- `field: keyof this`
|
|
744
727
|
|
|
745
|
-
####
|
|
728
|
+
#### modelBase.preventPersist · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
746
729
|
|
|
747
730
|
Prevent this instance from being persisted to the database.
|
|
748
731
|
|
|
@@ -758,7 +741,7 @@ user.name = "New Name";
|
|
|
758
741
|
user.preventPersist(); // Changes won't be saved
|
|
759
742
|
```
|
|
760
743
|
|
|
761
|
-
####
|
|
744
|
+
#### modelBase.delete · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
762
745
|
|
|
763
746
|
Delete this model instance from the database.
|
|
764
747
|
|
|
@@ -773,7 +756,7 @@ const user = User.get("user123");
|
|
|
773
756
|
user.delete(); // Removes from database
|
|
774
757
|
```
|
|
775
758
|
|
|
776
|
-
####
|
|
759
|
+
#### modelBase.validate · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
777
760
|
|
|
778
761
|
Validate all fields in this model instance.
|
|
779
762
|
|
|
@@ -781,7 +764,7 @@ Validate all fields in this model instance.
|
|
|
781
764
|
|
|
782
765
|
**Parameters:**
|
|
783
766
|
|
|
784
|
-
- `raise: boolean` (optional) -
|
|
767
|
+
- `raise: boolean` (optional) - If true, throw on first validation error.
|
|
785
768
|
|
|
786
769
|
**Returns:** Array of validation errors (empty if valid).
|
|
787
770
|
|
|
@@ -795,7 +778,7 @@ if (errors.length > 0) {
|
|
|
795
778
|
}
|
|
796
779
|
```
|
|
797
780
|
|
|
798
|
-
####
|
|
781
|
+
#### modelBase.isValid · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
799
782
|
|
|
800
783
|
Check if this model instance is valid.
|
|
801
784
|
|
|
@@ -810,19 +793,19 @@ const user = new User({name: "John"});
|
|
|
810
793
|
if (!user.isValid()) shoutAtTheUser();
|
|
811
794
|
```
|
|
812
795
|
|
|
813
|
-
####
|
|
796
|
+
#### modelBase.getState · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
814
797
|
|
|
815
798
|
**Signature:** `() => "created" | "deleted" | "loaded" | "lazy"`
|
|
816
799
|
|
|
817
|
-
####
|
|
800
|
+
#### modelBase.toString · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
818
801
|
|
|
819
802
|
**Signature:** `() => string`
|
|
820
803
|
|
|
821
|
-
####
|
|
804
|
+
#### modelBase.[Symbol.for('nodejs.util.inspect.custom')] · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
822
805
|
|
|
823
806
|
**Signature:** `() => string`
|
|
824
807
|
|
|
825
|
-
### defineModel · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
808
|
+
### defineModel · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
826
809
|
|
|
827
810
|
Register a model class with the Edinburgh ORM system.
|
|
828
811
|
|
|
@@ -840,12 +823,22 @@ typed fields, primary key access, and optional secondary and unique indexes.
|
|
|
840
823
|
|
|
841
824
|
**Parameters:**
|
|
842
825
|
|
|
843
|
-
- `
|
|
844
|
-
- `
|
|
826
|
+
- `tableName: string` - The database table name for this model.
|
|
827
|
+
- `cls: T` - A plain class whose properties use E.field().
|
|
828
|
+
- `opts?: { pk?: PK, unique?: UNIQUE, index?: INDEX, override?: boolean }` - Registration options.
|
|
845
829
|
|
|
846
830
|
**Returns:** The enhanced model constructor.
|
|
847
831
|
|
|
848
|
-
###
|
|
832
|
+
### deleteEverything · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
833
|
+
|
|
834
|
+
Delete every key/value entry in the database and reinitialize all registered models.
|
|
835
|
+
|
|
836
|
+
This clears rows, index metadata, and schema-version records. It is mainly useful
|
|
837
|
+
for tests, local resets, or tooling that needs a completely empty database.
|
|
838
|
+
|
|
839
|
+
**Signature:** `() => Promise<void>`
|
|
840
|
+
|
|
841
|
+
### field · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L76)
|
|
849
842
|
|
|
850
843
|
Create a field definition for a model property.
|
|
851
844
|
|
|
@@ -861,34 +854,27 @@ This allows for both runtime introspection and compile-time type safety.
|
|
|
861
854
|
|
|
862
855
|
**Parameters:**
|
|
863
856
|
|
|
864
|
-
- `type: TypeWrapper<T>` -
|
|
865
|
-
- `options: Partial<FieldConfig<T>>` (optional) -
|
|
857
|
+
- `type: TypeWrapper<T>` - The type wrapper for this field.
|
|
858
|
+
- `options: Partial<FieldConfig<T>>` (optional) - Additional field configuration options.
|
|
866
859
|
|
|
867
860
|
**Returns:** The field value (typed as T, but actually returns FieldConfig<T>).
|
|
868
861
|
|
|
869
862
|
**Examples:**
|
|
870
863
|
|
|
871
864
|
```typescript
|
|
872
|
-
const User = E.defineModel(class {
|
|
865
|
+
const User = E.defineModel("User", class {
|
|
873
866
|
name = E.field(E.string, {description: "User's full name"});
|
|
874
867
|
age = E.field(E.opt(E.number), {description: "User's age", default: 25});
|
|
875
868
|
});
|
|
876
869
|
```
|
|
877
870
|
|
|
878
|
-
###
|
|
879
|
-
|
|
880
|
-
Returns the current transaction from AsyncLocalStorage.
|
|
881
|
-
Throws if called outside a transact() callback.
|
|
882
|
-
|
|
883
|
-
**Signature:** `() => Transaction`
|
|
884
|
-
|
|
885
|
-
### string · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
|
|
871
|
+
### string · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
886
872
|
|
|
887
873
|
Type wrapper instance for the string type.
|
|
888
874
|
|
|
889
875
|
**Value:** `TypeWrapper<string>`
|
|
890
876
|
|
|
891
|
-
### orderedString · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
877
|
+
### orderedString · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
892
878
|
|
|
893
879
|
Type wrapper instance for the ordered string type, which is just like a string
|
|
894
880
|
except that it sorts lexicographically in the database (instead of by incrementing
|
|
@@ -898,37 +884,37 @@ may not contain null characters.
|
|
|
898
884
|
|
|
899
885
|
**Value:** `TypeWrapper<string>`
|
|
900
886
|
|
|
901
|
-
### number · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
887
|
+
### number · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
902
888
|
|
|
903
889
|
Type wrapper instance for the number type.
|
|
904
890
|
|
|
905
891
|
**Value:** `TypeWrapper<number>`
|
|
906
892
|
|
|
907
|
-
### dateTime · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
893
|
+
### dateTime · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
908
894
|
|
|
909
895
|
Type wrapper instance for the date/time type. Stored without timezone info, rounded to whole seconds.
|
|
910
896
|
|
|
911
897
|
**Value:** `TypeWrapper<Date>`
|
|
912
898
|
|
|
913
|
-
### boolean · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
899
|
+
### boolean · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
914
900
|
|
|
915
901
|
Type wrapper instance for the boolean type.
|
|
916
902
|
|
|
917
903
|
**Value:** `TypeWrapper<boolean>`
|
|
918
904
|
|
|
919
|
-
### identifier · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
905
|
+
### identifier · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
920
906
|
|
|
921
907
|
Type wrapper instance for the identifier type.
|
|
922
908
|
|
|
923
909
|
**Value:** `TypeWrapper<string>`
|
|
924
910
|
|
|
925
|
-
### undef · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
911
|
+
### undef · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
926
912
|
|
|
927
913
|
Type wrapper instance for the 'undefined' type.
|
|
928
914
|
|
|
929
915
|
**Value:** `TypeWrapper<undefined>`
|
|
930
916
|
|
|
931
|
-
### opt · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
917
|
+
### opt · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
932
918
|
|
|
933
919
|
Create an optional type wrapper (allows undefined).
|
|
934
920
|
|
|
@@ -940,7 +926,7 @@ Create an optional type wrapper (allows undefined).
|
|
|
940
926
|
|
|
941
927
|
**Parameters:**
|
|
942
928
|
|
|
943
|
-
- `inner: T` -
|
|
929
|
+
- `inner: T` - The inner type to make optional.
|
|
944
930
|
|
|
945
931
|
**Returns:** A union type that accepts the inner type or undefined.
|
|
946
932
|
|
|
@@ -951,7 +937,7 @@ const optionalString = E.opt(E.string);
|
|
|
951
937
|
const optionalNumber = E.opt(E.number);
|
|
952
938
|
```
|
|
953
939
|
|
|
954
|
-
### or · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
940
|
+
### or · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
955
941
|
|
|
956
942
|
Create a union type wrapper from multiple type choices.
|
|
957
943
|
|
|
@@ -963,7 +949,7 @@ Create a union type wrapper from multiple type choices.
|
|
|
963
949
|
|
|
964
950
|
**Parameters:**
|
|
965
951
|
|
|
966
|
-
- `choices: T` -
|
|
952
|
+
- `choices: T` - The type choices for the union.
|
|
967
953
|
|
|
968
954
|
**Returns:** A union type instance.
|
|
969
955
|
|
|
@@ -974,7 +960,7 @@ const stringOrNumber = E.or(E.string, E.number);
|
|
|
974
960
|
const status = E.or("active", "inactive", "pending");
|
|
975
961
|
```
|
|
976
962
|
|
|
977
|
-
### array · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
963
|
+
### array · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
978
964
|
|
|
979
965
|
Create an array type wrapper with optional length constraints.
|
|
980
966
|
|
|
@@ -986,8 +972,8 @@ Create an array type wrapper with optional length constraints.
|
|
|
986
972
|
|
|
987
973
|
**Parameters:**
|
|
988
974
|
|
|
989
|
-
- `inner: TypeWrapper<T>` -
|
|
990
|
-
- `opts: {min?: number, max?: number}` (optional) -
|
|
975
|
+
- `inner: TypeWrapper<T>` - Type wrapper for array elements.
|
|
976
|
+
- `opts: {min?: number, max?: number}` (optional) - Optional constraints (min/max length).
|
|
991
977
|
|
|
992
978
|
**Returns:** An array type instance.
|
|
993
979
|
|
|
@@ -998,7 +984,7 @@ const stringArray = E.array(E.string);
|
|
|
998
984
|
const boundedArray = E.array(E.number, {min: 1, max: 10});
|
|
999
985
|
```
|
|
1000
986
|
|
|
1001
|
-
### set · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
987
|
+
### set · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
1002
988
|
|
|
1003
989
|
Create a Set type wrapper with optional length constraints.
|
|
1004
990
|
|
|
@@ -1010,8 +996,8 @@ Create a Set type wrapper with optional length constraints.
|
|
|
1010
996
|
|
|
1011
997
|
**Parameters:**
|
|
1012
998
|
|
|
1013
|
-
- `inner: TypeWrapper<T>` -
|
|
1014
|
-
- `opts: {min?: number, max?: number}` (optional) -
|
|
999
|
+
- `inner: TypeWrapper<T>` - Type wrapper for set elements.
|
|
1000
|
+
- `opts: {min?: number, max?: number}` (optional) - Optional constraints (min/max length).
|
|
1015
1001
|
|
|
1016
1002
|
**Returns:** A set type instance.
|
|
1017
1003
|
|
|
@@ -1022,7 +1008,7 @@ const stringSet = E.set(E.string);
|
|
|
1022
1008
|
const boundedSet = E.set(E.number, {min: 1, max: 10});
|
|
1023
1009
|
```
|
|
1024
1010
|
|
|
1025
|
-
### record · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1011
|
+
### record · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
1026
1012
|
|
|
1027
1013
|
Create a Record type wrapper for key-value objects with string or number keys.
|
|
1028
1014
|
|
|
@@ -1034,7 +1020,7 @@ Create a Record type wrapper for key-value objects with string or number keys.
|
|
|
1034
1020
|
|
|
1035
1021
|
**Parameters:**
|
|
1036
1022
|
|
|
1037
|
-
- `inner: TypeWrapper<T>` -
|
|
1023
|
+
- `inner: TypeWrapper<T>` - Type wrapper for record values.
|
|
1038
1024
|
|
|
1039
1025
|
**Returns:** A record type instance.
|
|
1040
1026
|
|
|
@@ -1044,7 +1030,7 @@ Create a Record type wrapper for key-value objects with string or number keys.
|
|
|
1044
1030
|
const scores = E.record(E.number); // Record<string | number, number>
|
|
1045
1031
|
```
|
|
1046
1032
|
|
|
1047
|
-
### literal · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1033
|
+
### literal · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
1048
1034
|
|
|
1049
1035
|
Create a literal type wrapper for a constant value.
|
|
1050
1036
|
|
|
@@ -1056,7 +1042,7 @@ Create a literal type wrapper for a constant value.
|
|
|
1056
1042
|
|
|
1057
1043
|
**Parameters:**
|
|
1058
1044
|
|
|
1059
|
-
- `value: T` -
|
|
1045
|
+
- `value: T` - The literal value.
|
|
1060
1046
|
|
|
1061
1047
|
**Returns:** A literal type instance.
|
|
1062
1048
|
|
|
@@ -1067,7 +1053,7 @@ const statusType = E.literal("active");
|
|
|
1067
1053
|
const countType = E.literal(42);
|
|
1068
1054
|
```
|
|
1069
1055
|
|
|
1070
|
-
### link · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1056
|
+
### link · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
1071
1057
|
|
|
1072
1058
|
Create a link type wrapper for model relationships.
|
|
1073
1059
|
|
|
@@ -1079,155 +1065,215 @@ Create a link type wrapper for model relationships.
|
|
|
1079
1065
|
|
|
1080
1066
|
**Parameters:**
|
|
1081
1067
|
|
|
1082
|
-
- `TargetModel: T` -
|
|
1068
|
+
- `TargetModel: T` - The model class this link points to.
|
|
1083
1069
|
|
|
1084
1070
|
**Returns:** A link type instance.
|
|
1085
1071
|
|
|
1086
1072
|
**Examples:**
|
|
1087
1073
|
|
|
1088
1074
|
```typescript
|
|
1089
|
-
const Author = E.defineModel(class {
|
|
1075
|
+
const Author = E.defineModel("Author", class {
|
|
1090
1076
|
id = E.field(E.identifier);
|
|
1091
1077
|
posts = E.field(E.array(E.link(() => Book)));
|
|
1092
1078
|
}, { pk: "id" });
|
|
1093
1079
|
|
|
1094
|
-
const Book = E.defineModel(class {
|
|
1080
|
+
const Book = E.defineModel("Book", class {
|
|
1095
1081
|
id = E.field(E.identifier);
|
|
1096
1082
|
author = E.field(E.link(Author));
|
|
1097
1083
|
}, { pk: "id" });
|
|
1098
1084
|
```
|
|
1099
1085
|
|
|
1100
|
-
### dump · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1086
|
+
### dump · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
|
|
1087
|
+
|
|
1088
|
+
**Signature:** `() => void`
|
|
1089
|
+
|
|
1090
|
+
### FindOptions · [type](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L115)
|
|
1091
|
+
|
|
1092
|
+
Range-query options accepted by `find()`, `findBy()`, `batchProcess()`, and `batchProcessBy()`.
|
|
1093
|
+
|
|
1094
|
+
Supports exact-match lookups via `is`, inclusive bounds via `from` / `to`,
|
|
1095
|
+
exclusive bounds via `after` / `before`, and reverse scans.
|
|
1096
|
+
|
|
1097
|
+
For single-field indexes, values can be passed directly. For composite indexes,
|
|
1098
|
+
pass tuples or partial tuples for prefix matching.
|
|
1099
|
+
|
|
1100
|
+
**Type:** `(
|
|
1101
|
+
(
|
|
1102
|
+
{is: ArrayOrOnlyItem<ARG_TYPES>;} // Shortcut for setting `from` and `to` to the same value
|
|
1103
|
+
|
|
|
1104
|
+
(
|
|
1105
|
+
(
|
|
1106
|
+
{from: ArrayOrOnlyItem<ARG_TYPES>;}
|
|
1107
|
+
|
|
|
1108
|
+
{after: ArrayOrOnlyItem<ARG_TYPES>;}
|
|
1109
|
+
|
|
|
1110
|
+
{}
|
|
1111
|
+
)
|
|
1112
|
+
&
|
|
1113
|
+
(
|
|
1114
|
+
{to: ArrayOrOnlyItem<ARG_TYPES>;}
|
|
1115
|
+
|
|
|
1116
|
+
{before: ArrayOrOnlyItem<ARG_TYPES>;}
|
|
1117
|
+
|
|
|
1118
|
+
{}
|
|
1119
|
+
)
|
|
1120
|
+
)
|
|
1121
|
+
) &
|
|
1122
|
+
{
|
|
1123
|
+
reverse?: boolean;
|
|
1124
|
+
}
|
|
1125
|
+
& (FETCH extends undefined ? { fetch?: undefined } : { fetch: FETCH })
|
|
1126
|
+
)`
|
|
1127
|
+
|
|
1128
|
+
### IndexRangeIterator · [class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L73)
|
|
1129
|
+
|
|
1130
|
+
Iterator for range queries on indexes.
|
|
1131
|
+
Handles common iteration logic for both primary and unique indexes.
|
|
1132
|
+
Extends built-in Iterator to provide map/filter/reduce/toArray/etc.
|
|
1101
1133
|
|
|
1102
|
-
|
|
1134
|
+
**Type Parameters:**
|
|
1103
1135
|
|
|
1104
|
-
|
|
1105
|
-
This is primarily useful for development and debugging purposes.
|
|
1136
|
+
- `ITEM`
|
|
1106
1137
|
|
|
1107
|
-
|
|
1138
|
+
#### indexRangeIterator.[Symbol.iterator] · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L78)
|
|
1139
|
+
|
|
1140
|
+
**Signature:** `() => this`
|
|
1141
|
+
|
|
1142
|
+
#### indexRangeIterator.next · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L80)
|
|
1143
|
+
|
|
1144
|
+
**Signature:** `() => IteratorResult<ITEM, any>`
|
|
1108
1145
|
|
|
1109
|
-
|
|
1146
|
+
#### indexRangeIterator.count · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L102)
|
|
1147
|
+
|
|
1148
|
+
**Signature:** `() => number`
|
|
1149
|
+
|
|
1150
|
+
#### indexRangeIterator.fetch · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L105)
|
|
1151
|
+
|
|
1152
|
+
**Signature:** `() => ITEM`
|
|
1153
|
+
|
|
1154
|
+
### Change · [type](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L85)
|
|
1155
|
+
|
|
1156
|
+
**Type:** `Record<any, any> | "created" | "deleted"`
|
|
1110
1157
|
|
|
1111
|
-
|
|
1158
|
+
### FieldConfig · [interface](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L37)
|
|
1112
1159
|
|
|
1113
|
-
|
|
1160
|
+
Configuration interface for model fields.
|
|
1114
1161
|
|
|
1115
1162
|
**Type Parameters:**
|
|
1116
1163
|
|
|
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>`
|
|
1164
|
+
- `T` - The field type.
|
|
1120
1165
|
|
|
1121
|
-
|
|
1166
|
+
#### fieldConfig.type · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L45)
|
|
1122
1167
|
|
|
1123
|
-
|
|
1124
|
-
- `_fieldNames`: - Array of field names that make up this index.
|
|
1168
|
+
The type wrapper that defines how this field is serialized/validated.
|
|
1125
1169
|
|
|
1126
|
-
|
|
1170
|
+
**Type:** `TypeWrapper<T>`
|
|
1127
1171
|
|
|
1128
|
-
|
|
1172
|
+
#### fieldConfig.description · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L47)
|
|
1129
1173
|
|
|
1130
|
-
|
|
1174
|
+
Optional human-readable description of the field.
|
|
1131
1175
|
|
|
1132
|
-
|
|
1176
|
+
**Type:** `string`
|
|
1133
1177
|
|
|
1134
|
-
####
|
|
1178
|
+
#### fieldConfig.default · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L49)
|
|
1135
1179
|
|
|
1136
|
-
|
|
1180
|
+
Optional default value or function that generates default values.
|
|
1137
1181
|
|
|
1138
|
-
**
|
|
1182
|
+
**Type:** `T | ((model: Record<string, any>) => T)`
|
|
1139
1183
|
|
|
1140
|
-
|
|
1184
|
+
### TypeWrapper · [abstract class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L33)
|
|
1141
1185
|
|
|
1142
|
-
|
|
1186
|
+
**Type Parameters:**
|
|
1143
1187
|
|
|
1144
|
-
|
|
1188
|
+
- `T` - The TypeScript type this wrapper represents.
|
|
1145
1189
|
|
|
1146
|
-
|
|
1190
|
+
#### typeWrapper.kind · [abstract property](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L47)
|
|
1147
1191
|
|
|
1148
|
-
|
|
1192
|
+
A string identifier for this type, used during serialization
|
|
1193
|
+
|
|
1194
|
+
**Type:** `string`
|
|
1149
1195
|
|
|
1150
|
-
####
|
|
1196
|
+
#### typeWrapper.serialize · [abstract method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L52)
|
|
1151
1197
|
|
|
1152
|
-
|
|
1198
|
+
Serialize a value from an object property to a Pack.
|
|
1199
|
+
|
|
1200
|
+
**Signature:** `(value: T, pack: DataPack) => void`
|
|
1153
1201
|
|
|
1154
1202
|
**Parameters:**
|
|
1155
1203
|
|
|
1156
|
-
- `
|
|
1204
|
+
- `value: T` - The value to serialize.
|
|
1205
|
+
- `pack: DataPack` - The Pack instance to write to.
|
|
1157
1206
|
|
|
1158
|
-
####
|
|
1207
|
+
#### typeWrapper.deserialize · [abstract method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L59)
|
|
1159
1208
|
|
|
1160
|
-
|
|
1209
|
+
Deserialize a value from a Pack into an object property.
|
|
1161
1210
|
|
|
1162
|
-
**Signature:** `(
|
|
1211
|
+
**Signature:** `(pack: DataPack) => T`
|
|
1163
1212
|
|
|
1164
1213
|
**Parameters:**
|
|
1165
1214
|
|
|
1166
|
-
- `
|
|
1167
|
-
- `callback: (row: InstanceType<M>) => void | Promise<void>` - - Called for each matching row within a transaction
|
|
1215
|
+
- `pack: DataPack` - The Pack instance to read from.
|
|
1168
1216
|
|
|
1169
|
-
####
|
|
1217
|
+
#### typeWrapper.getError · [abstract method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L64)
|
|
1170
1218
|
|
|
1171
|
-
|
|
1219
|
+
Validate a value.
|
|
1172
1220
|
|
|
1173
|
-
|
|
1221
|
+
**Signature:** `(value: T) => void | DatabaseError`
|
|
1174
1222
|
|
|
1175
|
-
|
|
1176
|
-
Provides shared key serialization, write/delete/update logic.
|
|
1223
|
+
**Parameters:**
|
|
1177
1224
|
|
|
1178
|
-
|
|
1225
|
+
- `value: T` - The value to validate.
|
|
1179
1226
|
|
|
1180
|
-
-
|
|
1181
|
-
- `F extends readonly (keyof InstanceType<M> & string)[]`
|
|
1182
|
-
- `ARGS extends readonly any[] = IndexArgTypes<M, F>`
|
|
1227
|
+
**Returns:** - A DatabaseError if validation fails.
|
|
1183
1228
|
|
|
1184
|
-
|
|
1229
|
+
#### typeWrapper.serializeType · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L68)
|
|
1185
1230
|
|
|
1186
|
-
|
|
1231
|
+
Serialize type metadata to a Pack (for schema serialization).
|
|
1187
1232
|
|
|
1188
|
-
**
|
|
1233
|
+
**Signature:** `(pack: DataPack) => void`
|
|
1234
|
+
|
|
1235
|
+
**Parameters:**
|
|
1189
1236
|
|
|
1190
|
-
- `
|
|
1191
|
-
- `F extends readonly (keyof InstanceType<M> & string)[]`
|
|
1192
|
-
- `ARGS extends readonly any[] = IndexArgTypes<M, F>`
|
|
1237
|
+
- `pack: DataPack` - The Pack instance to write to.
|
|
1193
1238
|
|
|
1194
|
-
####
|
|
1239
|
+
#### typeWrapper.containsNull · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L77)
|
|
1195
1240
|
|
|
1196
|
-
|
|
1241
|
+
Check if indexing should be skipped for this field value.
|
|
1242
|
+
|
|
1243
|
+
**Signature:** `(value: T) => boolean`
|
|
1197
1244
|
|
|
1198
1245
|
**Parameters:**
|
|
1199
1246
|
|
|
1200
|
-
- `
|
|
1247
|
+
- `value: T`
|
|
1201
1248
|
|
|
1202
|
-
|
|
1249
|
+
**Returns:** true if indexing should be skipped.
|
|
1203
1250
|
|
|
1204
|
-
|
|
1251
|
+
#### typeWrapper.toString · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L78)
|
|
1205
1252
|
|
|
1206
|
-
**
|
|
1253
|
+
**Signature:** `() => string`
|
|
1207
1254
|
|
|
1208
|
-
|
|
1209
|
-
- `F extends readonly (keyof InstanceType<M> & string)[]`
|
|
1210
|
-
- `ARGS extends readonly any[] = IndexArgTypes<M, F>`
|
|
1255
|
+
#### typeWrapper.clone · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L81)
|
|
1211
1256
|
|
|
1212
|
-
|
|
1257
|
+
**Signature:** `(value: T) => T`
|
|
1213
1258
|
|
|
1214
|
-
**
|
|
1259
|
+
**Parameters:**
|
|
1215
1260
|
|
|
1216
|
-
|
|
1261
|
+
- `value: T`
|
|
1217
1262
|
|
|
1218
|
-
####
|
|
1263
|
+
#### typeWrapper.equals · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L85)
|
|
1219
1264
|
|
|
1220
|
-
**
|
|
1265
|
+
**Signature:** `(value1: T, value2: T) => boolean`
|
|
1221
1266
|
|
|
1222
|
-
|
|
1267
|
+
**Parameters:**
|
|
1223
1268
|
|
|
1224
|
-
|
|
1269
|
+
- `value1: T`
|
|
1270
|
+
- `value2: T`
|
|
1225
1271
|
|
|
1226
|
-
####
|
|
1272
|
+
#### typeWrapper.getLinkedModel · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L90)
|
|
1227
1273
|
|
|
1228
|
-
**
|
|
1274
|
+
**Signature:** `() => AnyModelClass`
|
|
1229
1275
|
|
|
1230
|
-
### DatabaseError · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1276
|
+
### DatabaseError · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L166)
|
|
1231
1277
|
|
|
1232
1278
|
The DatabaseError class is used to represent errors that occur during database operations.
|
|
1233
1279
|
It extends the built-in Error class and has a machine readable error code string property.
|
|
@@ -1237,7 +1283,7 @@ Invalid function arguments will throw TypeError.
|
|
|
1237
1283
|
|
|
1238
1284
|
**Value:** `DatabaseErrorConstructor`
|
|
1239
1285
|
|
|
1240
|
-
### runMigration · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1286
|
+
### runMigration · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L121)
|
|
1241
1287
|
|
|
1242
1288
|
Run database migration: populate secondary indexes for old-version rows,
|
|
1243
1289
|
convert old primary indices, rewrite row data, and clean up orphaned indices.
|
|
@@ -1250,13 +1296,13 @@ convert old primary indices, rewrite row data, and clean up orphaned indices.
|
|
|
1250
1296
|
|
|
1251
1297
|
### MigrationOptions · [interface](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L13)
|
|
1252
1298
|
|
|
1253
|
-
#### migrationOptions.tables · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1299
|
+
#### migrationOptions.tables · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L18)
|
|
1254
1300
|
|
|
1255
1301
|
Limit migration to specific table names.
|
|
1256
1302
|
|
|
1257
1303
|
**Type:** `string[]`
|
|
1258
1304
|
|
|
1259
|
-
#### migrationOptions.populateSecondaries · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1305
|
+
#### migrationOptions.populateSecondaries · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L22)
|
|
1260
1306
|
|
|
1261
1307
|
Populate secondary indexes for rows at old schema versions (default: true).
|
|
1262
1308
|
|
|
@@ -1268,27 +1314,27 @@ Convert old primary indices when primary key fields changed (default: true).
|
|
|
1268
1314
|
|
|
1269
1315
|
**Type:** `boolean`
|
|
1270
1316
|
|
|
1271
|
-
#### migrationOptions.rewriteData · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1317
|
+
#### migrationOptions.rewriteData · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L38)
|
|
1272
1318
|
|
|
1273
1319
|
Rewrite all row data to the latest schema version (default: false).
|
|
1274
1320
|
|
|
1275
1321
|
**Type:** `boolean`
|
|
1276
1322
|
|
|
1277
|
-
#### migrationOptions.removeOrphans · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1323
|
+
#### migrationOptions.removeOrphans · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L45)
|
|
1278
1324
|
|
|
1279
1325
|
Delete orphaned secondary/unique index entries (default: true).
|
|
1280
1326
|
|
|
1281
1327
|
**Type:** `boolean`
|
|
1282
1328
|
|
|
1283
|
-
#### migrationOptions.onProgress · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1329
|
+
#### migrationOptions.onProgress · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L45)
|
|
1284
1330
|
|
|
1285
1331
|
Progress callback.
|
|
1286
1332
|
|
|
1287
1333
|
**Type:** `(info: ProgressInfo) => void`
|
|
1288
1334
|
|
|
1289
|
-
### MigrationResult · [interface](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1335
|
+
### MigrationResult · [interface](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L50)
|
|
1290
1336
|
|
|
1291
|
-
#### migrationResult.secondaries · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1337
|
+
#### migrationResult.secondaries · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L52)
|
|
1292
1338
|
|
|
1293
1339
|
Per-table counts of secondary index entries populated.
|
|
1294
1340
|
|
|
@@ -1300,21 +1346,35 @@ Per-table counts of old primary rows migrated.
|
|
|
1300
1346
|
|
|
1301
1347
|
**Type:** `Record<string, number>`
|
|
1302
1348
|
|
|
1303
|
-
#### migrationResult.conversionFailures · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1349
|
+
#### migrationResult.conversionFailures · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L59)
|
|
1304
1350
|
|
|
1305
1351
|
Per-table conversion failure counts by reason.
|
|
1306
1352
|
|
|
1307
1353
|
**Type:** `Record<string, Record<string, number>>`
|
|
1308
1354
|
|
|
1309
|
-
#### migrationResult.rewritten · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1355
|
+
#### migrationResult.rewritten · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L63)
|
|
1310
1356
|
|
|
1311
1357
|
Per-table counts of rows rewritten to latest version.
|
|
1312
1358
|
|
|
1313
1359
|
**Type:** `Record<string, number>`
|
|
1314
1360
|
|
|
1315
|
-
#### migrationResult.orphans · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1361
|
+
#### migrationResult.orphans · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L67)
|
|
1316
1362
|
|
|
1317
1363
|
Number of orphaned index entries deleted.
|
|
1318
1364
|
|
|
1319
1365
|
**Type:** `number`
|
|
1320
1366
|
|
|
1367
|
+
### Transaction · [interface](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L54)
|
|
1368
|
+
|
|
1369
|
+
#### transaction.id · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L55)
|
|
1370
|
+
|
|
1371
|
+
**Type:** `number`
|
|
1372
|
+
|
|
1373
|
+
#### transaction.instances · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L56)
|
|
1374
|
+
|
|
1375
|
+
**Type:** `Map<number, ModelBase>`
|
|
1376
|
+
|
|
1377
|
+
### txnStorage · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L59)
|
|
1378
|
+
|
|
1379
|
+
**Value:** `AsyncLocalStorage<Transaction>`
|
|
1380
|
+
|