edinburgh 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +322 -262
  2. package/build/src/datapack.d.ts +9 -9
  3. package/build/src/datapack.js +9 -9
  4. package/build/src/edinburgh.d.ts +18 -7
  5. package/build/src/edinburgh.js +30 -51
  6. package/build/src/edinburgh.js.map +1 -1
  7. package/build/src/indexes.d.ts +85 -205
  8. package/build/src/indexes.js +150 -503
  9. package/build/src/indexes.js.map +1 -1
  10. package/build/src/migrate.js +8 -10
  11. package/build/src/migrate.js.map +1 -1
  12. package/build/src/models.d.ts +152 -107
  13. package/build/src/models.js +433 -144
  14. package/build/src/models.js.map +1 -1
  15. package/build/src/types.d.ts +30 -48
  16. package/build/src/types.js +25 -24
  17. package/build/src/types.js.map +1 -1
  18. package/build/src/utils.d.ts +4 -4
  19. package/build/src/utils.js +4 -4
  20. package/package.json +1 -1
  21. package/skill/AnyModelClass.md +7 -0
  22. package/skill/FindOptions.md +37 -0
  23. package/skill/Lifecycle Hooks.md +24 -0
  24. package/skill/{Model_delete.md → Lifecycle Hooks_delete.md } +1 -1
  25. package/skill/{Model_getPrimaryKeyHash.md → Lifecycle Hooks_getPrimaryKeyHash.md } +1 -1
  26. package/skill/{Model_isValid.md → Lifecycle Hooks_isValid.md } +1 -1
  27. package/skill/Lifecycle Hooks_migrate.md +26 -0
  28. package/skill/{Model_preCommit.md → Lifecycle Hooks_preCommit.md } +2 -2
  29. package/skill/{Model_preventPersist.md → Lifecycle Hooks_preventPersist.md } +1 -1
  30. package/skill/{Model_validate.md → Lifecycle Hooks_validate.md } +2 -2
  31. package/skill/ModelBase.md +7 -0
  32. package/skill/ModelClass.md +8 -0
  33. package/skill/SKILL.md +180 -132
  34. package/skill/Schema Evolution.md +19 -0
  35. package/skill/TypeWrapper_containsNull.md +11 -0
  36. package/skill/TypeWrapper_deserialize.md +9 -0
  37. package/skill/TypeWrapper_getError.md +11 -0
  38. package/skill/TypeWrapper_serialize.md +10 -0
  39. package/skill/TypeWrapper_serializeType.md +9 -0
  40. package/skill/array.md +2 -2
  41. package/skill/defineModel.md +3 -2
  42. package/skill/deleteEverything.md +8 -0
  43. package/skill/field.md +3 -3
  44. package/skill/link.md +3 -3
  45. package/skill/literal.md +1 -1
  46. package/skill/opt.md +1 -1
  47. package/skill/or.md +1 -1
  48. package/skill/record.md +1 -1
  49. package/skill/set.md +2 -2
  50. package/skill/setOnSaveCallback.md +2 -2
  51. package/skill/transact.md +1 -1
  52. package/src/datapack.ts +9 -9
  53. package/src/edinburgh.ts +43 -52
  54. package/src/indexes.ts +251 -599
  55. package/src/migrate.ts +9 -10
  56. package/src/models.ts +528 -231
  57. package/src/types.ts +36 -34
  58. package/src/utils.ts +4 -4
  59. package/skill/BaseIndex.md +0 -16
  60. package/skill/BaseIndex_batchProcess.md +0 -10
  61. package/skill/BaseIndex_find.md +0 -7
  62. package/skill/BaseIndex_find_2.md +0 -7
  63. package/skill/BaseIndex_find_3.md +0 -7
  64. package/skill/BaseIndex_find_4.md +0 -7
  65. package/skill/Model.md +0 -20
  66. package/skill/Model_batchProcess.md +0 -8
  67. package/skill/Model_migrate.md +0 -32
  68. package/skill/Model_replaceInto.md +0 -16
  69. package/skill/NonPrimaryIndex.md +0 -10
  70. package/skill/SecondaryIndex.md +0 -9
  71. package/skill/UniqueIndex.md +0 -9
  72. package/skill/dump.md +0 -8
