edinburgh 0.6.2 → 0.6.4

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/src/edinburgh.ts CHANGED
@@ -10,6 +10,7 @@ export {
10
10
  type ModelClass,
11
11
  type AnyModelClass,
12
12
  type ModelBase,
13
+ type ModelLookup,
13
14
  defineModel,
14
15
  deleteEverything,
15
16
  field,
@@ -158,6 +159,7 @@ export async function transact<T>(fn: () => T): Promise<T> {
158
159
  const txn: Transaction = { id: txnId, instances: new Map() };
159
160
  const onSaveItems: Map<Model<unknown>, Change> | undefined = onSaveCallback ? new Map() : undefined;
160
161
 
162
+ let retry = false;
161
163
  let result: T | undefined;
162
164
  try {
163
165
  await txnStorage.run(txn, async function() {
@@ -179,23 +181,33 @@ export async function transact<T>(fn: () => T): Promise<T> {
179
181
  onSaveItems.set(instance, change);
180
182
  }
181
183
  }
184
+
185
+ if (onSaveItems?.size) {
186
+ // Perform writes, and start a new transaction at or past the point-in-time of our commit
187
+ const commitResult = lowlevel.commitTransaction(txnId, true);
188
+ if (typeof commitResult === 'object') {
189
+ const commitSeq = await commitResult;
190
+ if (commitSeq <= 0) {
191
+ try { lowlevel.abortTransaction(txnId); } catch {}
192
+ retry = true;
193
+ return;
194
+ }
195
+ // Run the callback within our renewed transaction context, so it can fetch linked lazy fields if needed
196
+ try {
197
+ onSaveCallback!(commitSeq, onSaveItems);
198
+ } catch (e) {
199
+ throw e;
200
+ }
201
+ }
202
+ // else: only reads
203
+ }
182
204
  });
183
205
  } catch (e: any) {
184
206
  try { lowlevel.abortTransaction(txnId); } catch {}
185
207
  throw e;
186
208
  }
187
209
 
188
- if (onSaveItems?.size) {
189
- // Perform writes, and start a new transaction at or past the point-in-time of our commit
190
- const commitResult = lowlevel.commitTransaction(txnId, true);
191
- if (typeof commitResult === 'object') {
192
- const commitSeq = await commitResult;
193
- if (commitSeq <= 0) continue; // Race condition - retry
194
- // Run the callback within our new transaction context, so it can fetch linked lazy fields if needed
195
- onSaveCallback!(commitSeq, onSaveItems);
196
- }
197
- // else: only reads
198
- }
210
+ if (retry) continue;
199
211
 
200
212
  // Make the instances read-only to make it clear that their transaction has ended.
201
213
  for (const instance of txn.instances.values()) {
@@ -243,8 +255,8 @@ let onSaveCallback: ((commitId: number, items: Map<Model<unknown>, Change>) => v
243
255
  * - A sequential number. Higher numbers have been committed after lower numbers.
244
256
  * - A map of model instances to their changes. The change can be "created", "deleted", or an object containing the old values.
245
257
  *
246
- * The callback is called within a new transaction context, allowing lazy-loads to happen. However, any
247
- * changes made to Edinburgh models will not be saved.
258
+ * The callback is called within a new transaction context at or after the committed state, so lazy-loads
259
+ * and additional writes are allowed.
248
260
  */
249
261
  export function setOnSaveCallback(callback: ((commitId: number, items: Map<Model<unknown>, Change>) => void) | undefined) {
250
262
  onSaveCallback = callback;
package/src/models.ts CHANGED
@@ -65,6 +65,20 @@ function isObjectEmpty(obj: object) {
65
65
  export type Change = Record<any, any> | "created" | "deleted";
66
66
 
67
67
  type FieldsOf<T> = T extends new () => infer I ? I : never;
68
+ type ModelFields<T extends new () => any> = FieldsOf<T>;
69
+
70
+ export interface ModelLookup<PKA extends readonly any[] = readonly any[]> {
71
+ get(...args: PKA): any;
72
+ }
73
+
74
+ type ModelInstance<FIELDS, PKA extends readonly any[] = readonly any[]> = Model<FIELDS, ModelLookup<PKA>>;
75
+
76
+ type PublicModelOf<T extends new () => any> = Model<ModelFields<T>>;
77
+
78
+ type IndexSpec<T extends new () => any> =
79
+ | (keyof ModelFields<T> & string)
80
+ | readonly (keyof ModelFields<T> & string)[]
81
+ | ((instance: PublicModelOf<T>) => any);
68
82
 
69
83
  type PKArgs<FIELDS, PK> =
70
84
  PK extends readonly (keyof FIELDS & string)[]
@@ -82,14 +96,25 @@ type IndexArgs<FIELDS, SPEC> =
82
96
  ? R extends (infer V)[] ? [V] : [R]
83
97
  : never;
84
98
 
99
+ type PublicIndexSpec<SPEC> =
100
+ SPEC extends (instance: infer INSTANCE) => infer R
101
+ ? (instance: INSTANCE) => R
102
+ : SPEC;
103
+
104
+ type PublicIndexSpecs<SPECS> = {
105
+ [K in keyof SPECS]: PublicIndexSpec<SPECS[K]>;
106
+ };
107
+
85
108
  /**
86
109
  * A model constructor with its generic information erased.
87
110
  *
88
111
  * Useful when accepting or storing arbitrary registered model classes.
89
112
  */
90
- export type AnyModelClass = ModelClass<new () => any, readonly any[], any, any>;
113
+ export type AnyModelClass = ModelClass<object, any, readonly any[], any, any>;
114
+
115
+ type StaticMembers<T extends new () => any> = Pick<T, Exclude<keyof T, 'prototype'>>;
91
116
 
92
- type SecondaryRegistry<FIELDS> = Record<string, NonPrimaryIndex<Model<FIELDS>, readonly (keyof FIELDS & string)[], readonly any[]>>;
117
+ type SecondaryRegistry<FIELDS, PKA extends readonly any[]> = Record<string, NonPrimaryIndex<ModelInstance<FIELDS, PKA>, readonly (keyof FIELDS & string)[], readonly any[]>>;
93
118
 
94
119
  function copyStaticMembersFromClassChain(target: object, source: Function) {
95
120
  for (let current: any = source; current && current !== Function.prototype; current = Object.getPrototypeOf(current)) {
@@ -107,13 +132,13 @@ export const pendingModelInits = new Set<AnyModelClass>();
107
132
 
108
133
  // These static members are attached dynamically in defineModel(), so 'declare' tells TypeScript
109
134
  // they exist at runtime without emitting duplicate class fields that would shadow those assignments.
110
- class ModelClassRuntime<FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX = {}> extends PrimaryKey<Model<FIELDS>, readonly (keyof FIELDS & string)[], PKA> {
135
+ class ModelClassRuntime<FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX = {}> extends PrimaryKey<ModelInstance<FIELDS, PKA>, readonly (keyof FIELDS & string)[], PKA> {
111
136
  // Runtime table identifier used for index naming and diagnostics.
112
137
  declare tableName: string;
113
138
  // Field schema map used for validation and serialization.
114
139
  declare fields: Record<string | symbol | number, FieldConfig<unknown>>;
115
140
  // Registered unique/secondary indexes for this model.
116
- declare _secondaries?: SecondaryRegistry<FIELDS>;
141
+ declare _secondaries?: SecondaryRegistry<FIELDS, PKA>;
117
142
  // Cached list of non-primary fields used for value serialization.
118
143
  _nonKeyFields!: (keyof FIELDS & string)[];
119
144
  // Lazy getter/setter descriptors installed on unloaded non-key fields.
@@ -160,13 +185,13 @@ class ModelClassRuntime<FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX =
160
185
  this._lazyDescriptors[fieldName] = {
161
186
  configurable: true,
162
187
  enumerable: true,
163
- get(this: Model<FIELDS>) {
188
+ get(this: ModelInstance<FIELDS, PKA>) {
164
189
  this.constructor._lazyLoad(this);
165
- return this[fieldName];
190
+ return (this as any)[fieldName];
166
191
  },
167
- set(this: Model<FIELDS>, value: any) {
192
+ set(this: ModelInstance<FIELDS, PKA>, value: any) {
168
193
  this.constructor._lazyLoad(this);
169
- this[fieldName] = value;
194
+ (this as any)[fieldName] = value;
170
195
  },
171
196
  };
172
197
  this._resetDescriptors[fieldName] = {
@@ -200,9 +225,9 @@ class ModelClassRuntime<FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX =
200
225
  return index;
201
226
  }
202
227
 
203
- _get(txn: Transaction, args: PKA | Uint8Array, loadNow: false | Uint8Array): Model<FIELDS>;
204
- _get(txn: Transaction, args: PKA | Uint8Array, loadNow: true): Model<FIELDS> | undefined;
205
- _get(txn: Transaction, args: PKA | Uint8Array, loadNow: boolean | Uint8Array): Model<FIELDS> | undefined {
228
+ _get(txn: Transaction, args: PKA | Uint8Array, loadNow: false | Uint8Array): ModelInstance<FIELDS, PKA>;
229
+ _get(txn: Transaction, args: PKA | Uint8Array, loadNow: true): ModelInstance<FIELDS, PKA> | undefined;
230
+ _get(txn: Transaction, args: PKA | Uint8Array, loadNow: boolean | Uint8Array): ModelInstance<FIELDS, PKA> | undefined {
206
231
  let key: Uint8Array;
207
232
  let keyParts: readonly any[] | undefined;
208
233
  if (args instanceof Uint8Array) {
@@ -213,7 +238,7 @@ class ModelClassRuntime<FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX =
213
238
  }
214
239
 
215
240
  const keyHash = hashBytes(key);
216
- const cached = txn.instances.get(keyHash) as Model<FIELDS> | undefined;
241
+ const cached = txn.instances.get(keyHash) as ModelInstance<FIELDS, PKA> | undefined;
217
242
  if (cached) {
218
243
  if (loadNow && loadNow !== true) {
219
244
  Object.defineProperties(cached, this._resetDescriptors);
@@ -232,7 +257,7 @@ class ModelClassRuntime<FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX =
232
257
  }
233
258
  }
234
259
 
235
- const model = Object.create((this as any).prototype) as Model<FIELDS>;
260
+ const model = Object.create((this as any).prototype) as ModelInstance<FIELDS, PKA>;
236
261
  model._txn = txn;
237
262
  model._oldValues = {};
238
263
  txn.instances.set(keyHash, model);
@@ -259,7 +284,7 @@ class ModelClassRuntime<FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX =
259
284
  return model;
260
285
  }
261
286
 
262
- _lazyLoad(model: Model<FIELDS>) {
287
+ _lazyLoad(model: ModelInstance<FIELDS, PKA>) {
263
288
  const key = model._primaryKey!;
264
289
  const valueBuffer = dbGet(model._txn.id, key);
265
290
  if (!valueBuffer) throw new DatabaseError(`Lazy-loaded ${this.tableName}#${key} does not exist`, 'LAZY_FAIL');
@@ -276,7 +301,7 @@ class ModelClassRuntime<FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX =
276
301
  *
277
302
  * @returns The matching model, or `undefined` if no row exists.
278
303
  */
279
- get(...args: PKA): Model<FIELDS> | undefined {
304
+ get(...args: PKA): ModelInstance<FIELDS, PKA> | undefined {
280
305
  return this._get(currentTxn(), args, true);
281
306
  }
282
307
 
@@ -287,11 +312,11 @@ class ModelClassRuntime<FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX =
287
312
  *
288
313
  * Accessing a lazy field later will load the remaining fields transparently.
289
314
  */
290
- getLazy(...args: PKA): Model<FIELDS> {
315
+ getLazy(...args: PKA): ModelInstance<FIELDS, PKA> {
291
316
  return this._get(currentTxn(), args, false);
292
317
  }
293
318
 
294
- _pairToInstance(txn: Transaction, keyBuffer: ArrayBuffer, valueBuffer: ArrayBuffer): Model<FIELDS> {
319
+ _pairToInstance(txn: Transaction, keyBuffer: ArrayBuffer, valueBuffer: ArrayBuffer): ModelInstance<FIELDS, PKA> {
295
320
  return this._get(txn, new Uint8Array(keyBuffer), new Uint8Array(valueBuffer))!;
296
321
  }
297
322
 
@@ -303,7 +328,7 @@ class ModelClassRuntime<FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX =
303
328
  * @param obj Partial model data that **must** include every primary key field.
304
329
  * @returns The loaded-and-updated or newly created instance.
305
330
  */
306
- replaceInto(obj: Partial<FIELDS>): Model<FIELDS> {
331
+ replaceInto(obj: Partial<FIELDS>): ModelInstance<FIELDS, PKA> {
307
332
  const keyArgs: any[] = [];
308
333
  for (const fieldName of this._indexFields.keys()) {
309
334
  if (!(fieldName in (obj as any))) {
@@ -311,7 +336,7 @@ class ModelClassRuntime<FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX =
311
336
  }
312
337
  keyArgs.push((obj as any)[fieldName]);
313
338
  }
314
- const existing = this.get(...keyArgs as any) as Model<FIELDS> | undefined;
339
+ const existing = this.get(...keyArgs as any) as ModelInstance<FIELDS, PKA> | undefined;
315
340
  if (existing) {
316
341
  for (const key in obj as any) {
317
342
  if (!this._indexFields.has(key as any)) {
@@ -332,7 +357,7 @@ class ModelClassRuntime<FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX =
332
357
  * linked model uses a composite primary key, pass the full tuple in that slot.
333
358
  * @returns The matching model instance, if any.
334
359
  */
335
- getBy<K extends string & keyof UNIQUE>(name: K, ...args: IndexArgs<FIELDS, UNIQUE[K]>): Model<FIELDS> | undefined {
360
+ getBy<K extends string & keyof UNIQUE>(name: K, ...args: IndexArgs<FIELDS, UNIQUE[K]>): ModelInstance<FIELDS, PKA> | undefined {
336
361
  return (this._getSecondary(name) as any).getPK(...args);
337
362
  }
338
363
 
@@ -343,9 +368,9 @@ class ModelClassRuntime<FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX =
343
368
  * or `index` registration. Link-valued index fields accept either the linked
344
369
  * model instance or the linked model's primary key tuple/value.
345
370
  */
346
- findBy<K extends string & keyof (UNIQUE & INDEX)>(name: K, opts: FindOptions<IndexArgs<FIELDS, (UNIQUE & INDEX)[K]>, 'first'>): Model<FIELDS> | undefined;
347
- findBy<K extends string & keyof (UNIQUE & INDEX)>(name: K, opts: FindOptions<IndexArgs<FIELDS, (UNIQUE & INDEX)[K]>, 'single'>): Model<FIELDS>;
348
- findBy<K extends string & keyof (UNIQUE & INDEX)>(name: K, opts?: FindOptions<IndexArgs<FIELDS, (UNIQUE & INDEX)[K]>>): IndexRangeIterator<Model<FIELDS>>;
371
+ findBy<K extends string & keyof (UNIQUE & INDEX)>(name: K, opts: FindOptions<IndexArgs<FIELDS, (UNIQUE & INDEX)[K]>, 'first'>): ModelInstance<FIELDS, PKA> | undefined;
372
+ findBy<K extends string & keyof (UNIQUE & INDEX)>(name: K, opts: FindOptions<IndexArgs<FIELDS, (UNIQUE & INDEX)[K]>, 'single'>): ModelInstance<FIELDS, PKA>;
373
+ findBy<K extends string & keyof (UNIQUE & INDEX)>(name: K, opts?: FindOptions<IndexArgs<FIELDS, (UNIQUE & INDEX)[K]>>): IndexRangeIterator<ModelInstance<FIELDS, PKA>>;
349
374
  findBy(name: string, opts?: any): any {
350
375
  return this._getSecondary(name).find(opts);
351
376
  }
@@ -358,12 +383,12 @@ class ModelClassRuntime<FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX =
358
383
  batchProcessBy<K extends string & keyof (UNIQUE & INDEX)>(
359
384
  name: K,
360
385
  opts: FindOptions<IndexArgs<FIELDS, (UNIQUE & INDEX)[K]>> & { limitSeconds?: number; limitRows?: number },
361
- callback: (row: Model<FIELDS>) => any,
386
+ callback: (row: ModelInstance<FIELDS, PKA>) => any,
362
387
  ): Promise<void> {
363
388
  return this._getSecondary(name).batchProcess(opts, callback as any);
364
389
  }
365
390
 
366
- _loadValueFields(model: Model<FIELDS>, valueArray: Uint8Array) {
391
+ _loadValueFields(model: ModelInstance<FIELDS, PKA>, valueArray: Uint8Array) {
367
392
  const valuePack = new DataPack(valueArray);
368
393
  const version = valuePack.readNumber();
369
394
 
@@ -399,7 +424,7 @@ class ModelClassRuntime<FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX =
399
424
  return info;
400
425
  }
401
426
 
402
- _migrateValueFields(model: Model<FIELDS>, version: number, valuePack: DataPack) {
427
+ _migrateValueFields(model: ModelInstance<FIELDS, PKA>, version: number, valuePack: DataPack) {
403
428
  const versionInfo = this._loadVersionInfo(model._txn.id, version);
404
429
  const record: Record<string, any> = {};
405
430
  for (const [name] of this._indexFields.entries()) record[name] = (model as any)[name];
@@ -447,23 +472,23 @@ export const ModelClass = ModelClassRuntime;
447
472
  * helpers like `get()` and `getLazy()`, range-query helpers like `find()`, and
448
473
  * named-index helpers like `getBy()` and `findBy()`.
449
474
  *
450
- * @template T - The original class passed to `defineModel()`.
475
+ * @template FIELDS - The user-defined fields of the model instance.
451
476
  * @template PKA - Tuple of primary-key argument types.
452
477
  * @template UNIQUE - Named unique-index specifications.
453
478
  * @template INDEX - Named secondary-index specifications.
454
479
  */
455
- export type ModelClass<T extends new () => any, PKA extends readonly any[], UNIQUE = {}, INDEX = {}> =
456
- T
457
- & ModelClassRuntime<FieldsOf<T>, PKA, UNIQUE, INDEX>
480
+ export type ModelClass<STATICS, FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX = {}> =
481
+ STATICS
482
+ & ModelClassRuntime<FIELDS, PKA, UNIQUE, INDEX>
458
483
  & {
459
- new (initial?: Partial<FieldsOf<T>>, txn?: Transaction): Model<FieldsOf<T>>;
484
+ new (initial?: Partial<FIELDS>, txn?: Transaction): ModelInstance<FIELDS, PKA>;
460
485
  };
461
486
 
462
487
  /**
463
488
  * Minimal instance-side model shape used for typing the constructor property.
464
489
  */
465
- export interface ModelBase {
466
- constructor: AnyModelClass;
490
+ export interface ModelBase<LOOKUP extends ModelLookup = ModelLookup> {
491
+ constructor: LOOKUP & AnyModelClass;
467
492
  }
468
493
 
469
494
  /**
@@ -483,14 +508,20 @@ export interface ModelBase {
483
508
  */
484
509
  export function defineModel<
485
510
  T extends new () => any,
486
- const PK extends (keyof FieldsOf<T> & string) | readonly (keyof FieldsOf<T> & string)[],
487
- const UNIQUE extends Record<string, (keyof FieldsOf<T> & string) | readonly (keyof FieldsOf<T> & string)[] | ((instance: any) => any)>,
488
- const INDEX extends Record<string, (keyof FieldsOf<T> & string) | readonly (keyof FieldsOf<T> & string)[] | ((instance: any) => any)>,
511
+ const PK extends (keyof ModelFields<T> & string) | readonly (keyof ModelFields<T> & string)[],
512
+ const UNIQUE extends Record<string, IndexSpec<T>>,
513
+ const INDEX extends Record<string, IndexSpec<T>>,
489
514
  >(
490
515
  tableName: string,
491
516
  cls: T,
492
517
  opts?: { pk?: PK, unique?: UNIQUE, index?: INDEX, override?: boolean }
493
- ): ModelClass<T, PKArgs<FieldsOf<T>, PK>, UNIQUE, INDEX> {
518
+ ): ModelClass<
519
+ StaticMembers<T>,
520
+ ModelFields<T>,
521
+ PKArgs<ModelFields<T>, PK>,
522
+ PublicIndexSpecs<UNIQUE>,
523
+ PublicIndexSpecs<INDEX>
524
+ > {
494
525
  Object.setPrototypeOf(cls.prototype, ModelBase.prototype);
495
526
  const MockModel = function(this: any, initial?: Record<string, any>, txn: Transaction = currentTxn()) {
496
527
  this._txn = txn;
@@ -977,5 +1008,5 @@ export async function deleteEverything(): Promise<void> {
977
1008
  * A model instance, including its user-defined fields.
978
1009
  * @template FIELDS - The fields defined on this model.
979
1010
  */
980
- export type Model<FIELDS> = FIELDS & ModelBase;
1011
+ export type Model<FIELDS, LOOKUP extends ModelLookup = ModelLookup> = FIELDS & ModelBase<LOOKUP>;
981
1012
  export const Model = ModelBase;
package/src/types.ts CHANGED
@@ -2,7 +2,7 @@ import DataPack from "./datapack.js";
2
2
  import { DatabaseError } from "olmdb/lowlevel";
3
3
  import { currentTxn } from "./edinburgh.js";
4
4
  import { Model, modelRegistry } from "./models.js";
5
- import type { AnyModelClass } from "./models.js";
5
+ import type { AnyModelClass, ModelBase as ModelInstanceBase } from "./models.js";
6
6
  import { assert, addErrorPath, dbGet } from "./utils.js";
7
7
 
8
8
 
@@ -90,7 +90,7 @@ export interface TypeWrapper<T> {
90
90
  // Hidden type-only metadata used to widen lookup arguments without widening assignment types.
91
91
  export declare const QUERY_ARG: unique symbol;
92
92
 
93
- export type LinkTargetPKArgs<T extends new (...args: any) => any> =
93
+ export type LinkTargetPKArgs<T extends { get(...args: any): any }> =
94
94
  T extends { get(...args: infer PKA): any } ? PKA : never;
95
95
 
96
96
  export type LinkPrimaryKeyInput<PKA extends readonly any[]> =
@@ -102,17 +102,15 @@ type QueryArgCarrier<QUERY> = {
102
102
  readonly [QUERY_ARG]?: QUERY;
103
103
  };
104
104
 
105
- type QueryAnnotated<T, QUERY> = T & QueryArgCarrier<QUERY>;
106
-
107
105
  export type FieldValue<TYPE extends TypeWrapper<any>> =
108
106
  TYPE extends TypeWrapper<infer T>
109
- ? TYPE extends { readonly [QUERY_ARG]?: infer QUERY }
110
- ? QueryAnnotated<T, Exclude<QUERY, undefined>>
111
- : T
107
+ ? T
112
108
  : never;
113
109
 
114
110
  export type FieldQueryArg<T> =
115
- T extends { readonly [QUERY_ARG]?: infer QUERY }
111
+ T extends ModelInstanceBase<infer LOOKUP>
112
+ ? T | LinkPrimaryKeyInput<LinkTargetPKArgs<LOOKUP>>
113
+ : T extends { readonly [QUERY_ARG]?: infer QUERY }
116
114
  ? Exclude<QUERY, undefined>
117
115
  : T;
118
116
 
@@ -657,8 +655,8 @@ export class LinkType<T extends new (...args: any[]) => Model<any>> extends Type
657
655
  pack.write(model.getPrimaryKey());
658
656
  }
659
657
 
660
- deserialize(pack: DataPack) {
661
- return this.getLinkedModel()._get(currentTxn(), pack.readUint8Array(), false);
658
+ deserialize(pack: DataPack): InstanceType<T> {
659
+ return this.getLinkedModel()._get(currentTxn(), pack.readUint8Array(), false) as InstanceType<T>;
662
660
  }
663
661
 
664
662
  getError(value: InstanceType<T>) {
@@ -826,7 +824,7 @@ export function record<const T>(inner: TypeWrapper<T>): TypeWrapper<Record<strin
826
824
  */
827
825
  export function link<const T extends new (...args: any[]) => Model<any>>(
828
826
  TargetModel: T,
829
- ): TypeWrapper<InstanceType<T>> & QueryArgCarrier<InstanceType<T> | LinkPrimaryKeyInput<LinkTargetPKArgs<T>>>;
827
+ ): TypeWrapper<InstanceType<T>>;
830
828
  export function link<const T extends new (...args: any[]) => Model<any>>(TargetModel: () => T): TypeWrapper<InstanceType<T>>;
831
829
  export function link(TargetModel: any): TypeWrapper<any> {
832
830
  return new LinkType(TargetModel);