edinburgh 0.4.6 → 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 (77) hide show
  1. package/README.md +403 -461
  2. package/build/src/datapack.d.ts +9 -9
  3. package/build/src/datapack.js +10 -10
  4. package/build/src/datapack.js.map +1 -1
  5. package/build/src/edinburgh.d.ts +21 -10
  6. package/build/src/edinburgh.js +33 -55
  7. package/build/src/edinburgh.js.map +1 -1
  8. package/build/src/indexes.d.ts +99 -288
  9. package/build/src/indexes.js +253 -636
  10. package/build/src/indexes.js.map +1 -1
  11. package/build/src/migrate.js +17 -39
  12. package/build/src/migrate.js.map +1 -1
  13. package/build/src/models.d.ts +177 -113
  14. package/build/src/models.js +487 -259
  15. package/build/src/models.js.map +1 -1
  16. package/build/src/types.d.ts +41 -51
  17. package/build/src/types.js +39 -52
  18. package/build/src/types.js.map +1 -1
  19. package/build/src/utils.d.ts +4 -4
  20. package/build/src/utils.js +4 -4
  21. package/package.json +1 -3
  22. package/skill/AnyModelClass.md +7 -0
  23. package/skill/FindOptions.md +37 -0
  24. package/skill/Lifecycle Hooks.md +24 -0
  25. package/skill/{Model_delete.md → Lifecycle Hooks_delete.md } +2 -2
  26. package/skill/{Model_getPrimaryKeyHash.md → Lifecycle Hooks_getPrimaryKeyHash.md } +1 -1
  27. package/skill/{Model_isValid.md → Lifecycle Hooks_isValid.md } +1 -1
  28. package/skill/Lifecycle Hooks_migrate.md +26 -0
  29. package/skill/{Model_preCommit.md → Lifecycle Hooks_preCommit.md } +3 -5
  30. package/skill/{Model_preventPersist.md → Lifecycle Hooks_preventPersist.md } +2 -2
  31. package/skill/{Model_validate.md → Lifecycle Hooks_validate.md } +2 -2
  32. package/skill/ModelBase.md +7 -0
  33. package/skill/ModelClass.md +8 -0
  34. package/skill/SKILL.md +253 -215
  35. package/skill/Schema Evolution.md +19 -0
  36. package/skill/TypeWrapper_containsNull.md +11 -0
  37. package/skill/TypeWrapper_deserialize.md +9 -0
  38. package/skill/TypeWrapper_getError.md +11 -0
  39. package/skill/TypeWrapper_serialize.md +10 -0
  40. package/skill/TypeWrapper_serializeType.md +9 -0
  41. package/skill/array.md +2 -2
  42. package/skill/defineModel.md +23 -0
  43. package/skill/deleteEverything.md +8 -0
  44. package/skill/field.md +4 -4
  45. package/skill/link.md +12 -10
  46. package/skill/literal.md +1 -1
  47. package/skill/opt.md +1 -1
  48. package/skill/or.md +1 -1
  49. package/skill/record.md +1 -1
  50. package/skill/set.md +2 -2
  51. package/skill/setOnSaveCallback.md +2 -2
  52. package/skill/transact.md +3 -3
  53. package/src/datapack.ts +10 -10
  54. package/src/edinburgh.ts +46 -58
  55. package/src/indexes.ts +338 -802
  56. package/src/migrate.ts +15 -37
  57. package/src/models.ts +617 -314
  58. package/src/types.ts +61 -54
  59. package/src/utils.ts +4 -4
  60. package/skill/BaseIndex.md +0 -16
  61. package/skill/BaseIndex_batchProcess.md +0 -10
  62. package/skill/BaseIndex_find.md +0 -7
  63. package/skill/Model.md +0 -22
  64. package/skill/Model_findAll.md +0 -12
  65. package/skill/Model_migrate.md +0 -34
  66. package/skill/Model_replaceInto.md +0 -16
  67. package/skill/PrimaryIndex.md +0 -8
  68. package/skill/PrimaryIndex_get.md +0 -17
  69. package/skill/PrimaryIndex_getLazy.md +0 -13
  70. package/skill/SecondaryIndex.md +0 -9
  71. package/skill/UniqueIndex.md +0 -9
  72. package/skill/UniqueIndex_get.md +0 -17
  73. package/skill/dump.md +0 -8
  74. package/skill/index.md +0 -32
  75. package/skill/primary.md +0 -26
  76. package/skill/registerModel.md +0 -26
  77. package/skill/unique.md +0 -32
