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/skill/SKILL.md
CHANGED
|
@@ -26,7 +26,7 @@ import * as E from "edinburgh";
|
|
|
26
26
|
// Initialize the database (optional, defaults to ".edinburgh")
|
|
27
27
|
E.init("./my-database");
|
|
28
28
|
|
|
29
|
-
const User = E.defineModel(class {
|
|
29
|
+
const User = E.defineModel("User", class {
|
|
30
30
|
id = E.field(E.identifier);
|
|
31
31
|
name = E.field(E.string);
|
|
32
32
|
age = E.field(E.number);
|
|
@@ -46,9 +46,8 @@ const User = E.defineModel(class {
|
|
|
46
46
|
}, {
|
|
47
47
|
pk: "id",
|
|
48
48
|
unique: {
|
|
49
|
-
|
|
49
|
+
email: "email",
|
|
50
50
|
},
|
|
51
|
-
tableName: "User",
|
|
52
51
|
});
|
|
53
52
|
|
|
54
53
|
await E.transact(() => {
|
|
@@ -65,7 +64,7 @@ await E.transact(() => {
|
|
|
65
64
|
|
|
66
65
|
await E.transact(() => {
|
|
67
66
|
// Query by unique index
|
|
68
|
-
|
|
67
|
+
const john = User.getBy("email", "john@example.com")!;
|
|
69
68
|
|
|
70
69
|
// The transaction will retry if there's a conflict, such as another transaction
|
|
71
70
|
// modifying the same user (from another async function or another process)
|
|
@@ -81,12 +80,15 @@ await E.transact(() => {
|
|
|
81
80
|
|
|
82
81
|
### Defining Models
|
|
83
82
|
|
|
84
|
-
|
|
83
|
+
A model is defined using the `E.defineModel()` function by passing it..
|
|
84
|
+
- a consistent table name,
|
|
85
|
+
- an (anonymous) class containing `E.field` database properties and optionally regular properties/methods, and
|
|
86
|
+
- optional key/index configuration.
|
|
85
87
|
|
|
86
88
|
```typescript
|
|
87
89
|
import * as E from "edinburgh";
|
|
88
90
|
|
|
89
|
-
const User = E.defineModel(class {
|
|
91
|
+
const User = E.defineModel("User", class {
|
|
90
92
|
id = E.field(E.identifier);
|
|
91
93
|
name = E.field(E.string);
|
|
92
94
|
email = E.field(E.string);
|
|
@@ -94,9 +96,12 @@ const User = E.defineModel(class {
|
|
|
94
96
|
}, {
|
|
95
97
|
pk: "id",
|
|
96
98
|
unique: {
|
|
97
|
-
|
|
99
|
+
email: "email",
|
|
98
100
|
},
|
|
99
101
|
});
|
|
102
|
+
// Add this if you want to use User as a type annotation (e.g. `let u: User`).
|
|
103
|
+
// Not needed just to call User.get(), User.find(), new User(), etc.
|
|
104
|
+
type User = InstanceType<typeof User>;
|
|
100
105
|
```
|
|
101
106
|
|
|
102
107
|
Instance fields are declared with `E.field(type, options?)`. Available types:
|
|
@@ -120,7 +125,7 @@ Instance fields are declared with `E.field(type, options?)`. Available types:
|
|
|
120
125
|
#### Defaults
|
|
121
126
|
|
|
122
127
|
```typescript
|
|
123
|
-
const Post = E.defineModel(class {
|
|
128
|
+
const Post = E.defineModel("Post", class {
|
|
124
129
|
id = E.field(E.identifier); // auto-generated
|
|
125
130
|
title = E.field(E.string);
|
|
126
131
|
status = E.field(E.or("draft", "published"), {default: "draft"});
|
|
@@ -145,13 +150,13 @@ await E.transact(() => {
|
|
|
145
150
|
|
|
146
151
|
// Read + Update
|
|
147
152
|
await E.transact(() => {
|
|
148
|
-
const user = User.
|
|
153
|
+
const user = User.getBy("email", "alice@example.com");
|
|
149
154
|
if (user) user.age++;
|
|
150
155
|
});
|
|
151
156
|
|
|
152
157
|
// Return values from transactions
|
|
153
158
|
const name = await E.transact(() => {
|
|
154
|
-
const user = User.
|
|
159
|
+
const user = User.getBy("email", "alice@example.com");
|
|
155
160
|
return user?.name;
|
|
156
161
|
});
|
|
157
162
|
```
|
|
@@ -163,15 +168,15 @@ Transactions auto-retry on conflict (up to 6 times by default). Keep transaction
|
|
|
163
168
|
Edinburgh supports three index types:
|
|
164
169
|
|
|
165
170
|
```typescript
|
|
166
|
-
const Product = E.defineModel(class {
|
|
171
|
+
const Product = E.defineModel("Product", class {
|
|
167
172
|
sku = E.field(E.string);
|
|
168
173
|
name = E.field(E.string);
|
|
169
174
|
category = E.field(E.string);
|
|
170
175
|
price = E.field(E.number);
|
|
171
176
|
}, {
|
|
172
177
|
pk: "sku",
|
|
173
|
-
unique: {
|
|
174
|
-
index: {
|
|
178
|
+
unique: { name: "name" },
|
|
179
|
+
index: { category: "category" },
|
|
175
180
|
});
|
|
176
181
|
```
|
|
177
182
|
|
|
@@ -185,7 +190,7 @@ await E.transact(() => {
|
|
|
185
190
|
const p1 = Product.get("SKU-001");
|
|
186
191
|
|
|
187
192
|
// Unique index lookup
|
|
188
|
-
const p2 = Product.
|
|
193
|
+
const p2 = Product.getBy("name", "Widget");
|
|
189
194
|
|
|
190
195
|
// All return undefined if not found
|
|
191
196
|
});
|
|
@@ -193,12 +198,12 @@ await E.transact(() => {
|
|
|
193
198
|
|
|
194
199
|
#### Range Queries
|
|
195
200
|
|
|
196
|
-
|
|
201
|
+
Primary-key queries use `.find()`. Named unique and secondary indexes use `.findBy(name, ...)`:
|
|
197
202
|
|
|
198
203
|
```typescript
|
|
199
204
|
await E.transact(() => {
|
|
200
205
|
// Exact match
|
|
201
|
-
for (const p of Product.
|
|
206
|
+
for (const p of Product.findBy("category", {is: "electronics"})) {
|
|
202
207
|
console.log(p.name);
|
|
203
208
|
}
|
|
204
209
|
|
|
@@ -217,15 +222,15 @@ await E.transact(() => {
|
|
|
217
222
|
for (const p of Product.find({reverse: true})) { ... }
|
|
218
223
|
|
|
219
224
|
// Count and fetch helpers
|
|
220
|
-
const count = Product.
|
|
221
|
-
const first = Product.
|
|
225
|
+
const count = Product.findBy("category", {is: "electronics"}).count();
|
|
226
|
+
const first = Product.findBy("category", {is: "electronics"}).fetch(); // first match or undefined
|
|
222
227
|
});
|
|
223
228
|
```
|
|
224
229
|
|
|
225
230
|
#### Composite Primary Keys
|
|
226
231
|
|
|
227
232
|
```typescript
|
|
228
|
-
const Event = E.defineModel(class {
|
|
233
|
+
const Event = E.defineModel("Event", class {
|
|
229
234
|
year = E.field(E.number);
|
|
230
235
|
month = E.field(E.number);
|
|
231
236
|
id = E.field(E.identifier);
|
|
@@ -248,7 +253,7 @@ await E.transact(() => {
|
|
|
248
253
|
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.
|
|
249
254
|
|
|
250
255
|
```typescript
|
|
251
|
-
const User = E.defineModel(class {
|
|
256
|
+
const User = E.defineModel("User", class {
|
|
252
257
|
firstName = E.field(E.string);
|
|
253
258
|
lastName = E.field(E.string);
|
|
254
259
|
|
|
@@ -271,7 +276,7 @@ const User = E.defineModel(class {
|
|
|
271
276
|
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).
|
|
272
277
|
|
|
273
278
|
```typescript
|
|
274
|
-
const Article = E.defineModel(class {
|
|
279
|
+
const Article = E.defineModel("Article", class {
|
|
275
280
|
id = E.field(E.identifier);
|
|
276
281
|
firstName = E.field(E.string);
|
|
277
282
|
lastName = E.field(E.string);
|
|
@@ -280,11 +285,11 @@ const Article = E.defineModel(class {
|
|
|
280
285
|
}, {
|
|
281
286
|
pk: "id",
|
|
282
287
|
unique: {
|
|
283
|
-
|
|
288
|
+
fullName: (a: any) => [`${a.firstName} ${a.lastName}`], // computed covering unique index
|
|
284
289
|
},
|
|
285
290
|
index: {
|
|
286
|
-
|
|
287
|
-
|
|
291
|
+
domain: (a: any) => a.email ? [a.email.split("@")[1]] : [], // computed partial index
|
|
292
|
+
word: (a: any) => a.title.toLowerCase().split(" "), // computed multi-index
|
|
288
293
|
},
|
|
289
294
|
});
|
|
290
295
|
|
|
@@ -292,13 +297,13 @@ await E.transact(() => {
|
|
|
292
297
|
new Article({ firstName: "Jane", lastName: "Doe", title: "Hello World", email: "jane@acme.com" });
|
|
293
298
|
|
|
294
299
|
// Lookup via computed unique index
|
|
295
|
-
const jane = Article.
|
|
300
|
+
const jane = Article.getBy("fullName", "Jane Doe");
|
|
296
301
|
|
|
297
302
|
// Multi-value: each word in the title is indexed separately
|
|
298
|
-
for (const a of Article.
|
|
303
|
+
for (const a of Article.findBy("word", {is: "hello"})) { ... }
|
|
299
304
|
|
|
300
305
|
// Partial index: articles without email are skipped
|
|
301
|
-
for (const a of Article.
|
|
306
|
+
for (const a of Article.findBy("domain", {is: "acme.com"})) { ... }
|
|
302
307
|
});
|
|
303
308
|
```
|
|
304
309
|
|
|
@@ -307,12 +312,12 @@ await E.transact(() => {
|
|
|
307
312
|
Use `E.link(Model)` for foreign keys. Use a thunk (a function that just returns a value) for forward references when needed:
|
|
308
313
|
|
|
309
314
|
```typescript
|
|
310
|
-
const Author = E.defineModel(class {
|
|
315
|
+
const Author = E.defineModel("Author", class {
|
|
311
316
|
id = E.field(E.identifier);
|
|
312
317
|
name = E.field(E.string);
|
|
313
318
|
}, { pk: "id" });
|
|
314
319
|
|
|
315
|
-
const Book = E.defineModel(class {
|
|
320
|
+
const Book = E.defineModel("Book", class {
|
|
316
321
|
id = E.field(E.identifier);
|
|
317
322
|
title = E.field(E.string);
|
|
318
323
|
author = E.field(E.link(Author));
|
|
@@ -385,7 +390,7 @@ await Product.batchProcess({ limitRows: 1000 }, (product) => {
|
|
|
385
390
|
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:
|
|
386
391
|
|
|
387
392
|
```typescript
|
|
388
|
-
const UserV2 = E.defineModel(class {
|
|
393
|
+
const UserV2 = E.defineModel("User", class {
|
|
389
394
|
id = E.field(E.identifier);
|
|
390
395
|
name = E.field(E.string);
|
|
391
396
|
role = E.field(E.string); // newly added field
|
|
@@ -393,7 +398,7 @@ const UserV2 = E.defineModel(class {
|
|
|
393
398
|
static migrate(record: Record<string, any>) {
|
|
394
399
|
record.role ??= record.name.indexOf("admin") >= 0 ? "admin" : "user"; // set role based on name for old records
|
|
395
400
|
}
|
|
396
|
-
}
|
|
401
|
+
})
|
|
397
402
|
```
|
|
398
403
|
|
|
399
404
|
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...
|
|
@@ -428,7 +433,7 @@ console.log(result.secondaries); // { User: 1500 }
|
|
|
428
433
|
Compute derived fields before data is written:
|
|
429
434
|
|
|
430
435
|
```typescript
|
|
431
|
-
const Article = E.defineModel(class {
|
|
436
|
+
const Article = E.defineModel("Article", class {
|
|
432
437
|
id = E.field(E.identifier);
|
|
433
438
|
title = E.field(E.string);
|
|
434
439
|
slug = E.field(E.string);
|
|
@@ -436,7 +441,7 @@ const Article = E.defineModel(class {
|
|
|
436
441
|
preCommit() {
|
|
437
442
|
this.slug = this.title.toLowerCase().replace(/\s+/g, "-");
|
|
438
443
|
}
|
|
439
|
-
}
|
|
444
|
+
});
|
|
440
445
|
```
|
|
441
446
|
|
|
442
447
|
### Change Tracking
|
|
@@ -477,9 +482,12 @@ ln -s ../../node_modules/edinburgh/skill .claude/skills/edinburgh
|
|
|
477
482
|
|
|
478
483
|
The following is auto-generated from `src/edinburgh.ts`:
|
|
479
484
|
|
|
480
|
-
###
|
|
485
|
+
### currentTxn · function
|
|
481
486
|
|
|
482
|
-
|
|
487
|
+
Returns the current transaction from AsyncLocalStorage.
|
|
488
|
+
Throws if called outside a transact() callback.
|
|
489
|
+
|
|
490
|
+
**Signature:** `() => Transaction`
|
|
483
491
|
|
|
484
492
|
### [init](init.md) · function
|
|
485
493
|
|
|
@@ -500,82 +508,53 @@ The default value is 6. Setting it to 0 will disable retries and cause transacti
|
|
|
500
508
|
|
|
501
509
|
Set a callback function to be called after a model is saved and committed.
|
|
502
510
|
|
|
503
|
-
###
|
|
504
|
-
|
|
505
|
-
**Signature:** `() => Promise<void>`
|
|
511
|
+
### Model · class
|
|
506
512
|
|
|
507
|
-
|
|
513
|
+
**Type:** `typeof ModelBase`
|
|
508
514
|
|
|
509
|
-
|
|
515
|
+
### [ModelClass](ModelClass.md) · class
|
|
510
516
|
|
|
511
|
-
|
|
517
|
+
Runtime base constructor for model classes returned by `defineModel()`.
|
|
512
518
|
|
|
513
|
-
|
|
519
|
+
### [AnyModelClass](AnyModelClass.md) · type
|
|
514
520
|
|
|
515
|
-
|
|
521
|
+
A model constructor with its generic information erased.
|
|
516
522
|
|
|
517
|
-
|
|
523
|
+
### [ModelBase](ModelBase.md) · abstract class
|
|
518
524
|
|
|
519
|
-
|
|
525
|
+
Base class for all database models in the Edinburgh ORM.
|
|
520
526
|
|
|
521
|
-
|
|
527
|
+
### [Schema Evolution](Schema Evolution.md)
|
|
522
528
|
|
|
523
|
-
|
|
529
|
+
Edinburgh tracks the schema version of each model automatically. When you add, remove, or
|
|
530
|
+
change the types of fields, or add/remove indexes, Edinburgh detects the new schema version.
|
|
524
531
|
|
|
525
|
-
|
|
532
|
+
### [Lifecycle Hooks](Lifecycle Hooks.md)
|
|
526
533
|
|
|
527
|
-
|
|
534
|
+
- **`static migrate(record)`**: Called when deserializing rows written with an older schema
|
|
535
|
+
version. Receives a plain record object; mutate it in-place to match the current schema.
|
|
528
536
|
|
|
529
|
-
#### [
|
|
537
|
+
#### [ModelBase.migrate](Lifecycle Hooks_migrate.md) · static method
|
|
530
538
|
|
|
531
539
|
Optional migration function called when deserializing rows written with an older schema version.
|
|
532
|
-
Receives a plain record with all fields
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
#### Model.get · static method
|
|
540
|
+
Receives a plain record with all fields and should mutate it in-place to match the current schema.
|
|
541
|
+
It runs during lazy loading and during `runMigration()`. Changing this method creates a new schema version.
|
|
542
|
+
If it updates values used by secondary or unique indexes, those index entries are refreshed only by `runMigration()`.
|
|
536
543
|
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
**Parameters:**
|
|
540
|
-
|
|
541
|
-
- `args: any[]`
|
|
542
|
-
|
|
543
|
-
#### Model.getLazy · static method
|
|
544
|
-
|
|
545
|
-
**Signature:** `(...args: any[]) => any`
|
|
546
|
-
|
|
547
|
-
**Parameters:**
|
|
548
|
-
|
|
549
|
-
- `args: any[]`
|
|
550
|
-
|
|
551
|
-
#### Model.find · static method
|
|
552
|
-
|
|
553
|
-
**Signature:** `(opts?: any) => any`
|
|
554
|
-
|
|
555
|
-
**Parameters:**
|
|
556
|
-
|
|
557
|
-
- `opts?: any`
|
|
558
|
-
|
|
559
|
-
#### [Model.batchProcess](Model_batchProcess.md) · static method
|
|
560
|
-
|
|
561
|
-
#### [Model.replaceInto](Model_replaceInto.md) · static method
|
|
562
|
-
|
|
563
|
-
Load an existing instance by primary key and update it, or create a new one.
|
|
564
|
-
|
|
565
|
-
#### [model.preCommit](Model_preCommit.md) · method
|
|
544
|
+
#### [modelBase.preCommit](Lifecycle Hooks_preCommit.md) · method
|
|
566
545
|
|
|
567
546
|
Optional hook called on each modified instance right before the transaction commits.
|
|
568
547
|
Runs before data is written to disk, so changes made here are included in the commit.
|
|
569
548
|
|
|
570
|
-
####
|
|
549
|
+
#### modelBase.getPrimaryKey · method
|
|
571
550
|
|
|
572
551
|
**Signature:** `() => Uint8Array<ArrayBufferLike>`
|
|
573
552
|
|
|
574
553
|
**Returns:** The primary key for this instance.
|
|
575
554
|
|
|
576
|
-
#### [
|
|
555
|
+
#### [modelBase.getPrimaryKeyHash](Lifecycle Hooks_getPrimaryKeyHash.md) · method
|
|
577
556
|
|
|
578
|
-
####
|
|
557
|
+
#### modelBase.isLazyField · method
|
|
579
558
|
|
|
580
559
|
**Signature:** `(field: keyof this) => boolean`
|
|
581
560
|
|
|
@@ -583,31 +562,31 @@ Runs before data is written to disk, so changes made here are included in the co
|
|
|
583
562
|
|
|
584
563
|
- `field: keyof this`
|
|
585
564
|
|
|
586
|
-
#### [
|
|
565
|
+
#### [modelBase.preventPersist](Lifecycle Hooks_preventPersist.md) · method
|
|
587
566
|
|
|
588
567
|
Prevent this instance from being persisted to the database.
|
|
589
568
|
|
|
590
|
-
#### [
|
|
569
|
+
#### [modelBase.delete](Lifecycle Hooks_delete.md) · method
|
|
591
570
|
|
|
592
571
|
Delete this model instance from the database.
|
|
593
572
|
|
|
594
|
-
#### [
|
|
573
|
+
#### [modelBase.validate](Lifecycle Hooks_validate.md) · method
|
|
595
574
|
|
|
596
575
|
Validate all fields in this model instance.
|
|
597
576
|
|
|
598
|
-
#### [
|
|
577
|
+
#### [modelBase.isValid](Lifecycle Hooks_isValid.md) · method
|
|
599
578
|
|
|
600
579
|
Check if this model instance is valid.
|
|
601
580
|
|
|
602
|
-
####
|
|
581
|
+
#### modelBase.getState · method
|
|
603
582
|
|
|
604
583
|
**Signature:** `() => "created" | "deleted" | "loaded" | "lazy"`
|
|
605
584
|
|
|
606
|
-
####
|
|
585
|
+
#### modelBase.toString · method
|
|
607
586
|
|
|
608
587
|
**Signature:** `() => string`
|
|
609
588
|
|
|
610
|
-
####
|
|
589
|
+
#### modelBase.[Symbol.for('nodejs.util.inspect.custom')] · method
|
|
611
590
|
|
|
612
591
|
**Signature:** `() => string`
|
|
613
592
|
|
|
@@ -615,16 +594,13 @@ Check if this model instance is valid.
|
|
|
615
594
|
|
|
616
595
|
Register a model class with the Edinburgh ORM system.
|
|
617
596
|
|
|
618
|
-
### [
|
|
619
|
-
|
|
620
|
-
Create a field definition for a model property.
|
|
597
|
+
### [deleteEverything](deleteEverything.md) · function
|
|
621
598
|
|
|
622
|
-
|
|
599
|
+
Delete every key/value entry in the database and reinitialize all registered models.
|
|
623
600
|
|
|
624
|
-
|
|
625
|
-
Throws if called outside a transact() callback.
|
|
601
|
+
### [field](field.md) · function
|
|
626
602
|
|
|
627
|
-
|
|
603
|
+
Create a field definition for a model property.
|
|
628
604
|
|
|
629
605
|
### string · constant
|
|
630
606
|
|
|
@@ -700,68 +676,126 @@ Create a literal type wrapper for a constant value.
|
|
|
700
676
|
|
|
701
677
|
Create a link type wrapper for model relationships.
|
|
702
678
|
|
|
703
|
-
###
|
|
679
|
+
### dump · function
|
|
704
680
|
|
|
705
|
-
|
|
681
|
+
**Signature:** `() => void`
|
|
706
682
|
|
|
707
|
-
### [
|
|
683
|
+
### [FindOptions](FindOptions.md) · type
|
|
708
684
|
|
|
709
|
-
|
|
685
|
+
Range-query options accepted by `find()`, `findBy()`, `batchProcess()`, and `batchProcessBy()`.
|
|
710
686
|
|
|
711
|
-
|
|
687
|
+
### IndexRangeIterator · class
|
|
712
688
|
|
|
713
|
-
|
|
689
|
+
Iterator for range queries on indexes.
|
|
690
|
+
Handles common iteration logic for both primary and unique indexes.
|
|
691
|
+
Extends built-in Iterator to provide map/filter/reduce/toArray/etc.
|
|
714
692
|
|
|
715
|
-
|
|
693
|
+
**Type Parameters:**
|
|
716
694
|
|
|
717
|
-
|
|
695
|
+
- `ITEM`
|
|
718
696
|
|
|
719
|
-
#### [
|
|
697
|
+
#### indexRangeIterator.[Symbol.iterator] · method
|
|
720
698
|
|
|
721
|
-
|
|
699
|
+
**Signature:** `() => this`
|
|
722
700
|
|
|
723
|
-
####
|
|
701
|
+
#### indexRangeIterator.next · method
|
|
724
702
|
|
|
725
|
-
**Signature:** `() =>
|
|
703
|
+
**Signature:** `() => IteratorResult<ITEM, any>`
|
|
726
704
|
|
|
727
|
-
|
|
705
|
+
#### indexRangeIterator.count · method
|
|
728
706
|
|
|
729
|
-
|
|
730
|
-
Provides shared key serialization, write/delete/update logic.
|
|
707
|
+
**Signature:** `() => number`
|
|
731
708
|
|
|
732
|
-
|
|
709
|
+
#### indexRangeIterator.fetch · method
|
|
733
710
|
|
|
734
|
-
|
|
711
|
+
**Signature:** `() => ITEM`
|
|
735
712
|
|
|
736
|
-
|
|
713
|
+
### Change · type
|
|
737
714
|
|
|
738
|
-
**
|
|
715
|
+
**Type:** `Record<any, any> | "created" | "deleted"`
|
|
739
716
|
|
|
740
|
-
|
|
717
|
+
### FieldConfig · interface
|
|
741
718
|
|
|
742
|
-
|
|
719
|
+
Configuration interface for model fields.
|
|
743
720
|
|
|
744
|
-
|
|
721
|
+
**Type Parameters:**
|
|
745
722
|
|
|
746
|
-
|
|
723
|
+
- `T` - The field type.
|
|
747
724
|
|
|
748
|
-
|
|
725
|
+
#### fieldConfig.type · member
|
|
749
726
|
|
|
750
|
-
|
|
727
|
+
The type wrapper that defines how this field is serialized/validated.
|
|
751
728
|
|
|
752
|
-
|
|
729
|
+
**Type:** `TypeWrapper<T>`
|
|
753
730
|
|
|
754
|
-
####
|
|
731
|
+
#### fieldConfig.description · member
|
|
755
732
|
|
|
756
|
-
|
|
733
|
+
Optional human-readable description of the field.
|
|
757
734
|
|
|
758
|
-
|
|
735
|
+
**Type:** `string`
|
|
736
|
+
|
|
737
|
+
#### fieldConfig.default · member
|
|
738
|
+
|
|
739
|
+
Optional default value or function that generates default values.
|
|
740
|
+
|
|
741
|
+
**Type:** `T | ((model: Record<string, any>) => T)`
|
|
742
|
+
|
|
743
|
+
### TypeWrapper · abstract class
|
|
744
|
+
|
|
745
|
+
**Type Parameters:**
|
|
746
|
+
|
|
747
|
+
- `T` - The TypeScript type this wrapper represents.
|
|
748
|
+
|
|
749
|
+
#### typeWrapper.kind · abstract property
|
|
750
|
+
|
|
751
|
+
A string identifier for this type, used during serialization
|
|
752
|
+
|
|
753
|
+
**Type:** `string`
|
|
754
|
+
|
|
755
|
+
#### [typeWrapper.serialize](TypeWrapper_serialize.md) · abstract method
|
|
756
|
+
|
|
757
|
+
Serialize a value from an object property to a Pack.
|
|
758
|
+
|
|
759
|
+
#### [typeWrapper.deserialize](TypeWrapper_deserialize.md) · abstract method
|
|
760
|
+
|
|
761
|
+
Deserialize a value from a Pack into an object property.
|
|
762
|
+
|
|
763
|
+
#### [typeWrapper.getError](TypeWrapper_getError.md) · abstract method
|
|
764
|
+
|
|
765
|
+
Validate a value.
|
|
766
|
+
|
|
767
|
+
#### [typeWrapper.serializeType](TypeWrapper_serializeType.md) · method
|
|
768
|
+
|
|
769
|
+
Serialize type metadata to a Pack (for schema serialization).
|
|
770
|
+
|
|
771
|
+
#### [typeWrapper.containsNull](TypeWrapper_containsNull.md) · method
|
|
772
|
+
|
|
773
|
+
Check if indexing should be skipped for this field value.
|
|
759
774
|
|
|
760
|
-
|
|
775
|
+
#### typeWrapper.toString · method
|
|
761
776
|
|
|
762
|
-
|
|
777
|
+
**Signature:** `() => string`
|
|
778
|
+
|
|
779
|
+
#### typeWrapper.clone · method
|
|
780
|
+
|
|
781
|
+
**Signature:** `(value: T) => T`
|
|
782
|
+
|
|
783
|
+
**Parameters:**
|
|
784
|
+
|
|
785
|
+
- `value: T`
|
|
786
|
+
|
|
787
|
+
#### typeWrapper.equals · method
|
|
788
|
+
|
|
789
|
+
**Signature:** `(value1: T, value2: T) => boolean`
|
|
790
|
+
|
|
791
|
+
**Parameters:**
|
|
792
|
+
|
|
793
|
+
- `value1: T`
|
|
794
|
+
- `value2: T`
|
|
795
|
+
|
|
796
|
+
#### typeWrapper.getLinkedModel · method
|
|
763
797
|
|
|
764
|
-
**
|
|
798
|
+
**Signature:** `() => AnyModelClass`
|
|
765
799
|
|
|
766
800
|
### [DatabaseError](DatabaseError.md) · constant
|
|
767
801
|
|
|
@@ -843,3 +877,17 @@ Number of orphaned index entries deleted.
|
|
|
843
877
|
|
|
844
878
|
**Type:** `number`
|
|
845
879
|
|
|
880
|
+
### Transaction · interface
|
|
881
|
+
|
|
882
|
+
#### transaction.id · member
|
|
883
|
+
|
|
884
|
+
**Type:** `number`
|
|
885
|
+
|
|
886
|
+
#### transaction.instances · member
|
|
887
|
+
|
|
888
|
+
**Type:** `Map<number, ModelBase>`
|
|
889
|
+
|
|
890
|
+
### txnStorage · constant
|
|
891
|
+
|
|
892
|
+
**Value:** `AsyncLocalStorage<Transaction>`
|
|
893
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
### Schema Evolution
|
|
2
|
+
|
|
3
|
+
Edinburgh tracks the schema version of each model automatically. When you add, remove, or
|
|
4
|
+
change the types of fields, or add/remove indexes, Edinburgh detects the new schema version.
|
|
5
|
+
|
|
6
|
+
**Lazy migration:** Changes to non-key field values are migrated lazily, when a row with an
|
|
7
|
+
old schema version is read from disk, it is deserialized using the old schema and optionally
|
|
8
|
+
transformed by the static `migrate()` function. This happens transparently on every read
|
|
9
|
+
and requires no downtime or batch processing.
|
|
10
|
+
|
|
11
|
+
**Batch migration (via `npx migrate-edinburgh` or `runMigration()`):** Certain schema changes
|
|
12
|
+
require an explicit migration run:
|
|
13
|
+
- Adding or removing secondary/unique indexes
|
|
14
|
+
- Changing the fields or types of an existing index
|
|
15
|
+
- A `migrate()` function that changes values used in secondary index fields
|
|
16
|
+
|
|
17
|
+
The batch migration tool populates new indexes, deletes orphaned ones, and updates index
|
|
18
|
+
entries whose values were changed by `migrate()`. It does *not* rewrite primary data rows
|
|
19
|
+
(lazy migration handles that).
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#### typeWrapper.serialize · abstract method
|
|
2
|
+
|
|
3
|
+
Serialize a value from an object property to a Pack.
|
|
4
|
+
|
|
5
|
+
**Signature:** `(value: T, pack: DataPack) => void`
|
|
6
|
+
|
|
7
|
+
**Parameters:**
|
|
8
|
+
|
|
9
|
+
- `value: T` - The value to serialize.
|
|
10
|
+
- `pack: DataPack` - The Pack instance to write to.
|