package/src/types.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import DataPack from "./datapack.js";
2
2
  import { DatabaseError } from "olmdb/lowlevel";
3
- import { Model, modelRegistry, FieldConfig, currentTxn } from "./models.js";
3
+ import { currentTxn } from "./edinburgh.js";
4
+ import { Model, modelRegistry } from "./models.js";
5
+ import type { AnyModelClass } from "./models.js";
4
6
  import { assert, addErrorPath, dbGet } from "./utils.js";
5
7
 
6
8
 
@@ -24,34 +26,34 @@ export abstract class TypeWrapper<const T> {
24
26
 
25
27
  /**
26
28
  * Serialize a value from an object property to a Pack.
27
- * @param value - The value to serialize.
28
- * @param pack - The Pack instance to write to.
29
+ * @param value The value to serialize.
30
+ * @param pack The Pack instance to write to.
29
31
  */
30
32
  abstract serialize(value: T, pack: DataPack): void;
31
33
 
32
34
  /**
33
35
  * Deserialize a value from a Pack into an object property.
34
- * @param pack - The Pack instance to read from.
36
+ * @param pack The Pack instance to read from.
35
37
  */
36
38
  abstract deserialize(pack: DataPack): T;
37
39
 
38
40
  /**
39
41
  * Validate a value.
40
- * @param value - The value to validate.
42
+ * @param value The value to validate.
41
43
  * @returns - A DatabaseError if validation fails.
42
44
  */
43
45
  abstract getError(value: T): DatabaseError | void;
44
46
 
45
47
  /**
46
48
  * Serialize type metadata to a Pack (for schema serialization).
47
- * @param pack - The Pack instance to write to.
49
+ * @param pack The Pack instance to write to.
48
50
  */
49
51
  serializeType(pack: DataPack) {}
50
52
 
51
53
  /**
52
54
  * Check if indexing should be skipped for this field value.
53
- * @param obj - The object containing the value.
54
- * @param prop - The property name or index.
55
+ * @param obj The object containing the value.
56
+ * @param prop The property name or index.
55
57
  * @returns true if indexing should be skipped.
56
58
  */
57
59
  containsNull(value: T): boolean {
@@ -70,7 +72,7 @@ export abstract class TypeWrapper<const T> {
70
72
  return value1 === value2;
71
73
  }
72
74
 
73
- getLinkedModel(): undefined | typeof Model<unknown> {
75
+ getLinkedModel(): undefined | AnyModelClass {
74
76
  return;
75
77
  }
76
78
  }
@@ -79,7 +81,7 @@ export abstract class TypeWrapper<const T> {
79
81
  export interface TypeWrapper<T> {
80
82
  /**
81
83
  * Generate a default value for this type.
82
- * @param model - The model instance.
84
+ * @param model The model instance.
83
85
  * @returns The default value.
84
86
  */
85
87
  default?(model: any): T;
@@ -180,8 +182,8 @@ class ArrayType<T> extends TypeWrapper<T[]> {
180
182
 
181
183
  /**
182
184
  * Create a new ArrayType.
183
- * @param inner - Type wrapper for array elements.
184
- * @param opts - Array constraints (min/max length).
185
+ * @param inner Type wrapper for array elements.
186
+ * @param opts Array constraints (min/max length).
185
187
  */
186
188
  constructor(public inner: TypeWrapper<T>, public opts: {min?: number, max?: number} = {}) {
187
189
  super();
@@ -261,7 +263,7 @@ export class SetType<T> extends TypeWrapper<Set<T>> {
261
263
 
262
264
  /**
263
265
  * Create a new SetType.
264
- * @param inner - Type wrapper for set elements.
266
+ * @param inner Type wrapper for set elements.
265
267
  */
266
268
  constructor(public inner: TypeWrapper<T>, public opts: {min?: number, max?: number} = {}) {
267
269
  super();
@@ -430,7 +432,7 @@ class OrType<const T> extends TypeWrapper<T> {
430
432
 
431
433
  /**
432
434
  * Create a new OrType.
433
- * @param choices - Array of type wrappers representing the union choices.
435
+ * @param choices Array of type wrappers representing the union choices.
434
436
  */
435
437
  constructor(public choices: TypeWrapper<T>[]) {
436
438
  super();
@@ -521,7 +523,7 @@ class LiteralType<const T> extends TypeWrapper<T> {
521
523
 
522
524
  /**
523
525
  * Create a new LiteralType.
524
- * @param value - The literal value this type represents.
526
+ * @param value The literal value this type represents.
525
527
  */
526
528
  constructor(public value: T) {
527
529
  super();
@@ -595,7 +597,7 @@ class IdentifierType extends TypeWrapper<string> {
595
597
  let id: string;
596
598
  do {
597
599
  id = DataPack.generateIdentifier();
598
- } while (dbGet(model._txn.id, new DataPack().write(model.constructor._primary!._indexId!).writeIdentifier(id).toUint8Array()));
600
+ } while (dbGet(model._txn.id, new DataPack().write(model.constructor._indexId!).writeIdentifier(id).toUint8Array()));
599
601
  return id;
600
602
  }
601
603
  }
@@ -610,14 +612,14 @@ export class LinkType<T extends new (...args: any[]) => Model<any>> extends Type
610
612
 
611
613
  /**
612
614
  * Create a new LinkType.
613
- * @param TargetModel - The model class this link points to, or a thunk for forward references.
615
+ * @param TargetModel The model class this link points to, or a thunk for forward references.
614
616
  */
615
617
  constructor(TargetModel: T | (() => T)) {
616
618
  super();
617
619
  this.TargetModel = TargetModel;
618
620
  }
619
621
 
620
- getLinkedModel(): typeof Model<unknown> {
622
+ getLinkedModel(): AnyModelClass {
621
623
  if (!('getLazy' in this.TargetModel)) this.TargetModel = (this.TargetModel as unknown as () => T)();
622
624
  return this.TargetModel as any;
623
625
  }
@@ -627,7 +629,7 @@ export class LinkType<T extends new (...args: any[]) => Model<any>> extends Type
627
629
  }
628
630
 
629
631
  deserialize(pack: DataPack) {
630
- return this.getLinkedModel()._primary._get(currentTxn(), pack.readUint8Array(), false);
632
+ return this.getLinkedModel()._get(currentTxn(), pack.readUint8Array(), false);
631
633
  }
632
634
 
633
635
  getError(value: InstanceType<T>) {
@@ -680,7 +682,7 @@ export const undef = new LiteralType(undefined) as TypeWrapper<undefined>;
680
682
  /**
681
683
  * Create a literal type wrapper for a constant value.
682
684
  * @template T - The literal type.
683
- * @param value - The literal value.
685
+ * @param value The literal value.
684
686
  * @returns A literal type instance.
685
687
  *
686
688
  * @example
@@ -696,7 +698,7 @@ export function literal<const T>(value: T): TypeWrapper<T> {
696
698
  /**
697
699
  * Create a union type wrapper from multiple type choices.
698
700
  * @template T - Array of type wrapper or basic types.
699
- * @param choices - The type choices for the union.
701
+ * @param choices The type choices for the union.
700
702
  * @returns A union type instance.
701
703
  *
702
704
  * @example
@@ -712,7 +714,7 @@ export function or<const T extends (TypeWrapper<unknown>|BasicType)[]>(...choice
712
714
  /**
713
715
  * Create an optional type wrapper (allows undefined).
714
716
  * @template T - Type wrapper or basic type to make optional.
715
- * @param inner - The inner type to make optional.
717
+ * @param inner The inner type to make optional.
716
718
  * @returns A union type that accepts the inner type or undefined.
717
719
  *
718
720
  * @example
@@ -728,8 +730,8 @@ export function opt<const T extends TypeWrapper<unknown>|BasicType>(inner: T): T
728
730
  /**
729
731
  * Create an array type wrapper with optional length constraints.
730
732
  * @template T - The element type.
731
- * @param inner - Type wrapper for array elements.
732
- * @param opts - Optional constraints (min/max length).
733
+ * @param inner Type wrapper for array elements.
734
+ * @param opts Optional constraints (min/max length).
733
735
  * @returns An array type instance.
734
736
  *
735
737
  * @example
@@ -745,8 +747,8 @@ export function array<const T>(inner: TypeWrapper<T>, opts: {min?: number, max?:
745
747
  /**
746
748
  * Create a Set type wrapper with optional length constraints.
747
749
  * @template T - The element type.
748
- * @param inner - Type wrapper for set elements.
749
- * @param opts - Optional constraints (min/max length).
750
+ * @param inner Type wrapper for set elements.
751
+ * @param opts Optional constraints (min/max length).
750
752
  * @returns A set type instance.
751
753
  *
752
754
  * @example
@@ -762,7 +764,7 @@ export function set<const T>(inner: TypeWrapper<T>, opts: {min?: number, max?: n
762
764
  /**
763
765
  * Create a Record type wrapper for key-value objects with string or number keys.
764
766
  * @template T - The value type.
765
- * @param inner - Type wrapper for record values.
767
+ * @param inner Type wrapper for record values.
766
768
  * @returns A record type instance.
767
769
  *
768
770
  * @example
@@ -777,17 +779,17 @@ export function record<const T>(inner: TypeWrapper<T>): TypeWrapper<Record<strin
777
779
  /**
778
780
  * Create a link type wrapper for model relationships.
779
781
  * @template T - The target model class.
780
- * @param TargetModel - The model class this link points to.
782
+ * @param TargetModel The model class this link points to.
781
783
  * @returns A link type instance.
782
784
  *
783
785
  * @example
784
786
  * ```typescript
785
- * const Author = E.defineModel(class {
787
+ * const Author = E.defineModel("Author", class {
786
788
  * id = E.field(E.identifier);
787
789
  * posts = E.field(E.array(E.link(() => Book)));
788
790
  * }, { pk: "id" });
789
791
  *
790
- * const Book = E.defineModel(class {
792
+ * const Book = E.defineModel("Book", class {
791
793
  * id = E.field(E.identifier);
792
794
  * author = E.field(E.link(Author));
793
795
  * }, { pk: "id" });
@@ -815,8 +817,8 @@ function wrapIfLiteral(type: any) {
815
817
 
816
818
  /**
817
819
  * Serialize a type wrapper to a Pack for schema persistence.
818
- * @param arg - The type wrapper to serialize.
819
- * @param pack - The Pack instance to write to.
820
+ * @param arg The type wrapper to serialize.
821
+ * @param pack The Pack instance to write to.
820
822
  */
821
823
  export function serializeType(arg: TypeWrapper<any>, pack: DataPack) {
822
824
  pack.write(arg.kind);
@@ -839,8 +841,8 @@ const TYPE_WRAPPERS: Record<string, TypeWrapper<any> | {deserializeType: (pack:
839
841
 
840
842
  /**
841
843
  * Deserialize a type wrapper from a Pack.
842
- * @param pack - The Pack instance to read from.
843
- * @param featureFlags - Feature flags for version compatibility.
844
+ * @param pack The Pack instance to read from.
845
+ * @param featureFlags Feature flags for version compatibility.
844
846
  * @returns The deserialized type wrapper.
845
847
  */
846
848
  export function deserializeType(pack: DataPack, featureFlags: number): TypeWrapper<any> {
package/src/utils.ts CHANGED
@@ -2,8 +2,8 @@ import * as lowlevel from "olmdb/lowlevel";
2
2
 
3
3
  /**
4
4
  * Assert function for runtime checks with TypeScript assertion support.
5
- * @param cond - Condition to check.
6
- * @param message - Optional error message.
5
+ * @param cond Condition to check.
6
+ * @param message Optional error message.
7
7
  * @throws {Error} If condition is false.
8
8
  */
9
9
  export function assert(cond: any, message?: string): asserts cond {
@@ -58,8 +58,8 @@ export const ERROR_AT = /^(.*) at ([a-zA-Z0-9_.]+)$/;
58
58
 
59
59
  /**
60
60
  * Add a path segment to an exception for better error reporting.
61
- * @param error - The (Database)Error to modify.
62
- * @param path - The path segment to add (string or number).
61
+ * @param error The (Database)Error to modify.
62
+ * @param path The path segment to add (string or number).
63
63
  * @returns The modified DatabaseError.
64
64
  */
65
65
  export function addErrorPath<T>(error: T, path: string | number): T {
@@ -1,16 +0,0 @@
1
- ### BaseIndex · abstract class
2
-
3
- Base class for database indexes for efficient lookups on model fields.
4
-
5
- Indexes enable fast queries on specific field combinations and enforce uniqueness constraints.
6
-
7
- **Type Parameters:**
8
-
9
- - `M extends typeof Model` - The model class this index belongs to.
10
- - `F extends readonly (keyof InstanceType<M> & string)[]` - The field names that make up this index.
11
- - `ARGS extends readonly any[] = IndexArgTypes<M, F>`
12
-
13
- **Constructor Parameters:**
14
-
15
- - `MyModel`: - The model class this index belongs to.
16
- - `_fieldNames`: - Array of field names that make up this index.
@@ -1,10 +0,0 @@
1
- #### baseIndex.batchProcess · method
2
-
3
- [object Object],[object Object],[object Object]
4
-
5
- **Signature:** `(opts: FindOptions<ARGS, undefined> & { limitSeconds?: number; limitRows?: number; }, callback: (row: InstanceType<M>) => void | Promise<void>) => Promise<...>`
6
-
7
- **Parameters:**
8
-
9
- - `opts: FindOptions<ARGS> & { limitSeconds?: number; limitRows?: number }` (optional) - - Query options (same as `find()`), plus:
10
- - `callback: (row: InstanceType<M>) => void | Promise<void>` - - Called for each matching row within a transaction
@@ -1,7 +0,0 @@
1
- #### baseIndex.find · method
2
-
3
- **Signature:** `{ (opts?: FindOptions<ARGS, "first">): InstanceType<M>; (opts: FindOptions<ARGS, "single">): InstanceType<M>; (opts?: FindOptions<...>): IndexRangeIterator<...>; }`
4
-
5
- **Parameters:**
6
-
7
- - `opts?: FindOptions<ARGS, 'first'>`
@@ -1,7 +0,0 @@
1
- #### baseIndex.find · method
2
-
3
- **Signature:** `{ (opts?: FindOptions<ARGS, "first">): InstanceType<M>; (opts: FindOptions<ARGS, "single">): InstanceType<M>; (opts?: FindOptions<...>): IndexRangeIterator<...>; }`
4
-
5
- **Parameters:**
6
-
7
- - `opts: FindOptions<ARGS, 'single'>`
@@ -1,7 +0,0 @@
1
- #### baseIndex.find · method
2
-
3
- **Signature:** `{ (opts?: FindOptions<ARGS, "first">): InstanceType<M>; (opts: FindOptions<ARGS, "single">): InstanceType<M>; (opts?: FindOptions<...>): IndexRangeIterator<...>; }`
4
-
5
- **Parameters:**
6
-
7
- - `opts?: FindOptions<ARGS>`
@@ -1,7 +0,0 @@
1
- #### baseIndex.find · method
2
-
3
- **Signature:** `{ (opts?: FindOptions<ARGS, "first">): InstanceType<M>; (opts: FindOptions<ARGS, "single">): InstanceType<M>; (opts?: FindOptions<...>): IndexRangeIterator<...>; }`
4
-
5
- **Parameters:**
6
-
7
- - `opts: any` (optional)
package/skill/Model.md DELETED
@@ -1,20 +0,0 @@
1
- ### Model · abstract class
2
-
3
- [object Object],[object Object],[object Object],[object Object],[object Object]
4
-
5
- **Type Parameters:**
6
-
7
- - `SUB` - The concrete model subclass (for proper typing).
8
-
9
- **Examples:**
10
-
11
- ```typescript
12
- const User = E.defineModel(class {
13
- id = E.field(E.identifier);
14
- name = E.field(E.string);
15
- email = E.field(E.string);
16
- }, {
17
- pk: "id",
18
- unique: { byEmail: "email" },
19
- });
20
- ```
@@ -1,8 +0,0 @@
1
- #### Model.batchProcess · static method
2
-
3
- **Signature:** `(opts: any, callback?: any) => any`
4
-
5
- **Parameters:**
6
-
7
- - `opts: any`
8
- - `callback?: any`
@@ -1,32 +0,0 @@
1
- #### Model.migrate · static method
2
-
3
- Optional migration function called when deserializing rows written with an older schema version.
4
- Receives a plain record with all fields (primary key fields + value fields) and should mutate it
5
- in-place to match the current schema.
6
-
7
- This is called both during lazy loading (when a row is read from disk) and during batch
8
- migration (via `runMigration()` / `npx migrate-edinburgh`). The function's source code is hashed
9
- to detect changes. Modifying `migrate()` triggers a new schema version.
10
-
11
- If `migrate()` changes values of fields used in secondary or unique indexes, those indexes
12
- will only be updated when `runMigration()` is run (not during lazy loading).
13
-
14
- **Signature:** `(record: Record<string, any>) => void`
15
-
16
- **Parameters:**
17
-
18
- - `record: Record<string, any>` - - A plain object with all field values from the old schema version.
19
-
20
- **Examples:**
21
-
22
- ```typescript
23
- const User = E.defineModel(class {
24
- id = E.field(E.identifier);
25
- name = E.field(E.string);
26
- role = E.field(E.string); // new field
27
-
28
- static migrate(record: Record<string, any>) {
29
- record.role ??= "user"; // default for rows that predate the 'role' field
30
- }
31
- }, { pk: "id" });
32
- ```
@@ -1,16 +0,0 @@
1
- #### Model.replaceInto · static method
2
-
3
- Load an existing instance by primary key and update it, or create a new one.
4
-
5
- The provided object must contain all primary key fields. If a matching row exists,
6
- the remaining properties from `obj` are set on the loaded instance. Otherwise a
7
- new instance is created with `obj` as its initial properties.
8
-
9
- **Signature:** `<T extends typeof Model<any>>(this: T, obj: Partial<Record<string, any>>) => InstanceType<T>`
10
-
11
- **Parameters:**
12
-
13
- - `this: T`
14
- - `obj: Partial<Record<string, any>>` - - Partial model data that **must** include every primary key field.
15
-
16
- **Returns:** The loaded-and-updated or newly created instance.
@@ -1,10 +0,0 @@
1
- ### NonPrimaryIndex · abstract class
2
-
3
- Abstract base for all non-primary indexes (unique and secondary).
4
- Provides shared key serialization, write/delete/update logic.
5
-
6
- **Type Parameters:**
7
-
8
- - `M extends typeof Model`
9
- - `F extends readonly (keyof InstanceType<M> & string)[]`
10
- - `ARGS extends readonly any[] = IndexArgTypes<M, F>`
@@ -1,9 +0,0 @@
1
- ### SecondaryIndex · class
2
-
3
- Secondary index for non-unique lookups.
4
-
5
- **Type Parameters:**
6
-
7
- - `M extends typeof Model`
8
- - `F extends readonly (keyof InstanceType<M> & string)[]`
9
- - `ARGS extends readonly any[] = IndexArgTypes<M, F>`
@@ -1,9 +0,0 @@
1
- ### UniqueIndex · class
2
-
3
- Unique index that stores references to the primary key.
4
-
5
- **Type Parameters:**
6
-
7
- - `M extends typeof Model`
8
- - `F extends readonly (keyof InstanceType<M> & string)[]`
9
- - `ARGS extends readonly any[] = IndexArgTypes<M, F>`
package/skill/dump.md DELETED
@@ -1,8 +0,0 @@
1
- ### dump · function
2
-
3
- Dump database contents for debugging.
4
-
5
- Prints all indexes and their data to the console for inspection.
6
- This is primarily useful for development and debugging purposes.
7
-
8
- **Signature:** `() => void`