edinburgh 0.6.0 → 0.6.2

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 CHANGED
@@ -192,6 +192,22 @@ await E.transact(() => {
192
192
  });
193
193
  ```
194
194
 
195
+ If a primary key or named index includes a `link(...)` field, lookup helpers either accept the linked row's instance object or its primary key. For linked models with composite primary keys, pass the full tuple in that slot:
196
+
197
+ ```typescript
198
+ await E.transact(() => {
199
+ // So instead of..
200
+ const post1 = Post.getBy("author", Author.get(user.id), "Hello World");
201
+ // We can do..
202
+ const post2 = Post.getBy("author", user.id, "Hello World");
203
+ // Or..
204
+ const post3 = Post.getBy("author", [user.id], "Hello World");
205
+
206
+ // For an index that includes a link with a composite primary key..
207
+ const page = Comment.getBy("target", ["docs", "intro"], "overview");
208
+ });
209
+ ```
210
+
195
211
  #### Range Queries
196
212
 
197
213
  Primary-key queries use `.find()`. Named unique and secondary indexes use `.findBy(name, ...)`:
@@ -553,7 +569,7 @@ await E.transact(() => {
553
569
  });
554
570
  ```
555
571
 
556
- ### setMaxRetryCount · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L226)
572
+ ### setMaxRetryCount · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L232)
557
573
 
558
574
  Set the maximum number of retries for a transaction in case of conflicts.
559
575
  The default value is 6. Setting it to 0 will disable retries and cause transactions to fail immediately on conflict.
@@ -564,7 +580,7 @@ The default value is 6. Setting it to 0 will disable retries and cause transacti
564
580
 
565
581
  - `count: number` - The maximum number of retries for a transaction.
566
582
 
567
- ### setOnSaveCallback · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L240)
583
+ ### setOnSaveCallback · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L249)
568
584
 
569
585
  Set a callback function to be called after a model is saved and committed.
570
586
 
@@ -577,11 +593,14 @@ Set a callback function to be called after a model is saved and committed.
577
593
  - A sequential number. Higher numbers have been committed after lower numbers.
578
594
  - A map of model instances to their changes. The change can be "created", "deleted", or an object containing the old values.
579
595
 
580
- ### Model · [class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
596
+ The callback is called within a new transaction context, allowing lazy-loads to happen. However, any
597
+ changes made to Edinburgh models will not be saved.
598
+
599
+ ### Model · [class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
581
600
 
582
601
  **Type:** `typeof ModelBase`
583
602
 
584
- ### ModelClass · [class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
603
+ ### ModelClass · [class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
585
604
 
586
605
  Runtime base constructor for model classes returned by `defineModel()`.
587
606
 
@@ -590,7 +609,7 @@ Prefer the `ModelClass` type alias for annotations and the result of
590
609
 
591
610
  **Type:** `typeof ModelClassRuntime`
592
611
 
593
- ### AnyModelClass · [type](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L111)
612
+ ### AnyModelClass · [type](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L113)
594
613
 
595
614
  A model constructor with its generic information erased.
596
615
 
@@ -598,7 +617,7 @@ Useful when accepting or storing arbitrary registered model classes.
598
617
 
599
618
  **Type:** `ModelClass<new () => any, readonly any[], any, any>`
600
619
 
601
- ### ModelBase · [abstract class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
620
+ ### ModelBase · [abstract class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
602
621
 
603
622
  Base class for all database models in the Edinburgh ORM.
604
623
 