package/src/types.ts CHANGED
@@ -1,8 +1,9 @@
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
- import { PrimaryIndex, BaseIndex, IndexRangeIterator } from "./indexes.js";
6
7
 
7
8
 
8
9
  /**
@@ -25,34 +26,34 @@ export abstract class TypeWrapper<const T> {
25
26
 
26
27
  /**
27
28
  * Serialize a value from an object property to a Pack.
28
- * @param value - The value to serialize.
29
- * @param pack - The Pack instance to write to.
29
+ * @param value The value to serialize.
30
+ * @param pack The Pack instance to write to.
30
31
  */
31
32
  abstract serialize(value: T, pack: DataPack): void;
32
33
 
33
34
  /**
34
35
  * Deserialize a value from a Pack into an object property.
35
- * @param pack - The Pack instance to read from.
36
+ * @param pack The Pack instance to read from.
36
37
  */
37
38
  abstract deserialize(pack: DataPack): T;
38
39
 
39
40
  /**
40
41
  * Validate a value.
41
- * @param value - The value to validate.
42
+ * @param value The value to validate.
42
43
  * @returns - A DatabaseError if validation fails.
43
44
  */
44
45
  abstract getError(value: T): DatabaseError | void;
45
46
 
46
47
  /**
47
48
  * Serialize type metadata to a Pack (for schema serialization).
48
- * @param pack - The Pack instance to write to.
49
+ * @param pack The Pack instance to write to.
49
50
  */
50
51
  serializeType(pack: DataPack) {}
51
52
 
52
53
  /**
53
54
  * Check if indexing should be skipped for this field value.
54
- * @param obj - The object containing the value.
55
- * @param prop - The property name or index.
55
+ * @param obj The object containing the value.
56
+ * @param prop The property name or index.
56
57
  * @returns true if indexing should be skipped.
57
58
  */
