UNPKG

12.1 kBTypeScriptView Raw
1declare module '@ioc:Adonis/Lucid/Factory' {
2 import { faker } from '@faker-js/faker';
3 import { OneOrMany, QueryClientContract, TransactionClientContract } from '@ioc:Adonis/Lucid/Database';
4 import { LucidRow, LucidModel, ModelAttributes, ModelAdapterOptions, RelationshipsContract, ExtractModelRelations, ModelObject } from '@ioc:Adonis/Lucid/Orm';
5 /**
6 * ------------------------------------------------------
7 * Helpers
8 * ------------------------------------------------------
9 */
10 /**
11 * Extracts the attributes accepted by the lucid model set on a
12 * factory
13 */
14 export type ExtractFactoryAttributes<T extends FactoryModelContract<LucidModel>> = Partial<ModelAttributes<InstanceType<T['model']>>>;
15 /**
16 * ------------------------------------------------------
17 * Callbacks
18 * ------------------------------------------------------
19 */
20 /**
21 * Function to return the model attributes.
22 */
23 export type DefineCallback<Model extends LucidModel> = (ctx: FactoryContextContract) => Promise<Partial<ModelAttributes<InstanceType<Model>>>> | Partial<ModelAttributes<InstanceType<Model>>>;
24 /**
25 * Function to generate custom stub ids
26 */
27 export type StubIdCallback = (counter: number, model: LucidRow) => any;
28 /**
29 * Function to initiate a model instance. It will receive the
30 * attributes returned by the `define` method
31 */
32 export type NewUpCallback<T extends FactoryModelContract<LucidModel>> = (attributes: ExtractFactoryAttributes<T>, ctx: FactoryContextContract, model: T['model'], builder: FactoryBuilderContract<T>) => InstanceType<T['model']>;
33 /**
34 * Function to merge attributes defined during runtime
35 */
36 export type MergeCallback<T extends FactoryModelContract<LucidModel>> = (row: InstanceType<T['model']>, attributes: ExtractFactoryAttributes<T>, ctx: FactoryContextContract, builder: FactoryBuilderContract<T>) => void;
37 /**
38 * Callback to define a new model state
39 */
40 export type StateCallback<Model extends LucidModel> = (row: InstanceType<Model>, ctx: FactoryContextContract, builder: FactoryBuilderContract<FactoryModelContract<Model>>) => any | Promise<any>;
41 /**
42 * ------------------------------------------------------
43 * Hooks
44 * ------------------------------------------------------
45 */
46 /**
47 * List of events for which a factory will trigger hooks
48 */
49 export type EventsList = 'makeStubbed' | 'create' | 'make';
50 /**
51 * Shape of hooks handler
52 */
53 export type HooksHandler<Model extends FactoryModelContract<LucidModel>> = (builder: FactoryBuilderContract<Model>, row: InstanceType<Model['model']>, ctx: FactoryContextContract) => void | Promise<void>;
54 /**
55 * ------------------------------------------------------
56 * Runtime context
57 * ------------------------------------------------------
58 */
59 /**
60 * The runtime context of the factory builder. A new state is constructed
61 * for each `create/make` operation and passed down to relationships
62 * as well.
63 */
64 export interface FactoryContextContract {
65 faker: typeof faker;
66 isStubbed: boolean;
67 $trx: TransactionClientContract | undefined;
68 }
69 /**
70 * ------------------------------------------------------
71 * Relationships
72 * ------------------------------------------------------
73 */
74 /**
75 * Callback accepted by the `with` method and relationships
76 * `create` and `make` methods
77 */
78 export type RelationCallback = (builder: FactoryBuilderContract<FactoryModelContract<LucidModel>>) => void;
79 /**
80 * Shape of the factory relationships. To keep relationships slim, we will have
81 * a common interface for relationships vs fine tuning API for each type of
82 * relationship
83 */
84 export interface FactoryRelationContract {
85 parent: LucidRow;
86 /**
87 * Reference to the Lucid model relationship
88 */
89 relation: RelationshipsContract;
90 /**
91 * Merge attributes with the relationship and its children
92 */
93 merge(attributes: any): this;
94 /**
95 * Define custom pivot attributes for many to many
96 * relationship
97 */
98 pivotAttributes?(attributes: ModelObject | ModelObject[]): this;
99 /**
100 * Pass context to the relationship. Must be done everytime, so that
101 * relationships uses the same transaction as the parent model
102 */
103 useCtx(ctx: FactoryContextContract): this;
104 /**
105 * Create and persist
106 */
107 create(parent: LucidRow, callback?: RelationCallback, count?: number): Promise<void>;
108 /**
109 * Create and stub
110 */
111 make(parent: LucidRow, callback?: RelationCallback, count?: number): Promise<void>;
112 }
113 /**
114 * ------------------------------------------------------
115 * Runtime builder
116 * ------------------------------------------------------
117 */
118 /**
119 * Factory builder uses the factory model to create/make
120 * instances of lucid models
121 */
122 export interface FactoryBuilderContract<FactoryModel extends FactoryModelContract<LucidModel>> {
123 /**
124 * Reference to the factory
125 */
126 factory: FactoryModel;
127 /**
128 * Define custom database connection
129 */
130 connection(connection: string): this;
131 /**
132 * Define custom query client
133 */
134 client(client: QueryClientContract): this;
135 /**
136 * Apply pre-defined state
137 */
138 apply<K extends keyof FactoryModel['states']>(...states: K[]): this;
139 /**
140 * Create/make relationships for explicitly defined related factories
141 */
142 with<K extends keyof FactoryModel['relations']>(relation: K, count?: number, callback?: (
143 /**
144 * Receives the explicitly defined factory
145 */
146 builder: FactoryModel['relations'][K] extends () => FactoryBuilderContract<any> ? ReturnType<FactoryModel['relations'][K]> & {
147 parent: InstanceType<FactoryModel['model']>;
148 } : never) => void): this;
149 /**
150 * Define pivot attributes when persisting a many to many
151 * relationship. Results in a noop, when not called
152 * for a many to many relationship
153 */
154 pivotAttributes(attributes: ModelObject | ModelObject[]): this;
155 /**
156 * Merge custom set of attributes. They are passed to the merge method of
157 * the model factory
158 *
159 * For `createMany` and `makeMany`, you can pass an array of attributes mapped
160 * according to the array index.
161 */
162 merge(attributes: OneOrMany<ExtractFactoryAttributes<FactoryModel>>): this;
163 /**
164 * Merge custom set of attributes with the correct factory builder
165 * model and all of its relationships as well
166 */
167 mergeRecursive(attributes: any): this;
168 /**
169 * Define custom runtime context. This method is usually called by
170 * the relationships to ensure a single context is used by the
171 * parent and relationship factories.
172 *
173 * Do not define a custom context, unless you know what you are really
174 * doing.
175 */
176 useCtx(ctx: FactoryContextContract): this;
177 /**
178 * Tap into the persistence layer of factory builder. Allows one
179 * to modify the model instance just before it is persisted
180 * to the database
181 */
182 tap(callback: (row: InstanceType<FactoryModel['model']>, ctx: FactoryContextContract, builder: this) => void): this;
183 /**
184 * Make model instance without persitance. The make method
185 * doesn't process relationships
186 */
187 make(): Promise<InstanceType<FactoryModel['model']>>;
188 /**
189 * Create model instance and stub out the persistance
190 * mechanism
191 */
192 makeStubbed(): Promise<InstanceType<FactoryModel['model']>>;
193 /**
194 * Create and persist model instance
195 */
196 create(): Promise<InstanceType<FactoryModel['model']>>;
197 /**
198 * Make model instance without persitance. The makeMany method
199 * doesn't process relationships
200 */
201 makeMany(count: number): Promise<InstanceType<FactoryModel['model']>[]>;
202 /**
203 * Create one or more model instances and stub
204 * out the persistance mechanism.
205 */
206 makeStubbedMany(count: number): Promise<InstanceType<FactoryModel['model']>[]>;
207 /**
208 * Create and persist more than one model instance
209 */
210 createMany(count: number): Promise<InstanceType<FactoryModel['model']>[]>;
211 }
212 /**
213 * Query contract that initiates the factory builder. Since the factory builder
214 * API surface is small, we also proxy all of it's methods for a nicer DX
215 */
216 export interface FactoryBuilderQueryContract<FactoryModel extends FactoryModelContract<LucidModel>> extends FactoryBuilderContract<FactoryModel> {
217 query(options?: ModelAdapterOptions, viaRelation?: FactoryRelationContract): FactoryBuilderContract<FactoryModel>;
218 }
219 /**
220 * ------------------------------------------------------
221 * Factory model
222 * ------------------------------------------------------
223 */
224 /**
225 * Factory model exposes the API to defined a model factory with states
226 * and relationships
227 */
228 export interface FactoryModelContract<Model extends LucidModel> {
229 /**
230 * Reference to the underlying lucid model used by the factory
231 * model
232 */
233 model: Model;
234 /**
235 * Mainly for types support. Not used at runtime to derive any
236 * logic. Sorry, at times have to hack into typescript to
237 * get the desired output. :)
238 */
239 states: unknown;
240 relations: unknown;
241 /**
242 * Optionally define a custom method to instantiate the model
243 * instance and manage merging attributes
244 */
245 newUp(callback: NewUpCallback<this>): this;
246 merge(callback: MergeCallback<this>): this;
247 /**
248 * Define custom state for the factory. When executing the factory,
249 * you can apply the pre-defined states
250 */
251 state<K extends string>(state: K, callback: StateCallback<Model>): this & {
252 states: {
253 [P in K]: StateCallback<Model>;
254 };
255 };
256 /**
257 * Define a relationship on another factory
258 */
259 relation<K extends ExtractModelRelations<InstanceType<Model>>, Relation>(relation: K, callback: Relation): this & {
260 relations: {
261 [P in K]: Relation;
262 };
263 };
264 /**
265 * Define before hooks. Only `create` event is invoked
266 * during the before lifecycle
267 */
268 before(event: Exclude<EventsList, 'make'>, handler: HooksHandler<this>): this;
269 /**
270 * Define after hooks.
271 */
272 after(event: EventsList, handler: HooksHandler<this>): this;
273 /**
274 * Build model factory. This method returns the factory builder, which can be used to
275 * execute model queries
276 */
277 build(): FactoryBuilderQueryContract<this>;
278 }
279 /**
280 * ------------------------------------------------------
281 * Manager to register new factories
282 * ------------------------------------------------------
283 */
284 /**
285 * Factory manager to define new factories
286 */
287 export interface FactoryManagerContract {
288 /**
289 * Define a custom factory
290 */
291 define<Model extends LucidModel>(model: Model, callback: DefineCallback<Model>): FactoryModelContract<Model>;
292 /**
293 * Define a custom callback to generate stub ids
294 */
295 stubId(callback: StubIdCallback): void;
296 }
297 const Factory: FactoryManagerContract;
298 export default Factory;
299}