@@ -651,7 +670,7 @@ const User = E.defineModel("User", class {
651
670
  type User = InstanceType<typeof User>;
652
671
  ```
653
672
 
654
- #### ModelBase.migrate · [static method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
673
+ #### ModelBase.migrate · [static method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
655
674
 
656
675
  Optional migration function called when deserializing rows written with an older schema version.
657
676
  Receives a plain record with all fields and should mutate it in-place to match the current schema.
@@ -678,7 +697,7 @@ const User = E.defineModel("User", class {
678
697
  }, { pk: "id" });
679
698
  ```
680
699
 
681
- #### modelBase.preCommit · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
700
+ #### modelBase.preCommit · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
682
701
 
683
702
  Optional hook called on each modified instance right before the transaction commits.
684
703
  Runs before data is written to disk, so changes made here are included in the commit.
@@ -705,19 +724,19 @@ const Post = E.defineModel("Post", class {
705
724
  }, { pk: "id" });
706
725
  ```
707
726
 
708
- #### modelBase.getPrimaryKey · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
727
+ #### modelBase.getPrimaryKey · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
709
728
 
710
729
  **Signature:** `() => Uint8Array<ArrayBufferLike>`
711
730
 
712
731
  **Returns:** The primary key for this instance.
713
732
 
714
- #### modelBase.getPrimaryKeyHash · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
733
+ #### modelBase.getPrimaryKeyHash · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
715
734
 
716
735
  **Signature:** `() => number`
717
736
 
718
737
  **Returns:** A 53-bit positive integer non-cryptographic hash of the primary key, or undefined if not yet saved.
719
738
 
720
- #### modelBase.isLazyField · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
739
+ #### modelBase.isLazyField · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
721
740
 
722
741
  **Signature:** `(field: keyof this) => boolean`
723
742
 
@@ -725,7 +744,7 @@ const Post = E.defineModel("Post", class {
725
744
 
726
745
  - `field: keyof this`
727
746
 
728
- #### modelBase.preventPersist · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
747
+ #### modelBase.preventPersist · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
729
748
 
730
749
  Prevent this instance from being persisted to the database.
731
750
 
@@ -741,7 +760,7 @@ user.name = "New Name";
741
760
  user.preventPersist(); // Changes won't be saved
742
761
  ```
743
762
 
744
- #### modelBase.delete · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
763
+ #### modelBase.delete · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
745
764
 
746
765
  Delete this model instance from the database.
747
766
 
@@ -756,7 +775,7 @@ const user = User.get("user123");
756
775
  user.delete(); // Removes from database
757
776
  ```
758
777
 
759
- #### modelBase.validate · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
778
+ #### modelBase.validate · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
760
779
 
761
780
  Validate all fields in this model instance.
762
781
 
@@ -778,7 +797,7 @@ if (errors.length > 0) {
778
797
  }
779
798
  ```
780
799
 
781
- #### modelBase.isValid · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
800
+ #### modelBase.isValid · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
782
801
 
783
802
  Check if this model instance is valid.
784
803
 
@@ -793,19 +812,19 @@ const user = new User({name: "John"});
793
812
  if (!user.isValid()) shoutAtTheUser();
794
813
  ```
795
814
 
796
- #### modelBase.getState · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
815
+ #### modelBase.getState · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
797
816
 
798
817
  **Signature:** `() => "created" | "deleted" | "loaded" | "lazy"`
799
818
 
800
- #### modelBase.toString · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
819
+ #### modelBase.toString · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
801
820
 
802
821
  **Signature:** `() => string`
803
822
 
804
- #### modelBase.[Symbol.for('nodejs.util.inspect.custom')] · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
823
+ #### modelBase.[Symbol.for('nodejs.util.inspect.custom')] · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
805
824
 
806
825
  **Signature:** `() => string`
807
826
 
808
- ### defineModel · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
827
+ ### defineModel · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
809
828
 
810
829
  Register a model class with the Edinburgh ORM system.
811
830
 
@@ -829,7 +848,7 @@ typed fields, primary key access, and optional secondary and unique indexes.
829
848
 
830
849
  **Returns:** The enhanced model constructor.
831
850
 
832
- ### deleteEverything · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
851
+ ### deleteEverything · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
833
852
 
834
853
  Delete every key/value entry in the database and reinitialize all registered models.
835
854
 
@@ -838,7 +857,7 @@ for tests, local resets, or tooling that needs a completely empty database.
838
857
 
839
858
  **Signature:** `() => Promise<void>`
840
859
 
841
- ### field · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L76)
860
+ ### field · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L77)
842
861
 
843
862
  Create a field definition for a model property.
844
863
 
@@ -846,16 +865,16 @@ This function uses TypeScript magic to return the field configuration object
846
865
  while appearing to return the actual field value type to the type system.
847
866
  This allows for both runtime introspection and compile-time type safety.
848
867
 
849
- **Signature:** `<T>(type: TypeWrapper<T>, options?: Partial<FieldConfig<T>>) => T`
868
+ **Signature:** `<TYPE extends TypeWrapper<any>>(type: TYPE, options?: Partial<FieldConfig<FieldValue<TYPE>>>) => FieldValue<TYPE>`
850
869
 
851
870
  **Type Parameters:**
852
871
 
853
- - `T` - The field type.
872
+ - `TYPE extends TypeWrapper<any>` - The field type.
854
873
 
855
874
  **Parameters:**
856
875
 
857
- - `type: TypeWrapper<T>` - The type wrapper for this field.
858
- - `options: Partial<FieldConfig<T>>` (optional) - Additional field configuration options.
876
+ - `type: TYPE` - The type wrapper for this field.
877
+ - `options: Partial<FieldConfig<FieldValue<TYPE>>>` (optional) - Additional field configuration options.
859
878
 
860
879
  **Returns:** The field value (typed as T, but actually returns FieldConfig<T>).
861
880
 
@@ -868,13 +887,13 @@ const User = E.defineModel("User", class {
868
887
  });
869
888
  ```
870
889
 
871
- ### string · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
890
+ ### string · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
872
891
 
873
892
  Type wrapper instance for the string type.
874
893
 
875
894
  **Value:** `TypeWrapper<string>`
876
895
 
877
- ### orderedString · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
896
+ ### orderedString · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
878
897
 
879
898
  Type wrapper instance for the ordered string type, which is just like a string
880
899
  except that it sorts lexicographically in the database (instead of by incrementing
@@ -884,37 +903,37 @@ may not contain null characters.
884
903
 
885
904
  **Value:** `TypeWrapper<string>`
886
905
 
887
- ### number · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
906
+ ### number · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
888
907
 
889
908
  Type wrapper instance for the number type.
890
909
 
891
910
  **Value:** `TypeWrapper<number>`
892
911
 
893
- ### dateTime · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
912
+ ### dateTime · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
894
913
 
895
914
  Type wrapper instance for the date/time type. Stored without timezone info, rounded to whole seconds.
896
915
 
897
916
  **Value:** `TypeWrapper<Date>`
898
917
 
899
- ### boolean · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
918
+ ### boolean · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
900
919
 
901
920
  Type wrapper instance for the boolean type.
902
921
 
903
922
  **Value:** `TypeWrapper<boolean>`
904
923
 
905
- ### identifier · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
924
+ ### identifier · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
906
925
 
907
926
  Type wrapper instance for the identifier type.
908
927
 
909
928
  **Value:** `TypeWrapper<string>`
910
929
 
911
- ### undef · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
930
+ ### undef · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
912
931
 
913
932
  Type wrapper instance for the 'undefined' type.
914
933
 
915
934
  **Value:** `TypeWrapper<undefined>`
916
935
 
917
- ### opt · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
936
+ ### opt · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
918
937
 
919
938
  Create an optional type wrapper (allows undefined).
920
939
 
@@ -937,7 +956,7 @@ const optionalString = E.opt(E.string);
937
956
  const optionalNumber = E.opt(E.number);
938
957
  ```
939
958
 
940
- ### or · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
959
+ ### or · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
941
960
 
942
961
  Create a union type wrapper from multiple type choices.
943
962
 
@@ -960,7 +979,7 @@ const stringOrNumber = E.or(E.string, E.number);
960
979
  const status = E.or("active", "inactive", "pending");
961
980
  ```
962
981
 
963
- ### array · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
982
+ ### array · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
964
983
 
965
984
  Create an array type wrapper with optional length constraints.
966
985
 
@@ -984,7 +1003,7 @@ const stringArray = E.array(E.string);
984
1003
  const boundedArray = E.array(E.number, {min: 1, max: 10});
985
1004
  ```
986
1005
 
987
- ### set · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
1006
+ ### set · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
988
1007
 
989
1008
  Create a Set type wrapper with optional length constraints.
990
1009
 
@@ -1008,7 +1027,7 @@ const stringSet = E.set(E.string);
1008
1027
  const boundedSet = E.set(E.number, {min: 1, max: 10});
1009
1028
  ```
1010
1029
 
1011
- ### record · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
1030
+ ### record · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
1012
1031
 
1013
1032
  Create a Record type wrapper for key-value objects with string or number keys.
1014
1033
 
@@ -1030,7 +1049,7 @@ Create a Record type wrapper for key-value objects with string or number keys.
1030
1049
  const scores = E.record(E.number); // Record<string | number, number>
1031
1050
  ```
1032
1051
 
1033
- ### literal · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
1052
+ ### literal · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
1034
1053
 
1035
1054
  Create a literal type wrapper for a constant value.
1036
1055
 
@@ -1053,11 +1072,11 @@ const statusType = E.literal("active");
1053
1072
  const countType = E.literal(42);
1054
1073
  ```
1055
1074
 
1056
- ### link · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
1075
+ ### link · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
1057
1076
 
1058
1077
  Create a link type wrapper for model relationships.
1059
1078
 
1060
- **Signature:** `{ <const T extends new (...args: any[]) => Model<any>>(TargetModel: T): TypeWrapper<InstanceType<T>>; <const T extends new (...args: any[]) => Model<any>>(TargetModel: () => T): TypeWrapper<...>; }`
1079
+ **Signature:** `{ <const T extends new (...args: any[]) => Model<any>>(TargetModel: T): TypeWrapper<InstanceType<T>> & QueryArgCarrier<InstanceType<T> | LinkPrimaryKeyInput<LinkTargetPKArgs<T>>>; <const T extends new (...args: any[]) => Model<any>>(TargetModel: () => T): TypeWrapper<...>; }`
1061
1080
 
1062
1081
  **Type Parameters:**
1063
1082
 
@@ -1083,11 +1102,11 @@ const Book = E.defineModel("Book", class {
1083
1102
  }, { pk: "id" });
1084
1103
  ```
1085
1104
 
1086
- ### dump · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L243)
1105
+ ### dump · [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L252)
1087
1106
 
1088
1107
  **Signature:** `() => void`
1089
1108
 
1090
- ### FindOptions · [type](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L115)
1109
+ ### FindOptions · [type](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L141)
1091
1110
 
1092
1111
  Range-query options accepted by `find()`, `findBy()`, `batchProcess()`, and `batchProcessBy()`.
1093
1112
 
@@ -1095,7 +1114,10 @@ Supports exact-match lookups via `is`, inclusive bounds via `from` / `to`,
1095
1114
  exclusive bounds via `after` / `before`, and reverse scans.
1096
1115
 
1097
1116
  For single-field indexes, values can be passed directly. For composite indexes,
1098
- pass tuples or partial tuples for prefix matching.
1117
+ pass tuples or partial tuples for prefix matching. If an index field is a
1118
+ `link(...)`, you may pass either the linked model instance or the linked
1119
+ model's primary key. Composite linked primary keys are passed as tuples in
1120
+ that slot.
1099
1121
 
1100
1122
  **Type:** `(
1101
1123
  (
@@ -1125,7 +1147,7 @@ pass tuples or partial tuples for prefix matching.
1125
1147
  & (FETCH extends undefined ? { fetch?: undefined } : { fetch: FETCH })
1126
1148
  )`
1127
1149
 
1128
- ### IndexRangeIterator · [class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L73)
1150
+ ### IndexRangeIterator · [class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L90)
1129
1151
 
1130
1152
  Iterator for range queries on indexes.
1131
1153
  Handles common iteration logic for both primary and unique indexes.
@@ -1135,27 +1157,27 @@ Extends built-in Iterator to provide map/filter/reduce/toArray/etc.
1135
1157
 
1136
1158
  - `ITEM`
1137
1159
 
1138
- #### indexRangeIterator.[Symbol.iterator] · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L78)
1160
+ #### indexRangeIterator.[Symbol.iterator] · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L100)
1139
1161
 
1140
1162
  **Signature:** `() => this`
1141
1163
 
1142
- #### indexRangeIterator.next · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L80)
1164
+ #### indexRangeIterator.next · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L102)
1143
1165
 
1144
1166
  **Signature:** `() => IteratorResult<ITEM, any>`
1145
1167
 
1146
- #### indexRangeIterator.count · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L102)
1168
+ #### indexRangeIterator.count · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L110)
1147
1169
 
1148
1170
  **Signature:** `() => number`
1149
1171
 
1150
- #### indexRangeIterator.fetch · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L105)
1172
+ #### indexRangeIterator.fetch · [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L112)
1151
1173
 
1152
1174
  **Signature:** `() => ITEM`
1153
1175
 
1154
- ### Change · [type](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L85)
1176
+ ### Change · [type](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L90)
1155
1177
 
1156
1178
  **Type:** `Record<any, any> | "created" | "deleted"`
1157
1179
 
1158
- ### FieldConfig · [interface](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L37)
1180
+ ### FieldConfig · [interface](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L40)
1159
1181
 
1160
1182
  Configuration interface for model fields.
1161
1183
 
@@ -1169,13 +1191,13 @@ The type wrapper that defines how this field is serialized/validated.
1169
1191
 
1170
1192
  **Type:** `TypeWrapper<T>`
1171
1193
 
1172
- #### fieldConfig.description · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L47)
1194
+ #### fieldConfig.description · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L48)
1173
1195
 
1174
1196
  Optional human-readable description of the field.
1175
1197
 
1176
1198
  **Type:** `string`
1177
1199
 
1178
- #### fieldConfig.default · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L49)
1200
+ #### fieldConfig.default · [member](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L50)
1179
1201
 
1180
1202
  Optional default value or function that generates default values.
1181
1203
 
@@ -1273,7 +1295,7 @@ Check if indexing should be skipped for this field value.
1273
1295
 
1274
1296
  **Signature:** `() => AnyModelClass`
1275
1297
 
1276
- ### DatabaseError · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L166)
1298
+ ### DatabaseError · [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L182)
1277
1299
 
1278
1300
  The DatabaseError class is used to represent errors that occur during database operations.
1279
1301
  It extends the built-in Error class and has a machine readable error code string property.
@@ -84,5 +84,8 @@ export declare function setMaxRetryCount(count: number): void;
84
84
  * `transact()` commit that has changes, with the following arguments:
85
85
  * - A sequential number. Higher numbers have been committed after lower numbers.
86
86
  * - A map of model instances to their changes. The change can be "created", "deleted", or an object containing the old values.
87
+ *
88
+ * The callback is called within a new transaction context, allowing lazy-loads to happen. However, any
89
+ * changes made to Edinburgh models will not be saved.
87
90
  */
88
91
  export declare function setOnSaveCallback(callback: ((commitId: number, items: Map<Model<unknown>, Change>) => void) | undefined): void;
@@ -140,27 +140,31 @@ export async function transact(fn) {
140
140
  catch { }
141
141
  throw e;
142
142
  }
143
- finally {
144
- // Make the instances read-only to make it clear that their transaction has ended.
145
- for (const instance of txn.instances.values()) {
146
- delete instance._oldValues;
147
- Object.defineProperty(instance, "_txn", STALE_INSTANCE_DESCRIPTOR);
148
- Object.freeze(instance);
149
- }
150
- // Destroy the transaction object, to make sure things crash if they are used after
151
- // this point, and to help the GC reclaim memory.
152
- txn.id = txn.instances = undefined;
153
- }
154
- const commitResult = lowlevel.commitTransaction(txnId);
155
- const commitSeq = typeof commitResult === 'number' ? commitResult : await commitResult;
156
- if (commitSeq > 0) {
157
- // Success
158
- if (onSaveItems?.size) {
143
+ if (onSaveItems?.size) {
144
+ // Perform writes, and start a new transaction at or past the point-in-time of our commit
145
+ const commitResult = lowlevel.commitTransaction(txnId, true);
146
+ if (typeof commitResult === 'object') {
147
+ const commitSeq = await commitResult;
148
+ if (commitSeq <= 0)
149
+ continue; // Race condition - retry
150
+ // Run the callback within our new transaction context, so it can fetch linked lazy fields if needed
159
151
  onSaveCallback(commitSeq, onSaveItems);
160
152
  }
161
- return result;
153
+ // else: only reads
162
154
  }
163
- // Race condition - retry
155
+ // Make the instances read-only to make it clear that their transaction has ended.
156
+ for (const instance of txn.instances.values()) {
157
+ delete instance._oldValues;
158
+ Object.defineProperty(instance, "_txn", STALE_INSTANCE_DESCRIPTOR);
159
+ Object.freeze(instance);
160
+ }
161
+ // Destroy the transaction object, to make sure things crash if they are used after
162
+ // this point, and to help the GC reclaim memory.
163
+ txn.id = txn.instances = undefined;
164
+ // Commit the transaction and actually end it
165
+ if ((await lowlevel.commitTransaction(txnId)) <= 0)
166
+ continue; // Race condition - retry
167
+ return result;
164
168
  }
165
169
  throw new DatabaseError("Transaction keeps getting raced", "RACING_TRANSACTION");
166
170
  // } catch (e: Error | any) {
@@ -187,6 +191,9 @@ let onSaveCallback;
187
191
  * `transact()` commit that has changes, with the following arguments:
188
192
  * - A sequential number. Higher numbers have been committed after lower numbers.
189
193
  * - A map of model instances to their changes. The change can be "created", "deleted", or an object containing the old values.
194
+ *
195
+ * The callback is called within a new transaction context, allowing lazy-loads to happen. However, any
196
+ * changes made to Edinburgh models will not be saved.
190
197
  */
191
198
  export function setOnSaveCallback(callback) {
192
199
  onSaveCallback = callback;
@@ -1 +1 @@
1
- {"version":3,"file":"edinburgh.js","sourceRoot":"","sources":["../../src/edinburgh.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"edinburgh.js","sourceRoot":"","sources":["../../src/edinburgh.ts"],"names":[],"mappings":"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"}
@@ -48,7 +48,10 @@ type ArrayOrOnlyItem<ARG_TYPES extends readonly any[]> = ARG_TYPES extends reado
48
48
  * exclusive bounds via `after` / `before`, and reverse scans.
49
49
  *
50
50
  * For single-field indexes, values can be passed directly. For composite indexes,
51
- * pass tuples or partial tuples for prefix matching.
51
+ * pass tuples or partial tuples for prefix matching. If an index field is a
52
+ * `link(...)`, you may pass either the linked model instance or the linked
53
+ * model's primary key. Composite linked primary keys are passed as tuples in
54
+ * that slot.
52
55
  *
53
56
  * @template ARG_TYPES - Tuple of index argument types.
54
57
  * @template FETCH - Optional fetch mode used by overloads that return one row.
@@ -4,6 +4,15 @@ import DataPack from "./datapack.js";
4
4
  import { currentTxn, transact } from "./edinburgh.js";
5
5
  import { assert, logLevel, dbGet, dbPut, dbDel, hashBytes, hashFunction, bytesEqual, toBuffer } from "./utils.js";
6
6
  import { deserializeType, serializeType } from "./types.js";
7
+ function serializeIndexArg(fieldType, arg, pack) {
8
+ const linkedModel = fieldType.getLinkedModel();
9
+ if (!linkedModel || arg instanceof linkedModel) {
10
+ fieldType.serialize(arg, pack);
11
+ return;
12
+ }
13
+ // Link lookups may pass the target row's primary key instead of a loaded instance.
14
+ pack.write(linkedModel._argsToKeyBytes(Array.isArray(arg) ? arg : [arg], false).toUint8Array());
15
+ }
7
16
  const MAX_INDEX_ID_PREFIX = -1;
8
17
  const INDEX_ID_PREFIX = -2;
9
18
  const VERSION_INFO_PREFIX = -3;
@@ -107,7 +116,7 @@ export class BaseIndex {
107
116
  for (const fieldType of this._indexFields.values()) {
108
117
  if (index >= args.length)
109
118
  break;
110
- fieldType.serialize(args[index++], bytes);
119
+ serializeIndexArg(fieldType, args[index++], bytes);
111
120
  }
112
121
  }
113
122
  return bytes;