58
59
  containsNull(value: T): boolean {
@@ -71,7 +72,7 @@ export abstract class TypeWrapper<const T> {
71
72
  return value1 === value2;
72
73
  }
73
74
 
74
- getLinkedModel(): (typeof Model<unknown>) | undefined {
75
+ getLinkedModel(): undefined | AnyModelClass {
75
76
  return;
76
77
  }
77
78
  }
@@ -80,7 +81,7 @@ export abstract class TypeWrapper<const T> {
80
81
  export interface TypeWrapper<T> {
81
82
  /**
82
83
  * Generate a default value for this type.
83
- * @param model - The model instance.
84
+ * @param model The model instance.
84
85
  * @returns The default value.
85
86
  */
86
87
  default?(model: any): T;
@@ -181,8 +182,8 @@ class ArrayType<T> extends TypeWrapper<T[]> {
181
182
 
182
183
  /**
183
184
  * Create a new ArrayType.
184
- * @param inner - Type wrapper for array elements.
185
- * @param opts - Array constraints (min/max length).
185
+ * @param inner Type wrapper for array elements.
186
+ * @param opts Array constraints (min/max length).
186
187
  */
187
188
  constructor(public inner: TypeWrapper<T>, public opts: {min?: number, max?: number} = {}) {
188
189
  super();
@@ -262,7 +263,7 @@ export class SetType<T> extends TypeWrapper<Set<T>> {
262
263
 
263
264
  /**
264
265
  * Create a new SetType.
265
- * @param inner - Type wrapper for set elements.
266
+ * @param inner Type wrapper for set elements.
266
267
  */
267
268
  constructor(public inner: TypeWrapper<T>, public opts: {min?: number, max?: number} = {}) {
268
269
  super();
@@ -355,7 +356,7 @@ class RecordType<T> extends TypeWrapper<Record<string | number, T>> {
355
356
 
356
357
  serialize(value: Record<string | number, T>, pack: DataPack) {
357
358
  pack.writeCollectionBoundary('object');
358
- for (const key of Object.keys(value)) {
359
+ for (const key in value) {
359
360
  pack.writeObjectKey(key);
360
361
  this.inner.serialize(value[key], pack);
361
362
  }
@@ -374,7 +375,7 @@ class RecordType<T> extends TypeWrapper<Record<string | number, T>> {
374
375
  }
375
376
 
376
377
  getError(value: Record<string | number, T>) {
377
- if (typeof value !== 'object' || value === null || Array.isArray(value)) {
378
+ if (typeof value !== 'object' || value === null || Array.isArray(value) || (typeof value.length === 'number' && typeof value[Symbol.iterator as any] === 'function')) {
378
379
  return new DatabaseError(`Expected object, got ${typeof value}`, 'INVALID_TYPE');
379
380
  }
380
381
  for (const key of Object.keys(value)) {
@@ -431,7 +432,7 @@ class OrType<const T> extends TypeWrapper<T> {
431
432
 
432
433
  /**
433
434
  * Create a new OrType.
434
- * @param choices - Array of type wrappers representing the union choices.
435
+ * @param choices Array of type wrappers representing the union choices.
435
436
  */
436
437
  constructor(public choices: TypeWrapper<T>[]) {
437
438
  super();
@@ -522,7 +523,7 @@ class LiteralType<const T> extends TypeWrapper<T> {
522
523
 
523
524
  /**
524
525
  * Create a new LiteralType.
525
- * @param value - The literal value this type represents.
526
+ * @param value The literal value this type represents.
526
527
  */
527
528
  constructor(public value: T) {
528
529
  super();
@@ -596,7 +597,7 @@ class IdentifierType extends TypeWrapper<string> {
596
597
  let id: string;
597
598
  do {
598
599
  id = DataPack.generateIdentifier();
599
- } 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()));
600
601
  return id;
601
602
  }
602
603
  }
@@ -605,17 +606,22 @@ class IdentifierType extends TypeWrapper<string> {
605
606
  * @internal Type wrapper for model relationships (foreign keys).
606
607
  * @template T - The target model class type.
607
608
  */
608
- export class LinkType<T extends typeof Model<unknown>> extends TypeWrapper<InstanceType<T>> {
609
+ export class LinkType<T extends new (...args: any[]) => Model<any>> extends TypeWrapper<InstanceType<T>> {
609
610
  kind = 'link';
610
- tableName: string;
611
+ private TargetModel: T | (() => T);
611
612
 
612
613
  /**
613
614
  * Create a new LinkType.
614
- * @param TargetModel - The model class this link points to.
615
+ * @param TargetModel The model class this link points to, or a thunk for forward references.
615
616
  */
616
- constructor(TargetModel: T) {
617
+ constructor(TargetModel: T | (() => T)) {
617
618
  super();
618
- this.tableName = (TargetModel as any).tableName || TargetModel.name;
619
+ this.TargetModel = TargetModel;
620
+ }
621
+
622
+ getLinkedModel(): AnyModelClass {
623
+ if (!('getLazy' in this.TargetModel)) this.TargetModel = (this.TargetModel as unknown as () => T)();
624
+ return this.TargetModel as any;
619
625
  }
620
626
 
621
627
  serialize(model: InstanceType<T>, pack: DataPack) {
@@ -623,31 +629,28 @@ export class LinkType<T extends typeof Model<unknown>> extends TypeWrapper<Insta
623
629
  }
624
630
 
625
631
  deserialize(pack: DataPack) {
626
- return modelRegistry[this.tableName]._primary!._get(currentTxn(), pack.readUint8Array(), false);
632
+ return this.getLinkedModel()._get(currentTxn(), pack.readUint8Array(), false);
627
633
  }
628
634
 
629
635
  getError(value: InstanceType<T>) {
630
- if (!(value instanceof modelRegistry[this.tableName])) {
631
- return new DatabaseError(`Expected instance of ${this.tableName}, got ${typeof value}`, 'VALUE_ERROR');
636
+ const TargetModel = this.getLinkedModel();
637
+ if (!((value as any) instanceof TargetModel)) {
638
+ return new DatabaseError(`Expected instance of ${TargetModel.tableName}, got ${typeof value}`, 'VALUE_ERROR');
632
639
  }
633
640
  }
634
641
 
635
642
  serializeType(pack: DataPack): void {
636
- pack.write(this.tableName);
643
+ pack.write(this.getLinkedModel().tableName);
637
644
  }
638
645
 
639
646
  static deserializeType(pack: DataPack, featureFlags: number): LinkType<any> {
640
647
  const tableName = pack.readString();
641
648
  const targetModel = modelRegistry[tableName];
642
649
  if (!targetModel) throw new DatabaseError(`Could not deserialize undefined model ${tableName}`, 'DESERIALIZATION_ERROR');
643
- return new LinkType(targetModel);
650
+ return new LinkType(targetModel as any);
644
651
  }
645
652
 
646
- toString() { return `link<${this.tableName}>`; }
647
-
648
- getLinkedModel(): T {
649
- return modelRegistry[this.tableName] as T;
650
- }
653
+ toString() { return `link<${this.getLinkedModel().tableName}>`; }
651
654
  }
652
655
 
653
656
  /** Type wrapper instance for the string type. */
@@ -679,7 +682,7 @@ export const undef = new LiteralType(undefined) as TypeWrapper<undefined>;
679
682
  /**
680
683
  * Create a literal type wrapper for a constant value.
681
684
  * @template T - The literal type.
682
- * @param value - The literal value.
685
+ * @param value The literal value.
683
686
  * @returns A literal type instance.
684
687
  *
685
688
  * @example
@@ -695,7 +698,7 @@ export function literal<const T>(value: T): TypeWrapper<T> {
695
698
  /**
696
699
  * Create a union type wrapper from multiple type choices.
697
700
  * @template T - Array of type wrapper or basic types.
698
- * @param choices - The type choices for the union.
701
+ * @param choices The type choices for the union.
699
702
  * @returns A union type instance.
700
703
  *
701
704
  * @example
@@ -711,7 +714,7 @@ export function or<const T extends (TypeWrapper<unknown>|BasicType)[]>(...choice
711
714
  /**
712
715
  * Create an optional type wrapper (allows undefined).
713
716
  * @template T - Type wrapper or basic type to make optional.
714
- * @param inner - The inner type to make optional.
717
+ * @param inner The inner type to make optional.
715
718
  * @returns A union type that accepts the inner type or undefined.
716
719
  *
717
720
  * @example
@@ -727,8 +730,8 @@ export function opt<const T extends TypeWrapper<unknown>|BasicType>(inner: T): T
727
730
  /**
728
731
  * Create an array type wrapper with optional length constraints.
729
732
  * @template T - The element type.
730
- * @param inner - Type wrapper for array elements.
731
- * @param opts - Optional constraints (min/max length).
733
+ * @param inner Type wrapper for array elements.
734
+ * @param opts Optional constraints (min/max length).
732
735
  * @returns An array type instance.
733
736
  *
734
737
  * @example
@@ -744,8 +747,8 @@ export function array<const T>(inner: TypeWrapper<T>, opts: {min?: number, max?:
744
747
  /**
745
748
  * Create a Set type wrapper with optional length constraints.
746
749
  * @template T - The element type.
747
- * @param inner - Type wrapper for set elements.
748
- * @param opts - Optional constraints (min/max length).
750
+ * @param inner Type wrapper for set elements.
751
+ * @param opts Optional constraints (min/max length).
749
752
  * @returns A set type instance.
750
753
  *
751
754
  * @example
@@ -761,7 +764,7 @@ export function set<const T>(inner: TypeWrapper<T>, opts: {min?: number, max?: n
761
764
  /**
762
765
  * Create a Record type wrapper for key-value objects with string or number keys.
763
766
  * @template T - The value type.
764
- * @param inner - Type wrapper for record values.
767
+ * @param inner Type wrapper for record values.
765
768
  * @returns A record type instance.
766
769
  *
767
770
  * @example
@@ -776,21 +779,25 @@ export function record<const T>(inner: TypeWrapper<T>): TypeWrapper<Record<strin
776
779
  /**
777
780
  * Create a link type wrapper for model relationships.
778
781
  * @template T - The target model class.
779
- * @param TargetModel - The model class this link points to.
782
+ * @param TargetModel The model class this link points to.
780
783
  * @returns A link type instance.
781
784
  *
782
785
  * @example
783
786
  * ```typescript
784
- * class User extends E.Model<User> {
785
- * posts = E.field(E.array(E.link(Post, 'author')));
786
- * }
787
+ * const Author = E.defineModel("Author", class {
788
+ * id = E.field(E.identifier);
789
+ * posts = E.field(E.array(E.link(() => Book)));
790
+ * }, { pk: "id" });
787
791
  *
788
- * class Post extends E.Model<Post> {
789
- * author = E.field(E.link(User));
790
- * }
792
+ * const Book = E.defineModel("Book", class {
793
+ * id = E.field(E.identifier);
794
+ * author = E.field(E.link(Author));
795
+ * }, { pk: "id" });
791
796
  * ```
792
797
  */
793
- export function link<const T extends typeof Model<any>>(TargetModel: T): TypeWrapper<InstanceType<T>> {
798
+ export function link<const T extends new (...args: any[]) => Model<any>>(TargetModel: T): TypeWrapper<InstanceType<T>>;
799
+ export function link<const T extends new (...args: any[]) => Model<any>>(TargetModel: () => T): TypeWrapper<InstanceType<T>>;
800
+ export function link(TargetModel: any): TypeWrapper<any> {
794
801
  return new LinkType(TargetModel);
795
802
  }
796
803
 
@@ -810,8 +817,8 @@ function wrapIfLiteral(type: any) {
810
817
 
811
818
  /**
812
819
  * Serialize a type wrapper to a Pack for schema persistence.
813
- * @param arg - The type wrapper to serialize.
814
- * @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.
815
822
  */
816
823
  export function serializeType(arg: TypeWrapper<any>, pack: DataPack) {
817
824
  pack.write(arg.kind);
@@ -834,8 +841,8 @@ const TYPE_WRAPPERS: Record<string, TypeWrapper<any> | {deserializeType: (pack:
834
841
 
835
842
  /**
836
843
  * Deserialize a type wrapper from a Pack.
837
- * @param pack - The Pack instance to read from.
838
- * @param featureFlags - Feature flags for version compatibility.
844
+ * @param pack The Pack instance to read from.
845
+ * @param featureFlags Feature flags for version compatibility.
839
846
  * @returns The deserialized type wrapper.
840
847
  */
841
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> & { 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>) => IndexRangeIterator<M>`
4
-
5
- **Parameters:**
6
-
7
- - `opts: FindOptions<ARGS>` (optional)
package/skill/Model.md DELETED
@@ -1,22 +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
- ⁣@E.registerModel
13
- class User extends E.Model<User> {
14
- static pk = E.primary(User, "id");
15
-
16
- id = E.field(E.identifier);
17
- name = E.field(E.string);
18
- email = E.field(E.string);
19
-
20
- static byEmail = E.unique(User, "email");
21
- }
22
- ```
@@ -1,12 +0,0 @@
1
- #### Model.findAll · static method
2
-
3
- Find all instances of this model in the database, ordered by primary key.
4
-
5
- **Signature:** `<T extends typeof Model<unknown>>(this: T, opts?: { reverse?: boolean; }) => IndexRangeIterator<T>`
6
-
7
- **Parameters:**
8
-
9
- - `this: T`
10
- - `opts?: {reverse?: boolean}` - - Optional parameters.
11
-
12
- **Returns:** An iterator.
@@ -1,34 +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
- ⁣@E.registerModel
24
- class User extends E.Model<User> {
25
- static pk = E.primary(User, "id");
26
- id = E.field(E.identifier);
27
- name = E.field(E.string);
28
- role = E.field(E.string); // new field
29
-
30
- static migrate(record: Record<string, any>) {
31
- record.role ??= "user"; // default for rows that predate the 'role' field
32
- }
33
- }
34
- ```
@@ -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<Omit<InstanceType<T>, "constructor">>) => InstanceType<T>`
10
-
11
- **Parameters:**
12
-
13
- - `this: T`
14
- - `obj: Partial<Omit<InstanceType<T>, "constructor">>` - - Partial model data that **must** include every primary key field.
15
-
16
- **Returns:** The loaded-and-updated or newly created instance.
@@ -1,8 +0,0 @@
1
- ### PrimaryIndex · class
2
-
3
- Primary index that stores the actual model data.
4
-
5
- **Type Parameters:**
6
-
7
- - `M extends typeof Model` - The model class this index belongs to.
8
- - `F extends readonly (keyof InstanceType<M> & string)[]` - The field names that make up this index.
@@ -1,17 +0,0 @@
1
- #### primaryIndex.get · method
2
-
3
- Get a model instance by primary key values.
4
-
5
- **Signature:** `(...args: IndexArgTypes<M, F>) => InstanceType<M>`
6
-
7
- **Parameters:**
8
-
9
- - `args: IndexArgTypes<M, F>` - - The primary key values.
10
-
11
- **Returns:** The model instance if found, undefined otherwise.
12
-
13
- **Examples:**
14
-
15
- ```typescript
16
- const user = User.pk.get("john_doe");
17
- ```
@@ -1,13 +0,0 @@
1
- #### primaryIndex.getLazy · method
2
-
3
- Does the same as as `get()`, but will delay loading the instance from disk until the first
4
- property access. In case it turns out the instance doesn't exist, an error will be thrown
5
- at that time.
6
-
7
- **Signature:** `(...args: IndexArgTypes<M, F>) => InstanceType<M>`
8
-
9
- **Parameters:**
10
-
11
- - `args: IndexArgTypes<M, F>` - Primary key field values. (Or a single Uint8Array containing the key.)
12
-
13
- **Returns:** The (lazily loaded) model instance.
@@ -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` - The model class this index belongs to.
8
- - `F extends readonly (keyof InstanceType<M> & string)[]` - The field names that make up this index.
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` - The model class this index belongs to.
8
- - `F extends readonly (keyof InstanceType<M> & string)[]` - The field names that make up this index.
9
- - `ARGS extends readonly any[] = IndexArgTypes<M, F>`
@@ -1,17 +0,0 @@
1
- #### uniqueIndex.get · method
2
-
3
- Get a model instance by unique index key values.
4
-
5
- **Signature:** `(...args: ARGS) => InstanceType<M>`
6
-
7
- **Parameters:**
8
-
9
- - `args: ARGS` - - The unique index key values.
10
-
11
- **Returns:** The model instance if found, undefined otherwise.
12
-
13
- **Examples:**
14
-
15
- ```typescript
16
- const userByEmail = User.byEmail.get("john@example.com");
17
- ```
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`
package/skill/index.md DELETED
@@ -1,32 +0,0 @@
1
- ### index · function
2
-
3
- Create a secondary index on model fields, or a computed secondary index using a function.
4
-
5
- For field-based indexes, pass a field name or array of field names.
6
- For computed indexes, pass a function that takes a model instance and returns an array of
7
- index keys. Return `[]` to skip indexing for that instance. Each array element creates a
8
- separate index entry, enabling multi-value indexes (e.g., indexing by each word in a name).
9
-
10
- **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)[]>(...`
11
-
12
- **Type Parameters:**
13
-
14
- - `M extends typeof Model` - The model class.
15
- - `V` - The computed index value type (for function-based indexes).
16
-
17
- **Parameters:**
18
-
19
- - `MyModel: M` - - The model class to create the index for.
20
- - `fn: (instance: InstanceType<M>) => V[]`
21
-
22
- **Returns:** A new SecondaryIndex instance.
23
-
24
- **Examples:**
25
-
26
- ```typescript
27
- class User extends E.Model<User> {
28
- static byAge = E.index(User, "age");
29
- static byTagsDate = E.index(User, ["tags", "createdAt"]);
30
- static byWord = E.index(User, (u: User) => u.name.split(" "));
31
- }
32
- ```
package/skill/primary.md DELETED
@@ -1,26 +0,0 @@
1
- ### primary · function
2
-
3
- Create a primary index on model fields.
4
-
5
- **Signature:** `{ <M extends typeof Model, const F extends (keyof InstanceType<M> & string)>(MyModel: M, field: F): PrimaryIndex<M, [F]>; <M extends typeof Model, const FS extends readonly (keyof InstanceType<M> & string)[]>(MyModel: M, fields: FS): PrimaryIndex<...>; }`
6
-
7
- **Type Parameters:**
8
-
9
- - `M extends typeof Model` - The model class.
10
- - `F extends (keyof InstanceType<M> & string)` - The field name (for single field index).
11
-
12
- **Parameters:**
13
-
14
- - `MyModel: M` - - The model class to create the index for.
15
- - `field: F` - - Single field name for simple indexes.
16
-
17
- **Returns:** A new PrimaryIndex instance.
18
-
19
- **Examples:**
20
-
21
- ```typescript
22
- class User extends E.Model<User> {
23
- static pk = E.primary(User, ["id"]);
24
- static pkSingle = E.primary(User, "id");
25
- }
26
- ```
@@ -1,26 +0,0 @@
1
- ### registerModel · function
2
-
3
- Register a model class with the Edinburgh ORM system.
4
-
5
- **Signature:** `<T extends typeof Model<unknown>>(MyModel: T) => T`
6
-
7
- **Type Parameters:**
8
-
9
- - `T extends typeof Model<unknown>` - The model class type.
10
-
11
- **Parameters:**
12
-
13
- - `MyModel: T` - - The model class to register.
14
-
15
- **Returns:** The enhanced model class with ORM capabilities.
16
-
17
- **Examples:**
18
-
19
- ```typescript
20
- ⁣@E.registerModel
21
- class User extends E.Model<User> {
22
- static pk = E.index(User, ["id"], "primary");
23
- id = E.field(E.identifier);
24
- name = E.field(E.string);
25
- }
26
- ```