edinburgh 0.4.4 → 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 +58 -101
- 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 +53 -39
- package/build/src/migrate.js.map +1 -1
- package/build/src/models.d.ts +1 -1
- package/build/src/models.js +2 -2
- package/build/src/models.js.map +1 -1
- package/package.json +6 -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 +90 -720
- 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/migrate-cli.ts +44 -46
- package/src/migrate.ts +64 -46
- package/src/models.ts +2 -2
package/skill/SKILL.md
CHANGED
|
@@ -392,13 +392,9 @@ await Product.byCategory.batchProcess({is: "old"}, (product) => {
|
|
|
392
392
|
// Commits every ~1 second or 4096 rows (configurable via limitSeconds, limitRows)
|
|
393
393
|
```
|
|
394
394
|
|
|
395
|
-
### Schema
|
|
395
|
+
### Lazy Schema Migrations
|
|
396
396
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
- **Adding/removing fields**: Old rows are lazily migrated on read. New fields use their default value.
|
|
400
|
-
- **Changing field types**: Requires a `static migrate()` function.
|
|
401
|
-
- **Adding/removing indexes**: Requires running `npx migrate-edinburgh`.
|
|
397
|
+
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.
|
|
402
398
|
|
|
403
399
|
```typescript
|
|
404
400
|
@E.registerModel
|
|
@@ -406,15 +402,40 @@ class User extends E.Model<User> {
|
|
|
406
402
|
static pk = E.primary(User, "id");
|
|
407
403
|
id = E.field(E.identifier);
|
|
408
404
|
name = E.field(E.string);
|
|
409
|
-
role = E.field(E.string
|
|
405
|
+
role = E.field(E.string); // newly added field
|
|
410
406
|
|
|
411
407
|
static migrate(record: Record<string, any>) {
|
|
412
|
-
record.role ??= "user";
|
|
408
|
+
record.role ??= record.name.indexOf("admin") >= 0 ? "admin" : "user"; // set role based on name for old records
|
|
413
409
|
}
|
|
414
410
|
}
|
|
415
411
|
```
|
|
416
412
|
|
|
417
|
-
|
|
413
|
+
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...
|
|
414
|
+
- Is idempotent (meaning it can be safely run multiple times on the same row without changing the result after the first run), and
|
|
415
|
+
- Should perform *all* transformation steps starting from the oldest version that could possibly still be in the database. (See the next section.)
|
|
416
|
+
|
|
417
|
+
While lazy migration is convenient and often sufficient, in some cases you need migrations to happen immediately...
|
|
418
|
+
|
|
419
|
+
### Forced Schema Migrations
|
|
420
|
+
|
|
421
|
+
The `migrate-edinburgh` CLI tool will scan the entire database, pro-actively performing the following migrations:
|
|
422
|
+
- **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).
|
|
423
|
+
- **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.
|
|
424
|
+
- **Remove orphaned indexes**: If you removed or changed an index, the stale data will be deleted from the database.
|
|
425
|
+
- **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.
|
|
426
|
+
|
|
427
|
+
```bash
|
|
428
|
+
npx migrate-edinburgh ./src/models.ts
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
Run `npx migrate-edinburgh` without arguments to see all options. You can also call `runMigration()` programmatically:
|
|
432
|
+
|
|
433
|
+
```typescript
|
|
434
|
+
import { runMigration } from "edinburgh";
|
|
435
|
+
|
|
436
|
+
const result = await runMigration({ tables: ["User"] });
|
|
437
|
+
console.log(result.secondaries); // { User: 1500 }
|
|
438
|
+
```
|
|
418
439
|
|
|
419
440
|
### preCommit Hook
|
|
420
441
|
|
|
@@ -476,125 +497,33 @@ The following is auto-generated from `src/edinburgh.ts`:
|
|
|
476
497
|
|
|
477
498
|
**Signature:** `() => void`
|
|
478
499
|
|
|
479
|
-
### init · function
|
|
500
|
+
### [init](init.md) · function
|
|
480
501
|
|
|
481
502
|
Initialize the database with the specified directory path.
|
|
482
503
|
This function may be called multiple times with the same parameters. If it is not called before the first transact(),
|
|
483
504
|
the database will be automatically initialized with the default directory.
|
|
484
505
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
**Parameters:**
|
|
488
|
-
|
|
489
|
-
- `dbDir: string`
|
|
490
|
-
|
|
491
|
-
**Examples:**
|
|
492
|
-
|
|
493
|
-
```typescript
|
|
494
|
-
init("./my-database");
|
|
495
|
-
```
|
|
496
|
-
|
|
497
|
-
### transact · function
|
|
506
|
+
### [transact](transact.md) · function
|
|
498
507
|
|
|
499
508
|
Executes a function within a database transaction context.
|
|
500
509
|
|
|
501
|
-
|
|
502
|
-
within a transaction.
|
|
503
|
-
|
|
504
|
-
Transactions have a consistent view of the database, and changes made within a transaction are
|
|
505
|
-
isolated from other transactions until they are committed. In case a commit clashes with changes
|
|
506
|
-
made by another transaction, the transaction function will automatically be re-executed up to 6
|
|
507
|
-
times.
|
|
508
|
-
|
|
509
|
-
**Signature:** `<T>(fn: () => T) => Promise<T>`
|
|
510
|
-
|
|
511
|
-
**Type Parameters:**
|
|
512
|
-
|
|
513
|
-
- `T` - The return type of the transaction function.
|
|
514
|
-
|
|
515
|
-
**Parameters:**
|
|
516
|
-
|
|
517
|
-
- `fn: () => T` - - The function to execute within the transaction context. Receives a Transaction instance.
|
|
518
|
-
|
|
519
|
-
**Returns:** A promise that resolves with the function's return value.
|
|
520
|
-
|
|
521
|
-
**Throws:**
|
|
522
|
-
|
|
523
|
-
- With code "RACING_TRANSACTION" if the transaction fails after retries due to conflicts.
|
|
524
|
-
- With code "TXN_LIMIT" if maximum number of transactions is reached.
|
|
525
|
-
- With code "LMDB-{code}" for LMDB-specific errors.
|
|
526
|
-
|
|
527
|
-
**Examples:**
|
|
528
|
-
|
|
529
|
-
```typescript
|
|
530
|
-
const paid = await E.transact(() => {
|
|
531
|
-
const user = User.pk.get("john_doe");
|
|
532
|
-
if (user.credits > 0) {
|
|
533
|
-
user.credits--;
|
|
534
|
-
return true;
|
|
535
|
-
}
|
|
536
|
-
return false;
|
|
537
|
-
});
|
|
538
|
-
```
|
|
539
|
-
```typescript
|
|
540
|
-
// Transaction with automatic retry on conflicts
|
|
541
|
-
await E.transact(() => {
|
|
542
|
-
const counter = Counter.pk.get("global") || new Counter({id: "global", value: 0});
|
|
543
|
-
counter.value++;
|
|
544
|
-
});
|
|
545
|
-
```
|
|
546
|
-
|
|
547
|
-
### setMaxRetryCount · function
|
|
510
|
+
### [setMaxRetryCount](setMaxRetryCount.md) · function
|
|
548
511
|
|
|
549
512
|
Set the maximum number of retries for a transaction in case of conflicts.
|
|
550
513
|
The default value is 6. Setting it to 0 will disable retries and cause transactions to fail immediately on conflict.
|
|
551
514
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
**Parameters:**
|
|
555
|
-
|
|
556
|
-
- `count: number` - The maximum number of retries for a transaction.
|
|
557
|
-
|
|
558
|
-
### setOnSaveCallback · function
|
|
515
|
+
### [setOnSaveCallback](setOnSaveCallback.md) · function
|
|
559
516
|
|
|
560
517
|
Set a callback function to be called after a model is saved and committed.
|
|
561
518
|
|
|
562
|
-
**Signature:** `(callback: (commitId: number, items: Map<Model<any>, Change>) => void) => void`
|
|
563
|
-
|
|
564
|
-
**Parameters:**
|
|
565
|
-
|
|
566
|
-
- `callback: ((commitId: number, items: Map<Model<any>, Change>) => void) | undefined` - The callback function to set. It gets called after each successful
|
|
567
|
-
`transact()` commit that has changes, with the following arguments:
|
|
568
|
-
- A sequential number. Higher numbers have been committed after lower numbers.
|
|
569
|
-
- A map of model instances to their changes. The change can be "created", "deleted", or an object containing the old values.
|
|
570
|
-
|
|
571
519
|
### deleteEverything · function
|
|
572
520
|
|
|
573
521
|
**Signature:** `() => Promise<void>`
|
|
574
522
|
|
|
575
|
-
### Model · abstract class
|
|
523
|
+
### [Model](Model.md) · abstract class
|
|
576
524
|
|
|
577
525
|
[object Object],[object Object],[object Object],[object Object],[object Object]
|
|
578
526
|
|
|
579
|
-
**Type Parameters:**
|
|
580
|
-
|
|
581
|
-
- `SUB` - The concrete model subclass (for proper typing).
|
|
582
|
-
|
|
583
|
-
**Examples:**
|
|
584
|
-
|
|
585
|
-
```typescript
|
|
586
|
-
@E.registerModel
|
|
587
|
-
class User extends E.Model<User> {
|
|
588
|
-
static pk = E.primary(User, "id");
|
|
589
|
-
|
|
590
|
-
id = E.field(E.identifier);
|
|
591
|
-
name = E.field(E.string);
|
|
592
|
-
email = E.field(E.string);
|
|
593
|
-
|
|
594
|
-
static byEmail = E.unique(User, "email");
|
|
595
|
-
}
|
|
596
|
-
```
|
|
597
|
-
|
|
598
527
|
#### Model.tableName · static property
|
|
599
528
|
|
|
600
529
|
The database table name (defaults to class name).
|
|
@@ -613,120 +542,32 @@ Field configuration metadata.
|
|
|
613
542
|
|
|
614
543
|
**Type:** `Record<string | number | symbol, FieldConfig<unknown>>`
|
|
615
544
|
|
|
616
|
-
#### Model.migrate · static method
|
|
545
|
+
#### [Model.migrate](Model_migrate.md) · static method
|
|
617
546
|
|
|
618
547
|
Optional migration function called when deserializing rows written with an older schema version.
|
|
619
548
|
Receives a plain record with all fields (primary key fields + value fields) and should mutate it
|
|
620
549
|
in-place to match the current schema.
|
|
621
550
|
|
|
622
|
-
|
|
623
|
-
migration (via `runMigration()` / `npx migrate-edinburgh`). The function's source code is hashed
|
|
624
|
-
to detect changes. Modifying `migrate()` triggers a new schema version.
|
|
625
|
-
|
|
626
|
-
If `migrate()` changes values of fields used in secondary or unique indexes, those indexes
|
|
627
|
-
will only be updated when `runMigration()` is run (not during lazy loading).
|
|
628
|
-
|
|
629
|
-
**Signature:** `(record: Record<string, any>) => void`
|
|
630
|
-
|
|
631
|
-
**Parameters:**
|
|
632
|
-
|
|
633
|
-
- `record: Record<string, any>` - - A plain object with all field values from the old schema version.
|
|
634
|
-
|
|
635
|
-
**Examples:**
|
|
636
|
-
|
|
637
|
-
```typescript
|
|
638
|
-
@E.registerModel
|
|
639
|
-
class User extends E.Model<User> {
|
|
640
|
-
static pk = E.primary(User, "id");
|
|
641
|
-
id = E.field(E.identifier);
|
|
642
|
-
name = E.field(E.string);
|
|
643
|
-
role = E.field(E.string); // new field
|
|
644
|
-
|
|
645
|
-
static migrate(record: Record<string, any>) {
|
|
646
|
-
record.role ??= "user"; // default for rows that predate the 'role' field
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
```
|
|
650
|
-
|
|
651
|
-
#### Model.findAll · static method
|
|
551
|
+
#### [Model.findAll](Model_findAll.md) · static method
|
|
652
552
|
|
|
653
553
|
Find all instances of this model in the database, ordered by primary key.
|
|
654
554
|
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
**Parameters:**
|
|
658
|
-
|
|
659
|
-
- `this: T`
|
|
660
|
-
- `opts?: {reverse?: boolean}` - - Optional parameters.
|
|
661
|
-
|
|
662
|
-
**Returns:** An iterator.
|
|
663
|
-
|
|
664
|
-
#### Model.replaceInto · static method
|
|
555
|
+
#### [Model.replaceInto](Model_replaceInto.md) · static method
|
|
665
556
|
|
|
666
557
|
Load an existing instance by primary key and update it, or create a new one.
|
|
667
558
|
|
|
668
|
-
|
|
669
|
-
the remaining properties from `obj` are set on the loaded instance. Otherwise a
|
|
670
|
-
new instance is created with `obj` as its initial properties.
|
|
671
|
-
|
|
672
|
-
**Signature:** `<T extends typeof Model<any>>(this: T, obj: Partial<Omit<InstanceType<T>, "constructor">>) => InstanceType<T>`
|
|
673
|
-
|
|
674
|
-
**Parameters:**
|
|
675
|
-
|
|
676
|
-
- `this: T`
|
|
677
|
-
- `obj: Partial<Omit<InstanceType<T>, "constructor">>` - - Partial model data that **must** include every primary key field.
|
|
678
|
-
|
|
679
|
-
**Returns:** The loaded-and-updated or newly created instance.
|
|
680
|
-
|
|
681
|
-
#### model.preCommit · method
|
|
559
|
+
#### [model.preCommit](Model_preCommit.md) · method
|
|
682
560
|
|
|
683
561
|
Optional hook called on each modified instance right before the transaction commits.
|
|
684
562
|
Runs before data is written to disk, so changes made here are included in the commit.
|
|
685
563
|
|
|
686
|
-
Common use cases:
|
|
687
|
-
- Computing derived or denormalized fields
|
|
688
|
-
- Enforcing cross-field validation rules
|
|
689
|
-
- Creating or updating related model instances (newly created instances will also
|
|
690
|
-
have their `preCommit()` called)
|
|
691
|
-
|
|
692
|
-
**Signature:** `() => void`
|
|
693
|
-
|
|
694
|
-
**Parameters:**
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
**Examples:**
|
|
698
|
-
|
|
699
|
-
```typescript
|
|
700
|
-
@E.registerModel
|
|
701
|
-
class Post extends E.Model<Post> {
|
|
702
|
-
static pk = E.primary(Post, "id");
|
|
703
|
-
id = E.field(E.identifier);
|
|
704
|
-
title = E.field(E.string);
|
|
705
|
-
slug = E.field(E.string);
|
|
706
|
-
|
|
707
|
-
preCommit() {
|
|
708
|
-
this.slug = this.title.toLowerCase().replace(/\s+/g, "-");
|
|
709
|
-
}
|
|
710
|
-
}
|
|
711
|
-
```
|
|
712
|
-
|
|
713
564
|
#### model.getPrimaryKey · method
|
|
714
565
|
|
|
715
566
|
**Signature:** `() => Uint8Array<ArrayBufferLike>`
|
|
716
567
|
|
|
717
|
-
**Parameters:**
|
|
718
|
-
|
|
719
|
-
|
|
720
568
|
**Returns:** The primary key for this instance.
|
|
721
569
|
|
|
722
|
-
#### model.getPrimaryKeyHash · method
|
|
723
|
-
|
|
724
|
-
**Signature:** `() => number`
|
|
725
|
-
|
|
726
|
-
**Parameters:**
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
**Returns:** A 53-bit positive integer non-cryptographic hash of the primary key, or undefined if not yet saved.
|
|
570
|
+
#### [model.getPrimaryKeyHash](Model_getPrimaryKeyHash.md) · method
|
|
730
571
|
|
|
731
572
|
#### model.isLazyField · method
|
|
732
573
|
|
|
@@ -736,161 +577,42 @@ class Post extends E.Model<Post> {
|
|
|
736
577
|
|
|
737
578
|
- `field: keyof this`
|
|
738
579
|
|
|
739
|
-
#### model.preventPersist · method
|
|
580
|
+
#### [model.preventPersist](Model_preventPersist.md) · method
|
|
740
581
|
|
|
741
582
|
Prevent this instance from being persisted to the database.
|
|
742
583
|
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
**Parameters:**
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
**Returns:** This model instance for chaining.
|
|
749
|
-
|
|
750
|
-
**Examples:**
|
|
751
|
-
|
|
752
|
-
```typescript
|
|
753
|
-
const user = User.load("user123");
|
|
754
|
-
user.name = "New Name";
|
|
755
|
-
user.preventPersist(); // Changes won't be saved
|
|
756
|
-
```
|
|
757
|
-
|
|
758
|
-
#### model.delete · method
|
|
584
|
+
#### [model.delete](Model_delete.md) · method
|
|
759
585
|
|
|
760
586
|
Delete this model instance from the database.
|
|
761
587
|
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
**Signature:** `() => void`
|
|
765
|
-
|
|
766
|
-
**Parameters:**
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
**Examples:**
|
|
770
|
-
|
|
771
|
-
```typescript
|
|
772
|
-
const user = User.load("user123");
|
|
773
|
-
user.delete(); // Removes from database
|
|
774
|
-
```
|
|
775
|
-
|
|
776
|
-
#### model.validate · method
|
|
588
|
+
#### [model.validate](Model_validate.md) · method
|
|
777
589
|
|
|
778
590
|
Validate all fields in this model instance.
|
|
779
591
|
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
**Parameters:**
|
|
783
|
-
|
|
784
|
-
- `raise: boolean` (optional) - - If true, throw on first validation error.
|
|
785
|
-
|
|
786
|
-
**Returns:** Array of validation errors (empty if valid).
|
|
787
|
-
|
|
788
|
-
**Examples:**
|
|
789
|
-
|
|
790
|
-
```typescript
|
|
791
|
-
const user = new User();
|
|
792
|
-
const errors = user.validate();
|
|
793
|
-
if (errors.length > 0) {
|
|
794
|
-
console.log("Validation failed:", errors);
|
|
795
|
-
}
|
|
796
|
-
```
|
|
797
|
-
|
|
798
|
-
#### model.isValid · method
|
|
592
|
+
#### [model.isValid](Model_isValid.md) · method
|
|
799
593
|
|
|
800
594
|
Check if this model instance is valid.
|
|
801
595
|
|
|
802
|
-
**Signature:** `() => boolean`
|
|
803
|
-
|
|
804
|
-
**Parameters:**
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
**Returns:** true if all validations pass.
|
|
808
|
-
|
|
809
|
-
**Examples:**
|
|
810
|
-
|
|
811
|
-
```typescript
|
|
812
|
-
const user = new User({name: "John"});
|
|
813
|
-
if (!user.isValid()) shoutAtTheUser();
|
|
814
|
-
```
|
|
815
|
-
|
|
816
596
|
#### model.getState · method
|
|
817
597
|
|
|
818
598
|
**Signature:** `() => "created" | "deleted" | "loaded" | "lazy"`
|
|
819
599
|
|
|
820
|
-
**Parameters:**
|
|
821
|
-
|
|
822
|
-
|
|
823
600
|
#### model.toString · method
|
|
824
601
|
|
|
825
602
|
**Signature:** `() => string`
|
|
826
603
|
|
|
827
|
-
**Parameters:**
|
|
828
|
-
|
|
829
|
-
|
|
830
604
|
#### model.[Symbol.for('nodejs.util.inspect.custom')] · method
|
|
831
605
|
|
|
832
606
|
**Signature:** `() => string`
|
|
833
607
|
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
### registerModel · function
|
|
608
|
+
### [registerModel](registerModel.md) · function
|
|
838
609
|
|
|
839
610
|
Register a model class with the Edinburgh ORM system.
|
|
840
611
|
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
**Type Parameters:**
|
|
844
|
-
|
|
845
|
-
- `T extends typeof Model<unknown>` - The model class type.
|
|
846
|
-
|
|
847
|
-
**Parameters:**
|
|
848
|
-
|
|
849
|
-
- `MyModel: T` - - The model class to register.
|
|
850
|
-
|
|
851
|
-
**Returns:** The enhanced model class with ORM capabilities.
|
|
852
|
-
|
|
853
|
-
**Examples:**
|
|
854
|
-
|
|
855
|
-
```typescript
|
|
856
|
-
@E.registerModel
|
|
857
|
-
class User extends E.Model<User> {
|
|
858
|
-
static pk = E.index(User, ["id"], "primary");
|
|
859
|
-
id = E.field(E.identifier);
|
|
860
|
-
name = E.field(E.string);
|
|
861
|
-
}
|
|
862
|
-
```
|
|
863
|
-
|
|
864
|
-
### field · function
|
|
612
|
+
### [field](field.md) · function
|
|
865
613
|
|
|
866
614
|
Create a field definition for a model property.
|
|
867
615
|
|
|
868
|
-
This function uses TypeScript magic to return the field configuration object
|
|
869
|
-
while appearing to return the actual field value type to the type system.
|
|
870
|
-
This allows for both runtime introspection and compile-time type safety.
|
|
871
|
-
|
|
872
|
-
**Signature:** `<T>(type: TypeWrapper<T>, options?: Partial<FieldConfig<T>>) => T`
|
|
873
|
-
|
|
874
|
-
**Type Parameters:**
|
|
875
|
-
|
|
876
|
-
- `T` - The field type.
|
|
877
|
-
|
|
878
|
-
**Parameters:**
|
|
879
|
-
|
|
880
|
-
- `type: TypeWrapper<T>` - - The type wrapper for this field.
|
|
881
|
-
- `options: Partial<FieldConfig<T>>` (optional) - - Additional field configuration options.
|
|
882
|
-
|
|
883
|
-
**Returns:** The field value (typed as T, but actually returns FieldConfig<T>).
|
|
884
|
-
|
|
885
|
-
**Examples:**
|
|
886
|
-
|
|
887
|
-
```typescript
|
|
888
|
-
class User extends E.Model<User> {
|
|
889
|
-
name = E.field(E.string, {description: "User's full name"});
|
|
890
|
-
age = E.field(E.opt(E.number), {description: "User's age", default: 25});
|
|
891
|
-
}
|
|
892
|
-
```
|
|
893
|
-
|
|
894
616
|
### string · constant
|
|
895
617
|
|
|
896
618
|
Type wrapper instance for the string type.
|
|
@@ -937,397 +659,90 @@ Type wrapper instance for the 'undefined' type.
|
|
|
937
659
|
|
|
938
660
|
**Value:** `TypeWrapper<undefined>`
|
|
939
661
|
|
|
940
|
-
### opt · function
|
|
662
|
+
### [opt](opt.md) · function
|
|
941
663
|
|
|
942
664
|
Create an optional type wrapper (allows undefined).
|
|
943
665
|
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
**Type Parameters:**
|
|
947
|
-
|
|
948
|
-
- `T extends TypeWrapper<unknown>|BasicType` - Type wrapper or basic type to make optional.
|
|
949
|
-
|
|
950
|
-
**Parameters:**
|
|
951
|
-
|
|
952
|
-
- `inner: T` - - The inner type to make optional.
|
|
953
|
-
|
|
954
|
-
**Returns:** A union type that accepts the inner type or undefined.
|
|
955
|
-
|
|
956
|
-
**Examples:**
|
|
957
|
-
|
|
958
|
-
```typescript
|
|
959
|
-
const optionalString = E.opt(E.string);
|
|
960
|
-
const optionalNumber = E.opt(E.number);
|
|
961
|
-
```
|
|
962
|
-
|
|
963
|
-
### or · function
|
|
666
|
+
### [or](or.md) · function
|
|
964
667
|
|
|
965
668
|
Create a union type wrapper from multiple type choices.
|
|
966
669
|
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
**Type Parameters:**
|
|
970
|
-
|
|
971
|
-
- `T extends (TypeWrapper<unknown>|BasicType)[]` - Array of type wrapper or basic types.
|
|
972
|
-
|
|
973
|
-
**Parameters:**
|
|
974
|
-
|
|
975
|
-
- `choices: T` - - The type choices for the union.
|
|
976
|
-
|
|
977
|
-
**Returns:** A union type instance.
|
|
978
|
-
|
|
979
|
-
**Examples:**
|
|
980
|
-
|
|
981
|
-
```typescript
|
|
982
|
-
const stringOrNumber = E.or(E.string, E.number);
|
|
983
|
-
const status = E.or("active", "inactive", "pending");
|
|
984
|
-
```
|
|
985
|
-
|
|
986
|
-
### array · function
|
|
670
|
+
### [array](array.md) · function
|
|
987
671
|
|
|
988
672
|
Create an array type wrapper with optional length constraints.
|
|
989
673
|
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
**Type Parameters:**
|
|
993
|
-
|
|
994
|
-
- `T` - The element type.
|
|
995
|
-
|
|
996
|
-
**Parameters:**
|
|
997
|
-
|
|
998
|
-
- `inner: TypeWrapper<T>` - - Type wrapper for array elements.
|
|
999
|
-
- `opts: {min?: number, max?: number}` (optional) - - Optional constraints (min/max length).
|
|
1000
|
-
|
|
1001
|
-
**Returns:** An array type instance.
|
|
1002
|
-
|
|
1003
|
-
**Examples:**
|
|
1004
|
-
|
|
1005
|
-
```typescript
|
|
1006
|
-
const stringArray = E.array(E.string);
|
|
1007
|
-
const boundedArray = E.array(E.number, {min: 1, max: 10});
|
|
1008
|
-
```
|
|
1009
|
-
|
|
1010
|
-
### set · function
|
|
674
|
+
### [set](set.md) · function
|
|
1011
675
|
|
|
1012
676
|
Create a Set type wrapper with optional length constraints.
|
|
1013
677
|
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
**Type Parameters:**
|
|
1017
|
-
|
|
1018
|
-
- `T` - The element type.
|
|
1019
|
-
|
|
1020
|
-
**Parameters:**
|
|
1021
|
-
|
|
1022
|
-
- `inner: TypeWrapper<T>` - - Type wrapper for set elements.
|
|
1023
|
-
- `opts: {min?: number, max?: number}` (optional) - - Optional constraints (min/max length).
|
|
1024
|
-
|
|
1025
|
-
**Returns:** A set type instance.
|
|
1026
|
-
|
|
1027
|
-
**Examples:**
|
|
1028
|
-
|
|
1029
|
-
```typescript
|
|
1030
|
-
const stringSet = E.set(E.string);
|
|
1031
|
-
const boundedSet = E.set(E.number, {min: 1, max: 10});
|
|
1032
|
-
```
|
|
1033
|
-
|
|
1034
|
-
### record · function
|
|
678
|
+
### [record](record.md) · function
|
|
1035
679
|
|
|
1036
680
|
Create a Record type wrapper for key-value objects with string or number keys.
|
|
1037
681
|
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
**Type Parameters:**
|
|
1041
|
-
|
|
1042
|
-
- `T` - The value type.
|
|
1043
|
-
|
|
1044
|
-
**Parameters:**
|
|
1045
|
-
|
|
1046
|
-
- `inner: TypeWrapper<T>` - - Type wrapper for record values.
|
|
1047
|
-
|
|
1048
|
-
**Returns:** A record type instance.
|
|
1049
|
-
|
|
1050
|
-
**Examples:**
|
|
1051
|
-
|
|
1052
|
-
```typescript
|
|
1053
|
-
const scores = E.record(E.number); // Record<string | number, number>
|
|
1054
|
-
```
|
|
1055
|
-
|
|
1056
|
-
### literal · function
|
|
682
|
+
### [literal](literal.md) · function
|
|
1057
683
|
|
|
1058
684
|
Create a literal type wrapper for a constant value.
|
|
1059
685
|
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
**Type Parameters:**
|
|
1063
|
-
|
|
1064
|
-
- `T` - The literal type.
|
|
1065
|
-
|
|
1066
|
-
**Parameters:**
|
|
1067
|
-
|
|
1068
|
-
- `value: T` - - The literal value.
|
|
1069
|
-
|
|
1070
|
-
**Returns:** A literal type instance.
|
|
1071
|
-
|
|
1072
|
-
**Examples:**
|
|
1073
|
-
|
|
1074
|
-
```typescript
|
|
1075
|
-
const statusType = E.literal("active");
|
|
1076
|
-
const countType = E.literal(42);
|
|
1077
|
-
```
|
|
1078
|
-
|
|
1079
|
-
### link · function
|
|
686
|
+
### [link](link.md) · function
|
|
1080
687
|
|
|
1081
688
|
Create a link type wrapper for model relationships.
|
|
1082
689
|
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
**Type Parameters:**
|
|
1086
|
-
|
|
1087
|
-
- `T extends typeof Model<any>` - The target model class.
|
|
1088
|
-
|
|
1089
|
-
**Parameters:**
|
|
1090
|
-
|
|
1091
|
-
- `TargetModel: T` - - The model class this link points to.
|
|
1092
|
-
|
|
1093
|
-
**Returns:** A link type instance.
|
|
1094
|
-
|
|
1095
|
-
**Examples:**
|
|
1096
|
-
|
|
1097
|
-
```typescript
|
|
1098
|
-
class User extends E.Model<User> {
|
|
1099
|
-
posts = E.field(E.array(E.link(Post, 'author')));
|
|
1100
|
-
}
|
|
1101
|
-
|
|
1102
|
-
class Post extends E.Model<Post> {
|
|
1103
|
-
author = E.field(E.link(User));
|
|
1104
|
-
}
|
|
1105
|
-
```
|
|
1106
|
-
|
|
1107
|
-
### index · function
|
|
690
|
+
### [index](index.md) · function
|
|
1108
691
|
|
|
1109
692
|
Create a secondary index on model fields, or a computed secondary index using a function.
|
|
1110
693
|
|
|
1111
|
-
|
|
1112
|
-
For computed indexes, pass a function that takes a model instance and returns an array of
|
|
1113
|
-
index keys. Return `[]` to skip indexing for that instance. Each array element creates a
|
|
1114
|
-
separate index entry, enabling multi-value indexes (e.g., indexing by each word in a name).
|
|
1115
|
-
|
|
1116
|
-
**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)[]>(...`
|
|
1117
|
-
|
|
1118
|
-
**Type Parameters:**
|
|
1119
|
-
|
|
1120
|
-
- `M extends typeof Model` - The model class.
|
|
1121
|
-
- `V` - The computed index value type (for function-based indexes).
|
|
1122
|
-
|
|
1123
|
-
**Parameters:**
|
|
1124
|
-
|
|
1125
|
-
- `MyModel: M` - - The model class to create the index for.
|
|
1126
|
-
- `fn: (instance: InstanceType<M>) => V[]`
|
|
1127
|
-
|
|
1128
|
-
**Returns:** A new SecondaryIndex instance.
|
|
1129
|
-
|
|
1130
|
-
**Examples:**
|
|
1131
|
-
|
|
1132
|
-
```typescript
|
|
1133
|
-
class User extends E.Model<User> {
|
|
1134
|
-
static byAge = E.index(User, "age");
|
|
1135
|
-
static byTagsDate = E.index(User, ["tags", "createdAt"]);
|
|
1136
|
-
static byWord = E.index(User, (u: User) => u.name.split(" "));
|
|
1137
|
-
}
|
|
1138
|
-
```
|
|
1139
|
-
|
|
1140
|
-
### primary · function
|
|
694
|
+
### [primary](primary.md) · function
|
|
1141
695
|
|
|
1142
696
|
Create a primary index on model fields.
|
|
1143
697
|
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
**Type Parameters:**
|
|
1147
|
-
|
|
1148
|
-
- `M extends typeof Model` - The model class.
|
|
1149
|
-
- `F extends (keyof InstanceType<M> & string)` - The field name (for single field index).
|
|
1150
|
-
|
|
1151
|
-
**Parameters:**
|
|
1152
|
-
|
|
1153
|
-
- `MyModel: M` - - The model class to create the index for.
|
|
1154
|
-
- `field: F` - - Single field name for simple indexes.
|
|
1155
|
-
|
|
1156
|
-
**Returns:** A new PrimaryIndex instance.
|
|
1157
|
-
|
|
1158
|
-
**Examples:**
|
|
1159
|
-
|
|
1160
|
-
```typescript
|
|
1161
|
-
class User extends E.Model<User> {
|
|
1162
|
-
static pk = E.primary(User, ["id"]);
|
|
1163
|
-
static pkSingle = E.primary(User, "id");
|
|
1164
|
-
}
|
|
1165
|
-
```
|
|
1166
|
-
|
|
1167
|
-
### unique · function
|
|
698
|
+
### [unique](unique.md) · function
|
|
1168
699
|
|
|
1169
700
|
Create a unique index on model fields, or a computed unique index using a function.
|
|
1170
701
|
|
|
1171
|
-
|
|
1172
|
-
For computed indexes, pass a function that takes a model instance and returns an array of
|
|
1173
|
-
index keys. Return `[]` to skip indexing for that instance. Each array element creates a
|
|
1174
|
-
separate index entry, enabling multi-value indexes (e.g., indexing by each word in a name).
|
|
1175
|
-
|
|
1176
|
-
**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...`
|
|
1177
|
-
|
|
1178
|
-
**Type Parameters:**
|
|
1179
|
-
|
|
1180
|
-
- `M extends typeof Model` - The model class.
|
|
1181
|
-
- `V` - The computed index value type (for function-based indexes).
|
|
1182
|
-
|
|
1183
|
-
**Parameters:**
|
|
1184
|
-
|
|
1185
|
-
- `MyModel: M` - - The model class to create the index for.
|
|
1186
|
-
- `fn: (instance: InstanceType<M>) => V[]`
|
|
1187
|
-
|
|
1188
|
-
**Returns:** A new UniqueIndex instance.
|
|
1189
|
-
|
|
1190
|
-
**Examples:**
|
|
1191
|
-
|
|
1192
|
-
```typescript
|
|
1193
|
-
class User extends E.Model<User> {
|
|
1194
|
-
static byEmail = E.unique(User, "email");
|
|
1195
|
-
static byNameAge = E.unique(User, ["name", "age"]);
|
|
1196
|
-
static byFullName = E.unique(User, (u: User) => [`${u.firstName} ${u.lastName}`]);
|
|
1197
|
-
}
|
|
1198
|
-
```
|
|
1199
|
-
|
|
1200
|
-
### dump · function
|
|
702
|
+
### [dump](dump.md) · function
|
|
1201
703
|
|
|
1202
704
|
Dump database contents for debugging.
|
|
1203
705
|
|
|
1204
|
-
|
|
1205
|
-
This is primarily useful for development and debugging purposes.
|
|
1206
|
-
|
|
1207
|
-
**Signature:** `() => void`
|
|
1208
|
-
|
|
1209
|
-
### BaseIndex · abstract class
|
|
706
|
+
### [BaseIndex](BaseIndex.md) · abstract class
|
|
1210
707
|
|
|
1211
708
|
Base class for database indexes for efficient lookups on model fields.
|
|
1212
709
|
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
**Type Parameters:**
|
|
1216
|
-
|
|
1217
|
-
- `M extends typeof Model` - The model class this index belongs to.
|
|
1218
|
-
- `F extends readonly (keyof InstanceType<M> & string)[]` - The field names that make up this index.
|
|
1219
|
-
- `ARGS extends readonly any[] = IndexArgTypes<M, F>`
|
|
1220
|
-
|
|
1221
|
-
**Constructor Parameters:**
|
|
710
|
+
#### [baseIndex.find](BaseIndex_find.md) · method
|
|
1222
711
|
|
|
1223
|
-
|
|
1224
|
-
- `_fieldNames`: - Array of field names that make up this index.
|
|
1225
|
-
|
|
1226
|
-
#### baseIndex.find · method
|
|
1227
|
-
|
|
1228
|
-
**Signature:** `(opts?: FindOptions<ARGS>) => IndexRangeIterator<M>`
|
|
1229
|
-
|
|
1230
|
-
**Parameters:**
|
|
1231
|
-
|
|
1232
|
-
- `opts: FindOptions<ARGS>` (optional)
|
|
1233
|
-
|
|
1234
|
-
#### baseIndex.batchProcess · method
|
|
712
|
+
#### [baseIndex.batchProcess](BaseIndex_batchProcess.md) · method
|
|
1235
713
|
|
|
1236
714
|
[object Object],[object Object],[object Object]
|
|
1237
715
|
|
|
1238
|
-
**Signature:** `(opts: FindOptions<ARGS> & { limitSeconds?: number; limitRows?: number; }, callback: (row: InstanceType<M>) => void | Promise<void>) => Promise<...>`
|
|
1239
|
-
|
|
1240
|
-
**Parameters:**
|
|
1241
|
-
|
|
1242
|
-
- `opts: FindOptions<ARGS> & { limitSeconds?: number; limitRows?: number }` (optional) - - Query options (same as `find()`), plus:
|
|
1243
|
-
- `callback: (row: InstanceType<M>) => void | Promise<void>` - - Called for each matching row within a transaction
|
|
1244
|
-
|
|
1245
716
|
#### baseIndex.toString · method
|
|
1246
717
|
|
|
1247
718
|
**Signature:** `() => string`
|
|
1248
719
|
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
### UniqueIndex · class
|
|
720
|
+
### [UniqueIndex](UniqueIndex.md) · class
|
|
1253
721
|
|
|
1254
722
|
Unique index that stores references to the primary key.
|
|
1255
723
|
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
- `M extends typeof Model` - The model class this index belongs to.
|
|
1259
|
-
- `F extends readonly (keyof InstanceType<M> & string)[]` - The field names that make up this index.
|
|
1260
|
-
- `ARGS extends readonly any[] = IndexArgTypes<M, F>`
|
|
1261
|
-
|
|
1262
|
-
#### uniqueIndex.get · method
|
|
724
|
+
#### [uniqueIndex.get](UniqueIndex_get.md) · method
|
|
1263
725
|
|
|
1264
726
|
Get a model instance by unique index key values.
|
|
1265
727
|
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
**Parameters:**
|
|
1269
|
-
|
|
1270
|
-
- `args: ARGS` - - The unique index key values.
|
|
1271
|
-
|
|
1272
|
-
**Returns:** The model instance if found, undefined otherwise.
|
|
1273
|
-
|
|
1274
|
-
**Examples:**
|
|
1275
|
-
|
|
1276
|
-
```typescript
|
|
1277
|
-
const userByEmail = User.byEmail.get("john@example.com");
|
|
1278
|
-
```
|
|
1279
|
-
|
|
1280
|
-
### PrimaryIndex · class
|
|
728
|
+
### [PrimaryIndex](PrimaryIndex.md) · class
|
|
1281
729
|
|
|
1282
730
|
Primary index that stores the actual model data.
|
|
1283
731
|
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
- `M extends typeof Model` - The model class this index belongs to.
|
|
1287
|
-
- `F extends readonly (keyof InstanceType<M> & string)[]` - The field names that make up this index.
|
|
1288
|
-
|
|
1289
|
-
#### primaryIndex.get · method
|
|
732
|
+
#### [primaryIndex.get](PrimaryIndex_get.md) · method
|
|
1290
733
|
|
|
1291
734
|
Get a model instance by primary key values.
|
|
1292
735
|
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
**Parameters:**
|
|
1296
|
-
|
|
1297
|
-
- `args: IndexArgTypes<M, F>` - - The primary key values.
|
|
1298
|
-
|
|
1299
|
-
**Returns:** The model instance if found, undefined otherwise.
|
|
1300
|
-
|
|
1301
|
-
**Examples:**
|
|
1302
|
-
|
|
1303
|
-
```typescript
|
|
1304
|
-
const user = User.pk.get("john_doe");
|
|
1305
|
-
```
|
|
1306
|
-
|
|
1307
|
-
#### primaryIndex.getLazy · method
|
|
736
|
+
#### [primaryIndex.getLazy](PrimaryIndex_getLazy.md) · method
|
|
1308
737
|
|
|
1309
738
|
Does the same as as `get()`, but will delay loading the instance from disk until the first
|
|
1310
739
|
property access. In case it turns out the instance doesn't exist, an error will be thrown
|
|
1311
740
|
at that time.
|
|
1312
741
|
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
**Parameters:**
|
|
1316
|
-
|
|
1317
|
-
- `args: IndexArgTypes<M, F>` - Primary key field values. (Or a single Uint8Array containing the key.)
|
|
1318
|
-
|
|
1319
|
-
**Returns:** The (lazily loaded) model instance.
|
|
1320
|
-
|
|
1321
|
-
### SecondaryIndex · class
|
|
742
|
+
### [SecondaryIndex](SecondaryIndex.md) · class
|
|
1322
743
|
|
|
1323
744
|
Secondary index for non-unique lookups.
|
|
1324
745
|
|
|
1325
|
-
**Type Parameters:**
|
|
1326
|
-
|
|
1327
|
-
- `M extends typeof Model` - The model class this index belongs to.
|
|
1328
|
-
- `F extends readonly (keyof InstanceType<M> & string)[]` - The field names that make up this index.
|
|
1329
|
-
- `ARGS extends readonly any[] = IndexArgTypes<M, F>`
|
|
1330
|
-
|
|
1331
746
|
### Change · type
|
|
1332
747
|
|
|
1333
748
|
**Type:** `Record<any, any> | "created" | "deleted"`
|
|
@@ -1346,26 +761,15 @@ Secondary index for non-unique lookups.
|
|
|
1346
761
|
|
|
1347
762
|
**Type:** `Map<number, Model<unknown>>`
|
|
1348
763
|
|
|
1349
|
-
### DatabaseError · constant
|
|
764
|
+
### [DatabaseError](DatabaseError.md) · constant
|
|
1350
765
|
|
|
1351
766
|
The DatabaseError class is used to represent errors that occur during database operations.
|
|
1352
767
|
It extends the built-in Error class and has a machine readable error code string property.
|
|
1353
768
|
|
|
1354
|
-
|
|
1355
|
-
Invalid function arguments will throw TypeError.
|
|
1356
|
-
|
|
1357
|
-
**Value:** `DatabaseErrorConstructor`
|
|
1358
|
-
|
|
1359
|
-
### runMigration · function
|
|
1360
|
-
|
|
1361
|
-
Run database migration: upgrade all rows to the latest schema version,
|
|
1362
|
-
convert old primary indices, and clean up orphaned secondary indices.
|
|
1363
|
-
|
|
1364
|
-
**Signature:** `(options?: MigrationOptions) => Promise<MigrationResult>`
|
|
1365
|
-
|
|
1366
|
-
**Parameters:**
|
|
769
|
+
### [runMigration](runMigration.md) · function
|
|
1367
770
|
|
|
1368
|
-
|
|
771
|
+
Run database migration: populate secondary indexes for old-version rows,
|
|
772
|
+
convert old primary indices, rewrite row data, and clean up orphaned indices.
|
|
1369
773
|
|
|
1370
774
|
### MigrationOptions · interface
|
|
1371
775
|
|
|
@@ -1375,21 +779,27 @@ Limit migration to specific table names.
|
|
|
1375
779
|
|
|
1376
780
|
**Type:** `string[]`
|
|
1377
781
|
|
|
1378
|
-
#### migrationOptions.
|
|
782
|
+
#### migrationOptions.populateSecondaries · member
|
|
1379
783
|
|
|
1380
|
-
|
|
784
|
+
Populate secondary indexes for rows at old schema versions (default: true).
|
|
1381
785
|
|
|
1382
786
|
**Type:** `boolean`
|
|
1383
787
|
|
|
1384
|
-
#### migrationOptions.
|
|
788
|
+
#### migrationOptions.migratePrimaries · member
|
|
1385
789
|
|
|
1386
|
-
|
|
790
|
+
Convert old primary indices when primary key fields changed (default: true).
|
|
1387
791
|
|
|
1388
792
|
**Type:** `boolean`
|
|
1389
793
|
|
|
1390
|
-
#### migrationOptions.
|
|
794
|
+
#### migrationOptions.rewriteData · member
|
|
1391
795
|
|
|
1392
|
-
|
|
796
|
+
Rewrite all row data to the latest schema version (default: false).
|
|
797
|
+
|
|
798
|
+
**Type:** `boolean`
|
|
799
|
+
|
|
800
|
+
#### migrationOptions.removeOrphans · member
|
|
801
|
+
|
|
802
|
+
Delete orphaned secondary/unique index entries (default: true).
|
|
1393
803
|
|
|
1394
804
|
**Type:** `boolean`
|
|
1395
805
|
|
|
@@ -1403,13 +813,13 @@ Progress callback.
|
|
|
1403
813
|
|
|
1404
814
|
#### migrationResult.secondaries · member
|
|
1405
815
|
|
|
1406
|
-
Per-table
|
|
816
|
+
Per-table counts of secondary index entries populated.
|
|
1407
817
|
|
|
1408
818
|
**Type:** `Record<string, number>`
|
|
1409
819
|
|
|
1410
820
|
#### migrationResult.primaries · member
|
|
1411
821
|
|
|
1412
|
-
Per-table
|
|
822
|
+
Per-table counts of old primary rows migrated.
|
|
1413
823
|
|
|
1414
824
|
**Type:** `Record<string, number>`
|
|
1415
825
|
|
|
@@ -1419,55 +829,15 @@ Per-table conversion failure counts by reason.
|
|
|
1419
829
|
|
|
1420
830
|
**Type:** `Record<string, Record<string, number>>`
|
|
1421
831
|
|
|
1422
|
-
#### migrationResult.
|
|
832
|
+
#### migrationResult.rewritten · member
|
|
1423
833
|
|
|
1424
|
-
|
|
834
|
+
Per-table counts of rows rewritten to latest version.
|
|
1425
835
|
|
|
1426
|
-
**Type:** `number
|
|
1427
|
-
|
|
1428
|
-
## Schema Migrations
|
|
1429
|
-
|
|
1430
|
-
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.
|
|
1431
|
-
|
|
1432
|
-
### What happens automatically (lazy migration)
|
|
1433
|
-
|
|
1434
|
-
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.
|
|
1435
|
-
|
|
1436
|
-
```typescript
|
|
1437
|
-
@E.registerModel
|
|
1438
|
-
class User extends E.Model<User> {
|
|
1439
|
-
static pk = E.primary(User, "id");
|
|
1440
|
-
id = E.field(E.identifier);
|
|
1441
|
-
name = E.field(E.string);
|
|
1442
|
-
role = E.field(E.string); // newly added field
|
|
1443
|
-
|
|
1444
|
-
static migrate(record: Record<string, any>) {
|
|
1445
|
-
record.role ??= "user"; // provide a default for old rows
|
|
1446
|
-
}
|
|
1447
|
-
}
|
|
1448
|
-
```
|
|
1449
|
-
|
|
1450
|
-
### What requires `migrate-edinburgh`
|
|
1451
|
-
|
|
1452
|
-
The `migrate-edinburgh` CLI tool (or the `runMigration()` API) must be run when:
|
|
1453
|
-
|
|
1454
|
-
- **Adding or removing** secondary or unique indexes
|
|
1455
|
-
- **Changing the fields or types** of an existing index
|
|
1456
|
-
- A **`migrate()` function changes values** that are used in index fields
|
|
1457
|
-
|
|
1458
|
-
The tool populates new indexes, removes orphaned ones, and updates index entries whose values were changed by `migrate()`. It does *not* rewrite primary data rows - lazy migration handles that on read.
|
|
1459
|
-
|
|
1460
|
-
```bash
|
|
1461
|
-
npx migrate-edinburgh --import ./src/models.ts
|
|
1462
|
-
```
|
|
836
|
+
**Type:** `Record<string, number>`
|
|
1463
837
|
|
|
1464
|
-
|
|
838
|
+
#### migrationResult.orphans · member
|
|
1465
839
|
|
|
1466
|
-
|
|
840
|
+
Number of orphaned index entries deleted.
|
|
1467
841
|
|
|
1468
|
-
|
|
1469
|
-
import { runMigration } from "edinburgh";
|
|
842
|
+
**Type:** `number`
|
|
1470
843
|
|
|
1471
|
-
const result = await runMigration({ tables: ["User"] });
|
|
1472
|
-
console.log(result.upgraded); // { User: 1500 }
|
|
1473
|
-
```
|