@nestbolt/factory 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.
Files changed (48) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +412 -0
  3. package/dist/base-factory.d.ts +7 -0
  4. package/dist/base-factory.js +7 -0
  5. package/dist/base-factory.js.map +1 -0
  6. package/dist/events/factory.events.d.ts +18 -0
  7. package/dist/events/factory.events.js +10 -0
  8. package/dist/events/factory.events.js.map +1 -0
  9. package/dist/events/index.d.ts +1 -0
  10. package/dist/events/index.js +6 -0
  11. package/dist/events/index.js.map +1 -0
  12. package/dist/exceptions/factory-not-initialized.exception.d.ts +3 -0
  13. package/dist/exceptions/factory-not-initialized.exception.js +11 -0
  14. package/dist/exceptions/factory-not-initialized.exception.js.map +1 -0
  15. package/dist/exceptions/factory-not-registered.exception.d.ts +3 -0
  16. package/dist/exceptions/factory-not-registered.exception.js +11 -0
  17. package/dist/exceptions/factory-not-registered.exception.js.map +1 -0
  18. package/dist/exceptions/index.d.ts +2 -0
  19. package/dist/exceptions/index.js +8 -0
  20. package/dist/exceptions/index.js.map +1 -0
  21. package/dist/factory-builder.d.ts +28 -0
  22. package/dist/factory-builder.js +108 -0
  23. package/dist/factory-builder.js.map +1 -0
  24. package/dist/factory.constants.d.ts +1 -0
  25. package/dist/factory.constants.js +5 -0
  26. package/dist/factory.constants.js.map +1 -0
  27. package/dist/factory.module.d.ts +6 -0
  28. package/dist/factory.module.js +49 -0
  29. package/dist/factory.module.js.map +1 -0
  30. package/dist/factory.service.d.ts +28 -0
  31. package/dist/factory.service.js +105 -0
  32. package/dist/factory.service.js.map +1 -0
  33. package/dist/index.d.ts +10 -0
  34. package/dist/index.js +22 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/interfaces/factory-options.interface.d.ts +14 -0
  37. package/dist/interfaces/factory-options.interface.js +3 -0
  38. package/dist/interfaces/factory-options.interface.js.map +1 -0
  39. package/dist/interfaces/index.d.ts +2 -0
  40. package/dist/interfaces/index.js +3 -0
  41. package/dist/interfaces/index.js.map +1 -0
  42. package/dist/interfaces/seeder.interface.d.ts +5 -0
  43. package/dist/interfaces/seeder.interface.js +3 -0
  44. package/dist/interfaces/seeder.interface.js.map +1 -0
  45. package/dist/sequence.d.ts +10 -0
  46. package/dist/sequence.js +26 -0
  47. package/dist/sequence.js.map +1 -0
  48. package/package.json +82 -0
