edinburgh 0.4.2 → 0.4.5
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 +251 -170
- package/build/src/datapack.d.ts +17 -1
- package/build/src/datapack.js +44 -5
- package/build/src/datapack.js.map +1 -1
- package/build/src/edinburgh.d.ts +1 -1
- package/build/src/edinburgh.js +1 -1
- package/build/src/edinburgh.js.map +1 -1
- package/build/src/indexes.d.ts +34 -17
- package/build/src/indexes.js +126 -55
- package/build/src/indexes.js.map +1 -1
- package/build/src/migrate-cli.d.ts +1 -16
- package/build/src/migrate-cli.js +56 -42
- package/build/src/migrate-cli.js.map +1 -1
- package/build/src/migrate.d.ts +15 -11
- package/build/src/migrate.js +62 -32
- package/build/src/migrate.js.map +1 -1
- package/build/src/models.d.ts +1 -1
- package/build/src/models.js +20 -7
- package/build/src/models.js.map +1 -1
- package/build/src/types.d.ts +13 -1
- package/build/src/types.js +89 -1
- package/build/src/types.js.map +1 -1
- package/build/src/utils.d.ts +2 -0
- package/build/src/utils.js +12 -0
- package/build/src/utils.js.map +1 -1
- package/package.json +7 -4
- package/skill/BaseIndex.md +16 -0
- package/skill/BaseIndex_batchProcess.md +10 -0
- package/skill/BaseIndex_find.md +7 -0
- package/skill/DatabaseError.md +9 -0
- package/skill/Model.md +22 -0
- package/skill/Model_delete.md +14 -0
- package/skill/Model_findAll.md +12 -0
- package/skill/Model_getPrimaryKeyHash.md +5 -0
- package/skill/Model_isValid.md +14 -0
- package/skill/Model_migrate.md +34 -0
- package/skill/Model_preCommit.md +28 -0
- package/skill/Model_preventPersist.md +15 -0
- package/skill/Model_replaceInto.md +16 -0
- package/skill/Model_validate.md +21 -0
- package/skill/PrimaryIndex.md +8 -0
- package/skill/PrimaryIndex_get.md +17 -0
- package/skill/PrimaryIndex_getLazy.md +13 -0
- package/skill/SKILL.md +158 -664
- package/skill/SecondaryIndex.md +9 -0
- package/skill/UniqueIndex.md +9 -0
- package/skill/UniqueIndex_get.md +17 -0
- package/skill/array.md +23 -0
- package/skill/dump.md +8 -0
- package/skill/field.md +29 -0
- package/skill/index.md +32 -0
- package/skill/init.md +17 -0
- package/skill/link.md +27 -0
- package/skill/literal.md +22 -0
- package/skill/opt.md +22 -0
- package/skill/or.md +22 -0
- package/skill/primary.md +26 -0
- package/skill/record.md +21 -0
- package/skill/registerModel.md +26 -0
- package/skill/runMigration.md +10 -0
- package/skill/set.md +23 -0
- package/skill/setMaxRetryCount.md +10 -0
- package/skill/setOnSaveCallback.md +12 -0
- package/skill/transact.md +49 -0
- package/skill/unique.md +32 -0
- package/src/datapack.ts +49 -7
- package/src/edinburgh.ts +2 -0
- package/src/indexes.ts +143 -71
- package/src/migrate-cli.ts +44 -46
- package/src/migrate.ts +71 -39
- package/src/models.ts +19 -7
- package/src/types.ts +97 -1
- package/src/utils.ts +12 -0
package/README.md
CHANGED
|
@@ -117,6 +117,8 @@ Instance fields are declared with `E.field(type, options?)`. Available types:
|
|
|
117
117
|
| `E.or(A, B, ...)` | `A \| B \| ...` | Union type; args can be types or literal values |
|
|
118
118
|
| `E.literal(v)` | literal type | Constant value; defaults to that value |
|
|
119
119
|
| `E.array(T)` | `T[]` | Optional `{min, max}` constraints |
|
|
120
|
+
| `E.set(T)` | `Set<T>` | Optional `{min, max}` constraints |
|
|
121
|
+
| `E.record(T)` | `Record<string \| number, T>` | Key-value object with string/number keys |
|
|
120
122
|
| `E.link(Model)` | `Model` | Foreign key, lazy-loaded on access |
|
|
121
123
|
|
|
122
124
|
#### Defaults
|
|
@@ -250,6 +252,67 @@ await E.transact(() => {
|
|
|
250
252
|
});
|
|
251
253
|
```
|
|
252
254
|
|
|
255
|
+
#### Non-Persistent Properties
|
|
256
|
+
|
|
257
|
+
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.
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
@E.registerModel
|
|
261
|
+
class User extends E.Model<User> {
|
|
262
|
+
static pk = E.primary(User, "id");
|
|
263
|
+
id = E.field(E.identifier);
|
|
264
|
+
firstName = E.field(E.string);
|
|
265
|
+
lastName = E.field(E.string);
|
|
266
|
+
|
|
267
|
+
// Non-persisted property
|
|
268
|
+
cachedFullName?: string;
|
|
269
|
+
|
|
270
|
+
get fullName(): string {
|
|
271
|
+
this.cachedFullName ??= `${this.firstName} ${this.lastName}`;
|
|
272
|
+
return this.cachedFullName;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
greet(): string {
|
|
276
|
+
return `Hello, ${this.fullName}!`;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
#### Computed Indexes
|
|
282
|
+
|
|
283
|
+
Instead of naming fields, you can pass a **function** to `E.unique()` or `E.index()`. 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).
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
@E.registerModel
|
|
287
|
+
class Article extends E.Model<Article> {
|
|
288
|
+
static pk = E.primary(Article, "id");
|
|
289
|
+
static byFullName = E.unique(Article, (a: Article) => [`${a.firstName} ${a.lastName}`]);
|
|
290
|
+
static byWord = E.index(Article, (a: Article) => a.title.toLowerCase().split(" "));
|
|
291
|
+
static byDomain = E.index(Article, (a: Article) => a.email ? [a.email.split("@")[1]] : []);
|
|
292
|
+
|
|
293
|
+
id = E.field(E.identifier);
|
|
294
|
+
firstName = E.field(E.string);
|
|
295
|
+
lastName = E.field(E.string);
|
|
296
|
+
title = E.field(E.string);
|
|
297
|
+
email = E.field(E.opt(E.string));
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
await E.transact(() => {
|
|
301
|
+
new Article({ firstName: "Jane", lastName: "Doe", title: "Hello World", email: "jane@acme.com" });
|
|
302
|
+
|
|
303
|
+
// Lookup via computed unique index
|
|
304
|
+
const jane = Article.byFullName.get("Jane Doe");
|
|
305
|
+
|
|
306
|
+
// Multi-value: each word in the title is indexed separately
|
|
307
|
+
for (const a of Article.byWord.find({is: "hello"})) { ... }
|
|
308
|
+
|
|
309
|
+
// Partial index: articles without email are skipped
|
|
310
|
+
for (const a of Article.byDomain.find({is: "acme.com"})) { ... }
|
|
311
|
+
});
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Computed indexes also support `find()` range queries and `batchProcess()`, just like field-based indexes.
|
|
315
|
+
|
|
253
316
|
### Relationships (Links)
|
|
254
317
|
|
|
255
318
|
Use `E.link(Model)` for foreign keys:
|
|
@@ -325,13 +388,9 @@ await Product.byCategory.batchProcess({is: "old"}, (product) => {
|
|
|
325
388
|
// Commits every ~1 second or 4096 rows (configurable via limitSeconds, limitRows)
|
|
326
389
|
```
|
|
327
390
|
|
|
328
|
-
### Schema
|
|
329
|
-
|
|
330
|
-
Edinburgh handles schema changes automatically:
|
|
391
|
+
### Lazy Schema Migrations
|
|
331
392
|
|
|
332
|
-
|
|
333
|
-
- **Changing field types**: Requires a `static migrate()` function.
|
|
334
|
-
- **Adding/removing indexes**: Requires running `npx migrate-edinburgh`.
|
|
393
|
+
When you change a model's schema, Edinburgh will lazily try to migrate old records on access. This allows you to deploy code changes without downtime or a separate migration step. Optionally, you may provide a `static migrate(record: Record<string, any>)` function on the model to transform old records during lazy migration. If there is a migration error (like a new field without a default value, or an incompatible type change), a run-time error is thrown when loading the affected model instance.
|
|
335
394
|
|
|
336
395
|
```typescript
|
|
337
396
|
@E.registerModel
|
|
@@ -339,15 +398,40 @@ class User extends E.Model<User> {
|
|
|
339
398
|
static pk = E.primary(User, "id");
|
|
340
399
|
id = E.field(E.identifier);
|
|
341
400
|
name = E.field(E.string);
|
|
342
|
-
role = E.field(E.string
|
|
401
|
+
role = E.field(E.string); // newly added field
|
|
343
402
|
|
|
344
403
|
static migrate(record: Record<string, any>) {
|
|
345
|
-
record.role ??= "user";
|
|
404
|
+
record.role ??= record.name.indexOf("admin") >= 0 ? "admin" : "user"; // set role based on name for old records
|
|
346
405
|
}
|
|
347
406
|
}
|
|
348
407
|
```
|
|
349
408
|
|
|
350
|
-
|
|
409
|
+
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...
|
|
410
|
+
- Is idempotent (meaning it can be safely run multiple times on the same row without changing the result after the first run), and
|
|
411
|
+
- Should perform *all* transformation steps starting from the oldest version that could possibly still be in the database. (See the next section.)
|
|
412
|
+
|
|
413
|
+
While lazy migration is convenient and often sufficient, in some cases you need migrations to happen immediately...
|
|
414
|
+
|
|
415
|
+
### Forced Schema Migrations
|
|
416
|
+
|
|
417
|
+
The `migrate-edinburgh` CLI tool will scan the entire database, pro-actively performing the following migrations:
|
|
418
|
+
- **Populate secondary indexes**: If you added or changed secondary indexes, it will build them. Until you do, the indexes will be empty (or only contain instances that have been saved since the index was created).
|
|
419
|
+
- **Migrate primary indexes**: In case you changed the primary key fields or field types (not recommended!) of a model, it will build the new primary index, as well as all secondary indexes (to point at the new primary keys). Until you do, all of your old data will appear to be missing! Note that this may fail on duplicates.
|
|
420
|
+
- **Remove orphaned indexes**: If you removed or changed an index, the stale data will be deleted from the database.
|
|
421
|
+
- **Rewrite primary data**: These are the types of migrations that would normally be done lazily on instance access. As there's usually not much benefit to doing this forcibly, and it can be very time-consuming (and generates a lot of I/O), this is *not* done by default. It may however be useful if you want to clean up the contents of your `migrate()` function, if you have control over all application deployments. Use the `--rewrite-data` flag to enable this.
|
|
422
|
+
|
|
423
|
+
```bash
|
|
424
|
+
npx migrate-edinburgh ./src/models.ts
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
Run `npx migrate-edinburgh` without arguments to see all options. You can also call `runMigration()` programmatically:
|
|
428
|
+
|
|
429
|
+
```typescript
|
|
430
|
+
import { runMigration } from "edinburgh";
|
|
431
|
+
|
|
432
|
+
const result = await runMigration({ tables: ["User"] });
|
|
433
|
+
console.log(result.secondaries); // { User: 1500 }
|
|
434
|
+
```
|
|
351
435
|
|
|
352
436
|
### preCommit Hook
|
|
353
437
|
|
|
@@ -409,7 +493,7 @@ The following is auto-generated from `src/edinburgh.ts`:
|
|
|
409
493
|
|
|
410
494
|
**Signature:** `() => void`
|
|
411
495
|
|
|
412
|
-
### init · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
496
|
+
### init · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L67)
|
|
413
497
|
|
|
414
498
|
Initialize the database with the specified directory path.
|
|
415
499
|
This function may be called multiple times with the same parameters. If it is not called before the first transact(),
|
|
@@ -427,7 +511,7 @@ the database will be automatically initialized with the default directory.
|
|
|
427
511
|
init("./my-database");
|
|
428
512
|
```
|
|
429
513
|
|
|
430
|
-
### transact · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
514
|
+
### transact · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L118)
|
|
431
515
|
|
|
432
516
|
Executes a function within a database transaction context.
|
|
433
517
|
|
|
@@ -477,7 +561,7 @@ await E.transact(() => {
|
|
|
477
561
|
});
|
|
478
562
|
```
|
|
479
563
|
|
|
480
|
-
### setMaxRetryCount · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
564
|
+
### setMaxRetryCount · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L208)
|
|
481
565
|
|
|
482
566
|
Set the maximum number of retries for a transaction in case of conflicts.
|
|
483
567
|
The default value is 6. Setting it to 0 will disable retries and cause transactions to fail immediately on conflict.
|
|
@@ -488,7 +572,7 @@ The default value is 6. Setting it to 0 will disable retries and cause transacti
|
|
|
488
572
|
|
|
489
573
|
- `count: number` - The maximum number of retries for a transaction.
|
|
490
574
|
|
|
491
|
-
### setOnSaveCallback · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
575
|
+
### setOnSaveCallback · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L222)
|
|
492
576
|
|
|
493
577
|
Set a callback function to be called after a model is saved and committed.
|
|
494
578
|
|
|
@@ -501,11 +585,11 @@ Set a callback function to be called after a model is saved and committed.
|
|
|
501
585
|
- A sequential number. Higher numbers have been committed after lower numbers.
|
|
502
586
|
- A map of model instances to their changes. The change can be "created", "deleted", or an object containing the old values.
|
|
503
587
|
|
|
504
|
-
### deleteEverything · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
588
|
+
### deleteEverything · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L227)
|
|
505
589
|
|
|
506
590
|
**Signature:** `() => Promise<void>`
|
|
507
591
|
|
|
508
|
-
### Model · [abstract class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
592
|
+
### Model · [abstract class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L220)
|
|
509
593
|
|
|
510
594
|
[object Object],[object Object],[object Object],[object Object],[object Object]
|
|
511
595
|
|
|
@@ -528,25 +612,25 @@ class User extends E.Model<User> {
|
|
|
528
612
|
}
|
|
529
613
|
```
|
|
530
614
|
|
|
531
|
-
#### Model.tableName · [static property](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
615
|
+
#### Model.tableName · [static property](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L227)
|
|
532
616
|
|
|
533
617
|
The database table name (defaults to class name).
|
|
534
618
|
|
|
535
619
|
**Type:** `string`
|
|
536
620
|
|
|
537
|
-
#### Model.override · [static property](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
621
|
+
#### Model.override · [static property](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L231)
|
|
538
622
|
|
|
539
623
|
When true, registerModel replaces an existing model with the same tableName.
|
|
540
624
|
|
|
541
625
|
**Type:** `boolean`
|
|
542
626
|
|
|
543
|
-
#### Model.fields · [static property](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
627
|
+
#### Model.fields · [static property](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L232)
|
|
544
628
|
|
|
545
629
|
Field configuration metadata.
|
|
546
630
|
|
|
547
631
|
**Type:** `Record<string | number | symbol, FieldConfig<unknown>>`
|
|
548
632
|
|
|
549
|
-
#### Model.migrate · [static method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
633
|
+
#### Model.migrate · [static method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
550
634
|
|
|
551
635
|
Optional migration function called when deserializing rows written with an older schema version.
|
|
552
636
|
Receives a plain record with all fields (primary key fields + value fields) and should mutate it
|
|
@@ -581,7 +665,7 @@ class User extends E.Model<User> {
|
|
|
581
665
|
}
|
|
582
666
|
```
|
|
583
667
|
|
|
584
|
-
#### Model.findAll · [static method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
668
|
+
#### Model.findAll · [static method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
585
669
|
|
|
586
670
|
Find all instances of this model in the database, ordered by primary key.
|
|
587
671
|
|
|
@@ -594,7 +678,7 @@ Find all instances of this model in the database, ordered by primary key.
|
|
|
594
678
|
|
|
595
679
|
**Returns:** An iterator.
|
|
596
680
|
|
|
597
|
-
#### Model.replaceInto · [static method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
681
|
+
#### Model.replaceInto · [static method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
598
682
|
|
|
599
683
|
Load an existing instance by primary key and update it, or create a new one.
|
|
600
684
|
|
|
@@ -611,7 +695,7 @@ new instance is created with `obj` as its initial properties.
|
|
|
611
695
|
|
|
612
696
|
**Returns:** The loaded-and-updated or newly created instance.
|
|
613
697
|
|
|
614
|
-
#### model.preCommit · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
698
|
+
#### model.preCommit · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
615
699
|
|
|
616
700
|
Optional hook called on each modified instance right before the transaction commits.
|
|
617
701
|
Runs before data is written to disk, so changes made here are included in the commit.
|
|
@@ -624,9 +708,6 @@ Common use cases:
|
|
|
624
708
|
|
|
625
709
|
**Signature:** `() => void`
|
|
626
710
|
|
|
627
|
-
**Parameters:**
|
|
628
|
-
|
|
629
|
-
|
|
630
711
|
**Examples:**
|
|
631
712
|
|
|
632
713
|
```typescript
|
|
@@ -643,25 +724,19 @@ class Post extends E.Model<Post> {
|
|
|
643
724
|
}
|
|
644
725
|
```
|
|
645
726
|
|
|
646
|
-
#### model.getPrimaryKey · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
727
|
+
#### model.getPrimaryKey · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
647
728
|
|
|
648
729
|
**Signature:** `() => Uint8Array<ArrayBufferLike>`
|
|
649
730
|
|
|
650
|
-
**Parameters:**
|
|
651
|
-
|
|
652
|
-
|
|
653
731
|
**Returns:** The primary key for this instance.
|
|
654
732
|
|
|
655
|
-
#### model.getPrimaryKeyHash · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
733
|
+
#### model.getPrimaryKeyHash · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
656
734
|
|
|
657
735
|
**Signature:** `() => number`
|
|
658
736
|
|
|
659
|
-
**Parameters:**
|
|
660
|
-
|
|
661
|
-
|
|
662
737
|
**Returns:** A 53-bit positive integer non-cryptographic hash of the primary key, or undefined if not yet saved.
|
|
663
738
|
|
|
664
|
-
#### model.isLazyField · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
739
|
+
#### model.isLazyField · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
665
740
|
|
|
666
741
|
**Signature:** `(field: keyof this) => boolean`
|
|
667
742
|
|
|
@@ -669,15 +744,12 @@ class Post extends E.Model<Post> {
|
|
|
669
744
|
|
|
670
745
|
- `field: keyof this`
|
|
671
746
|
|
|
672
|
-
#### model.preventPersist · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
747
|
+
#### model.preventPersist · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
673
748
|
|
|
674
749
|
Prevent this instance from being persisted to the database.
|
|
675
750
|
|
|
676
751
|
**Signature:** `() => this`
|
|
677
752
|
|
|
678
|
-
**Parameters:**
|
|
679
|
-
|
|
680
|
-
|
|
681
753
|
**Returns:** This model instance for chaining.
|
|
682
754
|
|
|
683
755
|
**Examples:**
|
|
@@ -688,7 +760,7 @@ user.name = "New Name";
|
|
|
688
760
|
user.preventPersist(); // Changes won't be saved
|
|
689
761
|
```
|
|
690
762
|
|
|
691
|
-
#### model.delete · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
763
|
+
#### model.delete · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
692
764
|
|
|
693
765
|
Delete this model instance from the database.
|
|
694
766
|
|
|
@@ -696,9 +768,6 @@ Removes the instance and all its index entries from the database and prevents fu
|
|
|
696
768
|
|
|
697
769
|
**Signature:** `() => void`
|
|
698
770
|
|
|
699
|
-
**Parameters:**
|
|
700
|
-
|
|
701
|
-
|
|
702
771
|
**Examples:**
|
|
703
772
|
|
|
704
773
|
```typescript
|
|
@@ -706,7 +775,7 @@ const user = User.load("user123");
|
|
|
706
775
|
user.delete(); // Removes from database
|
|
707
776
|
```
|
|
708
777
|
|
|
709
|
-
#### model.validate · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
778
|
+
#### model.validate · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
710
779
|
|
|
711
780
|
Validate all fields in this model instance.
|
|
712
781
|
|
|
@@ -728,15 +797,12 @@ if (errors.length > 0) {
|
|
|
728
797
|
}
|
|
729
798
|
```
|
|
730
799
|
|
|
731
|
-
#### model.isValid · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
800
|
+
#### model.isValid · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
732
801
|
|
|
733
802
|
Check if this model instance is valid.
|
|
734
803
|
|
|
735
804
|
**Signature:** `() => boolean`
|
|
736
805
|
|
|
737
|
-
**Parameters:**
|
|
738
|
-
|
|
739
|
-
|
|
740
806
|
**Returns:** true if all validations pass.
|
|
741
807
|
|
|
742
808
|
**Examples:**
|
|
@@ -746,28 +812,19 @@ const user = new User({name: "John"});
|
|
|
746
812
|
if (!user.isValid()) shoutAtTheUser();
|
|
747
813
|
```
|
|
748
814
|
|
|
749
|
-
#### model.getState · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
815
|
+
#### model.getState · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
750
816
|
|
|
751
817
|
**Signature:** `() => "created" | "deleted" | "loaded" | "lazy"`
|
|
752
818
|
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
#### model.toString · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L251)
|
|
819
|
+
#### model.toString · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
757
820
|
|
|
758
821
|
**Signature:** `() => string`
|
|
759
822
|
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
#### model.[Symbol.for('nodejs.util.inspect.custom')] · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L251)
|
|
823
|
+
#### model.[Symbol.for('nodejs.util.inspect.custom')] · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
764
824
|
|
|
765
825
|
**Signature:** `() => string`
|
|
766
826
|
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
### registerModel · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L111)
|
|
827
|
+
### registerModel · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L113)
|
|
771
828
|
|
|
772
829
|
Register a model class with the Edinburgh ORM system.
|
|
773
830
|
|
|
@@ -794,7 +851,7 @@ class User extends E.Model<User> {
|
|
|
794
851
|
}
|
|
795
852
|
```
|
|
796
853
|
|
|
797
|
-
### field · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
854
|
+
### field · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L89)
|
|
798
855
|
|
|
799
856
|
Create a field definition for a model property.
|
|
800
857
|
|
|
@@ -824,13 +881,13 @@ class User extends E.Model<User> {
|
|
|
824
881
|
}
|
|
825
882
|
```
|
|
826
883
|
|
|
827
|
-
### string · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
884
|
+
### string · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
828
885
|
|
|
829
886
|
Type wrapper instance for the string type.
|
|
830
887
|
|
|
831
888
|
**Value:** `TypeWrapper<string>`
|
|
832
889
|
|
|
833
|
-
### orderedString · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
890
|
+
### orderedString · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
834
891
|
|
|
835
892
|
Type wrapper instance for the ordered string type, which is just like a string
|
|
836
893
|
except that it sorts lexicographically in the database (instead of by incrementing
|
|
@@ -840,37 +897,37 @@ may not contain null characters.
|
|
|
840
897
|
|
|
841
898
|
**Value:** `TypeWrapper<string>`
|
|
842
899
|
|
|
843
|
-
### number · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
900
|
+
### number · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
844
901
|
|
|
845
902
|
Type wrapper instance for the number type.
|
|
846
903
|
|
|
847
904
|
**Value:** `TypeWrapper<number>`
|
|
848
905
|
|
|
849
|
-
### dateTime · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
906
|
+
### dateTime · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
850
907
|
|
|
851
|
-
Type wrapper instance for the date/time type.
|
|
908
|
+
Type wrapper instance for the date/time type. Stored without timezone info, rounded to whole seconds.
|
|
852
909
|
|
|
853
910
|
**Value:** `TypeWrapper<Date>`
|
|
854
911
|
|
|
855
|
-
### boolean · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
912
|
+
### boolean · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
856
913
|
|
|
857
914
|
Type wrapper instance for the boolean type.
|
|
858
915
|
|
|
859
916
|
**Value:** `TypeWrapper<boolean>`
|
|
860
917
|
|
|
861
|
-
### identifier · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
918
|
+
### identifier · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
862
919
|
|
|
863
920
|
Type wrapper instance for the identifier type.
|
|
864
921
|
|
|
865
922
|
**Value:** `TypeWrapper<string>`
|
|
866
923
|
|
|
867
|
-
### undef · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
924
|
+
### undef · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
868
925
|
|
|
869
926
|
Type wrapper instance for the 'undefined' type.
|
|
870
927
|
|
|
871
928
|
**Value:** `TypeWrapper<undefined>`
|
|
872
929
|
|
|
873
|
-
### opt · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
930
|
+
### opt · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
874
931
|
|
|
875
932
|
Create an optional type wrapper (allows undefined).
|
|
876
933
|
|
|
@@ -893,7 +950,7 @@ const optionalString = E.opt(E.string);
|
|
|
893
950
|
const optionalNumber = E.opt(E.number);
|
|
894
951
|
```
|
|
895
952
|
|
|
896
|
-
### or · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
953
|
+
### or · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
897
954
|
|
|
898
955
|
Create a union type wrapper from multiple type choices.
|
|
899
956
|
|
|
@@ -916,7 +973,7 @@ const stringOrNumber = E.or(E.string, E.number);
|
|
|
916
973
|
const status = E.or("active", "inactive", "pending");
|
|
917
974
|
```
|
|
918
975
|
|
|
919
|
-
### array · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
976
|
+
### array · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
920
977
|
|
|
921
978
|
Create an array type wrapper with optional length constraints.
|
|
922
979
|
|
|
@@ -940,7 +997,53 @@ const stringArray = E.array(E.string);
|
|
|
940
997
|
const boundedArray = E.array(E.number, {min: 1, max: 10});
|
|
941
998
|
```
|
|
942
999
|
|
|
943
|
-
###
|
|
1000
|
+
### set · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
1001
|
+
|
|
1002
|
+
Create a Set type wrapper with optional length constraints.
|
|
1003
|
+
|
|
1004
|
+
**Signature:** `<const T>(inner: TypeWrapper<T>, opts?: { min?: number; max?: number; }) => TypeWrapper<Set<T>>`
|
|
1005
|
+
|
|
1006
|
+
**Type Parameters:**
|
|
1007
|
+
|
|
1008
|
+
- `T` - The element type.
|
|
1009
|
+
|
|
1010
|
+
**Parameters:**
|
|
1011
|
+
|
|
1012
|
+
- `inner: TypeWrapper<T>` - - Type wrapper for set elements.
|
|
1013
|
+
- `opts: {min?: number, max?: number}` (optional) - - Optional constraints (min/max length).
|
|
1014
|
+
|
|
1015
|
+
**Returns:** A set type instance.
|
|
1016
|
+
|
|
1017
|
+
**Examples:**
|
|
1018
|
+
|
|
1019
|
+
```typescript
|
|
1020
|
+
const stringSet = E.set(E.string);
|
|
1021
|
+
const boundedSet = E.set(E.number, {min: 1, max: 10});
|
|
1022
|
+
```
|
|
1023
|
+
|
|
1024
|
+
### record · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
1025
|
+
|
|
1026
|
+
Create a Record type wrapper for key-value objects with string or number keys.
|
|
1027
|
+
|
|
1028
|
+
**Signature:** `<const T>(inner: TypeWrapper<T>) => TypeWrapper<Record<string | number, T>>`
|
|
1029
|
+
|
|
1030
|
+
**Type Parameters:**
|
|
1031
|
+
|
|
1032
|
+
- `T` - The value type.
|
|
1033
|
+
|
|
1034
|
+
**Parameters:**
|
|
1035
|
+
|
|
1036
|
+
- `inner: TypeWrapper<T>` - - Type wrapper for record values.
|
|
1037
|
+
|
|
1038
|
+
**Returns:** A record type instance.
|
|
1039
|
+
|
|
1040
|
+
**Examples:**
|
|
1041
|
+
|
|
1042
|
+
```typescript
|
|
1043
|
+
const scores = E.record(E.number); // Record<string | number, number>
|
|
1044
|
+
```
|
|
1045
|
+
|
|
1046
|
+
### literal · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
944
1047
|
|
|
945
1048
|
Create a literal type wrapper for a constant value.
|
|
946
1049
|
|
|
@@ -963,7 +1066,7 @@ const statusType = E.literal("active");
|
|
|
963
1066
|
const countType = E.literal(42);
|
|
964
1067
|
```
|
|
965
1068
|
|
|
966
|
-
### link · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1069
|
+
### link · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
967
1070
|
|
|
968
1071
|
Create a link type wrapper for model relationships.
|
|
969
1072
|
|
|
@@ -991,21 +1094,26 @@ class Post extends E.Model<Post> {
|
|
|
991
1094
|
}
|
|
992
1095
|
```
|
|
993
1096
|
|
|
994
|
-
### index · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1097
|
+
### index · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
995
1098
|
|
|
996
|
-
Create a secondary index on model fields.
|
|
1099
|
+
Create a secondary index on model fields, or a computed secondary index using a function.
|
|
997
1100
|
|
|
998
|
-
|
|
1101
|
+
For field-based indexes, pass a field name or array of field names.
|
|
1102
|
+
For computed indexes, pass a function that takes a model instance and returns an array of
|
|
1103
|
+
index keys. Return `[]` to skip indexing for that instance. Each array element creates a
|
|
1104
|
+
separate index entry, enabling multi-value indexes (e.g., indexing by each word in a name).
|
|
1105
|
+
|
|
1106
|
+
**Signature:** `{ <M extends typeof Model, V>(MyModel: M, fn: (instance: InstanceType<M>) => V[]): SecondaryIndex<M, [], [V]>; <M extends typeof Model, const F extends (keyof InstanceType<M> & string)>(MyModel: M, field: F): SecondaryIndex<...>; <M extends typeof Model, const FS extends readonly (keyof InstanceType<M> & string)[]>(...`
|
|
999
1107
|
|
|
1000
1108
|
**Type Parameters:**
|
|
1001
1109
|
|
|
1002
1110
|
- `M extends typeof Model` - The model class.
|
|
1003
|
-
- `
|
|
1111
|
+
- `V` - The computed index value type (for function-based indexes).
|
|
1004
1112
|
|
|
1005
1113
|
**Parameters:**
|
|
1006
1114
|
|
|
1007
1115
|
- `MyModel: M` - - The model class to create the index for.
|
|
1008
|
-
- `
|
|
1116
|
+
- `fn: (instance: InstanceType<M>) => V[]`
|
|
1009
1117
|
|
|
1010
1118
|
**Returns:** A new SecondaryIndex instance.
|
|
1011
1119
|
|
|
@@ -1015,10 +1123,11 @@ Create a secondary index on model fields.
|
|
|
1015
1123
|
class User extends E.Model<User> {
|
|
1016
1124
|
static byAge = E.index(User, "age");
|
|
1017
1125
|
static byTagsDate = E.index(User, ["tags", "createdAt"]);
|
|
1126
|
+
static byWord = E.index(User, (u: User) => u.name.split(" "));
|
|
1018
1127
|
}
|
|
1019
1128
|
```
|
|
1020
1129
|
|
|
1021
|
-
### primary · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1130
|
+
### primary · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
1022
1131
|
|
|
1023
1132
|
Create a primary index on model fields.
|
|
1024
1133
|
|
|
@@ -1045,21 +1154,26 @@ class User extends E.Model<User> {
|
|
|
1045
1154
|
}
|
|
1046
1155
|
```
|
|
1047
1156
|
|
|
1048
|
-
### unique · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1157
|
+
### unique · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
1049
1158
|
|
|
1050
|
-
Create a unique index on model fields.
|
|
1159
|
+
Create a unique index on model fields, or a computed unique index using a function.
|
|
1051
1160
|
|
|
1052
|
-
|
|
1161
|
+
For field-based indexes, pass a field name or array of field names.
|
|
1162
|
+
For computed indexes, pass a function that takes a model instance and returns an array of
|
|
1163
|
+
index keys. Return `[]` to skip indexing for that instance. Each array element creates a
|
|
1164
|
+
separate index entry, enabling multi-value indexes (e.g., indexing by each word in a name).
|
|
1165
|
+
|
|
1166
|
+
**Signature:** `{ <M extends typeof Model, V>(MyModel: M, fn: (instance: InstanceType<M>) => V[]): UniqueIndex<M, [], [V]>; <M extends typeof Model, const F extends (keyof InstanceType<M> & string)>(MyModel: M, field: F): UniqueIndex<...>; <M extends typeof Model, const FS extends readonly (keyof InstanceType<M> & string)[]>(MyMode...`
|
|
1053
1167
|
|
|
1054
1168
|
**Type Parameters:**
|
|
1055
1169
|
|
|
1056
1170
|
- `M extends typeof Model` - The model class.
|
|
1057
|
-
- `
|
|
1171
|
+
- `V` - The computed index value type (for function-based indexes).
|
|
1058
1172
|
|
|
1059
1173
|
**Parameters:**
|
|
1060
1174
|
|
|
1061
1175
|
- `MyModel: M` - - The model class to create the index for.
|
|
1062
|
-
- `
|
|
1176
|
+
- `fn: (instance: InstanceType<M>) => V[]`
|
|
1063
1177
|
|
|
1064
1178
|
**Returns:** A new UniqueIndex instance.
|
|
1065
1179
|
|
|
@@ -1069,10 +1183,11 @@ Create a unique index on model fields.
|
|
|
1069
1183
|
class User extends E.Model<User> {
|
|
1070
1184
|
static byEmail = E.unique(User, "email");
|
|
1071
1185
|
static byNameAge = E.unique(User, ["name", "age"]);
|
|
1186
|
+
static byFullName = E.unique(User, (u: User) => [`${u.firstName} ${u.lastName}`]);
|
|
1072
1187
|
}
|
|
1073
1188
|
```
|
|
1074
1189
|
|
|
1075
|
-
### dump · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1190
|
+
### dump · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
1076
1191
|
|
|
1077
1192
|
Dump database contents for debugging.
|
|
1078
1193
|
|
|
@@ -1081,7 +1196,7 @@ This is primarily useful for development and debugging purposes.
|
|
|
1081
1196
|
|
|
1082
1197
|
**Signature:** `() => void`
|
|
1083
1198
|
|
|
1084
|
-
### BaseIndex · [abstract class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1199
|
+
### BaseIndex · [abstract class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L125)
|
|
1085
1200
|
|
|
1086
1201
|
Base class for database indexes for efficient lookups on model fields.
|
|
1087
1202
|
|
|
@@ -1091,39 +1206,37 @@ Indexes enable fast queries on specific field combinations and enforce uniquenes
|
|
|
1091
1206
|
|
|
1092
1207
|
- `M extends typeof Model` - The model class this index belongs to.
|
|
1093
1208
|
- `F extends readonly (keyof InstanceType<M> & string)[]` - The field names that make up this index.
|
|
1209
|
+
- `ARGS extends readonly any[] = IndexArgTypes<M, F>`
|
|
1094
1210
|
|
|
1095
1211
|
**Constructor Parameters:**
|
|
1096
1212
|
|
|
1097
1213
|
- `MyModel`: - The model class this index belongs to.
|
|
1098
1214
|
- `_fieldNames`: - Array of field names that make up this index.
|
|
1099
1215
|
|
|
1100
|
-
#### baseIndex.find · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1216
|
+
#### baseIndex.find · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
1101
1217
|
|
|
1102
|
-
**Signature:** `(opts?: FindOptions<
|
|
1218
|
+
**Signature:** `(opts?: FindOptions<ARGS>) => IndexRangeIterator<M>`
|
|
1103
1219
|
|
|
1104
1220
|
**Parameters:**
|
|
1105
1221
|
|
|
1106
|
-
- `opts: FindOptions<
|
|
1222
|
+
- `opts: FindOptions<ARGS>` (optional)
|
|
1107
1223
|
|
|
1108
|
-
#### baseIndex.batchProcess · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1224
|
+
#### baseIndex.batchProcess · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
1109
1225
|
|
|
1110
1226
|
[object Object],[object Object],[object Object]
|
|
1111
1227
|
|
|
1112
|
-
**Signature:** `(opts: FindOptions<
|
|
1228
|
+
**Signature:** `(opts: FindOptions<ARGS> & { limitSeconds?: number; limitRows?: number; }, callback: (row: InstanceType<M>) => void | Promise<void>) => Promise<...>`
|
|
1113
1229
|
|
|
1114
1230
|
**Parameters:**
|
|
1115
1231
|
|
|
1116
|
-
- `opts: FindOptions<
|
|
1232
|
+
- `opts: FindOptions<ARGS> & { limitSeconds?: number; limitRows?: number }` (optional) - - Query options (same as `find()`), plus:
|
|
1117
1233
|
- `callback: (row: InstanceType<M>) => void | Promise<void>` - - Called for each matching row within a transaction
|
|
1118
1234
|
|
|
1119
|
-
#### baseIndex.toString · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1235
|
+
#### baseIndex.toString · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
1120
1236
|
|
|
1121
1237
|
**Signature:** `() => string`
|
|
1122
1238
|
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
### UniqueIndex · [class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L251)
|
|
1239
|
+
### UniqueIndex · [class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
1127
1240
|
|
|
1128
1241
|
Unique index that stores references to the primary key.
|
|
1129
1242
|
|
|
@@ -1131,16 +1244,17 @@ Unique index that stores references to the primary key.
|
|
|
1131
1244
|
|
|
1132
1245
|
- `M extends typeof Model` - The model class this index belongs to.
|
|
1133
1246
|
- `F extends readonly (keyof InstanceType<M> & string)[]` - The field names that make up this index.
|
|
1247
|
+
- `ARGS extends readonly any[] = IndexArgTypes<M, F>`
|
|
1134
1248
|
|
|
1135
|
-
#### uniqueIndex.get · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1249
|
+
#### uniqueIndex.get · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
1136
1250
|
|
|
1137
1251
|
Get a model instance by unique index key values.
|
|
1138
1252
|
|
|
1139
|
-
**Signature:** `(...args:
|
|
1253
|
+
**Signature:** `(...args: ARGS) => InstanceType<M>`
|
|
1140
1254
|
|
|
1141
1255
|
**Parameters:**
|
|
1142
1256
|
|
|
1143
|
-
- `args:
|
|
1257
|
+
- `args: ARGS` - - The unique index key values.
|
|
1144
1258
|
|
|
1145
1259
|
**Returns:** The model instance if found, undefined otherwise.
|
|
1146
1260
|
|
|
@@ -1150,7 +1264,7 @@ Get a model instance by unique index key values.
|
|
|
1150
1264
|
const userByEmail = User.byEmail.get("john@example.com");
|
|
1151
1265
|
```
|
|
1152
1266
|
|
|
1153
|
-
### PrimaryIndex · [class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1267
|
+
### PrimaryIndex · [class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
1154
1268
|
|
|
1155
1269
|
Primary index that stores the actual model data.
|
|
1156
1270
|
|
|
@@ -1159,7 +1273,7 @@ Primary index that stores the actual model data.
|
|
|
1159
1273
|
- `M extends typeof Model` - The model class this index belongs to.
|
|
1160
1274
|
- `F extends readonly (keyof InstanceType<M> & string)[]` - The field names that make up this index.
|
|
1161
1275
|
|
|
1162
|
-
#### primaryIndex.get · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1276
|
+
#### primaryIndex.get · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
1163
1277
|
|
|
1164
1278
|
Get a model instance by primary key values.
|
|
1165
1279
|
|
|
@@ -1177,7 +1291,7 @@ Get a model instance by primary key values.
|
|
|
1177
1291
|
const user = User.pk.get("john_doe");
|
|
1178
1292
|
```
|
|
1179
1293
|
|
|
1180
|
-
#### primaryIndex.getLazy · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1294
|
+
#### primaryIndex.getLazy · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
1181
1295
|
|
|
1182
1296
|
Does the same as as `get()`, but will delay loading the instance from disk until the first
|
|
1183
1297
|
property access. In case it turns out the instance doesn't exist, an error will be thrown
|
|
@@ -1191,7 +1305,7 @@ at that time.
|
|
|
1191
1305
|
|
|
1192
1306
|
**Returns:** The (lazily loaded) model instance.
|
|
1193
1307
|
|
|
1194
|
-
### SecondaryIndex · [class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1308
|
+
### SecondaryIndex · [class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L253)
|
|
1195
1309
|
|
|
1196
1310
|
Secondary index for non-unique lookups.
|
|
1197
1311
|
|
|
@@ -1199,8 +1313,9 @@ Secondary index for non-unique lookups.
|
|
|
1199
1313
|
|
|
1200
1314
|
- `M extends typeof Model` - The model class this index belongs to.
|
|
1201
1315
|
- `F extends readonly (keyof InstanceType<M> & string)[]` - The field names that make up this index.
|
|
1316
|
+
- `ARGS extends readonly any[] = IndexArgTypes<M, F>`
|
|
1202
1317
|
|
|
1203
|
-
### Change · [type](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1318
|
+
### Change · [type](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L95)
|
|
1204
1319
|
|
|
1205
1320
|
**Type:** `Record<any, any> | "created" | "deleted"`
|
|
1206
1321
|
|
|
@@ -1214,11 +1329,11 @@ Secondary index for non-unique lookups.
|
|
|
1214
1329
|
|
|
1215
1330
|
**Type:** `Set<Model<unknown>>`
|
|
1216
1331
|
|
|
1217
|
-
#### transaction.instancesByPk · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1332
|
+
#### transaction.instancesByPk · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L46)
|
|
1218
1333
|
|
|
1219
1334
|
**Type:** `Map<number, Model<unknown>>`
|
|
1220
1335
|
|
|
1221
|
-
### DatabaseError · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1336
|
+
### DatabaseError · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L157)
|
|
1222
1337
|
|
|
1223
1338
|
The DatabaseError class is used to represent errors that occur during database operations.
|
|
1224
1339
|
It extends the built-in Error class and has a machine readable error code string property.
|
|
@@ -1228,10 +1343,10 @@ Invalid function arguments will throw TypeError.
|
|
|
1228
1343
|
|
|
1229
1344
|
**Value:** `DatabaseErrorConstructor`
|
|
1230
1345
|
|
|
1231
|
-
### runMigration · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1346
|
+
### runMigration · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L124)
|
|
1232
1347
|
|
|
1233
|
-
Run database migration:
|
|
1234
|
-
convert old primary indices, and clean up orphaned
|
|
1348
|
+
Run database migration: populate secondary indexes for old-version rows,
|
|
1349
|
+
convert old primary indices, rewrite row data, and clean up orphaned indices.
|
|
1235
1350
|
|
|
1236
1351
|
**Signature:** `(options?: MigrationOptions) => Promise<MigrationResult>`
|
|
1237
1352
|
|
|
@@ -1247,99 +1362,65 @@ Limit migration to specific table names.
|
|
|
1247
1362
|
|
|
1248
1363
|
**Type:** `string[]`
|
|
1249
1364
|
|
|
1250
|
-
#### migrationOptions.
|
|
1365
|
+
#### migrationOptions.populateSecondaries · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L23)
|
|
1366
|
+
|
|
1367
|
+
Populate secondary indexes for rows at old schema versions (default: true).
|
|
1368
|
+
|
|
1369
|
+
**Type:** `boolean`
|
|
1370
|
+
|
|
1371
|
+
#### migrationOptions.migratePrimaries · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L32)
|
|
1251
1372
|
|
|
1252
|
-
|
|
1373
|
+
Convert old primary indices when primary key fields changed (default: true).
|
|
1253
1374
|
|
|
1254
1375
|
**Type:** `boolean`
|
|
1255
1376
|
|
|
1256
|
-
#### migrationOptions.
|
|
1377
|
+
#### migrationOptions.rewriteData · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L40)
|
|
1257
1378
|
|
|
1258
|
-
|
|
1379
|
+
Rewrite all row data to the latest schema version (default: false).
|
|
1259
1380
|
|
|
1260
1381
|
**Type:** `boolean`
|
|
1261
1382
|
|
|
1262
|
-
#### migrationOptions.
|
|
1383
|
+
#### migrationOptions.removeOrphans · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L46)
|
|
1263
1384
|
|
|
1264
|
-
|
|
1385
|
+
Delete orphaned secondary/unique index entries (default: true).
|
|
1265
1386
|
|
|
1266
1387
|
**Type:** `boolean`
|
|
1267
1388
|
|
|
1268
|
-
#### migrationOptions.onProgress · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1389
|
+
#### migrationOptions.onProgress · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L48)
|
|
1269
1390
|
|
|
1270
1391
|
Progress callback.
|
|
1271
1392
|
|
|
1272
1393
|
**Type:** `(info: ProgressInfo) => void`
|
|
1273
1394
|
|
|
1274
|
-
### MigrationResult · [interface](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1395
|
+
### MigrationResult · [interface](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L51)
|
|
1275
1396
|
|
|
1276
|
-
#### migrationResult.secondaries · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1397
|
+
#### migrationResult.secondaries · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L54)
|
|
1277
1398
|
|
|
1278
|
-
Per-table
|
|
1399
|
+
Per-table counts of secondary index entries populated.
|
|
1279
1400
|
|
|
1280
1401
|
**Type:** `Record<string, number>`
|
|
1281
1402
|
|
|
1282
|
-
#### migrationResult.primaries · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1403
|
+
#### migrationResult.primaries · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L59)
|
|
1283
1404
|
|
|
1284
|
-
Per-table
|
|
1405
|
+
Per-table counts of old primary rows migrated.
|
|
1285
1406
|
|
|
1286
1407
|
**Type:** `Record<string, number>`
|
|
1287
1408
|
|
|
1288
|
-
#### migrationResult.conversionFailures · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#
|
|
1409
|
+
#### migrationResult.conversionFailures · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L59)
|
|
1289
1410
|
|
|
1290
1411
|
Per-table conversion failure counts by reason.
|
|
1291
1412
|
|
|
1292
1413
|
**Type:** `Record<string, Record<string, number>>`
|
|
1293
1414
|
|
|
1294
|
-
#### migrationResult.
|
|
1295
|
-
|
|
1296
|
-
Number of orphaned index entries deleted.
|
|
1297
|
-
|
|
1298
|
-
**Type:** `number`
|
|
1299
|
-
|
|
1300
|
-
## Schema Migrations
|
|
1301
|
-
|
|
1302
|
-
Edinburgh automatically tracks the schema version of each model. When you change fields, field types, indexes, or the `migrate()` function, Edinburgh detects a new schema version.
|
|
1303
|
-
|
|
1304
|
-
### What happens automatically (lazy migration)
|
|
1305
|
-
|
|
1306
|
-
Changes to regular (non-index) field values are migrated lazily. When a row with an old schema version is loaded from disk, it is deserialized using the old field types and transformed by the optional static `migrate()` function. This is transparent and requires no downtime.
|
|
1307
|
-
|
|
1308
|
-
```typescript
|
|
1309
|
-
@E.registerModel
|
|
1310
|
-
class User extends E.Model<User> {
|
|
1311
|
-
static pk = E.primary(User, "id");
|
|
1312
|
-
id = E.field(E.identifier);
|
|
1313
|
-
name = E.field(E.string);
|
|
1314
|
-
role = E.field(E.string); // newly added field
|
|
1315
|
-
|
|
1316
|
-
static migrate(record: Record<string, any>) {
|
|
1317
|
-
record.role ??= "user"; // provide a default for old rows
|
|
1318
|
-
}
|
|
1319
|
-
}
|
|
1320
|
-
```
|
|
1321
|
-
|
|
1322
|
-
### What requires `migrate-edinburgh`
|
|
1323
|
-
|
|
1324
|
-
The `migrate-edinburgh` CLI tool (or the `runMigration()` API) must be run when:
|
|
1325
|
-
|
|
1326
|
-
- **Adding or removing** secondary or unique indexes
|
|
1327
|
-
- **Changing the fields or types** of an existing index
|
|
1328
|
-
- A **`migrate()` function changes values** that are used in index fields
|
|
1415
|
+
#### migrationResult.rewritten · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L64)
|
|
1329
1416
|
|
|
1330
|
-
|
|
1417
|
+
Per-table counts of rows rewritten to latest version.
|
|
1331
1418
|
|
|
1332
|
-
|
|
1333
|
-
npx migrate-edinburgh --import ./src/models.ts
|
|
1334
|
-
```
|
|
1419
|
+
**Type:** `Record<string, number>`
|
|
1335
1420
|
|
|
1336
|
-
|
|
1421
|
+
#### migrationResult.orphans · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L68)
|
|
1337
1422
|
|
|
1338
|
-
|
|
1423
|
+
Number of orphaned index entries deleted.
|
|
1339
1424
|
|
|
1340
|
-
|
|
1341
|
-
import { runMigration } from "edinburgh";
|
|
1425
|
+
**Type:** `number`
|
|
1342
1426
|
|
|
1343
|
-
const result = await runMigration({ tables: ["User"] });
|
|
1344
|
-
console.log(result.upgraded); // { User: 1500 }
|
|
1345
|
-
```
|