edinburgh 0.6.1 → 0.6.3
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 +49 -30
- package/build/src/indexes.d.ts +4 -1
- package/build/src/indexes.js +10 -1
- package/build/src/indexes.js.map +1 -1
- package/build/src/models.d.ts +56 -34
- package/build/src/models.js +10 -2
- package/build/src/models.js.map +1 -1
- package/build/src/types.d.ts +28 -3
- package/build/src/types.js.map +1 -1
- package/package.json +2 -2
- package/skill/AnyModelClass.md +1 -1
- package/skill/FindOptions.md +4 -1
- package/skill/SKILL.md +16 -0
- package/skill/defineModel.md +3 -3
- package/skill/field.md +4 -4
- package/skill/link.md +1 -1
- package/src/indexes.ts +16 -2
- package/src/models.ts +91 -49
- package/src/types.ts +45 -5
package/src/models.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as lowlevel from "olmdb/lowlevel";
|
|
2
2
|
import { DatabaseError } from "olmdb/lowlevel";
|
|
3
3
|
import DataPack from "./datapack.js";
|
|
4
|
-
import { deserializeType, serializeType, TypeWrapper, identifier } from "./types.js";
|
|
4
|
+
import { deserializeType, serializeType, TypeWrapper, identifier, type FieldQueryArg, type FieldValue, type StripQueryArg } from "./types.js";
|
|
5
5
|
import { transact, currentTxn, type Transaction } from "./edinburgh.js";
|
|
6
6
|
|
|
7
7
|
import { PrimaryKey, NonPrimaryIndex, IndexRangeIterator, UniqueIndex, SecondaryIndex, FindOptions, VersionInfo } from "./indexes.js";
|
|
@@ -49,7 +49,7 @@ export interface FieldConfig<T> {
|
|
|
49
49
|
* });
|
|
50
50
|
* ```
|
|
51
51
|
*/
|
|
52
|
-
export function field<
|
|
52
|
+
export function field<TYPE extends TypeWrapper<any>>(type: TYPE, options: Partial<FieldConfig<FieldValue<TYPE>>> = {}): FieldValue<TYPE> {
|
|
53
53
|
// Return the config object, but TypeScript sees it as type T
|
|
54
54
|
options.type = type;
|
|
55
55
|
return options as any;
|
|
@@ -66,28 +66,54 @@ export type Change = Record<any, any> | "created" | "deleted";
|
|
|
66
66
|
|
|
67
67
|
type FieldsOf<T> = T extends new () => infer I ? I : never;
|
|
68
68
|
|
|
69
|
-
type
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
69
|
+
type PublicFields<FIELDS> = {
|
|
70
|
+
[K in keyof FIELDS]: StripQueryArg<FIELDS[K]>;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
type QueryFields<FIELDS> = {
|
|
74
|
+
[K in keyof FIELDS]: FieldQueryArg<FIELDS[K]>;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
type PublicModelOf<T extends new () => any> = Model<PublicFields<FieldsOf<T>>>;
|
|
78
|
+
|
|
79
|
+
type IndexSpec<T extends new () => any> =
|
|
80
|
+
| (keyof FieldsOf<T> & string)
|
|
81
|
+
| readonly (keyof FieldsOf<T> & string)[]
|
|
82
|
+
| ((instance: PublicModelOf<T>) => any);
|
|
83
|
+
|
|
84
|
+
type PKArgs<QUERY_FIELDS, PK> =
|
|
85
|
+
PK extends readonly (keyof QUERY_FIELDS & string)[]
|
|
86
|
+
? { [I in keyof PK]: PK[I] extends keyof QUERY_FIELDS ? QUERY_FIELDS[PK[I]] : never }
|
|
87
|
+
: PK extends keyof QUERY_FIELDS & string
|
|
88
|
+
? [QUERY_FIELDS[PK]]
|
|
74
89
|
: [string];
|
|
75
90
|
|
|
76
|
-
type IndexArgs<
|
|
77
|
-
SPEC extends readonly (keyof
|
|
78
|
-
? { [I in keyof SPEC]: SPEC[I] extends keyof
|
|
79
|
-
: SPEC extends keyof
|
|
80
|
-
? [
|
|
91
|
+
type IndexArgs<QUERY_FIELDS, SPEC> =
|
|
92
|
+
SPEC extends readonly (keyof QUERY_FIELDS & string)[]
|
|
93
|
+
? { [I in keyof SPEC]: SPEC[I] extends keyof QUERY_FIELDS ? QUERY_FIELDS[SPEC[I]] : never }
|
|
94
|
+
: SPEC extends keyof QUERY_FIELDS & string
|
|
95
|
+
? [QUERY_FIELDS[SPEC]]
|
|
81
96
|
: SPEC extends (instance: any) => infer R
|
|
82
97
|
? R extends (infer V)[] ? [V] : [R]
|
|
83
98
|
: never;
|
|
84
99
|
|
|
100
|
+
type PublicIndexSpec<SPEC> =
|
|
101
|
+
SPEC extends (instance: infer INSTANCE) => infer R
|
|
102
|
+
? (instance: INSTANCE) => R
|
|
103
|
+
: SPEC;
|
|
104
|
+
|
|
105
|
+
type PublicIndexSpecs<SPECS> = {
|
|
106
|
+
[K in keyof SPECS]: PublicIndexSpec<SPECS[K]>;
|
|
107
|
+
};
|
|
108
|
+
|
|
85
109
|
/**
|
|
86
110
|
* A model constructor with its generic information erased.
|
|
87
111
|
*
|
|
88
112
|
* Useful when accepting or storing arbitrary registered model classes.
|
|
89
113
|
*/
|
|
90
|
-
export type AnyModelClass = ModelClass<
|
|
114
|
+
export type AnyModelClass = ModelClass<object, any, any, readonly any[], any, any>;
|
|
115
|
+
|
|
116
|
+
type StaticMembers<T extends new () => any> = Pick<T, Exclude<keyof T, 'prototype'>>;
|
|
91
117
|
|
|
92
118
|
type SecondaryRegistry<FIELDS> = Record<string, NonPrimaryIndex<Model<FIELDS>, readonly (keyof FIELDS & string)[], readonly any[]>>;
|
|
93
119
|
|
|
@@ -107,15 +133,15 @@ export const pendingModelInits = new Set<AnyModelClass>();
|
|
|
107
133
|
|
|
108
134
|
// These static members are attached dynamically in defineModel(), so 'declare' tells TypeScript
|
|
109
135
|
// they exist at runtime without emitting duplicate class fields that would shadow those assignments.
|
|
110
|
-
class ModelClassRuntime<
|
|
136
|
+
class ModelClassRuntime<PUBLIC_FIELDS, QUERY_FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX = {}> extends PrimaryKey<Model<PUBLIC_FIELDS>, readonly (keyof PUBLIC_FIELDS & string)[], PKA> {
|
|
111
137
|
// Runtime table identifier used for index naming and diagnostics.
|
|
112
138
|
declare tableName: string;
|
|
113
139
|
// Field schema map used for validation and serialization.
|
|
114
140
|
declare fields: Record<string | symbol | number, FieldConfig<unknown>>;
|
|
115
141
|
// Registered unique/secondary indexes for this model.
|
|
116
|
-
declare _secondaries?: SecondaryRegistry<
|
|
142
|
+
declare _secondaries?: SecondaryRegistry<PUBLIC_FIELDS>;
|
|
117
143
|
// Cached list of non-primary fields used for value serialization.
|
|
118
|
-
_nonKeyFields!: (keyof
|
|
144
|
+
_nonKeyFields!: (keyof PUBLIC_FIELDS & string)[];
|
|
119
145
|
// Lazy getter/setter descriptors installed on unloaded non-key fields.
|
|
120
146
|
_lazyDescriptors: Record<string | symbol | number, PropertyDescriptor> = {};
|
|
121
147
|
// Writable descriptors temporarily installed before hydrating value fields.
|
|
@@ -160,13 +186,13 @@ class ModelClassRuntime<FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX =
|
|
|
160
186
|
this._lazyDescriptors[fieldName] = {
|
|
161
187
|
configurable: true,
|
|
162
188
|
enumerable: true,
|
|
163
|
-
get(this: Model<
|
|
189
|
+
get(this: Model<PUBLIC_FIELDS>) {
|
|
164
190
|
this.constructor._lazyLoad(this);
|
|
165
|
-
return this[fieldName];
|
|
191
|
+
return (this as any)[fieldName];
|
|
166
192
|
},
|
|
167
|
-
set(this: Model<
|
|
193
|
+
set(this: Model<PUBLIC_FIELDS>, value: any) {
|
|
168
194
|
this.constructor._lazyLoad(this);
|
|
169
|
-
this[fieldName] = value;
|
|
195
|
+
(this as any)[fieldName] = value;
|
|
170
196
|
},
|
|
171
197
|
};
|
|
172
198
|
this._resetDescriptors[fieldName] = {
|
|
@@ -200,20 +226,20 @@ class ModelClassRuntime<FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX =
|
|
|
200
226
|
return index;
|
|
201
227
|
}
|
|
202
228
|
|
|
203
|
-
_get(txn: Transaction, args: PKA | Uint8Array, loadNow: false | Uint8Array): Model<
|
|
204
|
-
_get(txn: Transaction, args: PKA | Uint8Array, loadNow: true): Model<
|
|
205
|
-
_get(txn: Transaction, args: PKA | Uint8Array, loadNow: boolean | Uint8Array): Model<
|
|
229
|
+
_get(txn: Transaction, args: PKA | Uint8Array, loadNow: false | Uint8Array): Model<PUBLIC_FIELDS>;
|
|
230
|
+
_get(txn: Transaction, args: PKA | Uint8Array, loadNow: true): Model<PUBLIC_FIELDS> | undefined;
|
|
231
|
+
_get(txn: Transaction, args: PKA | Uint8Array, loadNow: boolean | Uint8Array): Model<PUBLIC_FIELDS> | undefined {
|
|
206
232
|
let key: Uint8Array;
|
|
207
233
|
let keyParts: readonly any[] | undefined;
|
|
208
234
|
if (args instanceof Uint8Array) {
|
|
209
235
|
key = args;
|
|
210
236
|
} else {
|
|
211
237
|
key = this._argsToKeyBytes(args, false).toUint8Array();
|
|
212
|
-
keyParts =
|
|
238
|
+
keyParts = this._pkToArray(key);
|
|
213
239
|
}
|
|
214
240
|
|
|
215
241
|
const keyHash = hashBytes(key);
|
|
216
|
-
const cached = txn.instances.get(keyHash) as Model<
|
|
242
|
+
const cached = txn.instances.get(keyHash) as Model<PUBLIC_FIELDS> | undefined;
|
|
217
243
|
if (cached) {
|
|
218
244
|
if (loadNow && loadNow !== true) {
|
|
219
245
|
Object.defineProperties(cached, this._resetDescriptors);
|
|
@@ -232,7 +258,7 @@ class ModelClassRuntime<FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX =
|
|
|
232
258
|
}
|
|
233
259
|
}
|
|
234
260
|
|
|
235
|
-
const model = Object.create((this as any).prototype) as Model<
|
|
261
|
+
const model = Object.create((this as any).prototype) as Model<PUBLIC_FIELDS>;
|
|
236
262
|
model._txn = txn;
|
|
237
263
|
model._oldValues = {};
|
|
238
264
|
txn.instances.set(keyHash, model);
|
|
@@ -259,7 +285,7 @@ class ModelClassRuntime<FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX =
|
|
|
259
285
|
return model;
|
|
260
286
|
}
|
|
261
287
|
|
|
262
|
-
_lazyLoad(model: Model<
|
|
288
|
+
_lazyLoad(model: Model<PUBLIC_FIELDS>) {
|
|
263
289
|
const key = model._primaryKey!;
|
|
264
290
|
const valueBuffer = dbGet(model._txn.id, key);
|
|
265
291
|
if (!valueBuffer) throw new DatabaseError(`Lazy-loaded ${this.tableName}#${key} does not exist`, 'LAZY_FAIL');
|
|
@@ -269,23 +295,29 @@ class ModelClassRuntime<FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX =
|
|
|
269
295
|
|
|
270
296
|
/**
|
|
271
297
|
* Load a model by primary key inside the current transaction.
|
|
298
|
+
*
|
|
299
|
+
* For `link(...)` primary-key fields, each argument may be the linked model
|
|
300
|
+
* instance or the linked model's primary key. Composite linked primary keys
|
|
301
|
+
* are passed as a tuple in that argument slot.
|
|
272
302
|
*
|
|
273
303
|
* @returns The matching model, or `undefined` if no row exists.
|
|
274
304
|
*/
|
|
275
|
-
get(...args: PKA): Model<
|
|
305
|
+
get(...args: PKA): Model<PUBLIC_FIELDS> | undefined {
|
|
276
306
|
return this._get(currentTxn(), args, true);
|
|
277
307
|
}
|
|
278
308
|
|
|
279
309
|
/**
|
|
280
310
|
* Load a model by primary key without fetching its non-key fields immediately.
|
|
311
|
+
*
|
|
312
|
+
* Link-valued primary-key fields accept the same shorthand as `get()`.
|
|
281
313
|
*
|
|
282
314
|
* Accessing a lazy field later will load the remaining fields transparently.
|
|
283
315
|
*/
|
|
284
|
-
getLazy(...args: PKA): Model<
|
|
316
|
+
getLazy(...args: PKA): Model<PUBLIC_FIELDS> {
|
|
285
317
|
return this._get(currentTxn(), args, false);
|
|
286
318
|
}
|
|
287
319
|
|
|
288
|
-
_pairToInstance(txn: Transaction, keyBuffer: ArrayBuffer, valueBuffer: ArrayBuffer): Model<
|
|
320
|
+
_pairToInstance(txn: Transaction, keyBuffer: ArrayBuffer, valueBuffer: ArrayBuffer): Model<PUBLIC_FIELDS> {
|
|
289
321
|
return this._get(txn, new Uint8Array(keyBuffer), new Uint8Array(valueBuffer))!;
|
|
290
322
|
}
|
|
291
323
|
|
|
@@ -297,7 +329,7 @@ class ModelClassRuntime<FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX =
|
|
|
297
329
|
* @param obj Partial model data that **must** include every primary key field.
|
|
298
330
|
* @returns The loaded-and-updated or newly created instance.
|
|
299
331
|
*/
|
|
300
|
-
replaceInto(obj: Partial<
|
|
332
|
+
replaceInto(obj: Partial<PUBLIC_FIELDS>): Model<PUBLIC_FIELDS> {
|
|
301
333
|
const keyArgs: any[] = [];
|
|
302
334
|
for (const fieldName of this._indexFields.keys()) {
|
|
303
335
|
if (!(fieldName in (obj as any))) {
|
|
@@ -305,7 +337,7 @@ class ModelClassRuntime<FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX =
|
|
|
305
337
|
}
|
|
306
338
|
keyArgs.push((obj as any)[fieldName]);
|
|
307
339
|
}
|
|
308
|
-
const existing = this.get(...keyArgs as any) as Model<
|
|
340
|
+
const existing = this.get(...keyArgs as any) as Model<PUBLIC_FIELDS> | undefined;
|
|
309
341
|
if (existing) {
|
|
310
342
|
for (const key in obj as any) {
|
|
311
343
|
if (!this._indexFields.has(key as any)) {
|
|
@@ -321,10 +353,12 @@ class ModelClassRuntime<FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX =
|
|
|
321
353
|
* Look up a model through a named unique index.
|
|
322
354
|
*
|
|
323
355
|
* @param name The name from the model's `unique` definition.
|
|
324
|
-
|
|
356
|
+
* @param args The unique-index key values. For `link(...)` fields, pass
|
|
357
|
+
* either the linked model instance or the linked model's primary key. If the
|
|
358
|
+
* linked model uses a composite primary key, pass the full tuple in that slot.
|
|
325
359
|
* @returns The matching model instance, if any.
|
|
326
360
|
*/
|
|
327
|
-
getBy<K extends string & keyof UNIQUE>(name: K, ...args: IndexArgs<
|
|
361
|
+
getBy<K extends string & keyof UNIQUE>(name: K, ...args: IndexArgs<QUERY_FIELDS, UNIQUE[K]>): Model<PUBLIC_FIELDS> | undefined {
|
|
328
362
|
return (this._getSecondary(name) as any).getPK(...args);
|
|
329
363
|
}
|
|
330
364
|
|
|
@@ -332,11 +366,12 @@ class ModelClassRuntime<FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX =
|
|
|
332
366
|
* Query rows through a named unique or secondary index.
|
|
333
367
|
*
|
|
334
368
|
* This mirrors `find()`, but targets a named entry from the model's `unique`
|
|
335
|
-
|
|
369
|
+
* or `index` registration. Link-valued index fields accept either the linked
|
|
370
|
+
* model instance or the linked model's primary key tuple/value.
|
|
336
371
|
*/
|
|
337
|
-
findBy<K extends string & keyof (UNIQUE & INDEX)>(name: K, opts: FindOptions<IndexArgs<
|
|
338
|
-
findBy<K extends string & keyof (UNIQUE & INDEX)>(name: K, opts: FindOptions<IndexArgs<
|
|
339
|
-
findBy<K extends string & keyof (UNIQUE & INDEX)>(name: K, opts?: FindOptions<IndexArgs<
|
|
372
|
+
findBy<K extends string & keyof (UNIQUE & INDEX)>(name: K, opts: FindOptions<IndexArgs<QUERY_FIELDS, (UNIQUE & INDEX)[K]>, 'first'>): Model<PUBLIC_FIELDS> | undefined;
|
|
373
|
+
findBy<K extends string & keyof (UNIQUE & INDEX)>(name: K, opts: FindOptions<IndexArgs<QUERY_FIELDS, (UNIQUE & INDEX)[K]>, 'single'>): Model<PUBLIC_FIELDS>;
|
|
374
|
+
findBy<K extends string & keyof (UNIQUE & INDEX)>(name: K, opts?: FindOptions<IndexArgs<QUERY_FIELDS, (UNIQUE & INDEX)[K]>>): IndexRangeIterator<Model<PUBLIC_FIELDS>>;
|
|
340
375
|
findBy(name: string, opts?: any): any {
|
|
341
376
|
return this._getSecondary(name).find(opts);
|
|
342
377
|
}
|
|
@@ -348,13 +383,13 @@ class ModelClassRuntime<FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX =
|
|
|
348
383
|
*/
|
|
349
384
|
batchProcessBy<K extends string & keyof (UNIQUE & INDEX)>(
|
|
350
385
|
name: K,
|
|
351
|
-
opts: FindOptions<IndexArgs<
|
|
352
|
-
callback: (row: Model<
|
|
386
|
+
opts: FindOptions<IndexArgs<QUERY_FIELDS, (UNIQUE & INDEX)[K]>> & { limitSeconds?: number; limitRows?: number },
|
|
387
|
+
callback: (row: Model<PUBLIC_FIELDS>) => any,
|
|
353
388
|
): Promise<void> {
|
|
354
389
|
return this._getSecondary(name).batchProcess(opts, callback as any);
|
|
355
390
|
}
|
|
356
391
|
|
|
357
|
-
_loadValueFields(model: Model<
|
|
392
|
+
_loadValueFields(model: Model<PUBLIC_FIELDS>, valueArray: Uint8Array) {
|
|
358
393
|
const valuePack = new DataPack(valueArray);
|
|
359
394
|
const version = valuePack.readNumber();
|
|
360
395
|
|
|
@@ -390,7 +425,7 @@ class ModelClassRuntime<FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX =
|
|
|
390
425
|
return info;
|
|
391
426
|
}
|
|
392
427
|
|
|
393
|
-
_migrateValueFields(model: Model<
|
|
428
|
+
_migrateValueFields(model: Model<PUBLIC_FIELDS>, version: number, valuePack: DataPack) {
|
|
394
429
|
const versionInfo = this._loadVersionInfo(model._txn.id, version);
|
|
395
430
|
const record: Record<string, any> = {};
|
|
396
431
|
for (const [name] of this._indexFields.entries()) record[name] = (model as any)[name];
|
|
@@ -443,11 +478,11 @@ export const ModelClass = ModelClassRuntime;
|
|
|
443
478
|
* @template UNIQUE - Named unique-index specifications.
|
|
444
479
|
* @template INDEX - Named secondary-index specifications.
|
|
445
480
|
*/
|
|
446
|
-
export type ModelClass<
|
|
447
|
-
|
|
448
|
-
& ModelClassRuntime<
|
|
481
|
+
export type ModelClass<STATICS, PUBLIC_FIELDS, QUERY_FIELDS, PKA extends readonly any[], UNIQUE = {}, INDEX = {}> =
|
|
482
|
+
STATICS
|
|
483
|
+
& ModelClassRuntime<PUBLIC_FIELDS, QUERY_FIELDS, PKA, UNIQUE, INDEX>
|
|
449
484
|
& {
|
|
450
|
-
new (initial?: Partial<
|
|
485
|
+
new (initial?: Partial<PUBLIC_FIELDS>, txn?: Transaction): Model<PUBLIC_FIELDS>;
|
|
451
486
|
};
|
|
452
487
|
|
|
453
488
|
/**
|
|
@@ -475,13 +510,20 @@ export interface ModelBase {
|
|
|
475
510
|
export function defineModel<
|
|
476
511
|
T extends new () => any,
|
|
477
512
|
const PK extends (keyof FieldsOf<T> & string) | readonly (keyof FieldsOf<T> & string)[],
|
|
478
|
-
const UNIQUE extends Record<string,
|
|
479
|
-
const INDEX extends Record<string,
|
|
513
|
+
const UNIQUE extends Record<string, IndexSpec<T>>,
|
|
514
|
+
const INDEX extends Record<string, IndexSpec<T>>,
|
|
480
515
|
>(
|
|
481
516
|
tableName: string,
|
|
482
517
|
cls: T,
|
|
483
518
|
opts?: { pk?: PK, unique?: UNIQUE, index?: INDEX, override?: boolean }
|
|
484
|
-
): ModelClass<
|
|
519
|
+
): ModelClass<
|
|
520
|
+
StaticMembers<T>,
|
|
521
|
+
PublicFields<FieldsOf<T>>,
|
|
522
|
+
QueryFields<FieldsOf<T>>,
|
|
523
|
+
PKArgs<QueryFields<FieldsOf<T>>, PK>,
|
|
524
|
+
PublicIndexSpecs<UNIQUE>,
|
|
525
|
+
PublicIndexSpecs<INDEX>
|
|
526
|
+
> {
|
|
485
527
|
Object.setPrototypeOf(cls.prototype, ModelBase.prototype);
|
|
486
528
|
const MockModel = function(this: any, initial?: Record<string, any>, txn: Transaction = currentTxn()) {
|
|
487
529
|
this._txn = txn;
|
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
|
|
|
@@ -87,6 +87,44 @@ export interface TypeWrapper<T> {
|
|
|
87
87
|
default?(model: any): T;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
// Hidden type-only metadata used to widen lookup arguments without widening assignment types.
|
|
91
|
+
export declare const QUERY_ARG: unique symbol;
|
|
92
|
+
|
|
93
|
+
export type LinkTargetPKArgs<T extends new (...args: any) => any> =
|
|
94
|
+
T extends { get(...args: infer PKA): any } ? PKA : never;
|
|
95
|
+
|
|
96
|
+
export type LinkPrimaryKeyInput<PKA extends readonly any[]> =
|
|
97
|
+
PKA extends readonly [infer ONLY]
|
|
98
|
+
? ONLY | PKA
|
|
99
|
+
: PKA;
|
|
100
|
+
|
|
101
|
+
type QueryArgCarrier<QUERY> = {
|
|
102
|
+
readonly [QUERY_ARG]?: QUERY;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
type QueryAnnotated<T, QUERY> = T & QueryArgCarrier<QUERY>;
|
|
106
|
+
|
|
107
|
+
export type FieldValue<TYPE extends TypeWrapper<any>> =
|
|
108
|
+
TYPE extends TypeWrapper<infer T>
|
|
109
|
+
? TYPE extends { readonly [QUERY_ARG]?: infer QUERY }
|
|
110
|
+
? QueryAnnotated<T, Exclude<QUERY, undefined>>
|
|
111
|
+
: T
|
|
112
|
+
: never;
|
|
113
|
+
|
|
114
|
+
export type StripQueryArg<T> =
|
|
115
|
+
T extends ModelInstanceBase & { readonly [QUERY_ARG]?: any }
|
|
116
|
+
? Model<{
|
|
117
|
+
[K in Exclude<keyof T, keyof ModelInstanceBase | typeof QUERY_ARG>]: T[K]
|
|
118
|
+
}>
|
|
119
|
+
: T extends { readonly [QUERY_ARG]?: any }
|
|
120
|
+
? { [K in keyof T as K extends typeof QUERY_ARG ? never : K]: T[K] }
|
|
121
|
+
: T;
|
|
122
|
+
|
|
123
|
+
export type FieldQueryArg<T> =
|
|
124
|
+
T extends { readonly [QUERY_ARG]?: infer QUERY }
|
|
125
|
+
? Exclude<QUERY, undefined>
|
|
126
|
+
: T;
|
|
127
|
+
|
|
90
128
|
|
|
91
129
|
class StringType extends TypeWrapper<string> {
|
|
92
130
|
kind = 'string';
|
|
@@ -620,7 +658,7 @@ export class LinkType<T extends new (...args: any[]) => Model<any>> extends Type
|
|
|
620
658
|
}
|
|
621
659
|
|
|
622
660
|
getLinkedModel(): AnyModelClass {
|
|
623
|
-
if (!('getLazy' in this.TargetModel)) this.TargetModel = (this.TargetModel as unknown as () => T)();
|
|
661
|
+
if (!('getLazy' in (this.TargetModel as any))) this.TargetModel = (this.TargetModel as unknown as () => T)();
|
|
624
662
|
return this.TargetModel as any;
|
|
625
663
|
}
|
|
626
664
|
|
|
@@ -628,8 +666,8 @@ export class LinkType<T extends new (...args: any[]) => Model<any>> extends Type
|
|
|
628
666
|
pack.write(model.getPrimaryKey());
|
|
629
667
|
}
|
|
630
668
|
|
|
631
|
-
deserialize(pack: DataPack) {
|
|
632
|
-
return this.getLinkedModel()._get(currentTxn(), pack.readUint8Array(), false)
|
|
669
|
+
deserialize(pack: DataPack): InstanceType<T> {
|
|
670
|
+
return this.getLinkedModel()._get(currentTxn(), pack.readUint8Array(), false) as InstanceType<T>;
|
|
633
671
|
}
|
|
634
672
|
|
|
635
673
|
getError(value: InstanceType<T>) {
|
|
@@ -795,7 +833,9 @@ export function record<const T>(inner: TypeWrapper<T>): TypeWrapper<Record<strin
|
|
|
795
833
|
* }, { pk: "id" });
|
|
796
834
|
* ```
|
|
797
835
|
*/
|
|
798
|
-
export function link<const T extends new (...args: any[]) => Model<any>>(
|
|
836
|
+
export function link<const T extends new (...args: any[]) => Model<any>>(
|
|
837
|
+
TargetModel: T,
|
|
838
|
+
): TypeWrapper<InstanceType<T>> & QueryArgCarrier<InstanceType<T> | LinkPrimaryKeyInput<LinkTargetPKArgs<T>>>;
|
|
799
839
|
export function link<const T extends new (...args: any[]) => Model<any>>(TargetModel: () => T): TypeWrapper<InstanceType<T>>;
|
|
800
840
|
export function link(TargetModel: any): TypeWrapper<any> {
|
|
801
841
|
return new LinkType(TargetModel);
|