package/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Nestbolt
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,412 @@
1
+ <p align="center">
2
+ <h1 align="center">@nestbolt/factory</h1>
3
+ <p align="center">Model factories and database seeders for NestJS with TypeORM.</p>
4
+ </p>
5
+
6
+ <p align="center">
7
+ <a href="https://www.npmjs.com/package/@nestbolt/factory"><img src="https://img.shields.io/npm/v/@nestbolt/factory.svg?style=flat-square" alt="npm version"></a>
8
+ <a href="https://www.npmjs.com/package/@nestbolt/factory"><img src="https://img.shields.io/npm/dt/@nestbolt/factory.svg?style=flat-square" alt="npm downloads"></a>
9
+ <a href="https://github.com/nestbolt/factory/actions"><img src="https://img.shields.io/github/actions/workflow/status/nestbolt/factory/tests.yml?branch=main&style=flat-square&label=tests" alt="tests"></a>
10
+ <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square" alt="license"></a>
11
+ </p>
12
+
13
+ <hr>
14
+
15
+ This package provides **model factories and database seeders** for [NestJS](https://nestjs.com) that let you generate fake data for any TypeORM entity with a fluent, chainable API.
16
+
17
+ Once installed, using it is as simple as:
18
+
19
+ ```typescript
20
+ class UserFactory extends BaseFactory<User> {
21
+ get entity() { return User; }
22
+ definition(faker: Faker) {
23
+ return { name: faker.person.fullName(), email: faker.internet.email() };
24
+ }
25
+ }
26
+
27
+ await factoryService.use(UserFactory).count(5).state("admin").create();
28
+ ```
29
+
30
+ ## Table of Contents
31
+
32
+ - [Installation](#installation)
33
+ - [Quick Start](#quick-start)
34
+ - [Module Configuration](#module-configuration)
35
+ - [Static Configuration (forRoot)](#static-configuration-forroot)
36
+ - [Async Configuration (forRootAsync)](#async-configuration-forrootasync)
37
+ - [Defining Factories](#defining-factories)
38
+ - [Using the Factory Builder](#using-the-factory-builder)
39
+ - [States](#states)
40
+ - [Sequences](#sequences)
41
+ - [Seeders](#seeders)
42
+ - [Events](#events)
43
+ - [Using the Service Directly](#using-the-service-directly)
44
+ - [Configuration Options](#configuration-options)
45
+ - [Testing](#testing)
46
+ - [Changelog](#changelog)
47
+ - [Contributing](#contributing)
48
+ - [Security](#security)
49
+ - [Credits](#credits)
50
+ - [License](#license)
51
+
52
+ ## Installation
53
+
54
+ Install the package via npm:
55
+
56
+ ```bash
57
+ npm install @nestbolt/factory
58
+ ```
59
+
60
+ Or via yarn:
61
+
62
+ ```bash
63
+ yarn add @nestbolt/factory
64
+ ```
65
+
66
+ Or via pnpm:
67
+
68
+ ```bash
69
+ pnpm add @nestbolt/factory
70
+ ```
71
+
72
+ ### Peer Dependencies
73
+
74
+ This package requires the following peer dependencies, which you likely already have in a NestJS project:
75
+
76
+ ```
77
+ @nestjs/common ^10.0.0 || ^11.0.0
78
+ @nestjs/core ^10.0.0 || ^11.0.0
79
+ @nestjs/typeorm ^10.0.0 || ^11.0.0
80
+ typeorm ^0.3.0
81
+ reflect-metadata ^0.1.13 || ^0.2.0
82
+ ```
83
+
84
+ ### Included
85
+
86
+ ```
87
+ @faker-js/faker ^9.0.0 # Bundled — no need to install separately
88
+ ```
89
+
90
+ ### Optional
91
+
92
+ ```bash
93
+ npm install @nestjs/event-emitter # For seeder lifecycle events
94
+ ```
95
+
96
+ ## Quick Start
97
+
98
+ ### 1. Define a factory
99
+
100
+ ```typescript
101
+ import { BaseFactory } from "@nestbolt/factory";
102
+ import { Faker } from "@faker-js/faker";
103
+
104
+ export class UserFactory extends BaseFactory<User> {
105
+ get entity() { return User; }
106
+
107
+ definition(faker: Faker): Partial<User> {
108
+ return {
109
+ name: faker.person.fullName(),
110
+ email: faker.internet.email(),
111
+ role: "user",
112
+ };
113
+ }
114
+
115
+ admin(): Partial<User> {
116
+ return { role: "admin" };
117
+ }
118
+ }
119
+ ```
120
+
121
+ ### 2. Register the module
122
+
123
+ ```typescript
124
+ import { FactoryModule } from "@nestbolt/factory";
125
+
126
+ @Module({
127
+ imports: [
128
+ TypeOrmModule.forRoot({ /* ... */ }),
129
+ FactoryModule.forRoot({
130
+ factories: [UserFactory, PostFactory],
131
+ }),
132
+ ],
133
+ })
134
+ export class AppModule {}
135
+ ```
136
+
137
+ ### 3. Use in your code
138
+
139
+ ```typescript
140
+ import { FactoryService } from "@nestbolt/factory";
141
+
142
+ @Injectable()
143
+ export class SeedService {
144
+ constructor(private readonly factory: FactoryService) {}
145
+
146
+ async seed() {
147
+ await this.factory.use(UserFactory).count(10).create();
148
+ await this.factory.use(UserFactory).state("admin").create();
149
+ }
150
+ }
151
+ ```
152
+
153
+ ## Module Configuration
154
+
155
+ The module is registered globally — you only need to import it once.
156
+
157
+ ### Static Configuration (forRoot)
158
+
159
+ ```typescript
160
+ FactoryModule.forRoot({
161
+ factories: [UserFactory, PostFactory],
162
+ seeders: [DatabaseSeeder],
163
+ seed: 12345, // optional: reproducible faker data
164
+ });
165
+ ```
166
+
167
+ ### Async Configuration (forRootAsync)
168
+
169
+ ```typescript
170
+ FactoryModule.forRootAsync({
171
+ imports: [ConfigModule],
172
+ inject: [ConfigService],
173
+ useFactory: (config: ConfigService) => ({
174
+ factories: [UserFactory, PostFactory],
175
+ seed: config.get("FAKER_SEED"),
176
+ }),
177
+ });
178
+ ```
179
+
180
+ ## Defining Factories
181
+
182
+ Extend `BaseFactory<T>` and implement the `entity` getter and `definition()` method:
183
+
184
+ ```typescript
185
+ export class PostFactory extends BaseFactory<Post> {
186
+ get entity() { return Post; }
187
+
188
+ definition(faker: Faker): Partial<Post> {
189
+ return {
190
+ title: faker.lorem.sentence(),
191
+ body: faker.lorem.paragraphs(2),
192
+ status: "draft",
193
+ };
194
+ }
195
+
196
+ // Optional lifecycle hooks
197
+ async afterMake(entity: Post, faker: Faker) {
198
+ // Called after make() — entity is NOT persisted yet
199
+ }
200
+
201
+ async afterCreate(entity: Post, faker: Faker) {
202
+ // Called after create() — entity IS persisted
203
+ }
204
+ }
205
+ ```
206
+
207
+ ## Using the Factory Builder
208
+
209
+ The `FactoryBuilder` provides a fluent API for generating entities:
210
+
211
+ ```typescript
212
+ // Make without persisting
213
+ const user = await factoryService.use(UserFactory).make();
214
+
215
+ // Create and persist to database
216
+ const user = await factoryService.use(UserFactory).create();
217
+
218
+ // Multiple entities
219
+ const users = await factoryService.use(UserFactory).count(10).create();
220
+
221
+ // Always get an array (even for count=1)
222
+ const users = await factoryService.use(UserFactory).createMany();
223
+ const users = await factoryService.use(UserFactory).makeMany();
224
+ ```
225
+
226
+ | Method | Returns | Description |
227
+ |--------|---------|-------------|
228
+ | `count(n)` | `this` | Set number of entities to generate |
229
+ | `state(name \| object \| fn)` | `this` | Apply a state (see States) |
230
+ | `override(attrs)` | `this` | Override specific fields (highest priority) |
231
+ | `sequence(field, seq)` | `this` | Apply a sequence to a field |
232
+ | `afterCreating(fn)` | `this` | Callback after persist |
233
+ | `afterMaking(fn)` | `this` | Callback after instantiation |
234
+ | `create()` | `T \| T[]` | Persist and return |
235
+ | `make()` | `T \| T[]` | Instantiate without persisting |
236
+ | `createMany()` | `T[]` | Persist and always return array |
237
+ | `makeMany()` | `T[]` | Instantiate and always return array |
238
+
239
+ **Override priority:** `definition()` → `state()` → `sequence()` → `override()` (highest)
240
+
241
+ ## States
242
+
243
+ States let you define named variations of a factory:
244
+
245
+ ```typescript
246
+ export class UserFactory extends BaseFactory<User> {
247
+ // ... definition
248
+
249
+ admin(): Partial<User> {
250
+ return { role: "admin" };
251
+ }
252
+
253
+ inactive(): Partial<User> {
254
+ return { active: false };
255
+ }
256
+ }
257
+
258
+ // Usage
259
+ await factoryService.use(UserFactory).state("admin").create();
260
+ await factoryService.use(UserFactory).state("admin").state("inactive").create();
261
+
262
+ // Object and function states also work
263
+ await factoryService.use(UserFactory).state({ role: "moderator" }).create();
264
+ await factoryService.use(UserFactory).state((faker) => ({ age: faker.number.int({ min: 18, max: 30 }) })).create();
265
+ ```
266
+
267
+ ## Sequences
268
+
269
+ Use `Sequence` for auto-incrementing or cycling values:
270
+
271
+ ```typescript
272
+ import { Sequence } from "@nestbolt/factory";
273
+
274
+ // Auto-increment
275
+ await factoryService.use(UserFactory)
276
+ .count(3)
277
+ .sequence("email", Sequence.from(i => `user${i}@test.com`))
278
+ .create();
279
+ // → user0@test.com, user1@test.com, user2@test.com
280
+
281
+ // Increment numbers
282
+ Sequence.increment() // 1, 2, 3, ...
283
+ Sequence.increment(100) // 100, 101, 102, ...
284
+
285
+ // Cycle through values
286
+ Sequence.cycle(["draft", "published", "archived"])
287
+ // → draft, published, archived, draft, ...
288
+ ```
289
+
290
+ ## Seeders
291
+
292
+ Seeders are classes that populate your database with test data:
293
+
294
+ ```typescript
295
+ import { Seeder, FactoryService } from "@nestbolt/factory";
296
+
297
+ export class DatabaseSeeder implements Seeder {
298
+ order = 0; // lower runs first
299
+
300
+ async run(factory: FactoryService): Promise<void> {
301
+ await factory.use(UserFactory).count(10).create();
302
+ await factory.use(UserFactory).state("admin").count(2).create();
303
+ await factory.use(PostFactory).count(20).create();
304
+ }
305
+ }
306
+ ```
307
+
308
+ Register and run seeders:
309
+
310
+ ```typescript
311
+ // Register in module
312
+ FactoryModule.forRoot({
313
+ factories: [UserFactory, PostFactory],
314
+ seeders: [DatabaseSeeder],
315
+ });
316
+
317
+ // Run all seeders (sorted by order)
318
+ await factoryService.seed();
319
+
320
+ // Run a single seeder
321
+ await factoryService.runSeeder(DatabaseSeeder);
322
+ ```
323
+
324
+ ## Events
325
+
326
+ When `@nestjs/event-emitter` is installed, the package emits:
327
+
328
+ | Event | Payload | When |
329
+ |-------|---------|------|
330
+ | `factory.seeder.started` | `{ seederClass }` | Before a seeder runs |
331
+ | `factory.seeder.completed` | `{ seederClass }` | After a seeder completes |
332
+ | `factory.seed.all.started` | `{ seederCount }` | Before `seed()` runs all seeders |
333
+ | `factory.seed.all.completed` | `{ seederCount }` | After `seed()` completes all seeders |
334
+
335
+ ```typescript
336
+ import { FACTORY_EVENTS, SeederCompletedEvent } from "@nestbolt/factory";
337
+ import { OnEvent } from "@nestjs/event-emitter";
338
+
339
+ @OnEvent(FACTORY_EVENTS.SEEDER_COMPLETED)
340
+ handleSeederCompleted(event: SeederCompletedEvent) {
341
+ console.log(`Seeder ${event.seederClass} completed`);
342
+ }
343
+ ```
344
+
345
+ ## Using the Service Directly
346
+
347
+ Inject `FactoryService` for factory and seeder management:
348
+
349
+ ```typescript
350
+ import { FactoryService } from "@nestbolt/factory";
351
+
352
+ @Injectable()
353
+ export class SeedService {
354
+ constructor(private readonly factory: FactoryService) {}
355
+
356
+ async seedDatabase() {
357
+ const users = await this.factory.use(UserFactory).count(10).createMany();
358
+ const faker = this.factory.getFaker();
359
+ await this.factory.seed();
360
+ }
361
+ }
362
+ ```
363
+
364
+ | Method | Returns | Description |
365
+ |--------|---------|-------------|
366
+ | `use(FactoryClass)` | `FactoryBuilder<T>` | Get builder for a registered factory |
367
+ | `getFaker()` | `Faker` | Get the configured Faker instance |
368
+ | `seed()` | `Promise<void>` | Run all registered seeders (sorted by order) |
369
+ | `runSeeder(SeederClass)` | `Promise<void>` | Run a single seeder |
370
+ | `getOptions()` | `FactoryModuleOptions` | Get module configuration |
371
+
372
+ ## Configuration Options
373
+
374
+ | Option | Type | Default | Description |
375
+ |--------|------|---------|-------------|
376
+ | `factories` | `FactoryClass[]` | `[]` | Factory classes to register |
377
+ | `seeders` | `SeederClass[]` | `[]` | Seeder classes to register |
378
+ | `seed` | `number` | `undefined` | Faker seed for reproducible data |
379
+
380
+ ## Testing
381
+
382
+ ```bash
383
+ npm test
384
+ ```
385
+
386
+ Run tests in watch mode:
387
+
388
+ ```bash
389
+ npm run test:watch
390
+ ```
391
+
392
+ Generate coverage report:
393
+
394
+ ```bash
395
+ npm run test:cov
396
+ ```
397
+
398
+ ## Changelog
399
+
400
+ Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.
401
+
402
+ ## Contributing
403
+
404
+ Please see [CONTRIBUTING](CONTRIBUTING.md) for details.
405
+
406
+ ## Security
407
+
408
+ If you discover any security-related issues, please report them via [GitHub Issues](https://github.com/nestbolt/factory/issues) with the **security** label instead of using the public issue tracker.
409
+
410
+ ## License
411
+
412
+ The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
@@ -0,0 +1,7 @@
1
+ import type { Faker } from "@faker-js/faker";
2
+ export declare abstract class BaseFactory<T> {
3
+ abstract get entity(): new () => T;
4
+ abstract definition(faker: Faker): Partial<T>;
5
+ afterCreate?(entity: T, faker: Faker): Promise<void>;
6
+ afterMake?(entity: T, faker: Faker): Promise<void>;
7
+ }
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BaseFactory = void 0;
4
+ class BaseFactory {
5
+ }
6
+ exports.BaseFactory = BaseFactory;
7
+ //# sourceMappingURL=base-factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-factory.js","sourceRoot":"","sources":["../src/base-factory.ts"],"names":[],"mappings":";;;AAEA,MAAsB,WAAW;CAMhC;AAND,kCAMC"}
@@ -0,0 +1,18 @@
1
+ export declare const FACTORY_EVENTS: {
2
+ readonly SEEDER_STARTED: "factory.seeder.started";
3
+ readonly SEEDER_COMPLETED: "factory.seeder.completed";
4
+ readonly SEED_ALL_STARTED: "factory.seed.all.started";
5
+ readonly SEED_ALL_COMPLETED: "factory.seed.all.completed";
6
+ };
7
+ export interface SeederStartedEvent {
8
+ seederClass: string;
9
+ }
10
+ export interface SeederCompletedEvent {
11
+ seederClass: string;
12
+ }
13
+ export interface SeedAllStartedEvent {
14
+ seederCount: number;
15
+ }
16
+ export interface SeedAllCompletedEvent {
17
+ seederCount: number;
18
+ }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FACTORY_EVENTS = void 0;
4
+ exports.FACTORY_EVENTS = {
5
+ SEEDER_STARTED: "factory.seeder.started",
6
+ SEEDER_COMPLETED: "factory.seeder.completed",
7
+ SEED_ALL_STARTED: "factory.seed.all.started",
8
+ SEED_ALL_COMPLETED: "factory.seed.all.completed",
9
+ };
10
+ //# sourceMappingURL=factory.events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.events.js","sourceRoot":"","sources":["../../src/events/factory.events.ts"],"names":[],"mappings":";;;AAAa,QAAA,cAAc,GAAG;IAC5B,cAAc,EAAE,wBAAwB;IACxC,gBAAgB,EAAE,0BAA0B;IAC5C,gBAAgB,EAAE,0BAA0B;IAC5C,kBAAkB,EAAE,4BAA4B;CACxC,CAAC"}
@@ -0,0 +1 @@
1
+ export { FACTORY_EVENTS, type SeederStartedEvent, type SeederCompletedEvent, type SeedAllStartedEvent, type SeedAllCompletedEvent, } from "./factory.events";
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FACTORY_EVENTS = void 0;
4
+ var factory_events_1 = require("./factory.events");
5
+ Object.defineProperty(exports, "FACTORY_EVENTS", { enumerable: true, get: function () { return factory_events_1.FACTORY_EVENTS; } });
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/events/index.ts"],"names":[],"mappings":";;;AAAA,mDAM0B;AALxB,gHAAA,cAAc,OAAA"}
@@ -0,0 +1,3 @@
1
+ export declare class FactoryNotInitializedException extends Error {
2
+ constructor();
3
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FactoryNotInitializedException = void 0;
4
+ class FactoryNotInitializedException extends Error {
5
+ constructor() {
6
+ super("FactoryService has not been initialized. Make sure FactoryModule is imported in your application.");
7
+ this.name = "FactoryNotInitializedException";
8
+ }
9
+ }
10
+ exports.FactoryNotInitializedException = FactoryNotInitializedException;
11
+ //# sourceMappingURL=factory-not-initialized.exception.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory-not-initialized.exception.js","sourceRoot":"","sources":["../../src/exceptions/factory-not-initialized.exception.ts"],"names":[],"mappings":";;;AAAA,MAAa,8BAA+B,SAAQ,KAAK;IACvD;QACE,KAAK,CACH,mGAAmG,CACpG,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,gCAAgC,CAAC;IAC/C,CAAC;CACF;AAPD,wEAOC"}
@@ -0,0 +1,3 @@
1
+ export declare class FactoryNotRegisteredException extends Error {
2
+ constructor(factoryName: string);
3
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FactoryNotRegisteredException = void 0;
4
+ class FactoryNotRegisteredException extends Error {
5
+ constructor(factoryName) {
6
+ super(`Factory "${factoryName}" is not registered. Make sure it is included in the factories array of FactoryModule.forRoot().`);
7
+ this.name = "FactoryNotRegisteredException";
8
+ }
9
+ }
10
+ exports.FactoryNotRegisteredException = FactoryNotRegisteredException;
11
+ //# sourceMappingURL=factory-not-registered.exception.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory-not-registered.exception.js","sourceRoot":"","sources":["../../src/exceptions/factory-not-registered.exception.ts"],"names":[],"mappings":";;;AAAA,MAAa,6BAA8B,SAAQ,KAAK;IACtD,YAAY,WAAmB;QAC7B,KAAK,CACH,YAAY,WAAW,kGAAkG,CAC1H,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,+BAA+B,CAAC;IAC9C,CAAC;CACF;AAPD,sEAOC"}
@@ -0,0 +1,2 @@
1
+ export { FactoryNotInitializedException } from "./factory-not-initialized.exception";
2
+ export { FactoryNotRegisteredException } from "./factory-not-registered.exception";
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FactoryNotRegisteredException = exports.FactoryNotInitializedException = void 0;
4
+ var factory_not_initialized_exception_1 = require("./factory-not-initialized.exception");
5
+ Object.defineProperty(exports, "FactoryNotInitializedException", { enumerable: true, get: function () { return factory_not_initialized_exception_1.FactoryNotInitializedException; } });
6
+ var factory_not_registered_exception_1 = require("./factory-not-registered.exception");
7
+ Object.defineProperty(exports, "FactoryNotRegisteredException", { enumerable: true, get: function () { return factory_not_registered_exception_1.FactoryNotRegisteredException; } });
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/exceptions/index.ts"],"names":[],"mappings":";;;AAAA,yFAAqF;AAA5E,mJAAA,8BAA8B,OAAA;AACvC,uFAAmF;AAA1E,iJAAA,6BAA6B,OAAA"}
@@ -0,0 +1,28 @@
1
+ import type { Faker } from "@faker-js/faker";
2
+ import type { DataSource } from "typeorm";
3
+ import type { BaseFactory } from "./base-factory";
4
+ import type { Sequence } from "./sequence";
5
+ export declare class FactoryBuilder<T> {
6
+ private readonly factory;
7
+ private readonly faker;
8
+ private readonly dataSource;
9
+ private _count;
10
+ private _states;
11
+ private _overrides;
12
+ private _sequences;
13
+ private _afterCreating;
14
+ private _afterMaking;
15
+ constructor(factory: BaseFactory<T>, faker: Faker, dataSource: DataSource | null);
16
+ count(n: number): this;
17
+ state(stateOrOverrides: string | Partial<T> | ((faker: Faker) => Partial<T>)): this;
18
+ override(overrides: Partial<T>): this;
19
+ sequence<K extends keyof T>(field: K, seq: Sequence<T[K]>): this;
20
+ afterCreating(callback: (entity: T, faker: Faker) => Promise<void>): this;
21
+ afterMaking(callback: (entity: T, faker: Faker) => Promise<void>): this;
22
+ make(): Promise<T | T[]>;
23
+ makeMany(): Promise<T[]>;
24
+ create(): Promise<T | T[]>;
25
+ createMany(): Promise<T[]>;
26
+ private buildMany;
27
+ private buildOne;
28
+ }
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FactoryBuilder = void 0;
4
+ class FactoryBuilder {
5
+ constructor(factory, faker, dataSource) {
6
+ this.factory = factory;
7
+ this.faker = faker;
8
+ this.dataSource = dataSource;
9
+ this._count = 1;
10
+ this._states = [];
11
+ this._overrides = {};
12
+ this._sequences = new Map();
13
+ this._afterCreating = [];
14
+ this._afterMaking = [];
15
+ }
16
+ count(n) {
17
+ this._count = n;
18
+ return this;
19
+ }
20
+ state(stateOrOverrides) {
21
+ this._states.push(stateOrOverrides);
22
+ return this;
23
+ }
24
+ override(overrides) {
25
+ this._overrides = { ...this._overrides, ...overrides };
26
+ return this;
27
+ }
28
+ sequence(field, seq) {
29
+ this._sequences.set(field, seq);
30
+ return this;
31
+ }
32
+ afterCreating(callback) {
33
+ this._afterCreating.push(callback);
34
+ return this;
35
+ }
36
+ afterMaking(callback) {
37
+ this._afterMaking.push(callback);
38
+ return this;
39
+ }
40
+ async make() {
41
+ const results = await this.buildMany(false);
42
+ return this._count === 1 ? results[0] : results;
43
+ }
44
+ async makeMany() {
45
+ return this.buildMany(false);
46
+ }
47
+ async create() {
48
+ const results = await this.buildMany(true);
49
+ return this._count === 1 ? results[0] : results;
50
+ }
51
+ async createMany() {
52
+ return this.buildMany(true);
53
+ }
54
+ async buildMany(persist) {
55
+ const results = [];
56
+ for (let i = 0; i < this._count; i++) {
57
+ const entity = await this.buildOne(persist);
58
+ results.push(entity);
59
+ }
60
+ return results;
61
+ }
62
+ async buildOne(persist) {
63
+ let attrs = { ...this.factory.definition(this.faker) };
64
+ for (const s of this._states) {
65
+ if (typeof s === "string") {
66
+ const method = this.factory[s];
67
+ if (typeof method === "function") {
68
+ attrs = { ...attrs, ...method.call(this.factory) };
69
+ }
70
+ }
71
+ else if (typeof s === "function") {
72
+ attrs = { ...attrs, ...s(this.faker) };
73
+ }
74
+ else {
75
+ attrs = { ...attrs, ...s };
76
+ }
77
+ }
78
+ for (const [field, seq] of this._sequences) {
79
+ attrs[field] = seq.next();
80
+ }
81
+ attrs = { ...attrs, ...this._overrides };
82
+ const EntityClass = this.factory.entity;
83
+ const entity = Object.assign(new EntityClass(), attrs);
84
+ if (this.factory.afterMake) {
85
+ await this.factory.afterMake(entity, this.faker);
86
+ }
87
+ for (const cb of this._afterMaking) {
88
+ await cb(entity, this.faker);
89
+ }
90
+ if (persist) {
91
+ if (!this.dataSource) {
92
+ throw new Error("DataSource is not available. Cannot persist entities without a database connection.");
93
+ }
94
+ const repo = this.dataSource.getRepository(EntityClass);
95
+ const saved = await repo.save(entity);
96
+ Object.assign(entity, saved);
97
+ if (this.factory.afterCreate) {
98
+ await this.factory.afterCreate(entity, this.faker);
99
+ }
100
+ for (const cb of this._afterCreating) {
101
+ await cb(entity, this.faker);
102
+ }
103
+ }
104
+ return entity;
105
+ }
106
+ }
107
+ exports.FactoryBuilder = FactoryBuilder;
108
+ //# sourceMappingURL=factory-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory-builder.js","sourceRoot":"","sources":["../src/factory-builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare const FACTORY_OPTIONS = "FACTORY_OPTIONS";
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FACTORY_OPTIONS = void 0;
4
+ exports.FACTORY_OPTIONS = "FACTORY_OPTIONS";
5
+ //# sourceMappingURL=factory.constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.constants.js","sourceRoot":"","sources":["../src/factory.constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,eAAe,GAAG,iBAAiB,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { DynamicModule } from "@nestjs/common";
2
+ import type { FactoryModuleOptions, FactoryAsyncOptions } from "./interfaces";
3
+ export declare class FactoryModule {
4
+ static forRoot(options?: FactoryModuleOptions): DynamicModule;
5
+ static forRootAsync(asyncOptions: FactoryAsyncOptions): DynamicModule;
6
+ }
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var FactoryModule_1;
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.FactoryModule = void 0;
11
+ const common_1 = require("@nestjs/common");
12
+ const factory_constants_1 = require("./factory.constants");
13
+ const factory_service_1 = require("./factory.service");
14
+ let FactoryModule = FactoryModule_1 = class FactoryModule {
15
+ static forRoot(options = {}) {
16
+ const providers = [
17
+ { provide: factory_constants_1.FACTORY_OPTIONS, useValue: options },
18
+ factory_service_1.FactoryService,
19
+ ];
20
+ return {
21
+ module: FactoryModule_1,
22
+ global: true,
23
+ providers,
24
+ exports: [factory_service_1.FactoryService, factory_constants_1.FACTORY_OPTIONS],
25
+ };
26
+ }
27
+ static forRootAsync(asyncOptions) {
28
+ const providers = [
29
+ {
30
+ provide: factory_constants_1.FACTORY_OPTIONS,
31
+ useFactory: asyncOptions.useFactory,
32
+ inject: asyncOptions.inject ?? [],
33
+ },
34
+ factory_service_1.FactoryService,
35
+ ];
36
+ return {
37
+ module: FactoryModule_1,
38
+ global: true,
39
+ imports: [...(asyncOptions.imports ?? [])],
40
+ providers,
41
+ exports: [factory_service_1.FactoryService, factory_constants_1.FACTORY_OPTIONS],
42
+ };
43
+ }
44
+ };
45
+ exports.FactoryModule = FactoryModule;
46
+ exports.FactoryModule = FactoryModule = FactoryModule_1 = __decorate([
47
+ (0, common_1.Module)({})
48
+ ], FactoryModule);
49
+ //# sourceMappingURL=factory.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.module.js","sourceRoot":"","sources":["../src/factory.module.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2CAAsE;AACtE,2DAAsD;AACtD,uDAAmD;AAI5C,IAAM,aAAa,qBAAnB,MAAM,aAAa;IACxB,MAAM,CAAC,OAAO,CAAC,UAAgC,EAAE;QAC/C,MAAM,SAAS,GAAe;YAC5B,EAAE,OAAO,EAAE,mCAAe,EAAE,QAAQ,EAAE,OAAO,EAAE;YAC/C,gCAAc;SACf,CAAC;QAEF,OAAO;YACL,MAAM,EAAE,eAAa;YACrB,MAAM,EAAE,IAAI;YACZ,SAAS;YACT,OAAO,EAAE,CAAC,gCAAc,EAAE,mCAAe,CAAC;SAC3C,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,YAAY,CAAC,YAAiC;QACnD,MAAM,SAAS,GAAe;YAC5B;gBACE,OAAO,EAAE,mCAAe;gBACxB,UAAU,EAAE,YAAY,CAAC,UAAW;gBACpC,MAAM,EAAE,YAAY,CAAC,MAAM,IAAI,EAAE;aAClC;YACD,gCAAc;SACf,CAAC;QAEF,OAAO;YACL,MAAM,EAAE,eAAa;YACrB,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;YAC1C,SAAS;YACT,OAAO,EAAE,CAAC,gCAAc,EAAE,mCAAe,CAAC;SAC3C,CAAC;IACJ,CAAC;CACF,CAAA;AAjCY,sCAAa;wBAAb,aAAa;IADzB,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,aAAa,CAiCzB"}
@@ -0,0 +1,28 @@
1
+ import { OnModuleDestroy, OnModuleInit } from "@nestjs/common";
2
+ import { DataSource } from "typeorm";
3
+ import { Faker } from "@faker-js/faker";
4
+ import { FactoryBuilder } from "./factory-builder";
5
+ import type { FactoryModuleOptions, FactoryClass, SeederClass } from "./interfaces";
6
+ interface EventEmitterLike {
7
+ emit(event: string, ...args: any[]): boolean;
8
+ }
9
+ export declare class FactoryService implements OnModuleInit, OnModuleDestroy {
10
+ private readonly options;
11
+ private readonly dataSource?;
12
+ private readonly eventEmitter?;
13
+ private static instance;
14
+ private readonly logger;
15
+ private readonly factoryInstances;
16
+ private _faker;
17
+ constructor(options: FactoryModuleOptions, dataSource?: DataSource | undefined, eventEmitter?: EventEmitterLike | undefined);
18
+ onModuleInit(): void;
19
+ onModuleDestroy(): void;
20
+ static getInstance(): FactoryService | null;
21
+ getOptions(): FactoryModuleOptions;
22
+ getFaker(): Faker;
23
+ use<T>(factoryClass: FactoryClass<T>): FactoryBuilder<T>;
24
+ seed(): Promise<void>;
25
+ runSeeder(seederClass: SeederClass): Promise<void>;
26
+ private emit;
27
+ }
28
+ export {};
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ var FactoryService_1;
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.FactoryService = void 0;
17
+ const common_1 = require("@nestjs/common");
18
+ const typeorm_1 = require("typeorm");
19
+ const faker_1 = require("@faker-js/faker");
20
+ const factory_constants_1 = require("./factory.constants");
21
+ const factory_events_1 = require("./events/factory.events");
22
+ const factory_builder_1 = require("./factory-builder");
23
+ const factory_not_registered_exception_1 = require("./exceptions/factory-not-registered.exception");
24
+ let FactoryService = FactoryService_1 = class FactoryService {
25
+ constructor(options, dataSource, eventEmitter) {
26
+ this.options = options;
27
+ this.dataSource = dataSource;
28
+ this.eventEmitter = eventEmitter;
29
+ this.logger = new common_1.Logger(FactoryService_1.name);
30
+ this.factoryInstances = new Map();
31
+ this._faker = faker_1.faker;
32
+ if (options.seed != null) {
33
+ faker_1.faker.seed(options.seed);
34
+ }
35
+ if (options.factories) {
36
+ for (const FactoryClass of options.factories) {
37
+ const instance = new FactoryClass();
38
+ this.factoryInstances.set(FactoryClass.name, instance);
39
+ }
40
+ }
41
+ }
42
+ onModuleInit() {
43
+ FactoryService_1.instance = this;
44
+ this.logger.log("FactoryService initialized");
45
+ }
46
+ onModuleDestroy() {
47
+ if (FactoryService_1.instance === this) {
48
+ FactoryService_1.instance = null;
49
+ }
50
+ }
51
+ static getInstance() {
52
+ return FactoryService_1.instance;
53
+ }
54
+ getOptions() {
55
+ return this.options;
56
+ }
57
+ getFaker() {
58
+ return this._faker;
59
+ }
60
+ use(factoryClass) {
61
+ const instance = this.factoryInstances.get(factoryClass.name);
62
+ if (!instance) {
63
+ throw new factory_not_registered_exception_1.FactoryNotRegisteredException(factoryClass.name);
64
+ }
65
+ return new factory_builder_1.FactoryBuilder(instance, this._faker, this.dataSource ?? null);
66
+ }
67
+ async seed() {
68
+ const seeders = this.options.seeders ?? [];
69
+ this.emit(factory_events_1.FACTORY_EVENTS.SEED_ALL_STARTED, { seederCount: seeders.length });
70
+ const sorted = [...seeders].sort((a, b) => {
71
+ const orderA = new a().order ?? 0;
72
+ const orderB = new b().order ?? 0;
73
+ return orderA - orderB;
74
+ });
75
+ for (const SeederClass of sorted) {
76
+ await this.runSeeder(SeederClass);
77
+ }
78
+ this.emit(factory_events_1.FACTORY_EVENTS.SEED_ALL_COMPLETED, { seederCount: seeders.length });
79
+ }
80
+ async runSeeder(seederClass) {
81
+ const seeder = new seederClass();
82
+ const name = seederClass.name;
83
+ this.logger.log(`Running seeder: ${name}`);
84
+ this.emit(factory_events_1.FACTORY_EVENTS.SEEDER_STARTED, { seederClass: name });
85
+ await seeder.run(this);
86
+ this.logger.log(`Completed seeder: ${name}`);
87
+ this.emit(factory_events_1.FACTORY_EVENTS.SEEDER_COMPLETED, { seederClass: name });
88
+ }
89
+ emit(event, payload) {
90
+ if (this.eventEmitter) {
91
+ this.eventEmitter.emit(event, payload);
92
+ }
93
+ }
94
+ };
95
+ exports.FactoryService = FactoryService;
96
+ FactoryService.instance = null;
97
+ exports.FactoryService = FactoryService = FactoryService_1 = __decorate([
98
+ (0, common_1.Injectable)(),
99
+ __param(0, (0, common_1.Inject)(factory_constants_1.FACTORY_OPTIONS)),
100
+ __param(1, (0, common_1.Optional)()),
101
+ __param(2, (0, common_1.Optional)()),
102
+ __param(2, (0, common_1.Inject)("EventEmitter2")),
103
+ __metadata("design:paramtypes", [Object, typeorm_1.DataSource, Object])
104
+ ], FactoryService);
105
+ //# sourceMappingURL=factory.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.service.js","sourceRoot":"","sources":["../src/factory.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export { FactoryModule } from "./factory.module";
2
+ export { FactoryService } from "./factory.service";
3
+ export { BaseFactory } from "./base-factory";
4
+ export { FactoryBuilder } from "./factory-builder";
5
+ export { Sequence } from "./sequence";
6
+ export { FACTORY_OPTIONS } from "./factory.constants";
7
+ export { FACTORY_EVENTS, type SeederStartedEvent, type SeederCompletedEvent, type SeedAllStartedEvent, type SeedAllCompletedEvent, } from "./events";
8
+ export type { FactoryModuleOptions, FactoryAsyncOptions, FactoryClass, SeederClass, Seeder, } from "./interfaces";
9
+ export { FactoryNotInitializedException } from "./exceptions";
10
+ export { FactoryNotRegisteredException } from "./exceptions";
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FactoryNotRegisteredException = exports.FactoryNotInitializedException = exports.FACTORY_EVENTS = exports.FACTORY_OPTIONS = exports.Sequence = exports.FactoryBuilder = exports.BaseFactory = exports.FactoryService = exports.FactoryModule = void 0;
4
+ var factory_module_1 = require("./factory.module");
5
+ Object.defineProperty(exports, "FactoryModule", { enumerable: true, get: function () { return factory_module_1.FactoryModule; } });
6
+ var factory_service_1 = require("./factory.service");
7
+ Object.defineProperty(exports, "FactoryService", { enumerable: true, get: function () { return factory_service_1.FactoryService; } });
8
+ var base_factory_1 = require("./base-factory");
9
+ Object.defineProperty(exports, "BaseFactory", { enumerable: true, get: function () { return base_factory_1.BaseFactory; } });
10
+ var factory_builder_1 = require("./factory-builder");
11
+ Object.defineProperty(exports, "FactoryBuilder", { enumerable: true, get: function () { return factory_builder_1.FactoryBuilder; } });
12
+ var sequence_1 = require("./sequence");
13
+ Object.defineProperty(exports, "Sequence", { enumerable: true, get: function () { return sequence_1.Sequence; } });
14
+ var factory_constants_1 = require("./factory.constants");
15
+ Object.defineProperty(exports, "FACTORY_OPTIONS", { enumerable: true, get: function () { return factory_constants_1.FACTORY_OPTIONS; } });
16
+ var events_1 = require("./events");
17
+ Object.defineProperty(exports, "FACTORY_EVENTS", { enumerable: true, get: function () { return events_1.FACTORY_EVENTS; } });
18
+ var exceptions_1 = require("./exceptions");
19
+ Object.defineProperty(exports, "FactoryNotInitializedException", { enumerable: true, get: function () { return exceptions_1.FactoryNotInitializedException; } });
20
+ var exceptions_2 = require("./exceptions");
21
+ Object.defineProperty(exports, "FactoryNotRegisteredException", { enumerable: true, get: function () { return exceptions_2.FactoryNotRegisteredException; } });
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,mDAAiD;AAAxC,+GAAA,aAAa,OAAA;AACtB,qDAAmD;AAA1C,iHAAA,cAAc,OAAA;AACvB,+CAA6C;AAApC,2GAAA,WAAW,OAAA;AACpB,qDAAmD;AAA1C,iHAAA,cAAc,OAAA;AACvB,uCAAsC;AAA7B,oGAAA,QAAQ,OAAA;AACjB,yDAAsD;AAA7C,oHAAA,eAAe,OAAA;AACxB,mCAMkB;AALhB,wGAAA,cAAc,OAAA;AAahB,2CAA8D;AAArD,4HAAA,8BAA8B,OAAA;AACvC,2CAA6D;AAApD,2HAAA,6BAA6B,OAAA"}
@@ -0,0 +1,14 @@
1
+ import type { BaseFactory } from "../base-factory";
2
+ import type { Seeder } from "./seeder.interface";
3
+ export type FactoryClass<T = any> = new () => BaseFactory<T>;
4
+ export type SeederClass = new () => Seeder;
5
+ export interface FactoryModuleOptions {
6
+ factories?: FactoryClass[];
7
+ seeders?: SeederClass[];
8
+ seed?: number;
9
+ }
10
+ export interface FactoryAsyncOptions {
11
+ imports?: any[];
12
+ inject?: any[];
13
+ useFactory?: (...args: any[]) => Promise<FactoryModuleOptions> | FactoryModuleOptions;
14
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=factory-options.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory-options.interface.js","sourceRoot":"","sources":["../../src/interfaces/factory-options.interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export type { FactoryModuleOptions, FactoryAsyncOptions, FactoryClass, SeederClass, } from "./factory-options.interface";
2
+ export type { Seeder } from "./seeder.interface";
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/interfaces/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,5 @@
1
+ import type { FactoryService } from "../factory.service";
2
+ export interface Seeder {
3
+ order?: number;
4
+ run(factory: FactoryService): Promise<void>;
5
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=seeder.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seeder.interface.js","sourceRoot":"","sources":["../../src/interfaces/seeder.interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,10 @@
1
+ export declare class Sequence<T = any> {
2
+ private readonly callback;
3
+ private index;
4
+ constructor(callback: (index: number) => T);
5
+ static increment(start?: number): Sequence<number>;
6
+ static cycle<V>(values: V[]): Sequence<V>;
7
+ static from<V>(callback: (index: number) => V): Sequence<V>;
8
+ next(): T;
9
+ reset(): void;
10
+ }
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Sequence = void 0;
4
+ class Sequence {
5
+ constructor(callback) {
6
+ this.callback = callback;
7
+ this.index = 0;
8
+ }
9
+ static increment(start = 1) {
10
+ return new Sequence((i) => start + i);
11
+ }
12
+ static cycle(values) {
13
+ return new Sequence((i) => values[i % values.length]);
14
+ }
15
+ static from(callback) {
16
+ return new Sequence(callback);
17
+ }
18
+ next() {
19
+ return this.callback(this.index++);
20
+ }
21
+ reset() {
22
+ this.index = 0;
23
+ }
24
+ }
25
+ exports.Sequence = Sequence;
26
+ //# sourceMappingURL=sequence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sequence.js","sourceRoot":"","sources":["../src/sequence.ts"],"names":[],"mappings":";;;AAAA,MAAa,QAAQ;IAGnB,YAA6B,QAA8B;QAA9B,aAAQ,GAAR,QAAQ,CAAsB;QAFnD,UAAK,GAAG,CAAC,CAAC;IAE4C,CAAC;IAE/D,MAAM,CAAC,SAAS,CAAC,KAAK,GAAG,CAAC;QACxB,OAAO,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IACxC,CAAC;IAED,MAAM,CAAC,KAAK,CAAI,MAAW;QACzB,OAAO,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IACxD,CAAC;IAED,MAAM,CAAC,IAAI,CAAI,QAA8B;QAC3C,OAAO,IAAI,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IACrC,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;IACjB,CAAC;CACF;AAxBD,4BAwBC"}
package/package.json ADDED
@@ -0,0 +1,82 @@
1
+ {
2
+ "name": "@nestbolt/factory",
3
+ "version": "0.1.0",
4
+ "description": "Model factories and database seeders for NestJS with TypeORM.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist"
15
+ ],
16
+ "keywords": [
17
+ "nestjs",
18
+ "factory",
19
+ "factories",
20
+ "seeder",
21
+ "database-seeder",
22
+ "faker",
23
+ "test-data",
24
+ "typeorm",
25
+ "model-factory"
26
+ ],
27
+ "license": "MIT",
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/nestbolt/factory"
31
+ },
32
+ "engines": {
33
+ "node": ">=20.0.0"
34
+ },
35
+ "dependencies": {
36
+ "@faker-js/faker": "^9.0.0"
37
+ },
38
+ "peerDependencies": {
39
+ "@nestjs/common": "^10.0.0 || ^11.0.0",
40
+ "@nestjs/core": "^10.0.0 || ^11.0.0",
41
+ "@nestjs/event-emitter": "^2.0.0 || ^3.0.0",
42
+ "@nestjs/typeorm": "^10.0.0 || ^11.0.0",
43
+ "reflect-metadata": "^0.1.13 || ^0.2.0",
44
+ "typeorm": "^0.3.0"
45
+ },
46
+ "peerDependenciesMeta": {
47
+ "@nestjs/event-emitter": {
48
+ "optional": true
49
+ }
50
+ },
51
+ "devDependencies": {
52
+ "@eslint/js": "^9.0.0",
53
+ "@nestjs/common": "^11.0.0",
54
+ "@nestjs/core": "^11.0.0",
55
+ "@nestjs/testing": "^11.0.0",
56
+ "@nestjs/typeorm": "^11.0.0",
57
+ "@types/better-sqlite3": "^7.6.13",
58
+ "@types/node": "^20.0.0",
59
+ "@vitest/coverage-v8": "^4.1.0",
60
+ "better-sqlite3": "^12.8.0",
61
+ "eslint": "^9.0.0",
62
+ "eslint-config-prettier": "^10.0.0",
63
+ "eslint-plugin-prettier": "^5.0.0",
64
+ "prettier": "^3.0.0",
65
+ "reflect-metadata": "^0.2.2",
66
+ "rxjs": "^7.8.0",
67
+ "typeorm": "^0.3.0",
68
+ "typescript": "^5.5.0",
69
+ "typescript-eslint": "^8.0.0",
70
+ "vitest": "^4.1.0"
71
+ },
72
+ "scripts": {
73
+ "build": "tsc -p tsconfig.build.json",
74
+ "test": "vitest run",
75
+ "test:watch": "vitest",
76
+ "test:cov": "vitest run --coverage",
77
+ "test:results": "npx vitest run --coverage 2>&1 | grep -E \"All files|%\" | head -10",
78
+ "lint": "eslint 'src/**/*.ts' 'test/**/*.ts'",
79
+ "lint:fix": "eslint 'src/**/*.ts' 'test/**/*.ts' --fix",
80
+ "format": "prettier --write 'src/**/*.ts' 'test/**/*.ts'"
81
+ }
82
+ }