miragejs-orm 0.1.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.
- package/LICENSE +21 -0
- package/README.md +17 -0
- package/lib/dist/index.cjs +17 -0
- package/lib/dist/index.cjs.map +1 -0
- package/lib/dist/index.d.cts +3044 -0
- package/lib/dist/index.d.ts +3044 -0
- package/lib/dist/index.js +17 -0
- package/lib/dist/index.js.map +1 -0
- package/package.json +84 -0
|
@@ -0,0 +1,3044 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type for allowed ID types
|
|
3
|
+
*/
|
|
4
|
+
type IdType = number | string;
|
|
5
|
+
/**
|
|
6
|
+
* Type for ID generator function that takes current ID and returns next ID
|
|
7
|
+
* @template T - The type of ID
|
|
8
|
+
* @param currentId - The current ID
|
|
9
|
+
* @returns The next ID
|
|
10
|
+
*/
|
|
11
|
+
type IdGenerator<T> = (currentId: T) => T;
|
|
12
|
+
/**
|
|
13
|
+
* Configuration options for the IdentityManager
|
|
14
|
+
* @template T - The type of ID
|
|
15
|
+
* @param initialCounter - The initial counter value
|
|
16
|
+
* @param initialUsedIds - A set of initial used IDs
|
|
17
|
+
* @param idGenerator - Custom function to generate the next ID
|
|
18
|
+
*/
|
|
19
|
+
interface IdentityManagerConfig<T = string> {
|
|
20
|
+
initialCounter: T;
|
|
21
|
+
initialUsedIds?: T[];
|
|
22
|
+
idGenerator?: IdGenerator<T>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Manages unique identifiers for database records.
|
|
27
|
+
* Handles different types of IDs, ensuring uniqueness and proper sequencing.
|
|
28
|
+
* @template T - The type of ID to manage (defaults to string)
|
|
29
|
+
* @param options - Configuration options for the identity manager.
|
|
30
|
+
* @param options.initialCounter - The initial counter value.
|
|
31
|
+
* @param options.initialUsedIds - A set of initial used IDs.
|
|
32
|
+
* @param options.idGenerator - Custom function to generate the next ID.
|
|
33
|
+
* @example
|
|
34
|
+
* const identityManager = new IdentityManager();
|
|
35
|
+
* identityManager.get(); // => "1"
|
|
36
|
+
* identityManager.set("1");
|
|
37
|
+
* identityManager.get(); // => "2"
|
|
38
|
+
* identityManager.fetch(); // => "2"
|
|
39
|
+
* identityManager.get(); // => "3"
|
|
40
|
+
* identityManager.reset(); // => "1"
|
|
41
|
+
*/
|
|
42
|
+
declare class IdentityManager<T extends IdType = string> {
|
|
43
|
+
private _counter;
|
|
44
|
+
private _idGenerator;
|
|
45
|
+
private _initialCounter;
|
|
46
|
+
private _usedIds;
|
|
47
|
+
constructor(options: IdentityManagerConfig<T>);
|
|
48
|
+
/**
|
|
49
|
+
* Gets the next ID without incrementing the counter.
|
|
50
|
+
* @returns The next ID.
|
|
51
|
+
*/
|
|
52
|
+
get(): T;
|
|
53
|
+
/**
|
|
54
|
+
* Gets the next ID and increments the counter.
|
|
55
|
+
* @returns The next ID.
|
|
56
|
+
*/
|
|
57
|
+
fetch(): T;
|
|
58
|
+
/**
|
|
59
|
+
* Marks an ID as used and updates the counter if necessary.
|
|
60
|
+
* @param id - The ID to mark as used.
|
|
61
|
+
*/
|
|
62
|
+
set(id: T): void;
|
|
63
|
+
/**
|
|
64
|
+
* Increments the counter.
|
|
65
|
+
*/
|
|
66
|
+
inc(): void;
|
|
67
|
+
/**
|
|
68
|
+
* Resets the counter to its initial value and clears used IDs.
|
|
69
|
+
*/
|
|
70
|
+
reset(): void;
|
|
71
|
+
/**
|
|
72
|
+
* Gets the default generator for the ID type.
|
|
73
|
+
* @returns The default generator function.
|
|
74
|
+
*/
|
|
75
|
+
private getDefaultGenerator;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* String-based identity manager with sensible defaults.
|
|
79
|
+
* @example
|
|
80
|
+
* const identityManager = new StringIdentityManager();
|
|
81
|
+
* identityManager.fetch(); // => "1"
|
|
82
|
+
* identityManager.fetch(); // => "2"
|
|
83
|
+
*/
|
|
84
|
+
declare class StringIdentityManager extends IdentityManager<string> {
|
|
85
|
+
constructor(options?: Partial<IdentityManagerConfig<string>>);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Number-based identity manager with sensible defaults.
|
|
89
|
+
* @example
|
|
90
|
+
* const identityManager = new NumberIdentityManager();
|
|
91
|
+
* identityManager.fetch(); // => 1
|
|
92
|
+
* identityManager.fetch(); // => 2
|
|
93
|
+
*/
|
|
94
|
+
declare class NumberIdentityManager extends IdentityManager<number> {
|
|
95
|
+
constructor(options?: Partial<IdentityManagerConfig<number>>);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Base record type with an ID field
|
|
100
|
+
* @template TId - The type of the ID field
|
|
101
|
+
*/
|
|
102
|
+
type DbRecord<TId = IdType> = {
|
|
103
|
+
id: TId;
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Type for input data when creating or updating a record
|
|
107
|
+
* @template TRecord - The type of the record's attributes
|
|
108
|
+
*/
|
|
109
|
+
type DbRecordInput<TRecord extends DbRecord> = Partial<TRecord>;
|
|
110
|
+
/**
|
|
111
|
+
* Type for new record with optional id
|
|
112
|
+
* @template TRecord - The type of the record's attributes
|
|
113
|
+
*/
|
|
114
|
+
type NewDbRecord<TRecord extends DbRecord> = Omit<TRecord, 'id'> & {
|
|
115
|
+
id?: TRecord['id'] | null;
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* Type for database collections
|
|
119
|
+
*/
|
|
120
|
+
type DbCollections = Record<string, DbCollection<any>>;
|
|
121
|
+
/**
|
|
122
|
+
* Infers the collection type from data records
|
|
123
|
+
* @template TData - The type of data records
|
|
124
|
+
*/
|
|
125
|
+
type DbCollectionFromStaticData<TData> = TData extends Array<infer TRecord> ? TRecord extends DbRecord ? DbCollection<TRecord> : DbCollection<DbRecord> : DbCollection<DbRecord>;
|
|
126
|
+
/**
|
|
127
|
+
* Infers collections map from data object
|
|
128
|
+
* @template TData - The type of data object
|
|
129
|
+
*/
|
|
130
|
+
type DbCollectionsFromStaticData<TData> = {
|
|
131
|
+
[K in keyof TData]: DbCollectionFromStaticData<TData[K]>;
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* Gets the data of a collection
|
|
135
|
+
* @template T - The type of the collection
|
|
136
|
+
*/
|
|
137
|
+
type DbCollectionData<T> = T extends DbCollection<infer TAttrs> ? TAttrs[] : never;
|
|
138
|
+
/**
|
|
139
|
+
* Configuration for creating a database collection
|
|
140
|
+
* @template TRecord - The type of the record's attributes
|
|
141
|
+
*/
|
|
142
|
+
interface DbCollectionConfig<TRecord extends DbRecord> {
|
|
143
|
+
identityManager?: IdentityManager<TRecord['id']>;
|
|
144
|
+
initialData?: TRecord[];
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Type for a database's data
|
|
148
|
+
* @template TCollections - The type of collections in the database
|
|
149
|
+
*/
|
|
150
|
+
type DbData<TCollections extends Record<string, DbCollection<any>>> = {
|
|
151
|
+
[K in keyof TCollections]: DbCollectionData<TCollections[K]>;
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* Configuration for creating a DB instance
|
|
155
|
+
* @template TCollections - The type of collections in the database
|
|
156
|
+
*/
|
|
157
|
+
type DbConfig<TCollections extends Record<string, DbCollection<any>>> = {
|
|
158
|
+
initialData?: DbData<TCollections>;
|
|
159
|
+
};
|
|
160
|
+
/**
|
|
161
|
+
* Primitive types that support comparison operations
|
|
162
|
+
*/
|
|
163
|
+
type Primitive = string | number | boolean | Date;
|
|
164
|
+
/**
|
|
165
|
+
* Order direction for sorting
|
|
166
|
+
*/
|
|
167
|
+
type OrderDirection = 'asc' | 'desc';
|
|
168
|
+
/**
|
|
169
|
+
* Defines ordering for query results
|
|
170
|
+
* Can be an object mapping fields to directions, or an array of [field, direction] tuples
|
|
171
|
+
* @template TRecord - The record type
|
|
172
|
+
*/
|
|
173
|
+
type OrderBy<TRecord> = Partial<Record<keyof TRecord, OrderDirection>> | Array<readonly [keyof TRecord, OrderDirection]>;
|
|
174
|
+
/**
|
|
175
|
+
* Equality and membership operations
|
|
176
|
+
* @template T - The field type
|
|
177
|
+
*/
|
|
178
|
+
type EqualityOps<T> = {
|
|
179
|
+
/** Equals */
|
|
180
|
+
eq?: T;
|
|
181
|
+
/** Not equals */
|
|
182
|
+
ne?: T;
|
|
183
|
+
/** In array */
|
|
184
|
+
in?: T[];
|
|
185
|
+
/** Not in array */
|
|
186
|
+
nin?: T[];
|
|
187
|
+
/** Is null or undefined */
|
|
188
|
+
isNull?: boolean;
|
|
189
|
+
};
|
|
190
|
+
/**
|
|
191
|
+
* Range comparison operations for primitive types
|
|
192
|
+
* @template T - The primitive field type
|
|
193
|
+
*/
|
|
194
|
+
type RangeOps<T extends Primitive> = {
|
|
195
|
+
/** Less than */
|
|
196
|
+
lt?: T;
|
|
197
|
+
/** Less than or equal */
|
|
198
|
+
lte?: T;
|
|
199
|
+
/** Greater than */
|
|
200
|
+
gt?: T;
|
|
201
|
+
/** Greater than or equal */
|
|
202
|
+
gte?: T;
|
|
203
|
+
/** Between two values (inclusive) */
|
|
204
|
+
between?: readonly [T, T];
|
|
205
|
+
};
|
|
206
|
+
/**
|
|
207
|
+
* String-specific operations
|
|
208
|
+
*/
|
|
209
|
+
type StringOps = {
|
|
210
|
+
/** SQL-like pattern matching with % wildcards */
|
|
211
|
+
like?: string;
|
|
212
|
+
/** Case-insensitive like */
|
|
213
|
+
ilike?: string;
|
|
214
|
+
/** Starts with prefix */
|
|
215
|
+
startsWith?: string;
|
|
216
|
+
/** Ends with suffix */
|
|
217
|
+
endsWith?: string;
|
|
218
|
+
/** Contains substring */
|
|
219
|
+
contains?: string;
|
|
220
|
+
};
|
|
221
|
+
/**
|
|
222
|
+
* Array-specific operations
|
|
223
|
+
* @template E - The array element type
|
|
224
|
+
*/
|
|
225
|
+
type ArrayOps<E> = {
|
|
226
|
+
/** Array contains element(s) */
|
|
227
|
+
contains?: E | E[];
|
|
228
|
+
/** Array length operations */
|
|
229
|
+
length?: RangeOps<number>;
|
|
230
|
+
};
|
|
231
|
+
/**
|
|
232
|
+
* All available field operations based on field type
|
|
233
|
+
* @template T - The field type
|
|
234
|
+
*/
|
|
235
|
+
type FieldOps<T> = EqualityOps<T> & (T extends string ? StringOps : {}) & (T extends Primitive ? RangeOps<T> : {}) & (T extends readonly (infer E)[] ? ArrayOps<E> : {});
|
|
236
|
+
/**
|
|
237
|
+
* Leaf-level where clause for field matching
|
|
238
|
+
* Fields can be matched by direct value or by field operations
|
|
239
|
+
* @template TRecord - The record type
|
|
240
|
+
*/
|
|
241
|
+
type WhereLeaf<TRecord> = {
|
|
242
|
+
[K in keyof TRecord]?: TRecord[K] | FieldOps<TRecord[K]>;
|
|
243
|
+
};
|
|
244
|
+
/**
|
|
245
|
+
* Complete where clause with logical operators
|
|
246
|
+
* @template TRecord - The record type
|
|
247
|
+
*/
|
|
248
|
+
type Where<TRecord> = WhereLeaf<TRecord> & {
|
|
249
|
+
/** Logical AND - all conditions must match */
|
|
250
|
+
AND?: Where<TRecord>[];
|
|
251
|
+
/** Logical OR - at least one condition must match */
|
|
252
|
+
OR?: Where<TRecord>[];
|
|
253
|
+
/** Logical NOT - condition must not match */
|
|
254
|
+
NOT?: Where<TRecord>;
|
|
255
|
+
};
|
|
256
|
+
/**
|
|
257
|
+
* Helper functions for use in where callback predicates
|
|
258
|
+
* These are comparison utilities - users access record values and pass them to helpers
|
|
259
|
+
* @template TRecord - The record type
|
|
260
|
+
*/
|
|
261
|
+
type WhereHelperFns<TRecord> = {
|
|
262
|
+
/** Logical AND - all conditions must be true */
|
|
263
|
+
and: (...conditions: boolean[]) => boolean;
|
|
264
|
+
/** Logical OR - at least one condition must be true */
|
|
265
|
+
or: (...conditions: boolean[]) => boolean;
|
|
266
|
+
/** Logical NOT - inverts the condition */
|
|
267
|
+
not: (condition: boolean) => boolean;
|
|
268
|
+
/** Check equality */
|
|
269
|
+
eq: (value: any, compareWith: any) => boolean;
|
|
270
|
+
/** Check inequality */
|
|
271
|
+
ne: (value: any, compareWith: any) => boolean;
|
|
272
|
+
/** Greater than */
|
|
273
|
+
gt: (value: any, compareWith: any) => boolean;
|
|
274
|
+
/** Greater than or equal */
|
|
275
|
+
gte: (value: any, compareWith: any) => boolean;
|
|
276
|
+
/** Less than */
|
|
277
|
+
lt: (value: any, compareWith: any) => boolean;
|
|
278
|
+
/** Less than or equal */
|
|
279
|
+
lte: (value: any, compareWith: any) => boolean;
|
|
280
|
+
/** Between two values (inclusive) */
|
|
281
|
+
between: (value: any, min: any, max: any) => boolean;
|
|
282
|
+
/** SQL-like pattern matching */
|
|
283
|
+
like: (value: string, pattern: string) => boolean;
|
|
284
|
+
/** Case-insensitive like */
|
|
285
|
+
ilike: (value: string, pattern: string) => boolean;
|
|
286
|
+
/** Starts with string */
|
|
287
|
+
startsWith: (value: string, prefix: string) => boolean;
|
|
288
|
+
/** Ends with string */
|
|
289
|
+
endsWith: (value: string, suffix: string) => boolean;
|
|
290
|
+
/** Contains substring */
|
|
291
|
+
containsText: (value: string, substring: string) => boolean;
|
|
292
|
+
/** In array */
|
|
293
|
+
inArray: (value: any, values: any[]) => boolean;
|
|
294
|
+
/** Not in array */
|
|
295
|
+
notInArray: (value: any, values: any[]) => boolean;
|
|
296
|
+
/** Is null or undefined */
|
|
297
|
+
isNull: (value: any) => boolean;
|
|
298
|
+
/** Is not null and not undefined */
|
|
299
|
+
isNotNull: (value: any) => boolean;
|
|
300
|
+
};
|
|
301
|
+
/**
|
|
302
|
+
* Query options for finding records
|
|
303
|
+
* @template TRecord - The record type
|
|
304
|
+
*/
|
|
305
|
+
interface QueryOptions<TRecord> {
|
|
306
|
+
/** Filter criteria - object DSL or callback function */
|
|
307
|
+
where?: Where<TRecord> | ((record: TRecord, helpers: WhereHelperFns<TRecord>) => boolean);
|
|
308
|
+
/** Sorting specification */
|
|
309
|
+
orderBy?: OrderBy<TRecord>;
|
|
310
|
+
/** Number of records to skip (offset pagination) */
|
|
311
|
+
offset?: number;
|
|
312
|
+
/** Maximum number of records to return */
|
|
313
|
+
limit?: number;
|
|
314
|
+
/** Cursor for keyset pagination (must align with orderBy fields) */
|
|
315
|
+
cursor?: Partial<TRecord>;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* A collection of records in a database. Think of it as a table in a relational database.
|
|
320
|
+
* @param config - Configuration for the collection.
|
|
321
|
+
* @param config.name - The name of the collection.
|
|
322
|
+
* @param config.identityManager - The identity manager for the collection.
|
|
323
|
+
* @param config.initialData - Initial data for the collection.
|
|
324
|
+
* @example
|
|
325
|
+
* const users = new DbCollection({ name: 'users' });
|
|
326
|
+
* users.insert({ name: 'John' }); // => { id: "1", name: 'John' }
|
|
327
|
+
*/
|
|
328
|
+
declare class DbCollection<TRecord extends DbRecord = DbRecord> {
|
|
329
|
+
name: string;
|
|
330
|
+
identityManager: IdentityManager<TRecord['id']>;
|
|
331
|
+
private _records;
|
|
332
|
+
private _queryManager;
|
|
333
|
+
constructor(name: string, config?: DbCollectionConfig<TRecord>);
|
|
334
|
+
/**
|
|
335
|
+
* The next ID for the collection.
|
|
336
|
+
* @returns The next ID for the collection.
|
|
337
|
+
*/
|
|
338
|
+
get nextId(): TRecord['id'];
|
|
339
|
+
/**
|
|
340
|
+
* Returns the number of records in the collection.
|
|
341
|
+
* @returns The number of records in the collection.
|
|
342
|
+
*/
|
|
343
|
+
get size(): number;
|
|
344
|
+
/**
|
|
345
|
+
* Checks if the collection is empty.
|
|
346
|
+
* @returns `true` if the collection is empty, `false` otherwise.
|
|
347
|
+
*/
|
|
348
|
+
get isEmpty(): boolean;
|
|
349
|
+
/**
|
|
350
|
+
* Returns all records in the collection
|
|
351
|
+
* @returns An array of all records in the collection.
|
|
352
|
+
*/
|
|
353
|
+
all(): TRecord[];
|
|
354
|
+
/**
|
|
355
|
+
* Gets a record by its index position in the collection.
|
|
356
|
+
* @param index - The index of the record to get.
|
|
357
|
+
* @returns The record at the specified index, or `undefined` if out of bounds.
|
|
358
|
+
*/
|
|
359
|
+
at(index: number): TRecord | undefined;
|
|
360
|
+
/**
|
|
361
|
+
* Returns the first record in the collection.
|
|
362
|
+
* @returns The first record in the collection, or `undefined` if the collection is empty.
|
|
363
|
+
*/
|
|
364
|
+
first(): TRecord | undefined;
|
|
365
|
+
/**
|
|
366
|
+
* Returns the last record in the collection.
|
|
367
|
+
* @returns The last record in the collection, or `undefined` if the collection is empty.
|
|
368
|
+
*/
|
|
369
|
+
last(): TRecord | undefined;
|
|
370
|
+
/**
|
|
371
|
+
* Checks if a record exists in the collection.
|
|
372
|
+
* @param id - The ID of the record to check.
|
|
373
|
+
* @returns `true` if the record exists, `false` otherwise.
|
|
374
|
+
*/
|
|
375
|
+
has(id: TRecord['id']): boolean;
|
|
376
|
+
/**
|
|
377
|
+
* Finds the first record that matches the given ID, predicate object, or query options.
|
|
378
|
+
* @param input - ID, predicate object, or query options
|
|
379
|
+
* @returns The first record that matches, or `null` if not found.
|
|
380
|
+
* @example
|
|
381
|
+
* ```typescript
|
|
382
|
+
* // By ID
|
|
383
|
+
* collection.find('user-1');
|
|
384
|
+
*
|
|
385
|
+
* // By predicate object (simple equality)
|
|
386
|
+
* collection.find({ email: 'user@example.com' });
|
|
387
|
+
*
|
|
388
|
+
* // By query options (advanced filtering, sorting)
|
|
389
|
+
* collection.find({
|
|
390
|
+
* where: { email: { ilike: '%@example.com' } },
|
|
391
|
+
* orderBy: { createdAt: 'desc' },
|
|
392
|
+
* });
|
|
393
|
+
* ```
|
|
394
|
+
*/
|
|
395
|
+
find(input: TRecord['id'] | DbRecordInput<TRecord> | QueryOptions<TRecord>): TRecord | null;
|
|
396
|
+
/**
|
|
397
|
+
* Finds multiple records by IDs, predicate object, or query options.
|
|
398
|
+
* @param input - Array of IDs, predicate object, or query options
|
|
399
|
+
* @returns An array of records that match
|
|
400
|
+
* @example
|
|
401
|
+
* ```typescript
|
|
402
|
+
* // By IDs
|
|
403
|
+
* collection.findMany(['user-1', 'user-2']);
|
|
404
|
+
*
|
|
405
|
+
* // By predicate object (simple equality)
|
|
406
|
+
* collection.findMany({ active: true });
|
|
407
|
+
*
|
|
408
|
+
* // By query options (advanced filtering, sorting, pagination)
|
|
409
|
+
* collection.findMany({
|
|
410
|
+
* where: { age: { gte: 18 }, status: { in: ['active', 'pending'] } },
|
|
411
|
+
* orderBy: { createdAt: 'desc' },
|
|
412
|
+
* limit: 10,
|
|
413
|
+
* });
|
|
414
|
+
* ```
|
|
415
|
+
*/
|
|
416
|
+
findMany(input: TRecord['id'][] | DbRecordInput<TRecord> | QueryOptions<TRecord>): TRecord[];
|
|
417
|
+
/**
|
|
418
|
+
* Count records matching a where clause.
|
|
419
|
+
* @param where - Optional where clause to filter records
|
|
420
|
+
* @returns Number of matching records
|
|
421
|
+
* @example
|
|
422
|
+
* ```typescript
|
|
423
|
+
* collection.count({ status: 'active' });
|
|
424
|
+
* collection.count({ age: { gte: 18, lte: 65 } });
|
|
425
|
+
* ```
|
|
426
|
+
*/
|
|
427
|
+
count(where?: Where<TRecord>): number;
|
|
428
|
+
/**
|
|
429
|
+
* Check if any records match a where clause.
|
|
430
|
+
* @param where - Optional where clause to filter records
|
|
431
|
+
* @returns True if at least one record matches
|
|
432
|
+
* @example
|
|
433
|
+
* ```typescript
|
|
434
|
+
* collection.exists({ email: 'user@example.com' });
|
|
435
|
+
* collection.exists({ status: { in: ['active', 'pending'] } });
|
|
436
|
+
* ```
|
|
437
|
+
*/
|
|
438
|
+
exists(where?: Where<TRecord>): boolean;
|
|
439
|
+
/**
|
|
440
|
+
* Inserts a new record into the collection.
|
|
441
|
+
* @param data - The record data to insert.
|
|
442
|
+
* @returns The inserted record.
|
|
443
|
+
*/
|
|
444
|
+
insert(data: NewDbRecord<TRecord>): TRecord;
|
|
445
|
+
/**
|
|
446
|
+
* Inserts multiple records into the collection.
|
|
447
|
+
* @param data - An array of record data to insert.
|
|
448
|
+
* @returns An array of the inserted records.
|
|
449
|
+
*/
|
|
450
|
+
insertMany(data: NewDbRecord<TRecord>[]): TRecord[];
|
|
451
|
+
/**
|
|
452
|
+
* Updates a single record by ID.
|
|
453
|
+
* @param id - The record ID to update.
|
|
454
|
+
* @param patch - The data to update the record with.
|
|
455
|
+
* @returns The updated record, or `null` if the record was not found.
|
|
456
|
+
*/
|
|
457
|
+
update(id: TRecord['id'], patch: TRecord | DbRecordInput<TRecord>): TRecord | null;
|
|
458
|
+
/**
|
|
459
|
+
* Updates multiple records by IDs, predicate object, or query options.
|
|
460
|
+
* @param input - Array of IDs, predicate object, or query options to find records.
|
|
461
|
+
* @param patch - The data to update the records with.
|
|
462
|
+
* @returns Array of updated records.
|
|
463
|
+
*/
|
|
464
|
+
updateMany(input: TRecord['id'][] | DbRecordInput<TRecord> | QueryOptions<TRecord>, patch: TRecord | DbRecordInput<TRecord>): TRecord[];
|
|
465
|
+
/**
|
|
466
|
+
* Deletes a record from the collection by its ID.
|
|
467
|
+
* @param id - The ID of the record to delete.
|
|
468
|
+
* @returns `true` if the record was deleted, `false` if it was not found.
|
|
469
|
+
*/
|
|
470
|
+
delete(id: TRecord['id']): boolean;
|
|
471
|
+
/**
|
|
472
|
+
* Deletes multiple records by IDs, predicate object, or query options.
|
|
473
|
+
* @param input - Array of IDs, predicate object, or query options to find records.
|
|
474
|
+
* @returns The number of records that were deleted.
|
|
475
|
+
*/
|
|
476
|
+
deleteMany(input: TRecord['id'][] | DbRecordInput<TRecord> | QueryOptions<TRecord>): number;
|
|
477
|
+
/**
|
|
478
|
+
* Removes all records from the collection.
|
|
479
|
+
*/
|
|
480
|
+
clear(): void;
|
|
481
|
+
/**
|
|
482
|
+
* Prepares a record for insertion by generating an ID if it doesn't exist.
|
|
483
|
+
* @param data - The record to prepare.
|
|
484
|
+
* @returns The prepared record.
|
|
485
|
+
*/
|
|
486
|
+
private _prepareRecord;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* A database for storing and managing collections of records.
|
|
491
|
+
* @template TCollections - The type of collections in the database
|
|
492
|
+
* @example
|
|
493
|
+
* const db = DB.create({
|
|
494
|
+
* users: [{ id: "1", name: 'John' }],
|
|
495
|
+
* posts: [{ id: "1", title: 'Hello' }]
|
|
496
|
+
* });
|
|
497
|
+
* db.users.records;
|
|
498
|
+
*/
|
|
499
|
+
declare class DB<TCollections extends DbCollections> {
|
|
500
|
+
private _collections;
|
|
501
|
+
constructor(config?: DbConfig<TCollections>);
|
|
502
|
+
/**
|
|
503
|
+
* Checks if a collection exists.
|
|
504
|
+
* @param name - The name of the collection to check.
|
|
505
|
+
* @returns `true` if the collection exists, `false` otherwise.
|
|
506
|
+
*/
|
|
507
|
+
hasCollection(name: keyof TCollections): boolean;
|
|
508
|
+
/**
|
|
509
|
+
* Creates a new collection with the given name and initial data.
|
|
510
|
+
* @param name - The name of the collection to create.
|
|
511
|
+
* @param config - The configuration for the collection.
|
|
512
|
+
* @param config.initialData - The initial data to populate the collection with.
|
|
513
|
+
* @param config.identityManager - The identity manager for the collection.
|
|
514
|
+
* @returns The DB instance.
|
|
515
|
+
*/
|
|
516
|
+
createCollection<TAttrs extends DbRecord>(name: keyof TCollections, config?: Omit<DbCollectionConfig<TAttrs>, 'name'>): DbInstance<TCollections & {
|
|
517
|
+
[K in keyof TCollections]: DbCollection<TAttrs>;
|
|
518
|
+
}>;
|
|
519
|
+
/**
|
|
520
|
+
* Retrieves a collection by its name.
|
|
521
|
+
* @template T - The collection key
|
|
522
|
+
* @param name - The name of the collection to retrieve.
|
|
523
|
+
* @returns The collection with the specified name.
|
|
524
|
+
* @throws {Error} If the collection does not exist.
|
|
525
|
+
*/
|
|
526
|
+
getCollection<T extends keyof TCollections>(name: T): TCollections[T];
|
|
527
|
+
/**
|
|
528
|
+
* Retrieves the identity manager for a given collection name.
|
|
529
|
+
* @param collectionName - The name of the collection to get the identity manager for.
|
|
530
|
+
* @returns The identity manager for the given collection name.
|
|
531
|
+
* @throws {Error} If the collection does not exist.
|
|
532
|
+
*/
|
|
533
|
+
identityManagerFor(collectionName: keyof TCollections): IdentityManager<IdType>;
|
|
534
|
+
/**
|
|
535
|
+
* Loads collections data from a record into the database.
|
|
536
|
+
* @template TData - The type of data to load
|
|
537
|
+
* @param data - Record of collection names and their initial data
|
|
538
|
+
* @returns The DB instance with collection accessors for the loaded data.
|
|
539
|
+
*/
|
|
540
|
+
loadData<TData extends Record<string, DbRecord[]>>(data: TData): DbInstance<TCollections & DbCollectionsFromStaticData<TData>>;
|
|
541
|
+
/**
|
|
542
|
+
* Empties the data from all collections in the database.
|
|
543
|
+
*/
|
|
544
|
+
emptyData(): void;
|
|
545
|
+
/**
|
|
546
|
+
* Dumps the data from all collections in the database.
|
|
547
|
+
* @returns A record of collection names and their data.
|
|
548
|
+
*/
|
|
549
|
+
dump(): DbData<TCollections>;
|
|
550
|
+
private initCollectionAccessors;
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Type for a DB instance with collection accessors
|
|
554
|
+
* @template TCollections - The type of collections in the database
|
|
555
|
+
*/
|
|
556
|
+
type DbInstance<TCollections extends Record<string, DbCollection<any>>> = DB<TCollections> & {
|
|
557
|
+
[K in keyof TCollections]: TCollections[K];
|
|
558
|
+
};
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Logger class for outputting structured log messages.
|
|
562
|
+
*
|
|
563
|
+
* Provides debug, info, warn, and error logging methods with automatic level filtering.
|
|
564
|
+
* Used internally by the ORM to log database operations, seed/fixture loading, and errors.
|
|
565
|
+
* @example
|
|
566
|
+
* ```typescript
|
|
567
|
+
* const logger = new Logger({
|
|
568
|
+
* enabled: true,
|
|
569
|
+
* level: 'debug',
|
|
570
|
+
* prefix: '[MyApp]'
|
|
571
|
+
* });
|
|
572
|
+
*
|
|
573
|
+
* logger.debug('Operation started', { userId: '123' });
|
|
574
|
+
* logger.info('Loaded 10 records');
|
|
575
|
+
* logger.warn('Missing optional field', { field: 'email' });
|
|
576
|
+
* logger.error('Validation failed', { errors: [...] });
|
|
577
|
+
* ```
|
|
578
|
+
*/
|
|
579
|
+
declare class Logger {
|
|
580
|
+
private _config;
|
|
581
|
+
/**
|
|
582
|
+
* Creates a new Logger instance with the specified configuration.
|
|
583
|
+
* @param config - Logger configuration including enabled state, log level, and optional prefix
|
|
584
|
+
* @example
|
|
585
|
+
* ```typescript
|
|
586
|
+
* const logger = new Logger({
|
|
587
|
+
* enabled: true,
|
|
588
|
+
* level: 'debug',
|
|
589
|
+
* prefix: '[Mirage]'
|
|
590
|
+
* });
|
|
591
|
+
* ```
|
|
592
|
+
*/
|
|
593
|
+
constructor(config: LoggerConfig);
|
|
594
|
+
/**
|
|
595
|
+
* Logs a debug message with optional context.
|
|
596
|
+
*
|
|
597
|
+
* Debug logs are the most verbose and show low-level operational details.
|
|
598
|
+
* Use for troubleshooting, understanding flow, and performance analysis.
|
|
599
|
+
*
|
|
600
|
+
* Only outputs if logger is enabled and level is set to 'debug'.
|
|
601
|
+
* @param message - The debug message to log
|
|
602
|
+
* @param context - Optional context object with additional information
|
|
603
|
+
* @example
|
|
604
|
+
* ```typescript
|
|
605
|
+
* logger.debug('Query executed', { collection: 'users', query: { name: 'John' } });
|
|
606
|
+
* // Output: [Mirage] DEBUG: Query executed { collection: 'users', query: { name: 'John' } }
|
|
607
|
+
* ```
|
|
608
|
+
*/
|
|
609
|
+
debug(message: string, context?: Record<string, unknown>): void;
|
|
610
|
+
/**
|
|
611
|
+
* Logs an info message with optional context.
|
|
612
|
+
*
|
|
613
|
+
* Info logs show normal operations and important events.
|
|
614
|
+
* Use for high-level actions, successful operations, and summaries.
|
|
615
|
+
*
|
|
616
|
+
* Only outputs if logger is enabled and level is 'debug' or 'info'.
|
|
617
|
+
* @param message - The info message to log
|
|
618
|
+
* @param context - Optional context object with additional information
|
|
619
|
+
* @example
|
|
620
|
+
* ```typescript
|
|
621
|
+
* logger.info('Fixtures loaded', { collection: 'users', count: 50 });
|
|
622
|
+
* // Output: [Mirage] INFO: Fixtures loaded { collection: 'users', count: 50 }
|
|
623
|
+
* ```
|
|
624
|
+
*/
|
|
625
|
+
info(message: string, context?: Record<string, unknown>): void;
|
|
626
|
+
/**
|
|
627
|
+
* Logs a warning message with optional context.
|
|
628
|
+
*
|
|
629
|
+
* Warning logs indicate something unexpected but not breaking.
|
|
630
|
+
* Use for deprecated features, unusual patterns, and potential issues.
|
|
631
|
+
*
|
|
632
|
+
* Only outputs if logger is enabled and level is 'debug', 'info', or 'warn'.
|
|
633
|
+
* @param message - The warning message to log
|
|
634
|
+
* @param context - Optional context object with additional information
|
|
635
|
+
* @example
|
|
636
|
+
* ```typescript
|
|
637
|
+
* logger.warn('Foreign key mismatch', { postId: '1', authorId: '999' });
|
|
638
|
+
* // Output: [Mirage] WARN: Foreign key mismatch { postId: '1', authorId: '999' }
|
|
639
|
+
* ```
|
|
640
|
+
*/
|
|
641
|
+
warn(message: string, context?: Record<string, unknown>): void;
|
|
642
|
+
/**
|
|
643
|
+
* Logs an error message with optional context.
|
|
644
|
+
*
|
|
645
|
+
* Error logs indicate something failed or broke.
|
|
646
|
+
* Use for operations that couldn't complete and validation failures.
|
|
647
|
+
*
|
|
648
|
+
* Only outputs if logger is enabled and level is not 'silent'.
|
|
649
|
+
* @param message - The error message to log
|
|
650
|
+
* @param context - Optional context object with additional information
|
|
651
|
+
* @example
|
|
652
|
+
* ```typescript
|
|
653
|
+
* logger.error('Validation failed', { field: 'email', reason: 'required' });
|
|
654
|
+
* // Output: [Mirage] ERROR: Validation failed { field: 'email', reason: 'required' }
|
|
655
|
+
* ```
|
|
656
|
+
*/
|
|
657
|
+
error(message: string, context?: Record<string, unknown>): void;
|
|
658
|
+
/**
|
|
659
|
+
* Internal method to handle actual logging with level filtering.
|
|
660
|
+
*
|
|
661
|
+
* Checks if logging is enabled and if the message level meets the configured threshold.
|
|
662
|
+
* Routes messages to appropriate console methods based on severity.
|
|
663
|
+
* @param level - The log level of the message
|
|
664
|
+
* @param message - The message to log
|
|
665
|
+
* @param context - Optional context object
|
|
666
|
+
* @private
|
|
667
|
+
*/
|
|
668
|
+
private _log;
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Log level type defining the severity of log messages.
|
|
672
|
+
*
|
|
673
|
+
* Log levels follow a hierarchy where setting a level shows that level and everything above it:
|
|
674
|
+
* - `silent`: No logging
|
|
675
|
+
* - `error`: Only errors
|
|
676
|
+
* - `warn`: Warnings and errors
|
|
677
|
+
* - `info`: Info, warnings, and errors
|
|
678
|
+
* - `debug`: All messages (most verbose)
|
|
679
|
+
* @example
|
|
680
|
+
* ```typescript
|
|
681
|
+
* // Debug level - see everything
|
|
682
|
+
* schema().logging({ enabled: true, level: 'debug' })
|
|
683
|
+
*
|
|
684
|
+
* // Info level - only important operations
|
|
685
|
+
* schema().logging({ enabled: true, level: 'info' })
|
|
686
|
+
*
|
|
687
|
+
* // Error level - only failures
|
|
688
|
+
* schema().logging({ enabled: true, level: 'error' })
|
|
689
|
+
* ```
|
|
690
|
+
*/
|
|
691
|
+
type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';
|
|
692
|
+
/**
|
|
693
|
+
* Logger configuration options.
|
|
694
|
+
*/
|
|
695
|
+
interface LoggerConfig {
|
|
696
|
+
/**
|
|
697
|
+
* Whether logging is enabled. When false, no logs are output regardless of level.
|
|
698
|
+
* @default false
|
|
699
|
+
*/
|
|
700
|
+
enabled: boolean;
|
|
701
|
+
/**
|
|
702
|
+
* The minimum log level to output. Messages below this level are filtered out.
|
|
703
|
+
* @default 'info'
|
|
704
|
+
*/
|
|
705
|
+
level: LogLevel;
|
|
706
|
+
/**
|
|
707
|
+
* Custom prefix for log messages. Useful for distinguishing ORM logs from other output.
|
|
708
|
+
* @default '[Mirage]'
|
|
709
|
+
*/
|
|
710
|
+
prefix?: string;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
/**
|
|
714
|
+
* A collection of models with array-like interface
|
|
715
|
+
* @template TTemplate - The model template (most important for users)
|
|
716
|
+
* @template TSchema - The schema collections type for enhanced type inference
|
|
717
|
+
* @template TSerializer - The serializer type
|
|
718
|
+
*/
|
|
719
|
+
declare class ModelCollection<TTemplate extends ModelTemplate = ModelTemplate, TSchema extends SchemaCollections = SchemaCollections, TSerializer = undefined> {
|
|
720
|
+
private readonly _template;
|
|
721
|
+
readonly collectionName: string;
|
|
722
|
+
models: Array<ModelInstance<TTemplate, TSchema, TSerializer>>;
|
|
723
|
+
protected _serializer?: TSerializer;
|
|
724
|
+
constructor(template: TTemplate, models?: Array<ModelInstance<TTemplate, TSchema, TSerializer>>, serializer?: TSerializer);
|
|
725
|
+
/**
|
|
726
|
+
* Get the length of the collection
|
|
727
|
+
* @returns The number of models in the collection
|
|
728
|
+
*/
|
|
729
|
+
get length(): number;
|
|
730
|
+
/**
|
|
731
|
+
* Check if the collection is empty
|
|
732
|
+
* @returns True if the collection is empty, false otherwise
|
|
733
|
+
*/
|
|
734
|
+
get isEmpty(): boolean;
|
|
735
|
+
/**
|
|
736
|
+
* Get a model by index
|
|
737
|
+
* @param index - The index of the model to get
|
|
738
|
+
* @returns The model at the given index or undefined
|
|
739
|
+
*/
|
|
740
|
+
at(index: number): ModelInstance<TTemplate, TSchema, TSerializer> | undefined;
|
|
741
|
+
/**
|
|
742
|
+
* Get the first model in the collection
|
|
743
|
+
* @returns The first model or null if the collection is empty
|
|
744
|
+
*/
|
|
745
|
+
first(): ModelInstance<TTemplate, TSchema, TSerializer> | null;
|
|
746
|
+
/**
|
|
747
|
+
* Get the last model in the collection
|
|
748
|
+
* @returns The last model or null if the collection is empty
|
|
749
|
+
*/
|
|
750
|
+
last(): ModelInstance<TTemplate, TSchema, TSerializer> | null;
|
|
751
|
+
/**
|
|
752
|
+
* Execute a function for each model in the collection
|
|
753
|
+
* @param cb - The function to execute for each model
|
|
754
|
+
*/
|
|
755
|
+
forEach(cb: (model: ModelInstance<TTemplate, TSchema, TSerializer>, index: number, collection: this) => void): void;
|
|
756
|
+
/**
|
|
757
|
+
* Create a new array with the results of calling a function for each model
|
|
758
|
+
* @param cb - The function to call for each model
|
|
759
|
+
* @returns A new array with the results
|
|
760
|
+
*/
|
|
761
|
+
map(cb: (model: ModelInstance<TTemplate, TSchema, TSerializer>, index: number, collection: this) => ModelInstance<TTemplate, TSchema, TSerializer>): ModelCollection<TTemplate, TSchema, TSerializer>;
|
|
762
|
+
/**
|
|
763
|
+
* Create a new collection with models that pass a test
|
|
764
|
+
* @param cb - The test function
|
|
765
|
+
* @returns A new ModelCollection with the filtered models
|
|
766
|
+
*/
|
|
767
|
+
filter(cb: (model: ModelInstance<TTemplate, TSchema, TSerializer>, index: number, collection: this) => boolean): ModelCollection<TTemplate, TSchema, TSerializer>;
|
|
768
|
+
/**
|
|
769
|
+
* Find the first model that satisfies a test
|
|
770
|
+
* @param cb - The test function
|
|
771
|
+
* @returns The first model that passes the test, or undefined
|
|
772
|
+
*/
|
|
773
|
+
find(cb: (model: ModelInstance<TTemplate, TSchema, TSerializer>, index: number, collection: this) => boolean): ModelInstance<TTemplate, TSchema, TSerializer> | undefined;
|
|
774
|
+
/**
|
|
775
|
+
* Check if at least one model satisfies a test
|
|
776
|
+
* @param cb - The test function
|
|
777
|
+
* @returns True if at least one model passes the test
|
|
778
|
+
*/
|
|
779
|
+
some(cb: (model: ModelInstance<TTemplate, TSchema, TSerializer>, index: number, collection: this) => boolean): boolean;
|
|
780
|
+
/**
|
|
781
|
+
* Check if all models satisfy a test
|
|
782
|
+
* @param cb - The test function
|
|
783
|
+
* @returns True if all models pass the test
|
|
784
|
+
*/
|
|
785
|
+
every(cb: (model: ModelInstance<TTemplate, TSchema, TSerializer>, index: number, collection: this) => boolean): boolean;
|
|
786
|
+
/**
|
|
787
|
+
* Concatenate this collection with other collections or arrays
|
|
788
|
+
* @param others - Other collections or arrays to concatenate
|
|
789
|
+
* @returns A new ModelCollection with all models
|
|
790
|
+
*/
|
|
791
|
+
concat(...others: (ModelCollection<TTemplate, TSchema, TSerializer> | ModelInstance<TTemplate, TSchema, TSerializer>[])[]): ModelCollection<TTemplate, TSchema, TSerializer>;
|
|
792
|
+
/**
|
|
793
|
+
* Check if the collection includes a specific model
|
|
794
|
+
* @param model - The model to check for
|
|
795
|
+
* @returns True if the model is in the collection
|
|
796
|
+
*/
|
|
797
|
+
includes(model: ModelInstance<TTemplate, TSchema, TSerializer>): boolean;
|
|
798
|
+
/**
|
|
799
|
+
* Find the index of a model in the collection
|
|
800
|
+
* @param model - The model to find
|
|
801
|
+
* @returns The index of the model, or -1 if not found
|
|
802
|
+
*/
|
|
803
|
+
indexOf(model: ModelInstance<TTemplate, TSchema, TSerializer>): number;
|
|
804
|
+
/**
|
|
805
|
+
* Sort the models in the collection
|
|
806
|
+
* @param compareFn - The comparison function
|
|
807
|
+
* @returns A new sorted ModelCollection
|
|
808
|
+
*/
|
|
809
|
+
sort(compareFn?: (a: ModelInstance<TTemplate, TSchema, TSerializer>, b: ModelInstance<TTemplate, TSchema, TSerializer>) => number): ModelCollection<TTemplate, TSchema, TSerializer>;
|
|
810
|
+
/**
|
|
811
|
+
* Reverse the order of models in the collection
|
|
812
|
+
* @returns A new reversed ModelCollection
|
|
813
|
+
*/
|
|
814
|
+
reverse(): ModelCollection<TTemplate, TSchema, TSerializer>;
|
|
815
|
+
/**
|
|
816
|
+
* Add a model to the end of the collection (alias for push)
|
|
817
|
+
* @param model - The model to add
|
|
818
|
+
*/
|
|
819
|
+
add(model: ModelInstance<TTemplate, TSchema, TSerializer>): void;
|
|
820
|
+
/**
|
|
821
|
+
* Remove a model from the collection
|
|
822
|
+
* @param model - The model to remove
|
|
823
|
+
* @returns True if the model was removed, false if not found
|
|
824
|
+
*/
|
|
825
|
+
remove(model: ModelInstance<TTemplate, TSchema, TSerializer>): boolean;
|
|
826
|
+
/**
|
|
827
|
+
* Save all models in the collection
|
|
828
|
+
* @returns The collection instance for chaining
|
|
829
|
+
*/
|
|
830
|
+
save(): this;
|
|
831
|
+
/**
|
|
832
|
+
* Destroy all models in the collection
|
|
833
|
+
* @returns The collection instance for chaining
|
|
834
|
+
*/
|
|
835
|
+
destroy(): this;
|
|
836
|
+
/**
|
|
837
|
+
* Reload all models in the collection from the database
|
|
838
|
+
* @returns The collection instance for chaining
|
|
839
|
+
*/
|
|
840
|
+
reload(): this;
|
|
841
|
+
/**
|
|
842
|
+
* Update all models in the collection with the given attributes
|
|
843
|
+
* @param attrs - The attributes to update
|
|
844
|
+
* @returns The collection instance for chaining
|
|
845
|
+
*/
|
|
846
|
+
update(attrs: ModelUpdateAttrs<TTemplate, TSchema>): this;
|
|
847
|
+
/**
|
|
848
|
+
* Convert the collection to a plain array
|
|
849
|
+
* @returns An array of the models
|
|
850
|
+
*/
|
|
851
|
+
toArray(): ModelInstance<TTemplate, TSchema, TSerializer>[];
|
|
852
|
+
/**
|
|
853
|
+
* Get a string representation of the collection
|
|
854
|
+
* @returns A string representation showing the collection name and count
|
|
855
|
+
*/
|
|
856
|
+
toString(): string;
|
|
857
|
+
/**
|
|
858
|
+
* Convert the collection to JSON
|
|
859
|
+
* Uses serializer if configured, otherwise returns array of raw attributes
|
|
860
|
+
* @returns A serialized representation of the collection
|
|
861
|
+
*/
|
|
862
|
+
toJSON(): TSerializer extends {
|
|
863
|
+
serializeCollection(collection: any): infer TSerializedCollection;
|
|
864
|
+
} ? TSerializedCollection : ModelAttrs<TTemplate, TSchema>[];
|
|
865
|
+
/**
|
|
866
|
+
* Make the collection iterable
|
|
867
|
+
* @returns An iterator for the models
|
|
868
|
+
*/
|
|
869
|
+
[Symbol.iterator](): Iterator<ModelInstance<TTemplate, TSchema, TSerializer>>;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
/**
|
|
873
|
+
* Structural serializer options (schema-level or collection-level)
|
|
874
|
+
* Controls how the response is formatted/structured
|
|
875
|
+
*/
|
|
876
|
+
interface StructuralSerializerOptions {
|
|
877
|
+
/**
|
|
878
|
+
* Whether to wrap the serialized data in a root key
|
|
879
|
+
* - false: no wrapping (default)
|
|
880
|
+
* - true: wrap with modelName/collectionName
|
|
881
|
+
* - string: wrap with custom key name
|
|
882
|
+
*/
|
|
883
|
+
root?: boolean | string;
|
|
884
|
+
/**
|
|
885
|
+
* Whether to embed related models in the serialized output
|
|
886
|
+
* - false: exclude relationships (default)
|
|
887
|
+
* - true: include embedded relationships
|
|
888
|
+
*/
|
|
889
|
+
embed?: boolean;
|
|
890
|
+
}
|
|
891
|
+
/**
|
|
892
|
+
* Data selection serializer options (collection-level only)
|
|
893
|
+
* Controls what data to include in serialization
|
|
894
|
+
* @template TTemplate - The model template
|
|
895
|
+
*/
|
|
896
|
+
interface DataSerializerOptions<TTemplate extends ModelTemplate> {
|
|
897
|
+
/**
|
|
898
|
+
* Specific attributes to include in serialization
|
|
899
|
+
* If not provided, all attributes are included
|
|
900
|
+
* Note: This is model-specific and not available at schema level
|
|
901
|
+
*/
|
|
902
|
+
attrs?: (keyof InferModelAttrs<TTemplate>)[];
|
|
903
|
+
/**
|
|
904
|
+
* Relationship names to include in serialization
|
|
905
|
+
* Note: This is model-specific and not available at schema level
|
|
906
|
+
*/
|
|
907
|
+
include?: string[];
|
|
908
|
+
}
|
|
909
|
+
/**
|
|
910
|
+
* Complete serializer options (collection-level)
|
|
911
|
+
* Combines structural and data selection options
|
|
912
|
+
* @template TTemplate - The model template
|
|
913
|
+
*/
|
|
914
|
+
interface SerializerOptions<TTemplate extends ModelTemplate> extends StructuralSerializerOptions, DataSerializerOptions<TTemplate> {
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
/**
|
|
918
|
+
* Serializer class that handles model serialization with custom JSON types
|
|
919
|
+
* @template TTemplate - The model template
|
|
920
|
+
* @template TSerializedModel - The serialized model type (for single model)
|
|
921
|
+
* @template TSerializedCollection - The serialized collection type (for array of models)
|
|
922
|
+
* @template TOptions - The serializer options type
|
|
923
|
+
* @example
|
|
924
|
+
* ```typescript
|
|
925
|
+
* interface UserJSON {
|
|
926
|
+
* id: string;
|
|
927
|
+
* name: string;
|
|
928
|
+
* }
|
|
929
|
+
*
|
|
930
|
+
* interface UsersJSON {
|
|
931
|
+
* users: UserJSON[];
|
|
932
|
+
* }
|
|
933
|
+
*
|
|
934
|
+
* const serializer = new Serializer<UserTemplate, UserJSON, UsersJSON>(
|
|
935
|
+
* userTemplate,
|
|
936
|
+
* {
|
|
937
|
+
* attrs: ['id', 'name'],
|
|
938
|
+
* root: 'user'
|
|
939
|
+
* }
|
|
940
|
+
* );
|
|
941
|
+
* ```
|
|
942
|
+
*/
|
|
943
|
+
declare class Serializer<TTemplate extends ModelTemplate, TSerializedModel = InferModelAttrs<TTemplate>, TSerializedCollection = TSerializedModel[], TOptions extends SerializerOptions<TTemplate> = SerializerOptions<TTemplate>> {
|
|
944
|
+
protected _template: TTemplate;
|
|
945
|
+
protected _modelName: string;
|
|
946
|
+
protected _collectionName: string;
|
|
947
|
+
protected _attrs: TOptions['attrs'];
|
|
948
|
+
protected _root: TOptions['root'];
|
|
949
|
+
protected _embed: TOptions['embed'];
|
|
950
|
+
protected _include: TOptions['include'];
|
|
951
|
+
constructor(template: TTemplate, options?: TOptions);
|
|
952
|
+
/**
|
|
953
|
+
* Get the model name
|
|
954
|
+
* @returns The model name
|
|
955
|
+
*/
|
|
956
|
+
get modelName(): string;
|
|
957
|
+
/**
|
|
958
|
+
* Get the collection name
|
|
959
|
+
* @returns The collection name
|
|
960
|
+
*/
|
|
961
|
+
get collectionName(): string;
|
|
962
|
+
/**
|
|
963
|
+
* Serialize raw data from a model without structural wrapping
|
|
964
|
+
* This method extracts and returns the data (attributes + relationships)
|
|
965
|
+
* without applying any root wrapping. Used for embedding relationships.
|
|
966
|
+
* @param model - The model instance to serialize
|
|
967
|
+
* @returns The serialized model data without root wrapping
|
|
968
|
+
*/
|
|
969
|
+
serializeData<TSchema extends SchemaCollections>(model: ModelInstance<TTemplate, TSchema>): Record<string, any>;
|
|
970
|
+
/**
|
|
971
|
+
* Serialize a single model instance with structural formatting
|
|
972
|
+
* Applies root wrapping and side-loading if configured
|
|
973
|
+
* @param model - The model instance to serialize
|
|
974
|
+
* @returns The serialized model with structural formatting applied
|
|
975
|
+
*/
|
|
976
|
+
serialize<TSchema extends SchemaCollections>(model: ModelInstance<TTemplate, TSchema>): TSerializedModel;
|
|
977
|
+
/**
|
|
978
|
+
* Serialize raw data from a collection without structural wrapping
|
|
979
|
+
* Returns an array of serialized model data without root wrapping
|
|
980
|
+
* @param collection - The model collection to serialize
|
|
981
|
+
* @returns Array of serialized model data
|
|
982
|
+
*/
|
|
983
|
+
serializeCollectionData<TSchema extends SchemaCollections>(collection: ModelCollection<TTemplate, TSchema>): Record<string, any>[];
|
|
984
|
+
/**
|
|
985
|
+
* Serialize a model collection with structural formatting
|
|
986
|
+
* Applies root wrapping and side-loading if configured
|
|
987
|
+
* @param collection - The model collection to serialize
|
|
988
|
+
* @returns The serialized collection with structural formatting applied
|
|
989
|
+
*/
|
|
990
|
+
serializeCollection<TSchema extends SchemaCollections>(collection: ModelCollection<TTemplate, TSchema>): TSerializedCollection;
|
|
991
|
+
/**
|
|
992
|
+
* Get the attributes to include in serialization
|
|
993
|
+
* Can be overridden in subclasses for custom serialization logic
|
|
994
|
+
* @param model - The model instance
|
|
995
|
+
* @returns Object with attributes
|
|
996
|
+
*/
|
|
997
|
+
protected _getAttributes<TSchema extends SchemaCollections>(model: ModelInstance<TTemplate, TSchema>): Record<string, any>;
|
|
998
|
+
/**
|
|
999
|
+
* Get relationships to include in serialization
|
|
1000
|
+
* Returns embedded relationships, side-loaded relationships, and foreign keys
|
|
1001
|
+
* @param model - The model instance
|
|
1002
|
+
* @returns Object with embedded, sideLoaded, and foreignKeys
|
|
1003
|
+
*/
|
|
1004
|
+
protected _getRelationships<TSchema extends SchemaCollections>(model: ModelInstance<TTemplate, TSchema>): {
|
|
1005
|
+
embedded: Record<string, any>;
|
|
1006
|
+
sideLoaded: Record<string, any>;
|
|
1007
|
+
foreignKeys: string[];
|
|
1008
|
+
};
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
/**
|
|
1012
|
+
* Seed function that accepts a schema instance
|
|
1013
|
+
* @template TSchema - The schema collections type
|
|
1014
|
+
*/
|
|
1015
|
+
type SeedFunction<TSchema extends SchemaCollections = SchemaCollections> = (schema: SchemaInstance<TSchema>) => void | Promise<void>;
|
|
1016
|
+
/**
|
|
1017
|
+
* Named seed scenarios - object with named seed methods
|
|
1018
|
+
* @template TSchema - The schema collections type
|
|
1019
|
+
*/
|
|
1020
|
+
type SeedScenarios<TSchema extends SchemaCollections = SchemaCollections> = Record<string, SeedFunction<TSchema>>;
|
|
1021
|
+
/**
|
|
1022
|
+
* Seeds configuration - can be a function or object with named scenarios
|
|
1023
|
+
* @template TSchema - The schema collections type
|
|
1024
|
+
*/
|
|
1025
|
+
type Seeds<TSchema extends SchemaCollections = SchemaCollections> = SeedFunction<TSchema> | SeedScenarios<TSchema>;
|
|
1026
|
+
/**
|
|
1027
|
+
* Strategy for loading fixtures
|
|
1028
|
+
* - 'auto': Load fixtures automatically during schema setup
|
|
1029
|
+
* - 'manual': Load fixtures manually by calling loadFixtures()
|
|
1030
|
+
*/
|
|
1031
|
+
type FixtureLoadStrategy = 'auto' | 'manual';
|
|
1032
|
+
/**
|
|
1033
|
+
* A single fixture attributes object - matches the model attributes with optional foreign keys
|
|
1034
|
+
* @template TTemplate - The model template
|
|
1035
|
+
* @template TRelationships - The model relationships
|
|
1036
|
+
*/
|
|
1037
|
+
type FixtureAttrs<TTemplate extends ModelTemplate, TRelationships extends ModelRelationships = {}> = ModelAttrs<TTemplate> & (Record<string, never> extends TRelationships ? {} : Partial<ModelForeignKeys<TRelationships>>);
|
|
1038
|
+
/**
|
|
1039
|
+
* Fixture configuration for a collection
|
|
1040
|
+
* @template TTemplate - The model template
|
|
1041
|
+
* @template TRelationships - The model relationships
|
|
1042
|
+
*/
|
|
1043
|
+
interface FixtureConfig<TTemplate extends ModelTemplate, TRelationships extends ModelRelationships = {}> {
|
|
1044
|
+
/**
|
|
1045
|
+
* Array of fixture attributes to load
|
|
1046
|
+
*/
|
|
1047
|
+
records: FixtureAttrs<TTemplate, TRelationships>[];
|
|
1048
|
+
/**
|
|
1049
|
+
* When to load the fixtures (default: 'manual')
|
|
1050
|
+
*/
|
|
1051
|
+
strategy?: FixtureLoadStrategy;
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* Global schema configuration
|
|
1055
|
+
* @template TIdentityManager - The identity manager type
|
|
1056
|
+
* @template TGlobalConfig - The global serializer configuration type
|
|
1057
|
+
*/
|
|
1058
|
+
interface SchemaConfig<TIdentityManager extends IdentityManager = StringIdentityManager, TGlobalConfig extends StructuralSerializerOptions | undefined = undefined> {
|
|
1059
|
+
identityManager?: TIdentityManager;
|
|
1060
|
+
globalSerializerConfig?: TGlobalConfig;
|
|
1061
|
+
logging?: LoggerConfig;
|
|
1062
|
+
}
|
|
1063
|
+
/**
|
|
1064
|
+
* Type for collection config
|
|
1065
|
+
* @template TTemplate - The model template
|
|
1066
|
+
* @template TRelationships - The model relationships
|
|
1067
|
+
* @template TFactory - The factory type
|
|
1068
|
+
* @template TSerializer - The serializer instance type
|
|
1069
|
+
* @template TSchema - The schema collections type for seeds typing
|
|
1070
|
+
*/
|
|
1071
|
+
interface CollectionConfig<TTemplate extends ModelTemplate, TRelationships extends ModelRelationships = {}, TFactory extends Factory<TTemplate, any, any> | undefined = undefined, TSerializer = undefined, TSchema extends SchemaCollections = SchemaCollections> {
|
|
1072
|
+
model: TTemplate;
|
|
1073
|
+
factory?: TFactory;
|
|
1074
|
+
relationships?: TRelationships;
|
|
1075
|
+
identityManager?: IdentityManager<ModelId<TTemplate>>;
|
|
1076
|
+
/**
|
|
1077
|
+
* Serializer configuration object (attrs, root, embed, include)
|
|
1078
|
+
* Used when collection().serializer({...config}) is called
|
|
1079
|
+
*/
|
|
1080
|
+
serializerConfig?: SerializerOptions<TTemplate>;
|
|
1081
|
+
/**
|
|
1082
|
+
* Serializer instance (custom serializer class)
|
|
1083
|
+
* Used when collection().serializer(instance) is called
|
|
1084
|
+
*/
|
|
1085
|
+
serializerInstance?: TSerializer;
|
|
1086
|
+
/**
|
|
1087
|
+
* Seeds configuration - can be a function or object with named scenarios
|
|
1088
|
+
* Used when collection().seeds(...) is called
|
|
1089
|
+
*/
|
|
1090
|
+
seeds?: Seeds<TSchema>;
|
|
1091
|
+
/**
|
|
1092
|
+
* Fixtures configuration - static data to load into the collection
|
|
1093
|
+
* Used when collection().fixtures(...) is called
|
|
1094
|
+
*/
|
|
1095
|
+
fixtures?: FixtureConfig<TTemplate, TRelationships>;
|
|
1096
|
+
}
|
|
1097
|
+
/**
|
|
1098
|
+
* Type for schema collections - provides both string-based property access and symbol-based relationship resolution
|
|
1099
|
+
* @template TCollections - The string-keyed schema collections config
|
|
1100
|
+
*/
|
|
1101
|
+
type SchemaCollections = Record<string, CollectionConfig<any, any, any, any, any>>;
|
|
1102
|
+
/**
|
|
1103
|
+
* Type for schema collections - provides string-based property access
|
|
1104
|
+
* @template TCollections - The string-keyed schema collections config
|
|
1105
|
+
*/
|
|
1106
|
+
type SchemaCollectionAccessors<TCollections extends SchemaCollections> = {
|
|
1107
|
+
[K in keyof TCollections]: TCollections[K] extends CollectionConfig<infer TTemplate, infer TRelationships, infer TFactory, infer TSerializer, any> ? Collection<TCollections, TTemplate, TRelationships, TFactory, TSerializer> : never;
|
|
1108
|
+
};
|
|
1109
|
+
/**
|
|
1110
|
+
* Maps schema collection configs to database collections with inferred foreign keys
|
|
1111
|
+
* This ensures that database records include foreign key fields based on defined relationships
|
|
1112
|
+
*/
|
|
1113
|
+
type SchemaDbCollections<TCollections extends SchemaCollections> = {
|
|
1114
|
+
[K in keyof TCollections]: TCollections[K] extends CollectionConfig<infer TTemplate, infer TRelationships, any, any, any> ? DbCollection<ModelAttrs<TTemplate> & (TRelationships extends ModelRelationships ? ModelForeignKeys<TRelationships> : {})> : never;
|
|
1115
|
+
};
|
|
1116
|
+
/**
|
|
1117
|
+
* Type for collection create/factory attributes - all attributes are optional
|
|
1118
|
+
* Used for passing attributes to create() methods where factory provides defaults
|
|
1119
|
+
* @template TTemplate - The model template
|
|
1120
|
+
* @template TSchema - The schema collections type
|
|
1121
|
+
* @template TRelationships - The model relationships
|
|
1122
|
+
*/
|
|
1123
|
+
type CollectionCreateAttrs<TTemplate extends ModelTemplate, TSchema extends SchemaCollections = SchemaCollections, TRelationships extends ModelRelationships = RelationshipsByTemplate<TTemplate, TSchema>> = Partial<ModelAttrs<TTemplate, TSchema>> & (Record<string, never> extends TRelationships ? {} : Partial<RelatedModelAttrs<TSchema, TRelationships>>);
|
|
1124
|
+
/**
|
|
1125
|
+
* Simplified Collection instance type helper that only requires the template parameter.
|
|
1126
|
+
* Useful for typing collection references without verbose generic parameters.
|
|
1127
|
+
* @template TTemplate - The model template (required)
|
|
1128
|
+
* @template TRelationships - The model relationships (optional, defaults to {})
|
|
1129
|
+
* @template TFactory - The factory type (optional, defaults to undefined)
|
|
1130
|
+
* @template TSerializer - The serializer type (optional, defaults to undefined)
|
|
1131
|
+
* @example
|
|
1132
|
+
* ```typescript
|
|
1133
|
+
* import { CollectionInstance } from '@miragejs/orm';
|
|
1134
|
+
*
|
|
1135
|
+
* // Simple usage
|
|
1136
|
+
* const usersCollection: CollectionInstance<typeof userModel> = schema.users;
|
|
1137
|
+
*
|
|
1138
|
+
* // With relationships
|
|
1139
|
+
* const usersCollection: CollectionInstance<
|
|
1140
|
+
* typeof userModel,
|
|
1141
|
+
* { posts: HasMany<typeof postModel> }
|
|
1142
|
+
* > = schema.users;
|
|
1143
|
+
* ```
|
|
1144
|
+
*/
|
|
1145
|
+
type CollectionInstance<TTemplate extends ModelTemplate, TRelationships extends ModelRelationships = {}, TFactory extends Factory<TTemplate, SchemaCollections, ModelTraits<SchemaCollections, TTemplate>> | undefined = undefined, TSerializer = undefined> = Collection<SchemaCollections, TTemplate, TRelationships, TFactory, TSerializer>;
|
|
1146
|
+
|
|
1147
|
+
/**
|
|
1148
|
+
* Collection for managing models of a specific type
|
|
1149
|
+
* @template TSchema - The schema collections type for enhanced type inference
|
|
1150
|
+
* @template TTemplate - The model template type (most important for users)
|
|
1151
|
+
* @template TRelationships - The raw relationships configuration for this collection (inferred from config)
|
|
1152
|
+
* @template TFactory - The factory type (inferred from config)
|
|
1153
|
+
* @template TSerializer - The serializer type (inferred from config)
|
|
1154
|
+
*/
|
|
1155
|
+
declare class Collection<TSchema extends SchemaCollections = SchemaCollections, TTemplate extends ModelTemplate = ModelTemplate, TRelationships extends ModelRelationships = {}, TFactory extends Factory<TTemplate, TSchema, ModelTraits<TSchema, TTemplate>> | undefined = undefined, TSerializer = undefined> extends BaseCollection<TSchema, TTemplate, TRelationships, TFactory, TSerializer> {
|
|
1156
|
+
/**
|
|
1157
|
+
* Creates a new model instance (not persisted in the database).
|
|
1158
|
+
* @param attrs - The attributes to create the model with. All required attributes must be provided.
|
|
1159
|
+
* @returns The new model instance.
|
|
1160
|
+
*/
|
|
1161
|
+
new(attrs: ModelCreateAttrs<TTemplate, TSchema>): NewModelInstance<TTemplate, TSchema, TSerializer>;
|
|
1162
|
+
/**
|
|
1163
|
+
* Create a new model for the collection.
|
|
1164
|
+
* @param traitsAndDefaults - The traits or default values to use for the model.
|
|
1165
|
+
* @returns The new model instance.
|
|
1166
|
+
*/
|
|
1167
|
+
create(...traitsAndDefaults: (FactoryTraitNames<TFactory> | CollectionCreateAttrs<TTemplate, TSchema>)[]): ModelInstance<TTemplate, TSchema, TSerializer>;
|
|
1168
|
+
/**
|
|
1169
|
+
* Create a list of models for the collection.
|
|
1170
|
+
* @param count - The number of models to create.
|
|
1171
|
+
* @param traitsAndDefaults - The traits or default values to use for the models.
|
|
1172
|
+
* @returns A list of model instances.
|
|
1173
|
+
*/
|
|
1174
|
+
createList(count: number, ...traitsAndDefaults: (FactoryTraitNames<TFactory> | CollectionCreateAttrs<TTemplate, TSchema>)[]): ModelCollection<TTemplate, TSchema, TSerializer>;
|
|
1175
|
+
/**
|
|
1176
|
+
* Finds the first model matching the query or creates a new one.
|
|
1177
|
+
* @param query - The query to find the model by.
|
|
1178
|
+
* @param traitsAndDefaults - The traits or default values to use when creating a new model.
|
|
1179
|
+
* @returns The model instance.
|
|
1180
|
+
*/
|
|
1181
|
+
findOrCreateBy(query: DbRecordInput<ModelAttrs<TTemplate, TSchema>>, ...traitsAndDefaults: (FactoryTraitNames<TFactory> | CollectionCreateAttrs<TTemplate, TSchema>)[]): ModelInstance<TTemplate, TSchema, TSerializer>;
|
|
1182
|
+
/**
|
|
1183
|
+
* Finds or creates a specific number of models matching the query.
|
|
1184
|
+
* @param count - The number of models to find or create.
|
|
1185
|
+
* @param query - The query to find the models by (object or predicate function).
|
|
1186
|
+
* @param traitsAndDefaults - The traits or default values to use when creating new models.
|
|
1187
|
+
* @returns A collection of models.
|
|
1188
|
+
*/
|
|
1189
|
+
findManyOrCreateBy(count: number, query: DbRecordInput<ModelAttrs<TTemplate, TSchema>> | ((model: ModelInstance<TTemplate, TSchema, TSerializer>) => boolean), ...traitsAndDefaults: (FactoryTraitNames<TFactory> | CollectionCreateAttrs<TTemplate, TSchema>)[]): ModelCollection<TTemplate, TSchema, TSerializer>;
|
|
1190
|
+
/**
|
|
1191
|
+
* Load seeds for this collection.
|
|
1192
|
+
* If scenarioId is not provided, all seeds will be loaded (or 'default' if seeds is a function).
|
|
1193
|
+
* If scenarioId is provided, only that specific seed scenario will be loaded.
|
|
1194
|
+
* @param scenarioId - Optional scenario ID to load a specific seed
|
|
1195
|
+
* @throws {MirageError} If the specified scenarioId does not exist
|
|
1196
|
+
* @example
|
|
1197
|
+
* ```typescript
|
|
1198
|
+
* // Load all seeds
|
|
1199
|
+
* collection.loadSeeds();
|
|
1200
|
+
*
|
|
1201
|
+
* // Load specific scenario
|
|
1202
|
+
* collection.loadSeeds('userForm');
|
|
1203
|
+
* ```
|
|
1204
|
+
*/
|
|
1205
|
+
loadSeeds(scenarioId?: string): Promise<void>;
|
|
1206
|
+
/**
|
|
1207
|
+
* Load fixtures for this collection.
|
|
1208
|
+
* Fixtures are static data records that will be inserted into the collection.
|
|
1209
|
+
* This method will insert all fixture records into the database.
|
|
1210
|
+
* @example
|
|
1211
|
+
* ```typescript
|
|
1212
|
+
* // Load all fixtures
|
|
1213
|
+
* await collection.loadFixtures();
|
|
1214
|
+
* ```
|
|
1215
|
+
*/
|
|
1216
|
+
loadFixtures(): Promise<void>;
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
/**
|
|
1220
|
+
* Schema class that manages database and collections
|
|
1221
|
+
* @template TCollections - The type map of collection names to their configurations
|
|
1222
|
+
* @template TConfig - The schema configuration type with identity manager and global serializer config
|
|
1223
|
+
*/
|
|
1224
|
+
declare class Schema<TCollections extends SchemaCollections, TConfig extends SchemaConfig<any, any> = SchemaConfig<StringIdentityManager, undefined>> {
|
|
1225
|
+
readonly db: DbInstance<SchemaDbCollections<TCollections>>;
|
|
1226
|
+
readonly identityManager: TConfig extends SchemaConfig<infer TIdentityManager, any> ? TIdentityManager : StringIdentityManager;
|
|
1227
|
+
readonly logger?: Logger;
|
|
1228
|
+
private _collections;
|
|
1229
|
+
private _globalSerializerConfig?;
|
|
1230
|
+
constructor(collections: TCollections, config?: TConfig);
|
|
1231
|
+
/**
|
|
1232
|
+
* Get a schema collection by collection name
|
|
1233
|
+
* @param collectionName - The name of the collection
|
|
1234
|
+
* @returns The schema collection for the collection with proper typing
|
|
1235
|
+
*/
|
|
1236
|
+
getCollection<K extends keyof TCollections>(collectionName: K): TCollections[K] extends CollectionConfig<infer TTemplate, infer TRelationships, infer TFactory, infer TSerializer, any> ? Collection<TCollections, TTemplate, TRelationships, TFactory, TSerializer> : never;
|
|
1237
|
+
/**
|
|
1238
|
+
* Load all seeds for all collections in the schema.
|
|
1239
|
+
* This will run all seed scenarios for each collection.
|
|
1240
|
+
* To load specific scenarios, use collection.loadSeeds(scenarioId) on individual collections.
|
|
1241
|
+
* @example
|
|
1242
|
+
* ```typescript
|
|
1243
|
+
* // Load all seeds for all collections
|
|
1244
|
+
* await schema.loadSeeds();
|
|
1245
|
+
*
|
|
1246
|
+
* // Or load specific scenario for a single collection
|
|
1247
|
+
* await schema.users.loadSeeds('development');
|
|
1248
|
+
* ```
|
|
1249
|
+
*/
|
|
1250
|
+
loadSeeds(): Promise<void>;
|
|
1251
|
+
/**
|
|
1252
|
+
* Load all fixtures for all collections in the schema.
|
|
1253
|
+
* This will insert all fixture records into each collection's database.
|
|
1254
|
+
* @example
|
|
1255
|
+
* ```typescript
|
|
1256
|
+
* // Load all fixtures for all collections
|
|
1257
|
+
* await schema.loadFixtures();
|
|
1258
|
+
* ```
|
|
1259
|
+
*/
|
|
1260
|
+
loadFixtures(): Promise<void>;
|
|
1261
|
+
/**
|
|
1262
|
+
* Register collections from the configuration
|
|
1263
|
+
* @param collections - Collection configurations to register
|
|
1264
|
+
*/
|
|
1265
|
+
private _registerCollections;
|
|
1266
|
+
/**
|
|
1267
|
+
* Validate that all inverse relationships are correctly defined
|
|
1268
|
+
* This checks that explicit inverse relationships exist and point back correctly
|
|
1269
|
+
* @param collections - The schema collections to validate
|
|
1270
|
+
* @private
|
|
1271
|
+
*/
|
|
1272
|
+
private _validateInverseRelationships;
|
|
1273
|
+
/**
|
|
1274
|
+
* Merge global serializer config with collection-specific config
|
|
1275
|
+
* Collection config values override global config values
|
|
1276
|
+
* @param _template - The model template (used for type inference only)
|
|
1277
|
+
* @param collectionConfig - Collection-specific serializer config
|
|
1278
|
+
* @returns Merged serializer config or undefined if both are undefined
|
|
1279
|
+
*/
|
|
1280
|
+
private _mergeConfigs;
|
|
1281
|
+
}
|
|
1282
|
+
/**
|
|
1283
|
+
* Type for a complete schema instance with collections
|
|
1284
|
+
* Provides both string-based property access and symbol-based relationship resolution
|
|
1285
|
+
*/
|
|
1286
|
+
type SchemaInstance<TCollections extends SchemaCollections, TConfig extends SchemaConfig<any, any> = SchemaConfig<StringIdentityManager, undefined>> = Schema<TCollections, TConfig> & SchemaCollectionAccessors<TCollections>;
|
|
1287
|
+
|
|
1288
|
+
/**
|
|
1289
|
+
* Base collection class with query functionality.
|
|
1290
|
+
* @template TSchema - The schema collections type for enhanced type inference
|
|
1291
|
+
* @template TTemplate - The model template type (most important for users)
|
|
1292
|
+
* @template TRelationships - The raw relationships configuration for this collection (inferred from config)
|
|
1293
|
+
* @template TFactory - The factory type (inferred from config)
|
|
1294
|
+
* @template TSerializer - The serializer type (inferred from config)
|
|
1295
|
+
*/
|
|
1296
|
+
declare abstract class BaseCollection<TSchema extends SchemaCollections = SchemaCollections, TTemplate extends ModelTemplate = ModelTemplate, TRelationships extends ModelRelationships = {}, TFactory extends Factory<TTemplate, TSchema, ModelTraits<TSchema, TTemplate>> | undefined = undefined, TSerializer = undefined> {
|
|
1297
|
+
readonly modelName: string;
|
|
1298
|
+
readonly collectionName: string;
|
|
1299
|
+
protected readonly Model: ModelClass<TTemplate, TSchema, TSerializer>;
|
|
1300
|
+
protected readonly _template: TTemplate;
|
|
1301
|
+
protected readonly _schema: SchemaInstance<TSchema>;
|
|
1302
|
+
protected readonly _dbCollection: DbCollection<ModelAttrs<TTemplate, TSchema>>;
|
|
1303
|
+
protected readonly _identityManager: IdentityManager<ModelAttrs<TTemplate, TSchema>['id']>;
|
|
1304
|
+
protected readonly _logger?: Logger;
|
|
1305
|
+
protected readonly _factory?: TFactory;
|
|
1306
|
+
protected readonly _relationships?: TRelationships;
|
|
1307
|
+
protected readonly _serializer?: TSerializer;
|
|
1308
|
+
protected readonly _seeds?: Seeds<TSchema>;
|
|
1309
|
+
protected readonly _fixtures?: FixtureConfig<TTemplate, TRelationships>;
|
|
1310
|
+
constructor(schema: SchemaInstance<TSchema>, config: {
|
|
1311
|
+
factory?: TFactory;
|
|
1312
|
+
identityManager?: IdentityManager<ModelId<TTemplate>>;
|
|
1313
|
+
model: TTemplate;
|
|
1314
|
+
relationships?: TRelationships;
|
|
1315
|
+
serializer?: TSerializer;
|
|
1316
|
+
seeds?: Seeds<TSchema>;
|
|
1317
|
+
fixtures?: FixtureConfig<TTemplate, TRelationships>;
|
|
1318
|
+
});
|
|
1319
|
+
/**
|
|
1320
|
+
* Get the collection relationships.
|
|
1321
|
+
* @returns The collection relationships configuration.
|
|
1322
|
+
*/
|
|
1323
|
+
get relationships(): TRelationships | undefined;
|
|
1324
|
+
/**
|
|
1325
|
+
* Get the serializer for the collection.
|
|
1326
|
+
* @returns The collection serializer instance.
|
|
1327
|
+
*/
|
|
1328
|
+
get serializer(): TSerializer | undefined;
|
|
1329
|
+
/**
|
|
1330
|
+
* Get a model by index.
|
|
1331
|
+
* @param index - The index of the model to get.
|
|
1332
|
+
* @returns The model instance or undefined if not found.
|
|
1333
|
+
*/
|
|
1334
|
+
at(index: number): ModelInstance<TTemplate, TSchema, TSerializer> | undefined;
|
|
1335
|
+
/**
|
|
1336
|
+
* Returns all model instances in the collection.
|
|
1337
|
+
* @returns All model instances in the collection.
|
|
1338
|
+
*/
|
|
1339
|
+
all(): ModelCollection<TTemplate, TSchema, TSerializer>;
|
|
1340
|
+
/**
|
|
1341
|
+
* Returns the first model in the collection.
|
|
1342
|
+
* @returns The first model in the collection or null if the collection is empty.
|
|
1343
|
+
*/
|
|
1344
|
+
first(): ModelInstance<TTemplate, TSchema, TSerializer> | null;
|
|
1345
|
+
/**
|
|
1346
|
+
* Returns the last model in the collection.
|
|
1347
|
+
* @returns The last model in the collection or null if the collection is empty.
|
|
1348
|
+
*/
|
|
1349
|
+
last(): ModelInstance<TTemplate, TSchema, TSerializer> | null;
|
|
1350
|
+
/**
|
|
1351
|
+
* Finds a model by ID, predicate object, or query options.
|
|
1352
|
+
* @param input - The ID, predicate object, or query options to find by.
|
|
1353
|
+
* @returns The model instance or null if not found.
|
|
1354
|
+
* @example
|
|
1355
|
+
* ```typescript
|
|
1356
|
+
* // Find by ID
|
|
1357
|
+
* collection.find('1');
|
|
1358
|
+
*
|
|
1359
|
+
* // Find by predicate object
|
|
1360
|
+
* collection.find({ email: 'user@example.com' });
|
|
1361
|
+
*
|
|
1362
|
+
* // Find with query options
|
|
1363
|
+
* collection.find({ where: { age: { gte: 18 } }, orderBy: { name: 'asc' } });
|
|
1364
|
+
* ```
|
|
1365
|
+
*/
|
|
1366
|
+
find(input: ModelAttrs<TTemplate, TSchema>['id'] | DbRecordInput<ModelAttrs<TTemplate, TSchema>> | QueryOptions<ModelAttrs<TTemplate, TSchema>>): ModelInstance<TTemplate, TSchema, TSerializer> | null;
|
|
1367
|
+
/**
|
|
1368
|
+
* Finds multiple models by IDs, predicate object, or query options.
|
|
1369
|
+
* @param input - The array of IDs, predicate object, or query options to find by.
|
|
1370
|
+
* @returns A collection of matching model instances.
|
|
1371
|
+
* @example
|
|
1372
|
+
* ```typescript
|
|
1373
|
+
* // Find by IDs
|
|
1374
|
+
* collection.findMany(['1', '2', '3']);
|
|
1375
|
+
*
|
|
1376
|
+
* // Find by predicate object
|
|
1377
|
+
* collection.findMany({ status: 'active' });
|
|
1378
|
+
*
|
|
1379
|
+
* // Find with query options
|
|
1380
|
+
* collection.findMany({
|
|
1381
|
+
* where: { age: { gte: 18 } },
|
|
1382
|
+
* orderBy: { name: 'asc' },
|
|
1383
|
+
* limit: 10
|
|
1384
|
+
* });
|
|
1385
|
+
*
|
|
1386
|
+
* // Find with callback where clause
|
|
1387
|
+
* collection.findMany({
|
|
1388
|
+
* where: (model) => model.age >= 18 && model.status === 'active'
|
|
1389
|
+
* });
|
|
1390
|
+
* ```
|
|
1391
|
+
*/
|
|
1392
|
+
findMany(input: ModelAttrs<TTemplate, TSchema>['id'][] | DbRecordInput<ModelAttrs<TTemplate, TSchema>> | QueryOptions<ModelAttrs<TTemplate, TSchema>>): ModelCollection<TTemplate, TSchema, TSerializer>;
|
|
1393
|
+
/**
|
|
1394
|
+
* Deletes a model from the collection.
|
|
1395
|
+
* @param id - The id of the model to delete.
|
|
1396
|
+
*/
|
|
1397
|
+
delete(id: ModelAttrs<TTemplate, TSchema>['id']): void;
|
|
1398
|
+
/**
|
|
1399
|
+
* Deletes multiple models by IDs, predicate object, or query options.
|
|
1400
|
+
* @param input - The array of IDs, predicate object, or query options to delete by.
|
|
1401
|
+
* @returns The number of records that were deleted.
|
|
1402
|
+
* @example
|
|
1403
|
+
* ```typescript
|
|
1404
|
+
* // Delete by IDs
|
|
1405
|
+
* collection.deleteMany(['1', '2', '3']);
|
|
1406
|
+
*
|
|
1407
|
+
* // Delete by predicate object
|
|
1408
|
+
* collection.deleteMany({ status: 'inactive' });
|
|
1409
|
+
*
|
|
1410
|
+
* // Delete with query options
|
|
1411
|
+
* collection.deleteMany({
|
|
1412
|
+
* where: { age: { lt: 18 } },
|
|
1413
|
+
* limit: 10
|
|
1414
|
+
* });
|
|
1415
|
+
* ```
|
|
1416
|
+
*/
|
|
1417
|
+
deleteMany(input: ModelAttrs<TTemplate, TSchema>['id'][] | DbRecordInput<ModelAttrs<TTemplate, TSchema>> | QueryOptions<ModelAttrs<TTemplate, TSchema>>): number;
|
|
1418
|
+
/**
|
|
1419
|
+
* Converts QueryOptions with a callback where clause to work with models instead of raw records.
|
|
1420
|
+
* @param options - The query options with a callback where clause
|
|
1421
|
+
* @returns Query options with converted where clause
|
|
1422
|
+
*/
|
|
1423
|
+
private _convertQueryOptionsCallback;
|
|
1424
|
+
/**
|
|
1425
|
+
* Helper to create a model instance from a database record.
|
|
1426
|
+
* @param record - The database record to create the model from (must have ID).
|
|
1427
|
+
* @returns The model instance.
|
|
1428
|
+
*/
|
|
1429
|
+
protected _createModelFromRecord(record: ModelAttrs<TTemplate, TSchema>): ModelInstance<TTemplate, TSchema, TSerializer>;
|
|
1430
|
+
/**
|
|
1431
|
+
* Initialize and create the database collection if needed
|
|
1432
|
+
* @param identityManager - The identity manager to use for the collection
|
|
1433
|
+
* @returns The database collection instance
|
|
1434
|
+
* @private
|
|
1435
|
+
*/
|
|
1436
|
+
private _initializeDbCollection;
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
/**
|
|
1440
|
+
* A fluent builder for creating schema collection configurations.
|
|
1441
|
+
*
|
|
1442
|
+
* The CollectionBuilder provides a type-safe way to construct CollectionConfig instances
|
|
1443
|
+
* with configurable model template, factory, relationships, serializer, and identity manager. It follows
|
|
1444
|
+
* the builder pattern, allowing method chaining to progressively configure the collection.
|
|
1445
|
+
* @template TTemplate - The model template type
|
|
1446
|
+
* @template TRelationships - The model relationships configuration
|
|
1447
|
+
* @template TFactory - The factory type
|
|
1448
|
+
* @template TIdentityManager - The identity manager type
|
|
1449
|
+
* @example
|
|
1450
|
+
* ```typescript
|
|
1451
|
+
* const userCollection = collection(UserModel)
|
|
1452
|
+
* .relationships({
|
|
1453
|
+
* posts: associations.hasMany(PostModel),
|
|
1454
|
+
* })
|
|
1455
|
+
* .factory(userFactory)
|
|
1456
|
+
* .identityManager(userIdentityManager)
|
|
1457
|
+
* .create();
|
|
1458
|
+
* ```
|
|
1459
|
+
*/
|
|
1460
|
+
declare class CollectionBuilder<TTemplate extends ModelTemplate = ModelTemplate, TSchema extends SchemaCollections = SchemaCollections, TRelationships extends ModelRelationships = {}, TFactory extends Factory<TTemplate, TSchema, ModelTraits<TSchema, TTemplate>> | undefined = undefined, TIdentityManager extends IdentityManager = StringIdentityManager, TSerializer = undefined> {
|
|
1461
|
+
private _template?;
|
|
1462
|
+
private _factory?;
|
|
1463
|
+
private _relationships?;
|
|
1464
|
+
private _identityManager?;
|
|
1465
|
+
private _serializerConfig?;
|
|
1466
|
+
private _serializerInstance?;
|
|
1467
|
+
private _seeds?;
|
|
1468
|
+
private _fixtures?;
|
|
1469
|
+
/**
|
|
1470
|
+
* Creates a new CollectionBuilder instance.
|
|
1471
|
+
* @private
|
|
1472
|
+
*/
|
|
1473
|
+
constructor();
|
|
1474
|
+
/**
|
|
1475
|
+
* Sets the model template for this collection.
|
|
1476
|
+
*
|
|
1477
|
+
* The template defines the model type, and collection name
|
|
1478
|
+
* for this collection configuration.
|
|
1479
|
+
* @template T - The model template type
|
|
1480
|
+
* @param template - The model template instance
|
|
1481
|
+
* @returns A new CollectionBuilder instance with the specified template
|
|
1482
|
+
* @example
|
|
1483
|
+
* ```typescript
|
|
1484
|
+
* const builder = collection.model(userTemplate);
|
|
1485
|
+
* ```
|
|
1486
|
+
*/
|
|
1487
|
+
model<T extends ModelTemplate>(template: T): CollectionBuilder<T, TSchema, TRelationships, TFactory extends undefined ? undefined : Factory<T, TSchema, ModelTraits<TSchema, T>>, TIdentityManager, TSerializer>;
|
|
1488
|
+
/**
|
|
1489
|
+
* Sets the factory for creating model instances.
|
|
1490
|
+
*
|
|
1491
|
+
* The factory provides default attributes and traits for creating new model instances
|
|
1492
|
+
* in this collection.
|
|
1493
|
+
* @template F - The factory type
|
|
1494
|
+
* @param factory - The factory instance
|
|
1495
|
+
* @returns A new CollectionBuilder instance with the specified factory
|
|
1496
|
+
* @example
|
|
1497
|
+
* ```typescript
|
|
1498
|
+
* const builder = collection(UserModel).factory(userFactory);
|
|
1499
|
+
* ```
|
|
1500
|
+
*/
|
|
1501
|
+
factory<F extends Factory<any, any, any>>(factory: F): CollectionBuilder<TTemplate, TSchema, TRelationships, F, TIdentityManager, TSerializer>;
|
|
1502
|
+
/**
|
|
1503
|
+
* Sets the relationships configuration for this collection.
|
|
1504
|
+
*
|
|
1505
|
+
* Relationships define how this model relates to other models in the schema,
|
|
1506
|
+
* including belongsTo and hasMany associations.
|
|
1507
|
+
* @template R - The relationships type
|
|
1508
|
+
* @param relationships - The relationships configuration object
|
|
1509
|
+
* @returns A new CollectionBuilder instance with the specified relationships
|
|
1510
|
+
* @example
|
|
1511
|
+
* ```typescript
|
|
1512
|
+
* const builder = collection(UserModel)
|
|
1513
|
+
* .relationships({
|
|
1514
|
+
* posts: associations.hasMany(PostModel),
|
|
1515
|
+
* profile: associations.belongsTo(profileTemplate),
|
|
1516
|
+
* });
|
|
1517
|
+
* ```
|
|
1518
|
+
*/
|
|
1519
|
+
relationships<R extends ModelRelationships>(relationships: R): CollectionBuilder<TTemplate, TSchema, R, TFactory, TIdentityManager, TSerializer>;
|
|
1520
|
+
/**
|
|
1521
|
+
* Sets the serializer configuration or instance for this collection.
|
|
1522
|
+
*
|
|
1523
|
+
* Accepts either a configuration object (attrs, root, embed, include) or a custom
|
|
1524
|
+
* serializer instance. The config will be merged with global schema config if present.
|
|
1525
|
+
* @param configOrSerializer - The serializer configuration object or instance
|
|
1526
|
+
* @returns A new CollectionBuilder instance with the specified serializer
|
|
1527
|
+
* @example
|
|
1528
|
+
* ```typescript
|
|
1529
|
+
* // With config
|
|
1530
|
+
* const builder = collection()
|
|
1531
|
+
* .model(UserModel)
|
|
1532
|
+
* .serializer({ attrs: ['id', 'name'], root: true });
|
|
1533
|
+
*
|
|
1534
|
+
* // With custom serializer instance
|
|
1535
|
+
* const builder = collection()
|
|
1536
|
+
* .model(UserModel)
|
|
1537
|
+
* .serializer(new CustomUserSerializer(userModel));
|
|
1538
|
+
* ```
|
|
1539
|
+
*/
|
|
1540
|
+
serializer(configOrSerializer: SerializerOptions<TTemplate> | any): CollectionBuilder<TTemplate, TSchema, TRelationships, TFactory, TIdentityManager, any>;
|
|
1541
|
+
/**
|
|
1542
|
+
* Sets the identity manager for this collection.
|
|
1543
|
+
*
|
|
1544
|
+
* The identity manager handles ID generation and management for model instances
|
|
1545
|
+
* in this collection. If not specified, the schema's global identity manager will be used.
|
|
1546
|
+
* @template I - The identity manager type
|
|
1547
|
+
* @param identityManager - The identity manager instance
|
|
1548
|
+
* @returns A new CollectionBuilder instance with the specified identity manager
|
|
1549
|
+
* @example
|
|
1550
|
+
* ```typescript
|
|
1551
|
+
* const builder = collection
|
|
1552
|
+
* .model(UserModel)
|
|
1553
|
+
* .identityManager(new StringIdentityManager());
|
|
1554
|
+
* ```
|
|
1555
|
+
*/
|
|
1556
|
+
identityManager<I extends IdentityManager<any>>(identityManager: I): CollectionBuilder<TTemplate, TSchema, TRelationships, TFactory, I, TSerializer>;
|
|
1557
|
+
/**
|
|
1558
|
+
* Sets the seeds configuration for this collection.
|
|
1559
|
+
*
|
|
1560
|
+
* Seeds can be either a function or an object with named seed scenarios.
|
|
1561
|
+
* The function/methods receive the schema instance as a parameter.
|
|
1562
|
+
* @param seeds - A seed function or object with named seed scenarios
|
|
1563
|
+
* @returns A new CollectionBuilder instance with the specified seeds
|
|
1564
|
+
* @example
|
|
1565
|
+
* ```typescript
|
|
1566
|
+
* // With function
|
|
1567
|
+
* const builder = collection()
|
|
1568
|
+
* .model(UserModel)
|
|
1569
|
+
* .seeds((schema) => {
|
|
1570
|
+
* schema.users.create({ name: 'John' });
|
|
1571
|
+
* });
|
|
1572
|
+
*
|
|
1573
|
+
* // With named scenarios
|
|
1574
|
+
* const builder = collection()
|
|
1575
|
+
* .model(UserModel)
|
|
1576
|
+
* .seeds({
|
|
1577
|
+
* userForm: (schema) => {
|
|
1578
|
+
* schema.users.create({ name: 'John' });
|
|
1579
|
+
* },
|
|
1580
|
+
* userPosts: (schema) => {
|
|
1581
|
+
* const user = schema.users.create({ name: 'John' });
|
|
1582
|
+
* schema.posts.create({ title: 'Post 1', authorId: user.id });
|
|
1583
|
+
* },
|
|
1584
|
+
* });
|
|
1585
|
+
* ```
|
|
1586
|
+
*/
|
|
1587
|
+
seeds(seeds: Seeds<TSchema>): CollectionBuilder<TTemplate, TSchema, TRelationships, TFactory, TIdentityManager, TSerializer>;
|
|
1588
|
+
/**
|
|
1589
|
+
* Sets the fixtures configuration for this collection.
|
|
1590
|
+
*
|
|
1591
|
+
* Fixtures are static data records that can be loaded into the collection.
|
|
1592
|
+
* @param records - Array of fixture records to load
|
|
1593
|
+
* @param options - Configuration options for loading fixtures
|
|
1594
|
+
* @param options.strategy - The strategy to use for loading fixtures (default: 'manual')
|
|
1595
|
+
* @returns A new CollectionBuilder instance with the specified fixtures
|
|
1596
|
+
* @example
|
|
1597
|
+
* ```typescript
|
|
1598
|
+
* // Manual loading (default)
|
|
1599
|
+
* const builder = collection()
|
|
1600
|
+
* .model(UserModel)
|
|
1601
|
+
* .fixtures([
|
|
1602
|
+
* { id: '1', name: 'John', email: 'john@example.com' },
|
|
1603
|
+
* { id: '2', name: 'Jane', email: 'jane@example.com' },
|
|
1604
|
+
* ]);
|
|
1605
|
+
*
|
|
1606
|
+
* // Auto-load fixtures during schema setup
|
|
1607
|
+
* const builder = collection()
|
|
1608
|
+
* .model(UserModel)
|
|
1609
|
+
* .fixtures(
|
|
1610
|
+
* [
|
|
1611
|
+
* { id: '1', name: 'John', email: 'john@example.com' },
|
|
1612
|
+
* { id: '2', name: 'Jane', email: 'jane@example.com' },
|
|
1613
|
+
* ],
|
|
1614
|
+
* { strategy: 'auto' }
|
|
1615
|
+
* );
|
|
1616
|
+
* ```
|
|
1617
|
+
*/
|
|
1618
|
+
fixtures(records: FixtureAttrs<TTemplate, TRelationships>[], options?: {
|
|
1619
|
+
strategy?: FixtureLoadStrategy;
|
|
1620
|
+
}): CollectionBuilder<TTemplate, TSchema, TRelationships, TFactory, TIdentityManager, TSerializer>;
|
|
1621
|
+
/**
|
|
1622
|
+
* Creates the final schema collection configuration.
|
|
1623
|
+
* @returns The schema collection configuration
|
|
1624
|
+
*/
|
|
1625
|
+
create(): CollectionConfig<TTemplate, TRelationships, TFactory, TSerializer, TSchema>;
|
|
1626
|
+
}
|
|
1627
|
+
/**
|
|
1628
|
+
* Creates a new CollectionBuilder instance for building collection configurations.
|
|
1629
|
+
* @template TSchema - The schema collections type (optional)
|
|
1630
|
+
* @returns A new CollectionBuilder instance ready for model specification
|
|
1631
|
+
* @example
|
|
1632
|
+
* ```typescript
|
|
1633
|
+
* // Schema-typed collection
|
|
1634
|
+
* const userCollection = collection<TestSchema>()
|
|
1635
|
+
* .model(UserModel)
|
|
1636
|
+
* .factory(userFactory)
|
|
1637
|
+
* .create();
|
|
1638
|
+
*
|
|
1639
|
+
* // Schema-less collection
|
|
1640
|
+
* const userCollection = collection()
|
|
1641
|
+
* .model(UserModel)
|
|
1642
|
+
* .create();
|
|
1643
|
+
* ```
|
|
1644
|
+
*/
|
|
1645
|
+
declare function collection<TSchema extends SchemaCollections = SchemaCollections>(): CollectionBuilder<ModelTemplate, TSchema, {}, undefined, StringIdentityManager, undefined>;
|
|
1646
|
+
|
|
1647
|
+
/**
|
|
1648
|
+
* A fluent builder for creating schema instances.
|
|
1649
|
+
*
|
|
1650
|
+
* The SchemaBuilder provides a type-safe way to construct Schema instances with
|
|
1651
|
+
* configurable collections, identity manager, and global serializer. It follows the builder
|
|
1652
|
+
* pattern, allowing method chaining to progressively configure the schema.
|
|
1653
|
+
* @template TCollections - The schema collections configuration type
|
|
1654
|
+
* @template TIdentityManager - The global identity manager type
|
|
1655
|
+
* @template TGlobalConfig - The global serializer configuration type
|
|
1656
|
+
* @example
|
|
1657
|
+
* ```typescript
|
|
1658
|
+
* const appSchema = schema()
|
|
1659
|
+
* .collections({
|
|
1660
|
+
* users: userCollection,
|
|
1661
|
+
* posts: postCollection,
|
|
1662
|
+
* })
|
|
1663
|
+
* .serializer({ root: true })
|
|
1664
|
+
* .identityManager(appIdentityManager)
|
|
1665
|
+
* .setup();
|
|
1666
|
+
* ```
|
|
1667
|
+
*/
|
|
1668
|
+
declare class SchemaBuilder<TCollections extends SchemaCollections = SchemaCollections, TIdentityManager extends IdentityManager<any> = StringIdentityManager, TGlobalConfig extends StructuralSerializerOptions | undefined = undefined> {
|
|
1669
|
+
private _collections?;
|
|
1670
|
+
private _identityManager?;
|
|
1671
|
+
private _globalSerializerConfig?;
|
|
1672
|
+
private _loggingConfig?;
|
|
1673
|
+
/**
|
|
1674
|
+
* Creates a new SchemaBuilder instance.
|
|
1675
|
+
* @private
|
|
1676
|
+
*/
|
|
1677
|
+
constructor();
|
|
1678
|
+
/**
|
|
1679
|
+
* Sets the collections configuration for this schema.
|
|
1680
|
+
*
|
|
1681
|
+
* Collections define the models, factories, relationships, and other configuration
|
|
1682
|
+
* for each collection in the schema. Each collection is keyed by its collection name.
|
|
1683
|
+
* @template C - The collections configuration type
|
|
1684
|
+
* @param collections - The collections configuration object
|
|
1685
|
+
* @returns A new SchemaBuilder instance with the specified collections
|
|
1686
|
+
* @example
|
|
1687
|
+
* ```typescript
|
|
1688
|
+
* const builder = schema().collections({
|
|
1689
|
+
* users: userCollection,
|
|
1690
|
+
* posts: postCollection,
|
|
1691
|
+
* comments: commentCollection,
|
|
1692
|
+
* });
|
|
1693
|
+
* ```
|
|
1694
|
+
*/
|
|
1695
|
+
collections<C extends SchemaCollections>(collections: C): SchemaBuilder<C, TIdentityManager, TGlobalConfig>;
|
|
1696
|
+
/**
|
|
1697
|
+
* Sets the global identity manager for this schema.
|
|
1698
|
+
*
|
|
1699
|
+
* The identity manager handles ID generation and management for model instances
|
|
1700
|
+
* across all collections in the schema. Individual collections can override this
|
|
1701
|
+
* with their own identity managers.
|
|
1702
|
+
* @template I - The identity manager type
|
|
1703
|
+
* @param identityManager - The identity manager instance
|
|
1704
|
+
* @returns A new SchemaBuilder instance with the specified identity manager
|
|
1705
|
+
* @example
|
|
1706
|
+
* ```typescript
|
|
1707
|
+
* const builder = schema()
|
|
1708
|
+
* .collections({ users: userCollection })
|
|
1709
|
+
* .identityManager(new StringIdentityManager());
|
|
1710
|
+
* ```
|
|
1711
|
+
*/
|
|
1712
|
+
identityManager<I extends IdentityManager<any>>(identityManager: I): SchemaBuilder<TCollections, I, TGlobalConfig>;
|
|
1713
|
+
/**
|
|
1714
|
+
* Sets the global serializer configuration for this schema.
|
|
1715
|
+
*
|
|
1716
|
+
* The global serializer config defines structural serialization options (root, embed)
|
|
1717
|
+
* that apply to all collections by default. Individual collections can override
|
|
1718
|
+
* these settings or provide model-specific configuration (attrs, include).
|
|
1719
|
+
* @template TConfig - The global serializer configuration type
|
|
1720
|
+
* @param config - The global serializer configuration (only root and embed)
|
|
1721
|
+
* @returns A new SchemaBuilder instance with the specified global serializer config
|
|
1722
|
+
* @example
|
|
1723
|
+
* ```typescript
|
|
1724
|
+
* const builder = schema()
|
|
1725
|
+
* .serializer({ root: true, embed: false })
|
|
1726
|
+
* .collections({ users: userCollection });
|
|
1727
|
+
* ```
|
|
1728
|
+
*/
|
|
1729
|
+
serializer<TConfig extends StructuralSerializerOptions>(config: TConfig): SchemaBuilder<TCollections, TIdentityManager, TConfig>;
|
|
1730
|
+
/**
|
|
1731
|
+
* Sets the logging configuration for this schema.
|
|
1732
|
+
*
|
|
1733
|
+
* The logging config enables debug output for database operations, validations,
|
|
1734
|
+
* and other schema behavior. This is useful for debugging test setup and understanding
|
|
1735
|
+
* how the ORM is behaving.
|
|
1736
|
+
* @param config - The logging configuration (enabled, level, prefix)
|
|
1737
|
+
* @returns A new SchemaBuilder instance with the specified logging config
|
|
1738
|
+
* @example
|
|
1739
|
+
* ```typescript
|
|
1740
|
+
* const builder = schema()
|
|
1741
|
+
* .logging({ enabled: true, level: 'debug' })
|
|
1742
|
+
* .collections({ users: userCollection });
|
|
1743
|
+
* ```
|
|
1744
|
+
*/
|
|
1745
|
+
logging(config: LoggerConfig): SchemaBuilder<TCollections, TIdentityManager, TGlobalConfig>;
|
|
1746
|
+
/**
|
|
1747
|
+
* Sets up the final Schema instance with all configured options.
|
|
1748
|
+
*
|
|
1749
|
+
* This method produces the complete schema instance that can be used throughout
|
|
1750
|
+
* your application. Collections must be set before calling setup().
|
|
1751
|
+
* @returns The configured Schema instance with collection accessors
|
|
1752
|
+
* @throws Error if no collections have been configured
|
|
1753
|
+
* @example
|
|
1754
|
+
* ```typescript
|
|
1755
|
+
* const appSchema = schema()
|
|
1756
|
+
* .collections({
|
|
1757
|
+
* users: userCollection,
|
|
1758
|
+
* posts: postCollection,
|
|
1759
|
+
* })
|
|
1760
|
+
* .serializer({ root: true })
|
|
1761
|
+
* .identityManager(appIdentityManager)
|
|
1762
|
+
* .setup();
|
|
1763
|
+
*
|
|
1764
|
+
* // Use the schema
|
|
1765
|
+
* const userCollection = appSchema.getCollection('users');
|
|
1766
|
+
* const user = appSchema.users.create({ name: 'John' });
|
|
1767
|
+
* ```
|
|
1768
|
+
*/
|
|
1769
|
+
setup(): SchemaInstance<TCollections, SchemaConfig<TIdentityManager, TGlobalConfig>>;
|
|
1770
|
+
}
|
|
1771
|
+
/**
|
|
1772
|
+
* Creates a new SchemaBuilder instance for building schema configurations.
|
|
1773
|
+
*
|
|
1774
|
+
* This is the main entry point for creating schemas in the builder-based API.
|
|
1775
|
+
* The returned SchemaBuilder can be configured with collections and identity manager
|
|
1776
|
+
* before setting up the final schema instance.
|
|
1777
|
+
* @returns A new SchemaBuilder instance ready for configuration
|
|
1778
|
+
* @example
|
|
1779
|
+
* ```typescript
|
|
1780
|
+
* // Basic schema creation
|
|
1781
|
+
* const appSchema = schema()
|
|
1782
|
+
* .collections({
|
|
1783
|
+
* users: userCollection,
|
|
1784
|
+
* })
|
|
1785
|
+
* .setup();
|
|
1786
|
+
*
|
|
1787
|
+
* // Full schema configuration
|
|
1788
|
+
* const appSchema = schema()
|
|
1789
|
+
* .collections({
|
|
1790
|
+
* users: userCollection,
|
|
1791
|
+
* posts: postCollection,
|
|
1792
|
+
* })
|
|
1793
|
+
* .identityManager(new StringIdentityManager())
|
|
1794
|
+
* .setup();
|
|
1795
|
+
* ```
|
|
1796
|
+
* @see {@link SchemaBuilder} for available configuration methods
|
|
1797
|
+
*/
|
|
1798
|
+
declare function schema(): SchemaBuilder;
|
|
1799
|
+
|
|
1800
|
+
type FactoryAfterCreateHook<TSchema extends SchemaCollections = SchemaCollections, TTemplate extends ModelTemplate = ModelTemplate> = (model: ModelInstance<TTemplate, TSchema>, schema: SchemaInstance<TSchema>) => void;
|
|
1801
|
+
type TraitDefinition<TSchema extends SchemaCollections = SchemaCollections, TTemplate extends ModelTemplate = ModelTemplate> = Partial<FactoryAttrs<TTemplate>> & Partial<FactoryAssociations<TTemplate, TSchema>> & {
|
|
1802
|
+
afterCreate?: FactoryAfterCreateHook<TSchema, TTemplate>;
|
|
1803
|
+
};
|
|
1804
|
+
type ModelTraits<TSchema extends SchemaCollections = SchemaCollections, TTemplate extends ModelTemplate = ModelTemplate> = Record<string, TraitDefinition<TSchema, TTemplate>>;
|
|
1805
|
+
type TraitName<TTraits> = TTraits extends Record<string, any> ? Extract<keyof TTraits, string> : never;
|
|
1806
|
+
type FactoryAttrs<TTemplate extends ModelTemplate> = {
|
|
1807
|
+
[K in keyof ModelOnlyAttrs<TTemplate>]?: ModelOnlyAttrs<TTemplate>[K] | ((this: ModelOnlyAttrs<TTemplate>, modelId: NonNullable<ModelAttrs<TTemplate>['id']>) => InferModelAttrs<TTemplate>[K]);
|
|
1808
|
+
};
|
|
1809
|
+
type FactoryTraitNames<TFactory> = TFactory extends {
|
|
1810
|
+
traits: infer TTraits;
|
|
1811
|
+
} ? TTraits extends Record<string, any> ? Extract<keyof TTraits, string> : never : never;
|
|
1812
|
+
|
|
1813
|
+
/**
|
|
1814
|
+
* Factory that builds model attributes with optional schema support.
|
|
1815
|
+
* @template TTemplate - The model template (inferred from constructor)
|
|
1816
|
+
* @template TSchema - The schema collections type (never = sch)
|
|
1817
|
+
* @template TTraits - The factory traits (inferred from constructor)
|
|
1818
|
+
*/
|
|
1819
|
+
declare class Factory<TTemplate extends ModelTemplate = ModelTemplate, TSchema extends SchemaCollections = SchemaCollections, TTraits extends ModelTraits<TSchema, TTemplate> = {}> {
|
|
1820
|
+
readonly attributes: FactoryAttrs<TTemplate>;
|
|
1821
|
+
readonly traits: TTraits;
|
|
1822
|
+
readonly associations?: FactoryAssociations<TTemplate, TSchema>;
|
|
1823
|
+
readonly afterCreate?: FactoryAfterCreateHook<TSchema, TTemplate>;
|
|
1824
|
+
private readonly _template;
|
|
1825
|
+
private readonly _associationsManager;
|
|
1826
|
+
constructor(template: TTemplate, attributes: FactoryAttrs<TTemplate>, traits?: TTraits, associations?: FactoryAssociations<TTemplate, TSchema>, afterCreate?: FactoryAfterCreateHook<TSchema, TTemplate>);
|
|
1827
|
+
/**
|
|
1828
|
+
* Get the model template
|
|
1829
|
+
* @returns The model template
|
|
1830
|
+
*/
|
|
1831
|
+
get template(): TTemplate;
|
|
1832
|
+
/**
|
|
1833
|
+
* Build a model with the given model ID and trait names or default values.
|
|
1834
|
+
* @param modelId - The ID of the model to build.
|
|
1835
|
+
* @param traitsAndDefaults - The names of the traits to apply or default values for attributes.
|
|
1836
|
+
* @returns The built model.
|
|
1837
|
+
*/
|
|
1838
|
+
build(modelId: ModelId<TTemplate>, ...traitsAndDefaults: (TraitName<TTraits> | PartialModelAttrs<TTemplate, TSchema>)[]): ModelAttrs<TTemplate, TSchema>;
|
|
1839
|
+
/**
|
|
1840
|
+
* Process associations and return relationship values
|
|
1841
|
+
* This runs with schema context and creates/links related models
|
|
1842
|
+
* @param schema - The schema instance
|
|
1843
|
+
* @param skipKeys - Optional list of relationship keys to skip (e.g., if user provided them)
|
|
1844
|
+
* @param traitsAndDefaults - Optional trait names to include trait associations
|
|
1845
|
+
* @returns A record of relationship values
|
|
1846
|
+
*/
|
|
1847
|
+
processAssociations(schema: SchemaInstance<TSchema>, skipKeys?: string[], traitsAndDefaults?: (TraitName<TTraits> | PartialModelAttrs<TTemplate, TSchema>)[]): Record<string, ModelInstance<any, TSchema> | ModelCollection<any, TSchema>>;
|
|
1848
|
+
/**
|
|
1849
|
+
* Process the afterCreate hook and the trait hooks.
|
|
1850
|
+
* This method is intended to be called internally by schema collections.
|
|
1851
|
+
* @param schema - The schema instance.
|
|
1852
|
+
* @param model - The model to process.
|
|
1853
|
+
* @param traitsAndDefaults - The traits and defaults that were applied.
|
|
1854
|
+
* @returns The processed model.
|
|
1855
|
+
*/
|
|
1856
|
+
processAfterCreateHooks(schema: SchemaInstance<TSchema>, model: ModelInstance<TTemplate, TSchema>, ...traitsAndDefaults: (TraitName<TTraits> | PartialModelAttrs<TTemplate, TSchema>)[]): ModelInstance<TTemplate, TSchema>;
|
|
1857
|
+
private _processAttributes;
|
|
1858
|
+
private _buildWithTraits;
|
|
1859
|
+
/**
|
|
1860
|
+
* Check if a value is an association object
|
|
1861
|
+
* @param value - The value to check
|
|
1862
|
+
* @returns True if the value is an association
|
|
1863
|
+
*/
|
|
1864
|
+
private _isAssociation;
|
|
1865
|
+
/**
|
|
1866
|
+
* Extract associations from traits
|
|
1867
|
+
* @param traitsAndDefaults - The trait names to extract associations from
|
|
1868
|
+
* @returns The merged associations from all traits
|
|
1869
|
+
*/
|
|
1870
|
+
private _getTraitAssociations;
|
|
1871
|
+
private _mergeAttributes;
|
|
1872
|
+
private _sortAttrs;
|
|
1873
|
+
}
|
|
1874
|
+
|
|
1875
|
+
/**
|
|
1876
|
+
* Builder class for creating factories with fluent API
|
|
1877
|
+
* @template TTemplate - The model template
|
|
1878
|
+
* @template TSchema - The schema collections type
|
|
1879
|
+
* @template TTraits - The traits type
|
|
1880
|
+
*/
|
|
1881
|
+
declare class FactoryBuilder<TTemplate extends ModelTemplate = ModelTemplate, TSchema extends SchemaCollections = SchemaCollections, TTraits extends ModelTraits<TSchema, TTemplate> = {}> {
|
|
1882
|
+
protected _template?: TTemplate;
|
|
1883
|
+
protected _attributes: FactoryAttrs<TTemplate>;
|
|
1884
|
+
protected _traits: TTraits;
|
|
1885
|
+
protected _associations?: FactoryAssociations<TTemplate, TSchema>;
|
|
1886
|
+
protected _afterCreate?: FactoryAfterCreateHook<TSchema, TTemplate>;
|
|
1887
|
+
constructor();
|
|
1888
|
+
/**
|
|
1889
|
+
* Set the model template for the factory
|
|
1890
|
+
* @template T - The model template type
|
|
1891
|
+
* @param template - The model template
|
|
1892
|
+
* @returns A new builder instance with the specified template
|
|
1893
|
+
*/
|
|
1894
|
+
model<T extends ModelTemplate>(template: T): FactoryBuilder<T, TSchema, {}>;
|
|
1895
|
+
/**
|
|
1896
|
+
* Set the attributes for the factory
|
|
1897
|
+
* @param attributes - The factory attributes
|
|
1898
|
+
* @returns The builder instance for chaining
|
|
1899
|
+
*/
|
|
1900
|
+
attrs(attributes: FactoryAttrs<TTemplate>): this;
|
|
1901
|
+
/**
|
|
1902
|
+
* Add traits to the factory
|
|
1903
|
+
* @param traits - The traits to add
|
|
1904
|
+
* @returns A new builder instance with the added traits
|
|
1905
|
+
*/
|
|
1906
|
+
traits<T extends ModelTraits<TSchema, TTemplate>>(traits: T): FactoryBuilder<TTemplate, TSchema, TTraits & T>;
|
|
1907
|
+
/**
|
|
1908
|
+
* Set the afterCreate hook
|
|
1909
|
+
* @param hook - The afterCreate hook function
|
|
1910
|
+
* @returns The builder instance for chaining
|
|
1911
|
+
*/
|
|
1912
|
+
afterCreate(hook: FactoryAfterCreateHook<TSchema, TTemplate>): this;
|
|
1913
|
+
/**
|
|
1914
|
+
* Set factory associations for automatic relationship creation
|
|
1915
|
+
* @param associations - The associations configuration
|
|
1916
|
+
* @returns The builder instance for chaining
|
|
1917
|
+
*/
|
|
1918
|
+
associations(associations: FactoryAssociations<TTemplate, TSchema>): this;
|
|
1919
|
+
/**
|
|
1920
|
+
* Create a factory builder by extending an existing factory
|
|
1921
|
+
* @param originalFactory - The factory to extend
|
|
1922
|
+
* @returns A new factory builder based on the existing factory
|
|
1923
|
+
*/
|
|
1924
|
+
extend<TTemplate extends ModelTemplate = ModelTemplate, TSchema extends SchemaCollections = SchemaCollections, TTraits extends ModelTraits<TSchema, TTemplate> = {}>(originalFactory: Factory<TTemplate, TSchema, TTraits>): FactoryBuilder<TTemplate, TSchema, TTraits>;
|
|
1925
|
+
/**
|
|
1926
|
+
* Build the final factory instance
|
|
1927
|
+
* @returns The factory instance
|
|
1928
|
+
*/
|
|
1929
|
+
create(): Factory<TTemplate, TSchema, TTraits>;
|
|
1930
|
+
}
|
|
1931
|
+
/**
|
|
1932
|
+
* Create a factory builder with optional schema type
|
|
1933
|
+
* @template TSchema - The schema collections type (optional)
|
|
1934
|
+
* @returns Factory builder instance ready for model specification
|
|
1935
|
+
*/
|
|
1936
|
+
declare function factory<TSchema extends SchemaCollections>(): FactoryBuilder<ModelTemplate, TSchema, {}>;
|
|
1937
|
+
|
|
1938
|
+
/**
|
|
1939
|
+
* Extract the collection config for a model from the schema
|
|
1940
|
+
* @template TSchema - The schema collections type
|
|
1941
|
+
* @template TModel - The model template
|
|
1942
|
+
* @internal
|
|
1943
|
+
*/
|
|
1944
|
+
type CollectionConfigFor<TSchema extends SchemaCollections, TModel extends ModelTemplate> = TSchema[InferCollectionName<TModel>];
|
|
1945
|
+
/**
|
|
1946
|
+
* Extract the factory from a model's collection in the schema
|
|
1947
|
+
* @template TSchema - The schema collections type
|
|
1948
|
+
* @template TModel - The model template
|
|
1949
|
+
* @internal
|
|
1950
|
+
*/
|
|
1951
|
+
type FactoryFor<TSchema extends SchemaCollections, TModel extends ModelTemplate> = CollectionConfigFor<TSchema, TModel> extends CollectionConfig<any, any, infer TFactory, any, any> ? TFactory : undefined;
|
|
1952
|
+
/**
|
|
1953
|
+
* Extract valid trait names for a model from the schema
|
|
1954
|
+
* @template TSchema - The schema collections type
|
|
1955
|
+
* @template TModel - The model template
|
|
1956
|
+
* @internal
|
|
1957
|
+
*/
|
|
1958
|
+
type TraitNamesFor<TSchema extends SchemaCollections, TModel extends ModelTemplate> = FactoryTraitNames<FactoryFor<TSchema, TModel>>;
|
|
1959
|
+
/**
|
|
1960
|
+
* BelongsTo relationship - this model contains a foreign key to another model
|
|
1961
|
+
* Example: Post belongsTo User (Post has authorId pointing to User.id)
|
|
1962
|
+
* @template TTarget - The target model template this relationship points to
|
|
1963
|
+
* @template TForeign - The foreign key field name (defaults to "{targetModelName}Id")
|
|
1964
|
+
*/
|
|
1965
|
+
type BelongsTo<TTarget extends ModelTemplate, TForeign extends string = `${InferModelName<TTarget>}Id`> = {
|
|
1966
|
+
foreignKey: TForeign;
|
|
1967
|
+
targetModel: TTarget;
|
|
1968
|
+
type: 'belongsTo';
|
|
1969
|
+
/**
|
|
1970
|
+
* The name of the inverse relationship on the target model.
|
|
1971
|
+
* - `undefined`: Auto-detect inverse relationship (default behavior)
|
|
1972
|
+
* - `string`: Explicit inverse relationship name
|
|
1973
|
+
* - `null`: No inverse relationship (disable synchronization)
|
|
1974
|
+
*/
|
|
1975
|
+
inverse?: string | null;
|
|
1976
|
+
};
|
|
1977
|
+
/**
|
|
1978
|
+
* HasMany relationship - this model can have multiple related models
|
|
1979
|
+
* Example: User hasMany Posts (User has postIds array containing Post.id values)
|
|
1980
|
+
* @template TTarget - The target model template this relationship points to
|
|
1981
|
+
* @template TForeign - The foreign key array field name (defaults to "{targetModelName}Ids")
|
|
1982
|
+
*/
|
|
1983
|
+
type HasMany<TTarget extends ModelTemplate, TForeign extends string = `${InferModelName<TTarget>}Ids`> = {
|
|
1984
|
+
foreignKey: TForeign;
|
|
1985
|
+
targetModel: TTarget;
|
|
1986
|
+
type: 'hasMany';
|
|
1987
|
+
/**
|
|
1988
|
+
* The name of the inverse relationship on the target model.
|
|
1989
|
+
* - `undefined`: Auto-detect inverse relationship (default behavior)
|
|
1990
|
+
* - `string`: Explicit inverse relationship name
|
|
1991
|
+
* - `null`: No inverse relationship (disable synchronization)
|
|
1992
|
+
*/
|
|
1993
|
+
inverse?: string | null;
|
|
1994
|
+
};
|
|
1995
|
+
/**
|
|
1996
|
+
* All relationship types
|
|
1997
|
+
*/
|
|
1998
|
+
type Relationships = BelongsTo<any, any> | HasMany<any, any>;
|
|
1999
|
+
/**
|
|
2000
|
+
* The type of factory association
|
|
2001
|
+
*/
|
|
2002
|
+
type AssociationType = 'create' | 'createMany' | 'link' | 'linkMany';
|
|
2003
|
+
/**
|
|
2004
|
+
* Predicate function for filtering models in link/linkMany associations
|
|
2005
|
+
* @template TModel - The model type to filter
|
|
2006
|
+
*/
|
|
2007
|
+
type AssociationQueryPredicate<TModel> = (model: TModel) => boolean;
|
|
2008
|
+
/**
|
|
2009
|
+
* Query for finding models - can be an attributes object or a predicate function
|
|
2010
|
+
* @template TModel - The model type to query
|
|
2011
|
+
*/
|
|
2012
|
+
type AssociationQuery<TModel = any> = Partial<TModel> | AssociationQueryPredicate<TModel>;
|
|
2013
|
+
/**
|
|
2014
|
+
* Runtime storage for traits and defaults passed to factory associations.
|
|
2015
|
+
* Type validation happens at the factory level through typed builder functions.
|
|
2016
|
+
*/
|
|
2017
|
+
type AssociationTraitsAndDefaults = Array<string | Record<string, any>>;
|
|
2018
|
+
/**
|
|
2019
|
+
* Type-safe traits and defaults for a specific model in a schema.
|
|
2020
|
+
* Validates trait names against the model's factory and ensures defaults match model attributes.
|
|
2021
|
+
* @template TSchema - The schema collections type
|
|
2022
|
+
* @template TModel - The model template
|
|
2023
|
+
*/
|
|
2024
|
+
type TypedAssociationTraitsAndDefaults<TSchema extends SchemaCollections, TModel extends ModelTemplate> = Array<TraitNamesFor<TSchema, TModel> | Partial<InferModelAttrs<TModel>>>;
|
|
2025
|
+
/**
|
|
2026
|
+
* Base interface for all factory associations
|
|
2027
|
+
* @template TModel - The model template to associate
|
|
2028
|
+
*/
|
|
2029
|
+
interface BaseAssociation<TModel extends ModelTemplate = ModelTemplate> {
|
|
2030
|
+
/** The type of association */
|
|
2031
|
+
type: AssociationType;
|
|
2032
|
+
/** The model template to create or link */
|
|
2033
|
+
model: TModel;
|
|
2034
|
+
/** Optional relationship name - can be inferred from the key in FactoryAssociations */
|
|
2035
|
+
relationshipName?: string;
|
|
2036
|
+
/** Traits and defaults to apply when creating the associated model */
|
|
2037
|
+
traitsAndDefaults?: AssociationTraitsAndDefaults;
|
|
2038
|
+
}
|
|
2039
|
+
/**
|
|
2040
|
+
* Association that always creates one new related model
|
|
2041
|
+
* @template TModel - The model template to create
|
|
2042
|
+
*/
|
|
2043
|
+
interface CreateAssociation<TModel extends ModelTemplate = ModelTemplate> extends BaseAssociation<TModel> {
|
|
2044
|
+
type: 'create';
|
|
2045
|
+
}
|
|
2046
|
+
/**
|
|
2047
|
+
* Association that always creates N new related models
|
|
2048
|
+
* @template TModel - The model template to create
|
|
2049
|
+
*/
|
|
2050
|
+
interface CreateManyAssociation<TModel extends ModelTemplate = ModelTemplate> extends BaseAssociation<TModel> {
|
|
2051
|
+
type: 'createMany';
|
|
2052
|
+
/** Number of models to create */
|
|
2053
|
+
count: number;
|
|
2054
|
+
}
|
|
2055
|
+
/**
|
|
2056
|
+
* Association that tries to find an existing model, or creates one if not found
|
|
2057
|
+
* @template TModel - The model template to link or create
|
|
2058
|
+
*/
|
|
2059
|
+
interface LinkAssociation<TModel extends ModelTemplate = ModelTemplate> extends BaseAssociation<TModel> {
|
|
2060
|
+
type: 'link';
|
|
2061
|
+
/** Optional query to find existing models */
|
|
2062
|
+
query?: AssociationQuery;
|
|
2063
|
+
}
|
|
2064
|
+
/**
|
|
2065
|
+
* Association that tries to find N existing models, or creates more if needed
|
|
2066
|
+
* @template TModel - The model template to link or create
|
|
2067
|
+
*/
|
|
2068
|
+
interface LinkManyAssociation<TModel extends ModelTemplate = ModelTemplate> extends BaseAssociation<TModel> {
|
|
2069
|
+
type: 'linkMany';
|
|
2070
|
+
/** Number of models to link */
|
|
2071
|
+
count: number;
|
|
2072
|
+
/** Optional query to find existing models */
|
|
2073
|
+
query?: AssociationQuery;
|
|
2074
|
+
}
|
|
2075
|
+
/**
|
|
2076
|
+
* Union of all factory association types
|
|
2077
|
+
* @template TModel - The model template
|
|
2078
|
+
*/
|
|
2079
|
+
type Association<TModel extends ModelTemplate = ModelTemplate> = CreateAssociation<TModel> | CreateManyAssociation<TModel> | LinkAssociation<TModel> | LinkManyAssociation<TModel>;
|
|
2080
|
+
/**
|
|
2081
|
+
* Extract the target model template from a relationship
|
|
2082
|
+
* @template TRelationship - The relationship type (BelongsTo or HasMany)
|
|
2083
|
+
* @internal
|
|
2084
|
+
*/
|
|
2085
|
+
type RelationshipTargetTemplate<TRelationship> = TRelationship extends {
|
|
2086
|
+
targetModel: infer TTarget;
|
|
2087
|
+
} ? TTarget extends ModelTemplate ? TTarget : never : never;
|
|
2088
|
+
/**
|
|
2089
|
+
* Map of relationship names to factory associations for a model.
|
|
2090
|
+
* Keys are constrained to actual relationship names defined for the model.
|
|
2091
|
+
* Values must be associations for the correct target model of each relationship.
|
|
2092
|
+
* @template TTemplate - The model template
|
|
2093
|
+
* @template TSchema - The schema collections type
|
|
2094
|
+
* @example
|
|
2095
|
+
* ```typescript
|
|
2096
|
+
* // Post has relationships: { author: BelongsTo<UserModel>, comments: HasMany<CommentModel> }
|
|
2097
|
+
* const associations: FactoryAssociations<typeof postModel, AppSchema> = {
|
|
2098
|
+
* author: associations.create(userModel), // ✓ Valid: author relationship exists
|
|
2099
|
+
* comments: associations.createMany(commentModel, 3), // ✓ Valid: comments relationship exists
|
|
2100
|
+
* tags: associations.link(tagModel) // ✗ Error: no 'tags' relationship
|
|
2101
|
+
* }
|
|
2102
|
+
* ```
|
|
2103
|
+
*/
|
|
2104
|
+
type FactoryAssociations<TTemplate extends ModelTemplate, TSchema extends SchemaCollections = SchemaCollections> = RelationshipsByTemplate<TTemplate, TSchema> extends ModelRelationships ? {
|
|
2105
|
+
[K in keyof RelationshipsByTemplate<TTemplate, TSchema>]?: Association<RelationshipTargetTemplate<RelationshipsByTemplate<TTemplate, TSchema>[K]>>;
|
|
2106
|
+
} : {};
|
|
2107
|
+
|
|
2108
|
+
/**
|
|
2109
|
+
* Define a belongs-to relationship.
|
|
2110
|
+
* @param targetModel - The template of the model that is being related to.
|
|
2111
|
+
* @param opts - The options for the relationship.
|
|
2112
|
+
* @param opts.foreignKey - The foreign key of the relationship.
|
|
2113
|
+
* @param opts.inverse - The name of the inverse relationship on the target model, or null to disable.
|
|
2114
|
+
* @returns The relationship definition object.
|
|
2115
|
+
* @example
|
|
2116
|
+
* ```typescript
|
|
2117
|
+
* // Auto-detect inverse
|
|
2118
|
+
* author: belongsTo(userModel)
|
|
2119
|
+
*
|
|
2120
|
+
* // Explicit inverse
|
|
2121
|
+
* author: belongsTo(userModel, { inverse: 'authoredPosts' })
|
|
2122
|
+
*
|
|
2123
|
+
* // No inverse (no synchronization)
|
|
2124
|
+
* reviewer: belongsTo(userModel, { inverse: null })
|
|
2125
|
+
* ```
|
|
2126
|
+
*/
|
|
2127
|
+
declare function belongsTo<TTarget extends ModelTemplate, const TOpts extends {
|
|
2128
|
+
foreignKey?: string;
|
|
2129
|
+
inverse?: string | null;
|
|
2130
|
+
} | undefined = undefined>(targetModel: TTarget, opts?: TOpts): BelongsTo<TTarget, TOpts extends {
|
|
2131
|
+
foreignKey: infer F extends string;
|
|
2132
|
+
} ? F : `${InferModelName<TTarget>}Id`>;
|
|
2133
|
+
|
|
2134
|
+
/**
|
|
2135
|
+
* Always create one new related model and link it (with schema type for trait validation)
|
|
2136
|
+
* @template TSchema - The schema collections type
|
|
2137
|
+
* @template TModel - The model template (inferred from model parameter)
|
|
2138
|
+
* @param model - Model template to create
|
|
2139
|
+
* @param traitsAndDefaults - Traits and/or defaults to apply (variadic) - trait names are validated against schema
|
|
2140
|
+
* @returns The create association
|
|
2141
|
+
*/
|
|
2142
|
+
declare function create<TSchema extends SchemaCollections, TModel extends ModelTemplate>(model: TModel, ...traitsAndDefaults: TypedAssociationTraitsAndDefaults<TSchema, TModel>): CreateAssociation<TModel>;
|
|
2143
|
+
/**
|
|
2144
|
+
* Always create one new related model and link it (without schema type - traits not validated)
|
|
2145
|
+
* @template TModel - The model template (inferred from model parameter)
|
|
2146
|
+
* @param model - Model template to create
|
|
2147
|
+
* @param traitsAndDefaults - Traits and/or defaults to apply (variadic) - trait names are strings
|
|
2148
|
+
* @returns The create association
|
|
2149
|
+
*/
|
|
2150
|
+
declare function create<TModel extends ModelTemplate>(model: TModel, ...traitsAndDefaults: AssociationTraitsAndDefaults): CreateAssociation<TModel>;
|
|
2151
|
+
|
|
2152
|
+
/**
|
|
2153
|
+
* Always create N new related models and link them (with schema type for trait validation)
|
|
2154
|
+
* @template TSchema - The schema collections type
|
|
2155
|
+
* @template TModel - The model template (inferred from model parameter)
|
|
2156
|
+
* @param model - Model template to create
|
|
2157
|
+
* @param count - Number of models to create
|
|
2158
|
+
* @param traitsAndDefaults - Traits and/or defaults to apply (variadic) - trait names are validated against schema
|
|
2159
|
+
* @returns The create many association
|
|
2160
|
+
*/
|
|
2161
|
+
declare function createMany<TSchema extends SchemaCollections, TModel extends ModelTemplate>(model: TModel, count: number, ...traitsAndDefaults: TypedAssociationTraitsAndDefaults<TSchema, TModel>): CreateManyAssociation<TModel>;
|
|
2162
|
+
/**
|
|
2163
|
+
* Always create N new related models and link them (without schema type - traits not validated)
|
|
2164
|
+
* @template TModel - The model template (inferred from model parameter)
|
|
2165
|
+
* @param model - Model template to create
|
|
2166
|
+
* @param count - Number of models to create
|
|
2167
|
+
* @param traitsAndDefaults - Traits and/or defaults to apply (variadic) - trait names are strings
|
|
2168
|
+
* @returns The create many association
|
|
2169
|
+
*/
|
|
2170
|
+
declare function createMany<TModel extends ModelTemplate>(model: TModel, count: number, ...traitsAndDefaults: AssociationTraitsAndDefaults): CreateManyAssociation<TModel>;
|
|
2171
|
+
|
|
2172
|
+
/**
|
|
2173
|
+
* Define a has-many relationship.
|
|
2174
|
+
* @param targetModel - The template of the model that is being related to.
|
|
2175
|
+
* @param opts - The options for the relationship.
|
|
2176
|
+
* @param opts.foreignKey - The foreign key of the relationship.
|
|
2177
|
+
* @param opts.inverse - The name of the inverse relationship on the target model, or null to disable.
|
|
2178
|
+
* @returns The relationship definition object.
|
|
2179
|
+
* @example
|
|
2180
|
+
* ```typescript
|
|
2181
|
+
* // Auto-detect inverse
|
|
2182
|
+
* posts: hasMany(postModel)
|
|
2183
|
+
*
|
|
2184
|
+
* // Explicit inverse
|
|
2185
|
+
* authoredPosts: hasMany(postModel, { inverse: 'author' })
|
|
2186
|
+
*
|
|
2187
|
+
* // No inverse (no synchronization)
|
|
2188
|
+
* archivedPosts: hasMany(postModel, { inverse: null })
|
|
2189
|
+
* ```
|
|
2190
|
+
*/
|
|
2191
|
+
declare function hasMany<TTarget extends ModelTemplate, const TOpts extends {
|
|
2192
|
+
foreignKey?: string;
|
|
2193
|
+
inverse?: string | null;
|
|
2194
|
+
} | undefined = undefined>(targetModel: TTarget, opts?: TOpts): HasMany<TTarget, TOpts extends {
|
|
2195
|
+
foreignKey: infer F extends string;
|
|
2196
|
+
} ? F : `${InferModelName<TTarget>}Ids`>;
|
|
2197
|
+
|
|
2198
|
+
/**
|
|
2199
|
+
* Try to find existing model, else create one (with schema type for trait validation)
|
|
2200
|
+
* @template TSchema - The schema collections type
|
|
2201
|
+
* @template TModel - The model template (inferred from model parameter)
|
|
2202
|
+
* @param model - Model template to use
|
|
2203
|
+
* @param query - Optional query to filter models (attributes object or predicate function)
|
|
2204
|
+
* @param traitsAndDefaults - Traits and/or defaults to apply when creating (variadic) - trait names are validated against schema
|
|
2205
|
+
* @returns The link association
|
|
2206
|
+
*/
|
|
2207
|
+
declare function link<TSchema extends SchemaCollections, TModel extends ModelTemplate>(model: TModel, query?: AssociationQuery<InferModelAttrs<TModel>>, ...traitsAndDefaults: TypedAssociationTraitsAndDefaults<TSchema, TModel>): LinkAssociation<TModel>;
|
|
2208
|
+
/**
|
|
2209
|
+
* Try to find existing model, else create one (without schema type - traits not validated)
|
|
2210
|
+
* @template TModel - The model template (inferred from model parameter)
|
|
2211
|
+
* @param model - Model template to use
|
|
2212
|
+
* @param query - Optional query to filter models (attributes object or predicate function)
|
|
2213
|
+
* @param traitsAndDefaults - Traits and/or defaults to apply when creating (variadic) - trait names are strings
|
|
2214
|
+
* @returns The link association
|
|
2215
|
+
*/
|
|
2216
|
+
declare function link<TModel extends ModelTemplate>(model: TModel, query?: AssociationQuery<InferModelAttrs<TModel>>, ...traitsAndDefaults: AssociationTraitsAndDefaults): LinkAssociation<TModel>;
|
|
2217
|
+
|
|
2218
|
+
/**
|
|
2219
|
+
* Try to find N existing models, else create more as needed (with schema type for trait validation)
|
|
2220
|
+
* @template TSchema - The schema collections type
|
|
2221
|
+
* @template TModel - The model template (inferred from model parameter)
|
|
2222
|
+
* @param model - Model template to use
|
|
2223
|
+
* @param count - Number of models needed
|
|
2224
|
+
* @param query - Optional query to filter models (attributes object or predicate function)
|
|
2225
|
+
* @param traitsAndDefaults - Traits and/or defaults to apply when creating (variadic) - trait names are validated against schema
|
|
2226
|
+
* @returns The link many association
|
|
2227
|
+
*/
|
|
2228
|
+
declare function linkMany<TSchema extends SchemaCollections, TModel extends ModelTemplate>(model: TModel, count: number, query?: AssociationQuery<InferModelAttrs<TModel>>, ...traitsAndDefaults: TypedAssociationTraitsAndDefaults<TSchema, TModel>): LinkManyAssociation<TModel>;
|
|
2229
|
+
/**
|
|
2230
|
+
* Try to find N existing models, else create more as needed (without schema type - traits not validated)
|
|
2231
|
+
* @template TModel - The model template (inferred from model parameter)
|
|
2232
|
+
* @param model - Model template to use
|
|
2233
|
+
* @param count - Number of models needed
|
|
2234
|
+
* @param query - Optional query to filter models (attributes object or predicate function)
|
|
2235
|
+
* @param traitsAndDefaults - Traits and/or defaults to apply when creating (variadic) - trait names are strings
|
|
2236
|
+
* @returns The link many association
|
|
2237
|
+
*/
|
|
2238
|
+
declare function linkMany<TModel extends ModelTemplate>(model: TModel, count: number, query?: AssociationQuery<InferModelAttrs<TModel>>, ...traitsAndDefaults: AssociationTraitsAndDefaults): LinkManyAssociation<TModel>;
|
|
2239
|
+
|
|
2240
|
+
/**
|
|
2241
|
+
* Associations object with all helper functions:
|
|
2242
|
+
* - belongsTo, hasMany: for model relationship definitions
|
|
2243
|
+
* - create, createMany, link, linkMany: for factory associations
|
|
2244
|
+
*/
|
|
2245
|
+
declare const associations: {
|
|
2246
|
+
readonly belongsTo: typeof belongsTo;
|
|
2247
|
+
readonly hasMany: typeof hasMany;
|
|
2248
|
+
readonly create: typeof create;
|
|
2249
|
+
readonly createMany: typeof createMany;
|
|
2250
|
+
readonly link: typeof link;
|
|
2251
|
+
readonly linkMany: typeof linkMany;
|
|
2252
|
+
};
|
|
2253
|
+
|
|
2254
|
+
/**
|
|
2255
|
+
* ModelRelationshipsManager - Handles all relationship operations
|
|
2256
|
+
* Separated from core model logic for better maintainability
|
|
2257
|
+
* @template TTemplate - The model template
|
|
2258
|
+
* @template TSchema - The schema collections type
|
|
2259
|
+
* @template TRelationships - The relationships configuration
|
|
2260
|
+
*/
|
|
2261
|
+
declare class RelationshipsManager<TTemplate extends ModelTemplate, TSchema extends SchemaCollections, TRelationships extends ModelRelationships = RelationshipsByTemplate<TTemplate, TSchema>> {
|
|
2262
|
+
isApplyingPendingUpdates: boolean;
|
|
2263
|
+
private _model;
|
|
2264
|
+
private _pendingRelationshipOperations;
|
|
2265
|
+
private _relationshipDefs?;
|
|
2266
|
+
private _inverseMap;
|
|
2267
|
+
private _schema;
|
|
2268
|
+
constructor(model: Model<TTemplate, TSchema>, schema: SchemaInstance<TSchema>, relationships?: TRelationships);
|
|
2269
|
+
/**
|
|
2270
|
+
* Getter for the relationship definitions
|
|
2271
|
+
* @returns The relationship definitions
|
|
2272
|
+
*/
|
|
2273
|
+
get relationshipDefs(): RelationshipDefs<TRelationships> | undefined;
|
|
2274
|
+
/**
|
|
2275
|
+
* Getter for the schema
|
|
2276
|
+
* @returns The schema
|
|
2277
|
+
*/
|
|
2278
|
+
get schema(): SchemaInstance<TSchema>;
|
|
2279
|
+
/**
|
|
2280
|
+
* Set pending relationship updates by analyzing changes
|
|
2281
|
+
* Handles both model instances and raw foreign key values
|
|
2282
|
+
* Should be called BEFORE updating model attributes so we can access old FKs
|
|
2283
|
+
* @param relationshipUpdates - Raw relationship values from attrs (can be models or FK values)
|
|
2284
|
+
*/
|
|
2285
|
+
setPendingRelationshipUpdates(relationshipUpdates: Partial<RelatedModelAttrs<TSchema, TRelationships>>): void;
|
|
2286
|
+
/**
|
|
2287
|
+
* Apply inverse relationship updates for pending operations
|
|
2288
|
+
* Should be called AFTER saving the model (when FK changes are in the database)
|
|
2289
|
+
* Note: FK updates are already applied to the model by _processAttrs or link/unlink methods
|
|
2290
|
+
*/
|
|
2291
|
+
applyPendingInverseUpdates(): void;
|
|
2292
|
+
/**
|
|
2293
|
+
* Link this model to another model via a relationship
|
|
2294
|
+
* Returns foreign key updates without mutating model state
|
|
2295
|
+
* @param relationshipName - The name of the relationship
|
|
2296
|
+
* @param targetModel - The model to link to (or null to unlink)
|
|
2297
|
+
* @returns FK updates to apply and inverse relationship updates
|
|
2298
|
+
*/
|
|
2299
|
+
link<K extends RelationshipNames<TRelationships>>(relationshipName: K, targetModel: RelationshipTargetModel<TSchema, TRelationships, K>): RelationshipUpdateResult;
|
|
2300
|
+
/**
|
|
2301
|
+
* Unlink this model from another model via a relationship
|
|
2302
|
+
* Returns foreign key updates without mutating model state
|
|
2303
|
+
* @param relationshipName - The name of the relationship
|
|
2304
|
+
* @param targetModel - The specific model to unlink (optional for hasMany, unlinks all if not provided)
|
|
2305
|
+
* @returns FK updates to apply
|
|
2306
|
+
*/
|
|
2307
|
+
unlink<K extends RelationshipNames<TRelationships>>(relationshipName: K, targetModel?: RelationshipTargetModel<TSchema, TRelationships, K>): RelationshipUpdateResult;
|
|
2308
|
+
/**
|
|
2309
|
+
* Get related model(s) for a relationship with proper typing
|
|
2310
|
+
* @param relationshipName - The relationship name
|
|
2311
|
+
* @returns The related model(s) or null/empty collection
|
|
2312
|
+
*/
|
|
2313
|
+
related<K extends RelationshipNames<TRelationships>>(relationshipName: K): RelationshipTargetModel<TSchema, TRelationships, K> | null;
|
|
2314
|
+
/**
|
|
2315
|
+
* Get a relationship definition by name
|
|
2316
|
+
* @param relationshipName - The relationship name
|
|
2317
|
+
* @returns The relationship definition or undefined
|
|
2318
|
+
*/
|
|
2319
|
+
private _getRelationshipDef;
|
|
2320
|
+
/**
|
|
2321
|
+
* Get model attributes with proper typing
|
|
2322
|
+
* @returns Model attributes
|
|
2323
|
+
*/
|
|
2324
|
+
private _getModelAttrs;
|
|
2325
|
+
/**
|
|
2326
|
+
* Get foreign key value from model attrs
|
|
2327
|
+
* @param foreignKey - The foreign key to retrieve
|
|
2328
|
+
* @returns The foreign key value
|
|
2329
|
+
*/
|
|
2330
|
+
private _getForeignKeyValue;
|
|
2331
|
+
/**
|
|
2332
|
+
* Extract a single ID from foreign key value (for belongsTo relationships)
|
|
2333
|
+
* @param foreignKeyValue - The foreign key value
|
|
2334
|
+
* @returns A single ID or null
|
|
2335
|
+
*/
|
|
2336
|
+
private _extractSingleId;
|
|
2337
|
+
/**
|
|
2338
|
+
* Extract array of IDs from foreign key value
|
|
2339
|
+
* @param foreignKeyValue - The foreign key value
|
|
2340
|
+
* @returns Array of IDs
|
|
2341
|
+
*/
|
|
2342
|
+
private _extractIdsArray;
|
|
2343
|
+
/**
|
|
2344
|
+
* Parse relationships configuration into internal relationship definitions
|
|
2345
|
+
* This includes finding inverse relationships for bidirectional updates
|
|
2346
|
+
* @param relationships - The relationships configuration from schema
|
|
2347
|
+
* @returns Parsed relationship definitions with inverse information
|
|
2348
|
+
*/
|
|
2349
|
+
private _parseRelationshipDefs;
|
|
2350
|
+
/**
|
|
2351
|
+
* Update the inverse relationship on the target model
|
|
2352
|
+
* @param relationshipName - The name of the relationship being updated
|
|
2353
|
+
* @param targetModel - The target model to update
|
|
2354
|
+
* @param action - Whether to 'link' or 'unlink'
|
|
2355
|
+
*/
|
|
2356
|
+
private _updateInverseRelationship;
|
|
2357
|
+
/**
|
|
2358
|
+
* Extract foreign key value from a relationship value (model/array/collection)
|
|
2359
|
+
* @param relationship - The relationship configuration
|
|
2360
|
+
* @param value - The relationship value
|
|
2361
|
+
* @returns The extracted foreign key value
|
|
2362
|
+
*/
|
|
2363
|
+
private _extractForeignKeyFromValue;
|
|
2364
|
+
/**
|
|
2365
|
+
* Check if foreign key has a meaningful value
|
|
2366
|
+
* @param fk - The foreign key value to check
|
|
2367
|
+
* @returns True if the foreign key has a value
|
|
2368
|
+
*/
|
|
2369
|
+
private _hasForeignKeyValue;
|
|
2370
|
+
/**
|
|
2371
|
+
* Check if foreign key has changed
|
|
2372
|
+
* @param currentFk - The current foreign key value
|
|
2373
|
+
* @param newFk - The new foreign key value
|
|
2374
|
+
* @returns True if the foreign keys are different
|
|
2375
|
+
*/
|
|
2376
|
+
private _hasForeignKeyChanged;
|
|
2377
|
+
/**
|
|
2378
|
+
* Compare two arrays for equality
|
|
2379
|
+
* @param arr1 - First array
|
|
2380
|
+
* @param arr2 - Second array
|
|
2381
|
+
* @returns True if arrays are equal
|
|
2382
|
+
*/
|
|
2383
|
+
private _arraysEqual;
|
|
2384
|
+
}
|
|
2385
|
+
|
|
2386
|
+
/**
|
|
2387
|
+
* Model class for managing model instances with relationships
|
|
2388
|
+
* @template TTemplate - The model template (most important for users)
|
|
2389
|
+
* @template TSchema - The schema collections type for enhanced type inference
|
|
2390
|
+
* @template TSerializer - The serializer type
|
|
2391
|
+
*/
|
|
2392
|
+
declare class Model<TTemplate extends ModelTemplate = ModelTemplate, TSchema extends SchemaCollections = SchemaCollections, TSerializer = undefined> extends BaseModel<ModelAttrs<TTemplate, TSchema>, TSerializer> {
|
|
2393
|
+
readonly relationships?: RelationshipsByTemplate<TTemplate, TSchema>;
|
|
2394
|
+
protected _relationshipsManager?: RelationshipsManager<TTemplate, TSchema>;
|
|
2395
|
+
constructor(template: TTemplate, config: ModelConfig<TTemplate, TSchema, RelationshipsByTemplate<TTemplate, TSchema>, TSerializer>);
|
|
2396
|
+
/**
|
|
2397
|
+
* Define a model class with attribute accessors
|
|
2398
|
+
* @template TTemplate - The model template (most important for users)
|
|
2399
|
+
* @template TSchema - The schema collections type for enhanced type inference
|
|
2400
|
+
* @template TSerializer - The serializer type
|
|
2401
|
+
* @param template - The model template to define
|
|
2402
|
+
* @returns A model class that can be instantiated with 'new'
|
|
2403
|
+
*/
|
|
2404
|
+
static define<TTemplate extends ModelTemplate, TSchema extends SchemaCollections = SchemaCollections, TSerializer = undefined>(template: TTemplate): ModelClass<TTemplate, TSchema, TSerializer>;
|
|
2405
|
+
/**
|
|
2406
|
+
* Save the model to the database and apply pending relationship updates
|
|
2407
|
+
* @returns The model with saved instance type
|
|
2408
|
+
*/
|
|
2409
|
+
save(): this & ModelInstance<TTemplate, TSchema, TSerializer>;
|
|
2410
|
+
/**
|
|
2411
|
+
* Update the model attributes and save the model
|
|
2412
|
+
* @param attrs - The attributes to update
|
|
2413
|
+
* @returns The model with saved instance type
|
|
2414
|
+
*/
|
|
2415
|
+
update(attrs: ModelUpdateAttrs<TTemplate, TSchema>): this & ModelInstance<TTemplate, TSchema, TSerializer>;
|
|
2416
|
+
/**
|
|
2417
|
+
* Reload the model from the database
|
|
2418
|
+
* @returns The model with saved instance type
|
|
2419
|
+
*/
|
|
2420
|
+
reload(): this & ModelInstance<TTemplate, TSchema, TSerializer>;
|
|
2421
|
+
/**
|
|
2422
|
+
* Destroy the model from the database
|
|
2423
|
+
* @returns The model with new instance type
|
|
2424
|
+
*/
|
|
2425
|
+
destroy(): this & NewModelInstance<TTemplate, TSchema, TSerializer>;
|
|
2426
|
+
/**
|
|
2427
|
+
* Link this model to another model via a relationship
|
|
2428
|
+
* @param relationshipName - The name of the relationship
|
|
2429
|
+
* @param targetModel - The model to link to (or null to unlink)
|
|
2430
|
+
* @returns This model instance for chaining
|
|
2431
|
+
*/
|
|
2432
|
+
link<K extends RelationshipNames<RelationshipsByTemplate<TTemplate, TSchema>>>(relationshipName: K, targetModel: RelationshipTargetModel<TSchema, RelationshipsByTemplate<TTemplate, TSchema>, K>): this & ModelInstance<TTemplate, TSchema, TSerializer>;
|
|
2433
|
+
/**
|
|
2434
|
+
* Unlink this model from another model via a relationship
|
|
2435
|
+
* @param relationshipName - The name of the relationship
|
|
2436
|
+
* @param targetModel - The specific model to unlink (optional for hasMany, unlinks all if not provided)
|
|
2437
|
+
* @returns This model instance for chaining
|
|
2438
|
+
*/
|
|
2439
|
+
unlink<K extends RelationshipNames<RelationshipsByTemplate<TTemplate, TSchema>>>(relationshipName: K, targetModel?: RelationshipTargetModel<TSchema, RelationshipsByTemplate<TTemplate, TSchema>, K>): this & ModelInstance<TTemplate, TSchema, TSerializer>;
|
|
2440
|
+
/**
|
|
2441
|
+
* Get related model(s) for a relationship with proper typing
|
|
2442
|
+
* @param relationshipName - The relationship name
|
|
2443
|
+
* @returns The related model(s) or null/empty collection
|
|
2444
|
+
*/
|
|
2445
|
+
related<K extends RelationshipNames<RelationshipsByTemplate<TTemplate, TSchema>>>(relationshipName: K): RelationshipTargetModel<TSchema, RelationshipsByTemplate<TTemplate, TSchema>, K> | null;
|
|
2446
|
+
/**
|
|
2447
|
+
* Extract foreign key value from a relationship value
|
|
2448
|
+
* @param relationship - The relationship configuration
|
|
2449
|
+
* @param value - The value to extract the foreign key from
|
|
2450
|
+
* @returns The foreign key value
|
|
2451
|
+
*/
|
|
2452
|
+
private static _extractForeignKey;
|
|
2453
|
+
/**
|
|
2454
|
+
* Separate attributes into model attributes and relationship updates
|
|
2455
|
+
* Extracts foreign keys from relationship model instances and initializes default values
|
|
2456
|
+
* @param attrs - The attributes to separate
|
|
2457
|
+
* @param relationships - The relationships configuration
|
|
2458
|
+
* @returns Object containing:
|
|
2459
|
+
* - regularAttrs: Regular attributes (may include explicit FK values)
|
|
2460
|
+
* - relationshipValues: Relationship values
|
|
2461
|
+
* - foreignKeys: Foreign keys (extracted from relationship models or defaults)
|
|
2462
|
+
*/
|
|
2463
|
+
private static _separateAttrs;
|
|
2464
|
+
/**
|
|
2465
|
+
* Process constructor/update attributes before model initialization
|
|
2466
|
+
* Separates relationship model instances from regular attributes and extracts foreign keys
|
|
2467
|
+
* @param attrs - The attributes to process (can include both regular attrs and relationship instances)
|
|
2468
|
+
* @param relationships - The relationships configuration (optional)
|
|
2469
|
+
* @returns Object containing:
|
|
2470
|
+
* - modelAttrs: Regular attributes and foreign keys ready for the database
|
|
2471
|
+
* - relationshipUpdates: Relationship model instances to be linked after save
|
|
2472
|
+
* @example
|
|
2473
|
+
* // Input: { title: 'Post', author: authorModelInstance }
|
|
2474
|
+
* // Output: {
|
|
2475
|
+
* // modelAttrs: { title: 'Post', authorId: '1' },
|
|
2476
|
+
* // relationshipUpdates: { author: authorModelInstance }
|
|
2477
|
+
* // }
|
|
2478
|
+
*/
|
|
2479
|
+
static _processAttrs<TTemplate extends ModelTemplate, TSchema extends SchemaCollections, TRelationships extends ModelRelationships = RelationshipsByTemplate<TTemplate, TSchema>>(attrs: ModelCreateAttrs<TTemplate, TSchema, TRelationships> | ModelUpdateAttrs<TTemplate, TSchema, TRelationships> | Partial<ModelCreateAttrs<TTemplate, TSchema, TRelationships>> | Record<string, unknown>, relationships?: TRelationships): {
|
|
2480
|
+
modelAttrs: NewModelAttrs<ModelAttrs<TTemplate, TSchema>> | Partial<ModelAttrs<TTemplate, TSchema>>;
|
|
2481
|
+
relationshipUpdates: Partial<RelatedModelAttrs<TSchema, TRelationships>>;
|
|
2482
|
+
};
|
|
2483
|
+
/**
|
|
2484
|
+
* Initialize attribute accessors for all attributes except id
|
|
2485
|
+
*/
|
|
2486
|
+
private _initAttributeAccessors;
|
|
2487
|
+
/**
|
|
2488
|
+
* Initialize foreign key attributes if they don't exist
|
|
2489
|
+
*/
|
|
2490
|
+
private _initForeignKeys;
|
|
2491
|
+
/**
|
|
2492
|
+
* Initialize relationship accessors for all relationships
|
|
2493
|
+
*/
|
|
2494
|
+
private _initRelationshipAccessors;
|
|
2495
|
+
}
|
|
2496
|
+
|
|
2497
|
+
/**
|
|
2498
|
+
* Model template interface with hidden type properties
|
|
2499
|
+
*
|
|
2500
|
+
* This interface uses only 2 generics for clean type signatures,
|
|
2501
|
+
* while storing additional type metadata in hidden properties (__attrs, __json).
|
|
2502
|
+
* These hidden properties exist only in TypeScript's type system with zero runtime cost.
|
|
2503
|
+
*
|
|
2504
|
+
* Note: __attrs and __json are NOT defined in the base interface to avoid type pollution
|
|
2505
|
+
* when creating intersections. They are added via intersection types in ModelBuilder.create()
|
|
2506
|
+
* @template TModelName - The string literal type for the model name
|
|
2507
|
+
* @template TCollectionName - The string literal type for the collection name
|
|
2508
|
+
*/
|
|
2509
|
+
interface ModelTemplate<TModelName extends string = string, TCollectionName extends string = string> {
|
|
2510
|
+
readonly key: symbol;
|
|
2511
|
+
readonly modelName: TModelName;
|
|
2512
|
+
readonly collectionName: TCollectionName;
|
|
2513
|
+
}
|
|
2514
|
+
/**
|
|
2515
|
+
* Infer model attributes from template
|
|
2516
|
+
* Uses conditional type to properly extract __attrs from intersection types
|
|
2517
|
+
* @template T - The model template
|
|
2518
|
+
*/
|
|
2519
|
+
type InferModelAttrs<T> = T extends {
|
|
2520
|
+
__attrs: infer TAttrs extends {
|
|
2521
|
+
id: any;
|
|
2522
|
+
};
|
|
2523
|
+
} ? TAttrs : never;
|
|
2524
|
+
/**
|
|
2525
|
+
* Infer model ID type from template
|
|
2526
|
+
* @template T - The model template
|
|
2527
|
+
*/
|
|
2528
|
+
type ModelId<T> = InferModelAttrs<T>['id'];
|
|
2529
|
+
/**
|
|
2530
|
+
* Infer model name from template
|
|
2531
|
+
* @template T - The model template
|
|
2532
|
+
*/
|
|
2533
|
+
type InferModelName<T> = T extends ModelTemplate<infer Name, any> ? Name : never;
|
|
2534
|
+
/**
|
|
2535
|
+
* Infer collection name from template
|
|
2536
|
+
* @template T - The model template
|
|
2537
|
+
*/
|
|
2538
|
+
type InferCollectionName<T> = T extends ModelTemplate<any, infer Name> ? Name : never;
|
|
2539
|
+
/**
|
|
2540
|
+
* Infer serialized model type from template
|
|
2541
|
+
* Uses conditional type to properly extract from intersection types
|
|
2542
|
+
* @template T - The model template
|
|
2543
|
+
*/
|
|
2544
|
+
type InferSerializedModel<T> = T extends {
|
|
2545
|
+
__json: {
|
|
2546
|
+
model: infer M;
|
|
2547
|
+
};
|
|
2548
|
+
} ? M : InferModelAttrs<T>;
|
|
2549
|
+
/**
|
|
2550
|
+
* Infer serialized collection type from template
|
|
2551
|
+
* Uses conditional type to properly extract from intersection types
|
|
2552
|
+
* @template T - The model template
|
|
2553
|
+
*/
|
|
2554
|
+
type InferSerializedCollection<T> = T extends {
|
|
2555
|
+
__json: {
|
|
2556
|
+
collection: infer C;
|
|
2557
|
+
};
|
|
2558
|
+
} ? C : InferModelAttrs<T>[];
|
|
2559
|
+
/**
|
|
2560
|
+
* Model relationships configuration object
|
|
2561
|
+
* @example { posts: HasMany<PostTemplate>, author: BelongsTo<UserTemplate, 'authorId'> }
|
|
2562
|
+
*/
|
|
2563
|
+
type ModelRelationships = Record<string, Relationships>;
|
|
2564
|
+
/**
|
|
2565
|
+
* Type for foreign key values - either a single ID or array of IDs
|
|
2566
|
+
*/
|
|
2567
|
+
type ForeignKeyValue = string | number | string[] | number[] | null | undefined;
|
|
2568
|
+
/**
|
|
2569
|
+
* Result of a relationship operation (link/unlink)
|
|
2570
|
+
* Contains foreign key updates for the current model
|
|
2571
|
+
*/
|
|
2572
|
+
interface RelationshipUpdateResult {
|
|
2573
|
+
/** Foreign key updates to apply to the current model */
|
|
2574
|
+
foreignKeyUpdates: Record<string, ForeignKeyValue>;
|
|
2575
|
+
}
|
|
2576
|
+
/**
|
|
2577
|
+
* Internal relationship definition with inverse relationship information
|
|
2578
|
+
* Used internally by Model to track bidirectional relationships
|
|
2579
|
+
* @template TRelationship - The specific relationship type
|
|
2580
|
+
*/
|
|
2581
|
+
interface RelationshipDef<TRelationship extends Relationships = Relationships> {
|
|
2582
|
+
/** The original relationship configuration */
|
|
2583
|
+
relationship: TRelationship;
|
|
2584
|
+
/** The inverse relationship information, if it exists */
|
|
2585
|
+
inverse?: {
|
|
2586
|
+
/** The foreign key used by the inverse relationship */
|
|
2587
|
+
foreignKey: string;
|
|
2588
|
+
/** The name of the inverse relationship in the target model */
|
|
2589
|
+
relationshipName: string;
|
|
2590
|
+
/** The target model template that has the inverse relationship */
|
|
2591
|
+
targetModel: ModelTemplate;
|
|
2592
|
+
/** The type of the inverse relationship */
|
|
2593
|
+
type: 'belongsTo' | 'hasMany';
|
|
2594
|
+
};
|
|
2595
|
+
}
|
|
2596
|
+
/**
|
|
2597
|
+
* Relationship definitions for internal use by Model class
|
|
2598
|
+
* Maps relationship names to their definitions including inverse information
|
|
2599
|
+
* Preserves specific relationship types from the input relationships configuration
|
|
2600
|
+
* @template TRelationships - The model relationships configuration
|
|
2601
|
+
* @example
|
|
2602
|
+
* // Input: { posts: HasMany<PostTemplate>, author: BelongsTo<UserTemplate> }
|
|
2603
|
+
* // Output: {
|
|
2604
|
+
* // posts: RelationshipDef<HasMany<PostTemplate>>,
|
|
2605
|
+
* // author: RelationshipDef<BelongsTo<UserTemplate>>
|
|
2606
|
+
* // }
|
|
2607
|
+
*/
|
|
2608
|
+
type RelationshipDefs<TRelationships extends ModelRelationships = ModelRelationships> = {
|
|
2609
|
+
[K in keyof TRelationships]: RelationshipDef<TRelationships[K]>;
|
|
2610
|
+
};
|
|
2611
|
+
/**
|
|
2612
|
+
* Extract relationship names from relationships type
|
|
2613
|
+
* @template TRelationships - The relationships type
|
|
2614
|
+
*/
|
|
2615
|
+
type RelationshipNames<TRelationships extends ModelRelationships> = keyof TRelationships;
|
|
2616
|
+
/**
|
|
2617
|
+
* Extract the target model instance type for a specific relationship
|
|
2618
|
+
* @template TSchema - The schema collections type
|
|
2619
|
+
* @template TRelationships - The relationships type
|
|
2620
|
+
* @template K - The relationship name
|
|
2621
|
+
*/
|
|
2622
|
+
type RelationshipTargetModel<TSchema extends SchemaCollections, TRelationships extends ModelRelationships, K extends keyof TRelationships = keyof TRelationships> = TRelationships[K] extends BelongsTo<infer TTarget, any> ? ModelInstance<TTarget, TSchema> | null : TRelationships[K] extends HasMany<infer TTarget, any> ? ModelCollection<TTarget, TSchema> | ModelInstance<TTarget, TSchema>[] | null : never;
|
|
2623
|
+
/**
|
|
2624
|
+
* Type for collection by template model
|
|
2625
|
+
* @template TSchema - The schema collections
|
|
2626
|
+
* @template TTemplate - The model template
|
|
2627
|
+
*/
|
|
2628
|
+
type CollectionByTemplate<TSchema extends SchemaCollections, TTemplate extends ModelTemplate> = {
|
|
2629
|
+
[K in keyof TSchema]: TSchema[K] extends CollectionConfig<infer TModel, any, any, any, any> ? TModel extends TTemplate ? K : never : never;
|
|
2630
|
+
}[keyof TSchema];
|
|
2631
|
+
/**
|
|
2632
|
+
* Type for relationships by template model
|
|
2633
|
+
* @template TSchema - The schema collections
|
|
2634
|
+
* @template TTemplate - The model template
|
|
2635
|
+
*/
|
|
2636
|
+
type RelationshipsByTemplate<TTemplate extends ModelTemplate, TSchema extends SchemaCollections> = TSchema[CollectionByTemplate<TSchema, TTemplate>] extends CollectionConfig<any, infer TRelationships, any, any, any> ? TRelationships extends ModelRelationships ? TRelationships : {} : {};
|
|
2637
|
+
/**
|
|
2638
|
+
* Extract foreign key properties for BelongsTo relationships
|
|
2639
|
+
* @template TRelationships - The relationships configuration object
|
|
2640
|
+
*/
|
|
2641
|
+
type BelongsToForeignKeys<TRelationships extends ModelRelationships> = UnionToIntersection<{
|
|
2642
|
+
[K in keyof TRelationships]: TRelationships[K] extends BelongsTo<infer TTarget, infer TForeign> ? {
|
|
2643
|
+
[FK in NonNullable<TForeign>]: ModelId<TTarget> | null;
|
|
2644
|
+
} : never;
|
|
2645
|
+
}[keyof TRelationships]>;
|
|
2646
|
+
/**
|
|
2647
|
+
* Extract foreign key properties for HasMany relationships
|
|
2648
|
+
* @template TRelationships - The relationships configuration object
|
|
2649
|
+
*/
|
|
2650
|
+
type HasManyForeignKeys<TRelationships extends ModelRelationships> = UnionToIntersection<{
|
|
2651
|
+
[K in keyof TRelationships]: TRelationships[K] extends HasMany<infer TTarget, infer TForeign> ? {
|
|
2652
|
+
[FK in NonNullable<TForeign>]: ModelId<TTarget>[];
|
|
2653
|
+
} : never;
|
|
2654
|
+
}[keyof TRelationships]>;
|
|
2655
|
+
/**
|
|
2656
|
+
* Infer foreign key properties from relationships configuration
|
|
2657
|
+
* Creates properties like: authorId: string | null, postIds: string[]
|
|
2658
|
+
* @template TRelationships - The relationships configuration object
|
|
2659
|
+
*/
|
|
2660
|
+
type ModelForeignKeys<TRelationships extends ModelRelationships> = TRelationships extends never ? {} : BelongsToForeignKeys<TRelationships> & HasManyForeignKeys<TRelationships>;
|
|
2661
|
+
/**
|
|
2662
|
+
* Type for related model
|
|
2663
|
+
* @template TSchema - The schema collections
|
|
2664
|
+
* @template TRelationship - The relationship
|
|
2665
|
+
*/
|
|
2666
|
+
type RelatedModel<TSchema extends SchemaCollections, TRelationship extends Relationships> = TRelationship extends BelongsTo<infer TTarget, any> ? ModelInstance<TTarget, TSchema> | null : TRelationship extends HasMany<infer TTarget, any> ? ModelCollection<TTarget, TSchema> : never;
|
|
2667
|
+
type RelatedModelAttrs<TSchema extends SchemaCollections, TRelationships extends ModelRelationships> = TRelationships extends ModelRelationships ? {
|
|
2668
|
+
[K in keyof TRelationships]: TRelationships[K] extends BelongsTo<infer TTarget, any> ? ModelInstance<TTarget, TSchema> | null : TRelationships[K] extends HasMany<infer TTarget, any> ? ModelCollection<TTarget, TSchema> | ModelInstance<TTarget, TSchema>[] : never;
|
|
2669
|
+
} : {};
|
|
2670
|
+
type ForeignKeyAttrs<TRelationships extends ModelRelationships> = Partial<ModelForeignKeys<TRelationships>>;
|
|
2671
|
+
/**
|
|
2672
|
+
* Infer relationship accessor properties that can be updated
|
|
2673
|
+
* @template TSchema - The schema collections
|
|
2674
|
+
* @template TRelationships - The relationships configuration
|
|
2675
|
+
*/
|
|
2676
|
+
type ModelRelationshipAccessors<TSchema extends SchemaCollections, TRelationships extends ModelRelationships> = keyof TRelationships extends never ? {} : {
|
|
2677
|
+
[K in keyof TRelationships]: RelatedModel<TSchema, TRelationships[K]>;
|
|
2678
|
+
};
|
|
2679
|
+
/**
|
|
2680
|
+
* Type for base model attributes (allowing null id for unsaved models)
|
|
2681
|
+
* @template TTemplate - The model template
|
|
2682
|
+
*/
|
|
2683
|
+
type NewModelAttrs<TAttrs extends {
|
|
2684
|
+
id: any;
|
|
2685
|
+
}> = TAttrs | (Omit<TAttrs, 'id'> & {
|
|
2686
|
+
id?: TAttrs['id'] | null;
|
|
2687
|
+
});
|
|
2688
|
+
/**
|
|
2689
|
+
* Type for new base model instance with nullable ID
|
|
2690
|
+
* @template TAttrs - The model attributes type
|
|
2691
|
+
* @template TSerializer - The serializer type
|
|
2692
|
+
*/
|
|
2693
|
+
type NewBaseModelInstance<TAttrs extends {
|
|
2694
|
+
id: any;
|
|
2695
|
+
}, TSerializer = undefined> = BaseModel<TAttrs, TSerializer> & {
|
|
2696
|
+
attrs: NewModelAttrs<TAttrs>;
|
|
2697
|
+
id: TAttrs['id'] | null;
|
|
2698
|
+
};
|
|
2699
|
+
/**
|
|
2700
|
+
* Type for base model instance with required ID
|
|
2701
|
+
* @template TAttrs - The model attributes type
|
|
2702
|
+
* @template TSerializer - The serializer type
|
|
2703
|
+
*/
|
|
2704
|
+
type BaseModelInstance<TAttrs extends {
|
|
2705
|
+
id: any;
|
|
2706
|
+
}, TSerializer = undefined> = BaseModel<TAttrs, TSerializer> & {
|
|
2707
|
+
attrs: TAttrs;
|
|
2708
|
+
id: TAttrs['id'];
|
|
2709
|
+
};
|
|
2710
|
+
/**
|
|
2711
|
+
* Type for model attribute getters/setters
|
|
2712
|
+
* @template TTemplate - The model template
|
|
2713
|
+
*/
|
|
2714
|
+
type ModelAttrAccessors<TTemplate extends ModelTemplate> = {
|
|
2715
|
+
[K in keyof Omit<InferModelAttrs<TTemplate>, 'id'>]: InferModelAttrs<TTemplate>[K];
|
|
2716
|
+
};
|
|
2717
|
+
/**
|
|
2718
|
+
* Type for model only attributes without ID
|
|
2719
|
+
*/
|
|
2720
|
+
type ModelOnlyAttrs<TTemplate extends ModelTemplate> = Omit<InferModelAttrs<TTemplate>, 'id'>;
|
|
2721
|
+
/**
|
|
2722
|
+
* Type for model attributes that includes regular attributes, foreign keys, and relationship model instances
|
|
2723
|
+
* Only relationship-related properties are optional
|
|
2724
|
+
* @template TTemplate - The model template
|
|
2725
|
+
* @template TSchema - The schema collections type
|
|
2726
|
+
*/
|
|
2727
|
+
type ModelAttrs<TTemplate extends ModelTemplate, TSchema extends SchemaCollections = SchemaCollections, TRelationships extends ModelRelationships = RelationshipsByTemplate<TTemplate, TSchema>> = Omit<InferModelAttrs<TTemplate>, 'id'> & ModelForeignKeys<TRelationships> & {
|
|
2728
|
+
id: ModelId<TTemplate>;
|
|
2729
|
+
};
|
|
2730
|
+
/**
|
|
2731
|
+
* Type for partial model attributes
|
|
2732
|
+
* @template TTemplate - The model template
|
|
2733
|
+
* @template TSchema - The schema collections type
|
|
2734
|
+
*/
|
|
2735
|
+
type PartialModelAttrs<TTemplate extends ModelTemplate, TSchema extends SchemaCollections = SchemaCollections> = Partial<ModelAttrs<TTemplate, TSchema>>;
|
|
2736
|
+
/**
|
|
2737
|
+
* Type for constructor attributes that includes regular attributes and relationship model instances
|
|
2738
|
+
* @template TTemplate - The model template
|
|
2739
|
+
* @template TSchema - The schema collections type
|
|
2740
|
+
*/
|
|
2741
|
+
type ModelCreateAttrs<TTemplate extends ModelTemplate, TSchema extends SchemaCollections = SchemaCollections, TRelationships extends ModelRelationships = RelationshipsByTemplate<TTemplate, TSchema>> = Omit<InferModelAttrs<TTemplate>, 'id'> & {
|
|
2742
|
+
id?: ModelId<TTemplate> | null;
|
|
2743
|
+
} & (Record<string, never> extends TRelationships ? {} : ForeignKeyAttrs<TRelationships> & Partial<RelatedModelAttrs<TSchema, TRelationships>>);
|
|
2744
|
+
/**
|
|
2745
|
+
* Type for update method that includes attributes, foreign keys, and relationship model instances
|
|
2746
|
+
* All properties are optional for updates
|
|
2747
|
+
* @template TTemplate - The model template
|
|
2748
|
+
* @template TSchema - The schema collections type
|
|
2749
|
+
*/
|
|
2750
|
+
type ModelUpdateAttrs<TTemplate extends ModelTemplate, TSchema extends SchemaCollections = SchemaCollections, TRelationships extends ModelRelationships = RelationshipsByTemplate<TTemplate, TSchema>> = Partial<ModelAttrs<TTemplate, TSchema, TRelationships>> & (Record<string, never> extends TRelationships ? {} : Partial<RelatedModelAttrs<TSchema, TRelationships>>);
|
|
2751
|
+
/**
|
|
2752
|
+
* Configuration for creating a schema-aware model
|
|
2753
|
+
* @template TTemplate - The model template
|
|
2754
|
+
* @template TSchema - The schema collections type
|
|
2755
|
+
* @template TRelationships - The model relationships
|
|
2756
|
+
* @template TSerializer - The serializer type
|
|
2757
|
+
*/
|
|
2758
|
+
type ModelConfig<TTemplate extends ModelTemplate, TSchema extends SchemaCollections = SchemaCollections, TRelationships extends ModelRelationships = RelationshipsByTemplate<TTemplate, TSchema>, TSerializer = undefined> = {
|
|
2759
|
+
attrs: ModelCreateAttrs<TTemplate, TSchema, TRelationships>;
|
|
2760
|
+
schema: SchemaInstance<TSchema>;
|
|
2761
|
+
serializer?: TSerializer extends undefined ? any : TSerializer;
|
|
2762
|
+
} & (Record<string, never> extends TRelationships ? {
|
|
2763
|
+
relationships?: undefined;
|
|
2764
|
+
} : {
|
|
2765
|
+
relationships: TRelationships;
|
|
2766
|
+
});
|
|
2767
|
+
/**
|
|
2768
|
+
* Type for model class with attribute accessors (direct Model constructor)
|
|
2769
|
+
* @template TTemplate - The model template (most important for users)
|
|
2770
|
+
* @template TSchema - The schema collections type for enhanced type inference
|
|
2771
|
+
* @template TSerializer - The serializer type
|
|
2772
|
+
*/
|
|
2773
|
+
type ModelClass<TTemplate extends ModelTemplate, TSchema extends SchemaCollections = SchemaCollections, TSerializer = undefined> = {
|
|
2774
|
+
new (config: ModelConfig<TTemplate, TSchema, RelationshipsByTemplate<TTemplate, TSchema>, TSerializer>): NewModelInstance<TTemplate, TSchema, TSerializer>;
|
|
2775
|
+
};
|
|
2776
|
+
/**
|
|
2777
|
+
* Type for new model instance with accessors for the attributes (nullable id)
|
|
2778
|
+
* @template TTemplate - The model template (most important for users)
|
|
2779
|
+
* @template TSchema - The schema collections type for enhanced type inference
|
|
2780
|
+
* @template TSerializer - The serializer type
|
|
2781
|
+
*/
|
|
2782
|
+
type NewModelInstance<TTemplate extends ModelTemplate, TSchema extends SchemaCollections = SchemaCollections, TSerializer = undefined> = Model<TTemplate, TSchema, TSerializer> & {
|
|
2783
|
+
attrs: ModelAttrs<TTemplate, TSchema>;
|
|
2784
|
+
id: ModelAttrs<TTemplate, TSchema>['id'] | null;
|
|
2785
|
+
} & ModelAttrAccessors<TTemplate> & ModelForeignKeys<RelationshipsByTemplate<TTemplate, TSchema>> & ModelRelationshipAccessors<TSchema, RelationshipsByTemplate<TTemplate, TSchema>>;
|
|
2786
|
+
/**
|
|
2787
|
+
* Type for model instance with accessors for the attributes (required ID)
|
|
2788
|
+
* @template TTemplate - The model template (most important for users)
|
|
2789
|
+
* @template TSchema - The schema collections type for enhanced type inference
|
|
2790
|
+
* @template TSerializer - The serializer type
|
|
2791
|
+
*/
|
|
2792
|
+
type ModelInstance<TTemplate extends ModelTemplate, TSchema extends SchemaCollections = SchemaCollections, TSerializer = undefined> = Model<TTemplate, TSchema, TSerializer> & {
|
|
2793
|
+
attrs: ModelAttrs<TTemplate, TSchema>;
|
|
2794
|
+
id: ModelAttrs<TTemplate, TSchema>['id'];
|
|
2795
|
+
} & ModelAttrAccessors<TTemplate> & ModelForeignKeys<RelationshipsByTemplate<TTemplate, TSchema>> & ModelRelationshipAccessors<TSchema, RelationshipsByTemplate<TTemplate, TSchema>>;
|
|
2796
|
+
/**
|
|
2797
|
+
* Model status type
|
|
2798
|
+
*/
|
|
2799
|
+
type ModelStatus = 'new' | 'saved';
|
|
2800
|
+
|
|
2801
|
+
/**
|
|
2802
|
+
* BaseModel class for managing basic model operations without schema dependencies
|
|
2803
|
+
* Handles basic CRUD operations, db updates, attribute management, and status tracking
|
|
2804
|
+
* @template TAttrs - The model attributes type (e.g., { id: string, name: string })
|
|
2805
|
+
* @template TSerializer - The serializer type for custom JSON serialization
|
|
2806
|
+
*/
|
|
2807
|
+
declare class BaseModel<TAttrs extends {
|
|
2808
|
+
id: any;
|
|
2809
|
+
}, TSerializer = undefined> {
|
|
2810
|
+
readonly modelName: string;
|
|
2811
|
+
readonly collectionName: string;
|
|
2812
|
+
protected _attrs: NewModelAttrs<TAttrs>;
|
|
2813
|
+
protected _dbCollection: DbCollection<TAttrs>;
|
|
2814
|
+
protected _serializer?: TSerializer;
|
|
2815
|
+
protected _status: ModelStatus;
|
|
2816
|
+
constructor(modelName: string, collectionName: string, attrs: NewModelAttrs<TAttrs>, dbCollection?: DbCollection<TAttrs>, serializer?: TSerializer);
|
|
2817
|
+
/**
|
|
2818
|
+
* Getter for the protected id attribute
|
|
2819
|
+
* @returns The id of the model
|
|
2820
|
+
*/
|
|
2821
|
+
get id(): TAttrs['id'] | null;
|
|
2822
|
+
/**
|
|
2823
|
+
* Getter for the model attributes
|
|
2824
|
+
* @returns A copy of the model attributes
|
|
2825
|
+
*/
|
|
2826
|
+
get attrs(): NewModelAttrs<TAttrs>;
|
|
2827
|
+
/**
|
|
2828
|
+
* Save the model to the database
|
|
2829
|
+
* @returns The model with saved instance type
|
|
2830
|
+
*/
|
|
2831
|
+
save(): this & BaseModelInstance<TAttrs, TSerializer>;
|
|
2832
|
+
/**
|
|
2833
|
+
* Update the model attributes and save the model
|
|
2834
|
+
* @param attrs - The attributes to update
|
|
2835
|
+
* @returns The model instance for chaining
|
|
2836
|
+
*/
|
|
2837
|
+
update(attrs: Partial<TAttrs>): this & BaseModelInstance<TAttrs, TSerializer>;
|
|
2838
|
+
/**
|
|
2839
|
+
* Reload the model from the database
|
|
2840
|
+
* @returns The model with saved instance type
|
|
2841
|
+
*/
|
|
2842
|
+
reload(): this & BaseModelInstance<TAttrs, TSerializer>;
|
|
2843
|
+
/**
|
|
2844
|
+
* Destroy the model from the database
|
|
2845
|
+
* @returns The model with new instance type
|
|
2846
|
+
*/
|
|
2847
|
+
destroy(): this & NewBaseModelInstance<TAttrs, TSerializer>;
|
|
2848
|
+
/**
|
|
2849
|
+
* Check if the model is new
|
|
2850
|
+
* @returns True if the model is new, false otherwise
|
|
2851
|
+
*/
|
|
2852
|
+
isNew(): boolean;
|
|
2853
|
+
/**
|
|
2854
|
+
* Check if the model is saved
|
|
2855
|
+
* @returns True if the model is saved, false otherwise
|
|
2856
|
+
*/
|
|
2857
|
+
isSaved(): boolean;
|
|
2858
|
+
/**
|
|
2859
|
+
* Serialize the model to a JSON object
|
|
2860
|
+
* @returns The serialized model using the configured serializer or raw attributes
|
|
2861
|
+
*/
|
|
2862
|
+
toJSON(): TSerializer extends {
|
|
2863
|
+
serialize(model: any): infer TSerializedModel;
|
|
2864
|
+
} ? TSerializedModel : TAttrs;
|
|
2865
|
+
/**
|
|
2866
|
+
* Serialize the model to a string
|
|
2867
|
+
* @returns The simple string representation of the model and its id
|
|
2868
|
+
*/
|
|
2869
|
+
toString(): string;
|
|
2870
|
+
private _checkStatus;
|
|
2871
|
+
}
|
|
2872
|
+
|
|
2873
|
+
/**
|
|
2874
|
+
* A fluent builder for creating strongly-typed model templates.
|
|
2875
|
+
*
|
|
2876
|
+
* The ModelBuilder provides a type-safe way to construct ModelTemplate instances with
|
|
2877
|
+
* configurable model attributes. It follows the builder pattern, allowing method chaining
|
|
2878
|
+
* to progressively refine the template's type parameters.
|
|
2879
|
+
* @template TModelAttrs - The model attributes type (must have an 'id' property)
|
|
2880
|
+
* @template TModelName - The string literal type for the model name
|
|
2881
|
+
* @template TCollectionName - The string literal type for the collection name
|
|
2882
|
+
* @template TSerializedModel - The serialized model type (for toJSON)
|
|
2883
|
+
* @template TSerializedCollection - The serialized collection type (for toJSON)
|
|
2884
|
+
* @example
|
|
2885
|
+
* ```typescript
|
|
2886
|
+
* // Create a basic template
|
|
2887
|
+
* const userTemplate = model().name('user').collection('users').create();
|
|
2888
|
+
*
|
|
2889
|
+
* // Create a template with specific model attributes
|
|
2890
|
+
* interface User { id: string; name: string; email: string; }
|
|
2891
|
+
* const typedUserTemplate = model()
|
|
2892
|
+
* .name('user')
|
|
2893
|
+
* .collection('users')
|
|
2894
|
+
* .attrs<UserAttrs>()
|
|
2895
|
+
* .create();
|
|
2896
|
+
*
|
|
2897
|
+
* // With custom JSON types
|
|
2898
|
+
* const jsonTypedTemplate = model()
|
|
2899
|
+
* .name('user')
|
|
2900
|
+
* .collection('users')
|
|
2901
|
+
* .attrs<UserAttrs>()
|
|
2902
|
+
* .json<UserJSON, UsersJSON>()
|
|
2903
|
+
* .create();
|
|
2904
|
+
* ```
|
|
2905
|
+
*/
|
|
2906
|
+
declare class ModelBuilder<TModelAttrs extends {
|
|
2907
|
+
id: any;
|
|
2908
|
+
} = {
|
|
2909
|
+
id: string;
|
|
2910
|
+
}, TModelName extends string = string, TCollectionName extends string = string, TSerializedModel = TModelAttrs, TSerializedCollection = TSerializedModel[]> {
|
|
2911
|
+
private _modelName?;
|
|
2912
|
+
private _collectionName?;
|
|
2913
|
+
/**
|
|
2914
|
+
* Sets the model name identifier.
|
|
2915
|
+
* @template T - The string literal type for the model name
|
|
2916
|
+
* @param modelName - The name identifier for the model (e.g., 'user', 'post')
|
|
2917
|
+
* @returns A new ModelBuilder instance with the model name set
|
|
2918
|
+
* @example
|
|
2919
|
+
* ```typescript
|
|
2920
|
+
* const builder = model().name('user');
|
|
2921
|
+
* ```
|
|
2922
|
+
*/
|
|
2923
|
+
name<T extends string>(modelName: T): ModelBuilder<TModelAttrs, T, TCollectionName, TSerializedModel, TSerializedCollection>;
|
|
2924
|
+
/**
|
|
2925
|
+
* Sets the collection name identifier.
|
|
2926
|
+
* @template T - The string literal type for the collection name
|
|
2927
|
+
* @param collectionName - The name identifier for the collection (e.g., 'users', 'posts')
|
|
2928
|
+
* @returns A new ModelBuilder instance with the collection name set
|
|
2929
|
+
* @example
|
|
2930
|
+
* ```typescript
|
|
2931
|
+
* const builder = model().name('user').collection('users');
|
|
2932
|
+
* ```
|
|
2933
|
+
*/
|
|
2934
|
+
collection<T extends string>(collectionName: T): ModelBuilder<TModelAttrs, TModelName, T, TSerializedModel, TSerializedCollection>;
|
|
2935
|
+
/**
|
|
2936
|
+
* Sets the model attributes type.
|
|
2937
|
+
*
|
|
2938
|
+
* This method allows you to specify the exact shape of your model attributes,
|
|
2939
|
+
* providing strong typing for the resulting template. Serialization types are
|
|
2940
|
+
* reset to default to the new attributes type (use .json() to override).
|
|
2941
|
+
* @template T - The model attributes type (must extend { id: any })
|
|
2942
|
+
* @returns A new ModelBuilder instance with the specified model type
|
|
2943
|
+
* @example
|
|
2944
|
+
* ```typescript
|
|
2945
|
+
* interface User { id: string; name: string; email: string; }
|
|
2946
|
+
* const builder = model().name('user').collection('users').attrs<UserAttrs>();
|
|
2947
|
+
* ```
|
|
2948
|
+
*/
|
|
2949
|
+
attrs<T extends {
|
|
2950
|
+
id: any;
|
|
2951
|
+
}>(): ModelBuilder<T, TModelName, TCollectionName, T, T[]>;
|
|
2952
|
+
/**
|
|
2953
|
+
* Specifies serialization types for this model.
|
|
2954
|
+
*
|
|
2955
|
+
* This method sets the types returned by model.toJSON() and collection.toJSON().
|
|
2956
|
+
* If not called, toJSON() will return the model attributes type.
|
|
2957
|
+
* @template TModel - The serialized model type (single instance)
|
|
2958
|
+
* @template TCollection - The serialized collection type (array)
|
|
2959
|
+
* @returns A new ModelBuilder with serialization types
|
|
2960
|
+
* @example
|
|
2961
|
+
* ```typescript
|
|
2962
|
+
* interface UserJSON {
|
|
2963
|
+
* id: string;
|
|
2964
|
+
* name: string;
|
|
2965
|
+
* email: string;
|
|
2966
|
+
* }
|
|
2967
|
+
*
|
|
2968
|
+
* interface UsersJSON {
|
|
2969
|
+
* users: UserJSON[];
|
|
2970
|
+
* }
|
|
2971
|
+
*
|
|
2972
|
+
* const userModel = model()
|
|
2973
|
+
* .name('user')
|
|
2974
|
+
* .collection('users')
|
|
2975
|
+
* .attrs<UserAttrs>()
|
|
2976
|
+
* .json<UserJSON, UsersJSON>() // Specify serialization types
|
|
2977
|
+
* .create();
|
|
2978
|
+
* ```
|
|
2979
|
+
*/
|
|
2980
|
+
json<TModel = TModelAttrs, TCollection = TModel[]>(): ModelBuilder<TModelAttrs, TModelName, TCollectionName, TModel, TCollection>;
|
|
2981
|
+
/**
|
|
2982
|
+
* Creates the final ModelTemplate with all configured types and metadata.
|
|
2983
|
+
*
|
|
2984
|
+
* This method produces the immutable ModelTemplate that can be used throughout
|
|
2985
|
+
* your application for type-safe model operations. The template includes the
|
|
2986
|
+
* model and collection names, a unique symbol key, and hidden type properties
|
|
2987
|
+
* for attributes and serialization.
|
|
2988
|
+
* @returns The configured ModelTemplate instance with hidden type properties
|
|
2989
|
+
* @throws Error if model name or collection name is not set
|
|
2990
|
+
* @example
|
|
2991
|
+
* ```typescript
|
|
2992
|
+
* const userTemplate = model()
|
|
2993
|
+
* .name('user')
|
|
2994
|
+
* .collection('users')
|
|
2995
|
+
* .attrs<UserAttrs>()
|
|
2996
|
+
* .create();
|
|
2997
|
+
* ```
|
|
2998
|
+
*/
|
|
2999
|
+
create(): ModelTemplate<TModelName, TCollectionName> & {
|
|
3000
|
+
__attrs: TModelAttrs;
|
|
3001
|
+
__json: {
|
|
3002
|
+
model: TSerializedModel;
|
|
3003
|
+
collection: TSerializedCollection;
|
|
3004
|
+
};
|
|
3005
|
+
};
|
|
3006
|
+
}
|
|
3007
|
+
/**
|
|
3008
|
+
* Creates a new ModelBuilder for constructing type-safe model templates.
|
|
3009
|
+
*
|
|
3010
|
+
* This is the primary entry point for creating model templates. It provides a fluent
|
|
3011
|
+
* interface for configuring model attributes and metadata.
|
|
3012
|
+
* @returns A new ModelBuilder instance ready for configuration
|
|
3013
|
+
* @example
|
|
3014
|
+
* ```typescript
|
|
3015
|
+
* // Basic usage
|
|
3016
|
+
* const userTemplate = model()
|
|
3017
|
+
* .name('user')
|
|
3018
|
+
* .collection('users')
|
|
3019
|
+
* .create();
|
|
3020
|
+
*
|
|
3021
|
+
* // With typed attributes
|
|
3022
|
+
* interface UserAttrs { id: string; name: string; email: string; }
|
|
3023
|
+
* const typedUserTemplate = model()
|
|
3024
|
+
* .name('user')
|
|
3025
|
+
* .collection('users')
|
|
3026
|
+
* .attrs<UserAttrs>()
|
|
3027
|
+
* .create();
|
|
3028
|
+
*
|
|
3029
|
+
* // With custom JSON types
|
|
3030
|
+
* interface UserJSON { id: string; name: string; email: string; }
|
|
3031
|
+
* interface UsersJSON { users: UserJSON[]; }
|
|
3032
|
+
* const jsonTypedTemplate = model()
|
|
3033
|
+
* .name('user')
|
|
3034
|
+
* .collection('users')
|
|
3035
|
+
* .attrs<UserAttrs>()
|
|
3036
|
+
* .json<UserJSON, UsersJSON>()
|
|
3037
|
+
* .create();
|
|
3038
|
+
* ```
|
|
3039
|
+
*/
|
|
3040
|
+
declare function model(): ModelBuilder<{
|
|
3041
|
+
id: string;
|
|
3042
|
+
}, string, string>;
|
|
3043
|
+
|
|
3044
|
+
export { type Association, type BelongsTo, Collection, type CollectionConfig, type CollectionCreateAttrs, type CollectionInstance, type CreateAssociation, type CreateManyAssociation, type DataSerializerOptions, type DbRecordInput, Factory, type FactoryAfterCreateHook, type FactoryAttrs, type FixtureAttrs, type FixtureConfig, type FixtureLoadStrategy, type HasMany, IdentityManager, type InferCollectionName, type InferModelAttrs, type InferModelName, type InferSerializedCollection, type InferSerializedModel, type LinkAssociation, type LinkManyAssociation, type ModelAttrs, type ModelInstance, type ModelTemplate, type ModelTraits, type ModelUpdateAttrs, type NewModelInstance, NumberIdentityManager, type OrderBy, type PartialModelAttrs, type QueryOptions, type SchemaCollections, type SchemaInstance, type SeedFunction, type SeedScenarios, type Seeds, Serializer, type SerializerOptions, StringIdentityManager, type StructuralSerializerOptions, type TraitDefinition, type Where, associations, belongsTo, collection, create, createMany, factory, hasMany, link, linkMany, model, schema };
|