@ackplus/nest-seeder 1.1.9 → 1.1.12

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 (75) hide show
  1. package/LICENSE +22 -0
  2. package/QUICKSTART.md +213 -0
  3. package/README.md +1080 -6
  4. package/{src → dist}/cli.d.ts +0 -1
  5. package/{src → dist}/cli.js +42 -14
  6. package/dist/cli.js.map +1 -0
  7. package/{src → dist}/index.d.ts +0 -1
  8. package/dist/index.js +25 -0
  9. package/dist/index.js.map +1 -0
  10. package/{src → dist}/lib/decorators/factory.decorator.d.ts +0 -1
  11. package/{src → dist}/lib/decorators/factory.decorator.js +1 -0
  12. package/dist/lib/decorators/factory.decorator.js.map +1 -0
  13. package/{src → dist}/lib/factory/data.factory.d.ts +0 -1
  14. package/{src → dist}/lib/factory/data.factory.js +1 -11
  15. package/dist/lib/factory/data.factory.js.map +1 -0
  16. package/{src → dist}/lib/index.d.ts +0 -1
  17. package/dist/lib/index.js +21 -0
  18. package/dist/lib/index.js.map +1 -0
  19. package/{src → dist}/lib/interfaces/factory.interface.d.ts +0 -1
  20. package/{src → dist}/lib/interfaces/factory.interface.js +1 -0
  21. package/dist/lib/interfaces/factory.interface.js.map +1 -0
  22. package/{src → dist}/lib/interfaces/index.d.ts +0 -1
  23. package/dist/lib/interfaces/index.js +19 -0
  24. package/dist/lib/interfaces/index.js.map +1 -0
  25. package/{src → dist}/lib/interfaces/property-metadata.interface.d.ts +0 -1
  26. package/{src → dist}/lib/interfaces/property-metadata.interface.js +1 -0
  27. package/dist/lib/interfaces/property-metadata.interface.js.map +1 -0
  28. package/{src → dist}/lib/interfaces/seeder-module-async-options.interface.d.ts +0 -19
  29. package/{src → dist}/lib/interfaces/seeder-module-async-options.interface.js +1 -0
  30. package/dist/lib/interfaces/seeder-module-async-options.interface.js.map +1 -0
  31. package/dist/lib/interfaces/seeder-options-factory.interface.d.ts +4 -0
  32. package/{src → dist}/lib/interfaces/seeder-options-factory.interface.js +1 -0
  33. package/dist/lib/interfaces/seeder-options-factory.interface.js.map +1 -0
  34. package/{src → dist}/lib/seeder/seeder.d.ts +0 -1
  35. package/{src → dist}/lib/seeder/seeder.interface.d.ts +0 -1
  36. package/{src → dist}/lib/seeder/seeder.interface.js +1 -0
  37. package/dist/lib/seeder/seeder.interface.js.map +1 -0
  38. package/{src → dist}/lib/seeder/seeder.js +5 -2
  39. package/dist/lib/seeder/seeder.js.map +1 -0
  40. package/{src → dist}/lib/seeder/seeder.module.d.ts +0 -1
  41. package/{src → dist}/lib/seeder/seeder.module.js +9 -3
  42. package/dist/lib/seeder/seeder.module.js.map +1 -0
  43. package/{src → dist}/lib/seeder/seeder.service.d.ts +1 -2
  44. package/{src → dist}/lib/seeder/seeder.service.js +17 -6
  45. package/dist/lib/seeder/seeder.service.js.map +1 -0
  46. package/{src → dist}/lib/storages/factory.metadata.storage.d.ts +0 -1
  47. package/{src → dist}/lib/storages/factory.metadata.storage.js +2 -3
  48. package/dist/lib/storages/factory.metadata.storage.js.map +1 -0
  49. package/dist/tsconfig.build.tsbuildinfo +1 -0
  50. package/examples/post.seeder.example.ts +65 -0
  51. package/examples/product.factory.example.ts +84 -0
  52. package/examples/seed.script.example.ts +32 -0
  53. package/examples/seeder.config.example.ts +50 -0
  54. package/examples/user.factory.example.ts +59 -0
  55. package/examples/user.seeder.example.ts +55 -0
  56. package/package.json +107 -6
  57. package/src/cli.d.ts.map +0 -1
  58. package/src/index.d.ts.map +0 -1
  59. package/src/index.js +0 -11
  60. package/src/lib/decorators/factory.decorator.d.ts.map +0 -1
  61. package/src/lib/factory/data.factory.d.ts.map +0 -1
  62. package/src/lib/index.d.ts.map +0 -1
  63. package/src/lib/index.js +0 -7
  64. package/src/lib/interfaces/factory.interface.d.ts.map +0 -1
  65. package/src/lib/interfaces/index.d.ts.map +0 -1
  66. package/src/lib/interfaces/index.js +0 -5
  67. package/src/lib/interfaces/property-metadata.interface.d.ts.map +0 -1
  68. package/src/lib/interfaces/seeder-module-async-options.interface.d.ts.map +0 -1
  69. package/src/lib/interfaces/seeder-options-factory.interface.d.ts +0 -9
  70. package/src/lib/interfaces/seeder-options-factory.interface.d.ts.map +0 -1
  71. package/src/lib/seeder/seeder.d.ts.map +0 -1
  72. package/src/lib/seeder/seeder.interface.d.ts.map +0 -1
  73. package/src/lib/seeder/seeder.module.d.ts.map +0 -1
  74. package/src/lib/seeder/seeder.service.d.ts.map +0 -1
  75. package/src/lib/storages/factory.metadata.storage.d.ts.map +0 -1
package/README.md CHANGED
@@ -1,11 +1,1085 @@
1
- # nest-auth
1
+ # @ackplus/nest-seeder
2
2
 
3
- This library was generated with [Nx](https://nx.dev).
3
+ <p align="center">
4
+ <a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="120" alt="Nest Logo" /></a>
5
+ </p>
4
6
 
5
- ## Building
7
+ A powerful and flexible database seeding library for NestJS applications with support for factories, data generation using Faker.js, and CLI commands.
6
8
 
7
- Run `nx build nest-auth` to build the library.
9
+ ## 📋 Table of Contents
8
10
 
9
- ## Running unit tests
11
+ - [Features](#-features)
12
+ - [Installation](#-installation)
13
+ - [Quick Start](#-quick-start)
14
+ - [Configuration](#-configuration)
15
+ - [Basic Setup](#basic-setup)
16
+ - [Async Configuration](#async-configuration)
17
+ - [Creating Seeders](#-creating-seeders)
18
+ - [Basic Seeder](#basic-seeder)
19
+ - [Using TypeORM](#using-typeorm)
20
+ - [Using Mongoose](#using-mongoose)
21
+ - [Using Prisma](#using-prisma)
22
+ - [Data Factories](#-data-factories)
23
+ - [Basic Factory](#basic-factory)
24
+ - [Factory with Dependencies](#factory-with-dependencies)
25
+ - [Custom Generators](#custom-generators)
26
+ - [CLI Usage](#-cli-usage)
27
+ - [Setup CLI](#setup-cli)
28
+ - [CLI Commands](#cli-commands)
29
+ - [Configuration File](#configuration-file)
30
+ - [Programmatic Usage](#-programmatic-usage)
31
+ - [Advanced Examples](#-advanced-examples)
32
+ - [API Reference](#-api-reference)
33
+ - [Publishing](#-publishing)
10
34
 
11
- Run `nx test nest-auth` to execute the unit tests via [Jest](https://jestjs.io).
35
+ ## Features
36
+
37
+ - 🎯 **Type-safe** - Full TypeScript support
38
+ - 🏭 **Factory Pattern** - Generate fake data easily with decorators
39
+ - 🎲 **Faker.js Integration** - Built-in support for realistic fake data
40
+ - 🔄 **Refresh Mode** - Drop existing data before seeding
41
+ - 🎯 **Selective Seeding** - Run specific seeders by name
42
+ - 📦 **Multiple ORMs** - Works with TypeORM, Mongoose, Prisma, and more
43
+ - 🖥️ **CLI Support** - Run seeders from command line
44
+ - ⚙️ **Flexible Configuration** - Sync and async configuration options
45
+ - 🔗 **Dependency Management** - Handle relationships between seeders
46
+
47
+ ## 📦 Installation
48
+
49
+ ```bash
50
+ # Using npm
51
+ npm install @ackplus/nest-seeder @faker-js/faker
52
+
53
+ # Using yarn
54
+ yarn add @ackplus/nest-seeder @faker-js/faker
55
+
56
+ # Using pnpm
57
+ pnpm add @ackplus/nest-seeder @faker-js/faker
58
+ ```
59
+
60
+ ### Development Dependencies
61
+
62
+ ```bash
63
+ # If using TypeScript files for seeders (recommended)
64
+ npm install -D ts-node typescript
65
+
66
+ # If using CLI
67
+ npm install -D @nestjs/cli
68
+ ```
69
+
70
+ ## 🚀 Quick Start
71
+
72
+ ### 1. Create a Factory Class
73
+
74
+ Create a factory class with the `@Factory` decorator to define how to generate fake data:
75
+
76
+ ```typescript
77
+ // src/database/factories/user.factory.ts
78
+ import { Factory } from '@ackplus/nest-seeder';
79
+
80
+ export class UserFactory {
81
+ @Factory((faker) => faker.internet.email())
82
+ email: string;
83
+
84
+ @Factory((faker) => faker.person.firstName())
85
+ firstName: string;
86
+
87
+ @Factory((faker) => faker.person.lastName())
88
+ lastName: string;
89
+
90
+ @Factory((faker) => faker.internet.password())
91
+ password: string;
92
+
93
+ @Factory((faker) => faker.datatype.boolean())
94
+ isActive: boolean;
95
+ }
96
+ ```
97
+
98
+ ### 2. Create a Seeder
99
+
100
+ Create a seeder class that implements the `Seeder` interface:
101
+
102
+ ```typescript
103
+ // src/database/seeders/user.seeder.ts
104
+ import { Injectable } from '@nestjs/common';
105
+ import { InjectRepository } from '@nestjs/typeorm';
106
+ import { Repository } from 'typeorm';
107
+ import { Seeder, SeederServiceOptions, DataFactory } from '@ackplus/nest-seeder';
108
+ import { User } from '../entities/user.entity';
109
+ import { UserFactory } from '../factories/user.factory';
110
+
111
+ @Injectable()
112
+ export class UserSeeder implements Seeder {
113
+ constructor(
114
+ @InjectRepository(User)
115
+ private readonly userRepository: Repository<User>,
116
+ ) {}
117
+
118
+ async seed(options: SeederServiceOptions): Promise<void> {
119
+ // Generate 10 fake users
120
+ const factory = DataFactory.createForClass(UserFactory);
121
+ const users = factory.generate(10);
122
+
123
+ // Save to database
124
+ await this.userRepository.save(users);
125
+ }
126
+
127
+ async drop(options: SeederServiceOptions): Promise<void> {
128
+ // Clean up - delete all users
129
+ await this.userRepository.delete({});
130
+ }
131
+ }
132
+ ```
133
+
134
+ ### 3. Register Seeder Module
135
+
136
+ ```typescript
137
+ // src/app.module.ts
138
+ import { Module } from '@nestjs/common';
139
+ import { TypeOrmModule } from '@nestjs/typeorm';
140
+ import { SeederModule } from '@ackplus/nest-seeder';
141
+ import { User } from './database/entities/user.entity';
142
+ import { UserSeeder } from './database/seeders/user.seeder';
143
+
144
+ @Module({
145
+ imports: [
146
+ TypeOrmModule.forRoot({
147
+ type: 'postgres',
148
+ host: 'localhost',
149
+ port: 5432,
150
+ username: 'postgres',
151
+ password: 'postgres',
152
+ database: 'mydb',
153
+ entities: [User],
154
+ synchronize: true,
155
+ }),
156
+ TypeOrmModule.forFeature([User]),
157
+ SeederModule.register({
158
+ seeders: [UserSeeder],
159
+ }),
160
+ ],
161
+ })
162
+ export class AppModule {}
163
+ ```
164
+
165
+ ### 4. Run the Seeder
166
+
167
+ ```typescript
168
+ // src/seed.ts
169
+ import { NestFactory } from '@nestjs/core';
170
+ import { SeederService } from '@ackplus/nest-seeder';
171
+ import { AppModule } from './app.module';
172
+
173
+ async function bootstrap() {
174
+ const app = await NestFactory.createApplicationContext(AppModule);
175
+ const seeder = app.get(SeederService);
176
+
177
+ await seeder.run();
178
+
179
+ await app.close();
180
+ }
181
+
182
+ bootstrap();
183
+ ```
184
+
185
+ Run it:
186
+ ```bash
187
+ ts-node src/seed.ts
188
+ ```
189
+
190
+ ## ⚙️ Configuration
191
+
192
+ ### Basic Setup
193
+
194
+ Register the `SeederModule` with your seeders:
195
+
196
+ ```typescript
197
+ import { SeederModule } from '@ackplus/nest-seeder';
198
+
199
+ @Module({
200
+ imports: [
201
+ SeederModule.register({
202
+ seeders: [UserSeeder, PostSeeder, CommentSeeder],
203
+ imports: [TypeOrmModule.forFeature([User, Post, Comment])],
204
+ providers: [/* additional providers */],
205
+ }),
206
+ ],
207
+ })
208
+ export class AppModule {}
209
+ ```
210
+
211
+ ### Async Configuration
212
+
213
+ For dynamic configuration (e.g., loading from ConfigService):
214
+
215
+ #### Using Factory
216
+
217
+ ```typescript
218
+ import { SeederModule } from '@ackplus/nest-seeder';
219
+ import { ConfigModule, ConfigService } from '@nestjs/config';
220
+
221
+ @Module({
222
+ imports: [
223
+ SeederModule.forRootAsync({
224
+ imports: [ConfigModule, TypeOrmModule.forFeature([User, Post])],
225
+ inject: [UserSeeder, PostSeeder],
226
+ useFactory: async (config: ConfigService) => ({
227
+ seeders: [UserSeeder, PostSeeder],
228
+ refresh: config.get('SEED_REFRESH', false),
229
+ dummyData: config.get('SEED_DUMMY_DATA', false),
230
+ }),
231
+ isGlobal: true,
232
+ }),
233
+ ],
234
+ })
235
+ export class AppModule {}
236
+ ```
237
+
238
+ #### Using Class
239
+
240
+ ```typescript
241
+ import { Injectable } from '@nestjs/common';
242
+ import { SeederOptionsFactory, SeederModuleOptions } from '@ackplus/nest-seeder';
243
+ import { ConfigService } from '@nestjs/config';
244
+
245
+ @Injectable()
246
+ export class SeederConfigService implements SeederOptionsFactory {
247
+ constructor(private configService: ConfigService) {}
248
+
249
+ createSeederOptions(): SeederModuleOptions {
250
+ return {
251
+ seeders: [UserSeeder, PostSeeder],
252
+ refresh: this.configService.get('SEED_REFRESH', false),
253
+ };
254
+ }
255
+ }
256
+
257
+ @Module({
258
+ imports: [
259
+ SeederModule.forRootAsync({
260
+ imports: [ConfigModule],
261
+ useClass: SeederConfigService,
262
+ isGlobal: true,
263
+ }),
264
+ ],
265
+ })
266
+ export class AppModule {}
267
+ ```
268
+
269
+ ## 🌱 Creating Seeders
270
+
271
+ ### Basic Seeder
272
+
273
+ Every seeder must implement the `Seeder` interface with `seed()` and `drop()` methods:
274
+
275
+ ```typescript
276
+ import { Injectable } from '@nestjs/common';
277
+ import { Seeder, SeederServiceOptions } from '@ackplus/nest-seeder';
278
+
279
+ @Injectable()
280
+ export class BasicSeeder implements Seeder {
281
+ async seed(options: SeederServiceOptions): Promise<void> {
282
+ console.log('Seeding data...');
283
+ // Your seeding logic here
284
+ }
285
+
286
+ async drop(options: SeederServiceOptions): Promise<void> {
287
+ console.log('Dropping data...');
288
+ // Your cleanup logic here
289
+ }
290
+ }
291
+ ```
292
+
293
+ ### Using TypeORM
294
+
295
+ ```typescript
296
+ import { Injectable } from '@nestjs/common';
297
+ import { InjectRepository } from '@nestjs/typeorm';
298
+ import { Repository } from 'typeorm';
299
+ import { Seeder, SeederServiceOptions, DataFactory } from '@ackplus/nest-seeder';
300
+ import { User } from '../entities/user.entity';
301
+ import { UserFactory } from '../factories/user.factory';
302
+
303
+ @Injectable()
304
+ export class UserSeeder implements Seeder {
305
+ constructor(
306
+ @InjectRepository(User)
307
+ private readonly userRepository: Repository<User>,
308
+ ) {}
309
+
310
+ async seed(options: SeederServiceOptions): Promise<void> {
311
+ const factory = DataFactory.createForClass(UserFactory);
312
+
313
+ // Generate different amounts based on options
314
+ const count = options.dummyData ? 100 : 10;
315
+ const users = factory.generate(count);
316
+
317
+ // Insert in batches for better performance
318
+ const batchSize = 50;
319
+ for (let i = 0; i < users.length; i += batchSize) {
320
+ const batch = users.slice(i, i + batchSize);
321
+ await this.userRepository.save(batch);
322
+ }
323
+
324
+ console.log(`✅ Seeded ${users.length} users`);
325
+ }
326
+
327
+ async drop(options: SeederServiceOptions): Promise<void> {
328
+ await this.userRepository.delete({});
329
+ console.log('✅ Dropped all users');
330
+ }
331
+ }
332
+ ```
333
+
334
+ ### Using Mongoose
335
+
336
+ ```typescript
337
+ import { Injectable } from '@nestjs/common';
338
+ import { InjectModel } from '@nestjs/mongoose';
339
+ import { Model } from 'mongoose';
340
+ import { Seeder, SeederServiceOptions, DataFactory } from '@ackplus/nest-seeder';
341
+ import { User, UserDocument } from '../schemas/user.schema';
342
+ import { UserFactory } from '../factories/user.factory';
343
+
344
+ @Injectable()
345
+ export class UserSeeder implements Seeder {
346
+ constructor(
347
+ @InjectModel(User.name)
348
+ private userModel: Model<UserDocument>,
349
+ ) {}
350
+
351
+ async seed(options: SeederServiceOptions): Promise<void> {
352
+ const factory = DataFactory.createForClass(UserFactory);
353
+ const users = factory.generate(10);
354
+
355
+ await this.userModel.insertMany(users);
356
+ console.log('✅ Seeded 10 users');
357
+ }
358
+
359
+ async drop(options: SeederServiceOptions): Promise<void> {
360
+ await this.userModel.deleteMany({});
361
+ console.log('✅ Dropped all users');
362
+ }
363
+ }
364
+ ```
365
+
366
+ ### Using Prisma
367
+
368
+ ```typescript
369
+ import { Injectable } from '@nestjs/common';
370
+ import { Seeder, SeederServiceOptions, DataFactory } from '@ackplus/nest-seeder';
371
+ import { PrismaService } from '../prisma.service';
372
+ import { UserFactory } from '../factories/user.factory';
373
+
374
+ @Injectable()
375
+ export class UserSeeder implements Seeder {
376
+ constructor(private readonly prisma: PrismaService) {}
377
+
378
+ async seed(options: SeederServiceOptions): Promise<void> {
379
+ const factory = DataFactory.createForClass(UserFactory);
380
+ const users = factory.generate(10);
381
+
382
+ // Use createMany for better performance
383
+ await this.prisma.user.createMany({
384
+ data: users,
385
+ skipDuplicates: true,
386
+ });
387
+
388
+ console.log('✅ Seeded 10 users');
389
+ }
390
+
391
+ async drop(options: SeederServiceOptions): Promise<void> {
392
+ await this.prisma.user.deleteMany({});
393
+ console.log('✅ Dropped all users');
394
+ }
395
+ }
396
+ ```
397
+
398
+ ### Seeder with Relationships
399
+
400
+ ```typescript
401
+ import { Injectable } from '@nestjs/common';
402
+ import { InjectRepository } from '@nestjs/typeorm';
403
+ import { Repository } from 'typeorm';
404
+ import { Seeder, SeederServiceOptions, DataFactory } from '@ackplus/nest-seeder';
405
+ import { Post } from '../entities/post.entity';
406
+ import { User } from '../entities/user.entity';
407
+ import { PostFactory } from '../factories/post.factory';
408
+
409
+ @Injectable()
410
+ export class PostSeeder implements Seeder {
411
+ constructor(
412
+ @InjectRepository(Post)
413
+ private readonly postRepository: Repository<Post>,
414
+ @InjectRepository(User)
415
+ private readonly userRepository: Repository<User>,
416
+ ) {}
417
+
418
+ async seed(options: SeederServiceOptions): Promise<void> {
419
+ // Get existing users
420
+ const users = await this.userRepository.find();
421
+
422
+ if (users.length === 0) {
423
+ console.warn('⚠️ No users found. Please run UserSeeder first.');
424
+ return;
425
+ }
426
+
427
+ const factory = DataFactory.createForClass(PostFactory);
428
+
429
+ // Generate 5 posts per user
430
+ for (const user of users) {
431
+ const posts = factory.generate(5, {
432
+ authorId: user.id,
433
+ });
434
+ await this.postRepository.save(posts);
435
+ }
436
+
437
+ console.log(`✅ Seeded ${users.length * 5} posts`);
438
+ }
439
+
440
+ async drop(options: SeederServiceOptions): Promise<void> {
441
+ await this.postRepository.delete({});
442
+ console.log('✅ Dropped all posts');
443
+ }
444
+ }
445
+ ```
446
+
447
+ ## 🏭 Data Factories
448
+
449
+ ### Basic Factory
450
+
451
+ Use the `@Factory` decorator to define how each property should be generated:
452
+
453
+ ```typescript
454
+ import { Factory } from '@ackplus/nest-seeder';
455
+
456
+ export class UserFactory {
457
+ @Factory((faker) => faker.internet.email())
458
+ email: string;
459
+
460
+ @Factory((faker) => faker.person.firstName())
461
+ firstName: string;
462
+
463
+ @Factory((faker) => faker.person.lastName())
464
+ lastName: string;
465
+
466
+ @Factory((faker) => faker.internet.password({ length: 10 }))
467
+ password: string;
468
+
469
+ @Factory((faker) => faker.datatype.boolean())
470
+ isActive: boolean;
471
+
472
+ @Factory((faker) => faker.date.past())
473
+ createdAt: Date;
474
+ }
475
+ ```
476
+
477
+ ### Static Values
478
+
479
+ You can also provide static values instead of generators:
480
+
481
+ ```typescript
482
+ export class AdminFactory {
483
+ @Factory('admin')
484
+ role: string;
485
+
486
+ @Factory(true)
487
+ isActive: boolean;
488
+
489
+ @Factory((faker) => faker.internet.email())
490
+ email: string;
491
+ }
492
+ ```
493
+
494
+ ### Factory with Dependencies
495
+
496
+ Use the second parameter to specify dependencies between properties:
497
+
498
+ ```typescript
499
+ export class UserFactory {
500
+ @Factory((faker) => faker.person.firstName())
501
+ firstName: string;
502
+
503
+ @Factory((faker) => faker.person.lastName())
504
+ lastName: string;
505
+
506
+ // This field depends on firstName and lastName
507
+ @Factory((faker, ctx) => {
508
+ return `${ctx.firstName}.${ctx.lastName}@example.com`.toLowerCase();
509
+ }, ['firstName', 'lastName'])
510
+ email: string;
511
+
512
+ // This field depends on firstName and lastName
513
+ @Factory((faker, ctx) => {
514
+ return `${ctx.firstName} ${ctx.lastName}`;
515
+ }, ['firstName', 'lastName'])
516
+ fullName: string;
517
+ }
518
+ ```
519
+
520
+ ### Custom Generators
521
+
522
+ Create complex data with custom generator functions:
523
+
524
+ ```typescript
525
+ export class ProductFactory {
526
+ @Factory((faker) => faker.commerce.productName())
527
+ name: string;
528
+
529
+ @Factory((faker) => faker.commerce.productDescription())
530
+ description: string;
531
+
532
+ @Factory((faker) => parseFloat(faker.commerce.price()))
533
+ price: number;
534
+
535
+ @Factory((faker) => faker.number.int({ min: 0, max: 1000 }))
536
+ stock: number;
537
+
538
+ @Factory((faker) => faker.helpers.arrayElement(['electronics', 'clothing', 'food', 'books']))
539
+ category: string;
540
+
541
+ @Factory((faker) => {
542
+ return {
543
+ weight: faker.number.float({ min: 0.1, max: 100, precision: 0.1 }),
544
+ dimensions: {
545
+ width: faker.number.int({ min: 1, max: 100 }),
546
+ height: faker.number.int({ min: 1, max: 100 }),
547
+ depth: faker.number.int({ min: 1, max: 100 }),
548
+ },
549
+ };
550
+ })
551
+ metadata: object;
552
+
553
+ @Factory((faker) => faker.helpers.arrayElements(['red', 'blue', 'green', 'yellow'], { min: 1, max: 3 }))
554
+ colors: string[];
555
+ }
556
+ ```
557
+
558
+ ### Using Factories
559
+
560
+ ```typescript
561
+ import { DataFactory } from '@ackplus/nest-seeder';
562
+ import { UserFactory } from './user.factory';
563
+
564
+ // Create a factory
565
+ const factory = DataFactory.createForClass(UserFactory);
566
+
567
+ // Generate single object
568
+ const user = factory.generate(1)[0];
569
+
570
+ // Generate multiple objects
571
+ const users = factory.generate(10);
572
+
573
+ // Generate with custom values (override factory defaults)
574
+ const admins = factory.generate(5, {
575
+ role: 'admin',
576
+ isActive: true,
577
+ });
578
+
579
+ // Mix of factory-generated and custom values
580
+ const users = factory.generate(3, {
581
+ isActive: true, // Override this field
582
+ // Other fields will be generated by factory
583
+ });
584
+ ```
585
+
586
+ ## 🖥️ CLI Usage
587
+
588
+ ### Setup CLI
589
+
590
+ #### 1. Install CLI dependencies
591
+
592
+ ```bash
593
+ npm install -D ts-node typescript
594
+ ```
595
+
596
+ #### 2. Add CLI script to package.json
597
+
598
+ ```json
599
+ {
600
+ "scripts": {
601
+ "seed": "nest-seed -c ./src/database/seeder.config.ts",
602
+ "seed:refresh": "nest-seed -c ./src/database/seeder.config.ts --refresh",
603
+ "seed:user": "nest-seed -c ./src/database/seeder.config.ts --name UserSeeder"
604
+ }
605
+ }
606
+ ```
607
+
608
+ #### 3. Create a configuration file
609
+
610
+ ```typescript
611
+ // src/database/seeder.config.ts
612
+ import { TypeOrmModule } from '@nestjs/typeorm';
613
+ import { User } from './entities/user.entity';
614
+ import { Post } from './entities/post.entity';
615
+ import { UserSeeder } from './seeders/user.seeder';
616
+ import { PostSeeder } from './seeders/post.seeder';
617
+
618
+ export default {
619
+ imports: [
620
+ TypeOrmModule.forRoot({
621
+ type: 'postgres',
622
+ host: 'localhost',
623
+ port: 5432,
624
+ username: 'postgres',
625
+ password: 'postgres',
626
+ database: 'mydb',
627
+ entities: [User, Post],
628
+ synchronize: true,
629
+ }),
630
+ TypeOrmModule.forFeature([User, Post]),
631
+ ],
632
+ seeders: [UserSeeder, PostSeeder],
633
+ };
634
+ ```
635
+
636
+ ### CLI Commands
637
+
638
+ #### Run all seeders
639
+
640
+ ```bash
641
+ npm run seed
642
+ # or
643
+ nest-seed -c ./src/database/seeder.config.ts
644
+ ```
645
+
646
+ #### Refresh mode (drop and reseed)
647
+
648
+ ```bash
649
+ npm run seed:refresh
650
+ # or
651
+ nest-seed -c ./src/database/seeder.config.ts --refresh
652
+ # or short form
653
+ nest-seed -c ./src/database/seeder.config.ts -r
654
+ ```
655
+
656
+ #### Run specific seeder(s)
657
+
658
+ ```bash
659
+ # Single seeder
660
+ nest-seed -c ./src/database/seeder.config.ts --name UserSeeder
661
+ # or short form
662
+ nest-seed -c ./src/database/seeder.config.ts -n UserSeeder
663
+
664
+ # Multiple seeders
665
+ nest-seed -c ./src/database/seeder.config.ts -n UserSeeder -n PostSeeder
666
+ ```
667
+
668
+ #### With dummy data flag
669
+
670
+ ```bash
671
+ nest-seed -c ./src/database/seeder.config.ts --dummyData
672
+ # or short form
673
+ nest-seed -c ./src/database/seeder.config.ts -d
674
+ ```
675
+
676
+ #### Combined options
677
+
678
+ ```bash
679
+ # Refresh and run specific seeder with dummy data
680
+ nest-seed -c ./src/database/seeder.config.ts -r -n UserSeeder -d
681
+ ```
682
+
683
+ ### CLI Help
684
+
685
+ ```bash
686
+ nest-seed --help
687
+ ```
688
+
689
+ Output:
690
+ ```
691
+ Options:
692
+ --help Show help [boolean]
693
+ --version Show version number [boolean]
694
+ --config, -c Path to seeder configuration file [required]
695
+ --refresh, -r Drop all data before seeding [boolean] [default: false]
696
+ --name, -n Specific seeder names to run [array]
697
+ --dummyData, -d Include dummy data [boolean] [default: false]
698
+
699
+ Examples:
700
+ nest-seed -c ./seeder.config.ts Run all seeders
701
+ nest-seed -c ./seeder.config.ts --refresh Drop and reseed all data
702
+ nest-seed -c ./seeder.config.ts --name UserSeeder Run specific seeder
703
+ ```
704
+
705
+ ### Configuration File
706
+
707
+ The configuration file should export a default object with the following structure:
708
+
709
+ ```typescript
710
+ // seeder.config.ts
711
+ import { SeederModuleOptions } from '@ackplus/nest-seeder';
712
+
713
+ const config: SeederModuleOptions = {
714
+ // Required: Array of seeder providers
715
+ seeders: [UserSeeder, PostSeeder, CommentSeeder],
716
+
717
+ // Optional: Modules to import (e.g., TypeORM, Mongoose)
718
+ imports: [
719
+ TypeOrmModule.forRoot({ /* ... */ }),
720
+ TypeOrmModule.forFeature([User, Post, Comment]),
721
+ ],
722
+
723
+ // Optional: Additional providers
724
+ providers: [PrismaService, CustomService],
725
+ };
726
+
727
+ export default config;
728
+ ```
729
+
730
+ ## 📝 Programmatic Usage
731
+
732
+ ### Using Seeder Function
733
+
734
+ ```typescript
735
+ // src/seed.ts
736
+ import { seeder } from '@ackplus/nest-seeder';
737
+ import { TypeOrmModule } from '@nestjs/typeorm';
738
+ import { User } from './entities/user.entity';
739
+ import { UserSeeder } from './seeders/user.seeder';
740
+
741
+ seeder({
742
+ imports: [
743
+ TypeOrmModule.forRoot({
744
+ type: 'postgres',
745
+ host: 'localhost',
746
+ port: 5432,
747
+ username: 'postgres',
748
+ password: 'postgres',
749
+ database: 'mydb',
750
+ entities: [User],
751
+ synchronize: true,
752
+ }),
753
+ TypeOrmModule.forFeature([User]),
754
+ ],
755
+ }).run({
756
+ seeders: [UserSeeder],
757
+ });
758
+ ```
759
+
760
+ Run with CLI arguments:
761
+ ```bash
762
+ ts-node src/seed.ts --refresh
763
+ ts-node src/seed.ts --name UserSeeder
764
+ ts-node src/seed.ts -r -n UserSeeder -d
765
+ ```
766
+
767
+ ### Using SeederService Directly
768
+
769
+ ```typescript
770
+ import { NestFactory } from '@nestjs/core';
771
+ import { SeederService } from '@ackplus/nest-seeder';
772
+ import { AppModule } from './app.module';
773
+
774
+ async function seed() {
775
+ const app = await NestFactory.createApplicationContext(AppModule);
776
+ const seeder = app.get(SeederService);
777
+
778
+ // Run all seeders
779
+ await seeder.run();
780
+
781
+ // Or just seed (without drop)
782
+ await seeder.seed();
783
+
784
+ // Or just drop
785
+ await seeder.drop();
786
+
787
+ await app.close();
788
+ }
789
+
790
+ seed();
791
+ ```
792
+
793
+ ## 🔥 Advanced Examples
794
+
795
+ ### Conditional Seeding
796
+
797
+ ```typescript
798
+ @Injectable()
799
+ export class UserSeeder implements Seeder {
800
+ constructor(
801
+ @InjectRepository(User)
802
+ private readonly userRepository: Repository<User>,
803
+ ) {}
804
+
805
+ async seed(options: SeederServiceOptions): Promise<void> {
806
+ // Check if data already exists
807
+ const count = await this.userRepository.count();
808
+ if (count > 0 && !options.refresh) {
809
+ console.log('⏭️ Users already exist, skipping...');
810
+ return;
811
+ }
812
+
813
+ const factory = DataFactory.createForClass(UserFactory);
814
+
815
+ // Different amounts based on environment
816
+ const count = process.env.NODE_ENV === 'production' ? 10 : 100;
817
+ const users = factory.generate(count);
818
+
819
+ await this.userRepository.save(users);
820
+ console.log(`✅ Seeded ${users.length} users`);
821
+ }
822
+
823
+ async drop(options: SeederServiceOptions): Promise<void> {
824
+ await this.userRepository.delete({});
825
+ }
826
+ }
827
+ ```
828
+
829
+ ### Seeding with External Data
830
+
831
+ ```typescript
832
+ @Injectable()
833
+ export class CountrySeeder implements Seeder {
834
+ async seed(options: SeederServiceOptions): Promise<void> {
835
+ const countries = [
836
+ { code: 'US', name: 'United States' },
837
+ { code: 'GB', name: 'United Kingdom' },
838
+ { code: 'CA', name: 'Canada' },
839
+ // ... more countries
840
+ ];
841
+
842
+ await this.countryRepository.save(countries);
843
+ console.log(`✅ Seeded ${countries.length} countries`);
844
+ }
845
+
846
+ async drop(options: SeederServiceOptions): Promise<void> {
847
+ await this.countryRepository.delete({});
848
+ }
849
+ }
850
+ ```
851
+
852
+ ### Seeding from JSON File
853
+
854
+ ```typescript
855
+ import * as fs from 'fs';
856
+ import * as path from 'path';
857
+
858
+ @Injectable()
859
+ export class ProductSeeder implements Seeder {
860
+ async seed(options: SeederServiceOptions): Promise<void> {
861
+ const filePath = path.join(__dirname, '../data/products.json');
862
+ const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
863
+
864
+ await this.productRepository.save(data);
865
+ console.log(`✅ Seeded ${data.length} products from file`);
866
+ }
867
+
868
+ async drop(options: SeederServiceOptions): Promise<void> {
869
+ await this.productRepository.delete({});
870
+ }
871
+ }
872
+ ```
873
+
874
+ ### Transaction Support
875
+
876
+ ```typescript
877
+ @Injectable()
878
+ export class UserSeeder implements Seeder {
879
+ constructor(
880
+ @InjectRepository(User)
881
+ private readonly userRepository: Repository<User>,
882
+ private readonly dataSource: DataSource,
883
+ ) {}
884
+
885
+ async seed(options: SeederServiceOptions): Promise<void> {
886
+ const queryRunner = this.dataSource.createQueryRunner();
887
+ await queryRunner.connect();
888
+ await queryRunner.startTransaction();
889
+
890
+ try {
891
+ const factory = DataFactory.createForClass(UserFactory);
892
+ const users = factory.generate(10);
893
+
894
+ await queryRunner.manager.save(users);
895
+ await queryRunner.commitTransaction();
896
+
897
+ console.log('✅ Seeded 10 users');
898
+ } catch (error) {
899
+ await queryRunner.rollbackTransaction();
900
+ throw error;
901
+ } finally {
902
+ await queryRunner.release();
903
+ }
904
+ }
905
+
906
+ async drop(options: SeederServiceOptions): Promise<void> {
907
+ await this.userRepository.delete({});
908
+ }
909
+ }
910
+ ```
911
+
912
+ ### Multi-tenant Seeding
913
+
914
+ ```typescript
915
+ @Injectable()
916
+ export class TenantSeeder implements Seeder {
917
+ constructor(
918
+ @InjectRepository(Tenant)
919
+ private readonly tenantRepository: Repository<Tenant>,
920
+ @InjectRepository(User)
921
+ private readonly userRepository: Repository<User>,
922
+ ) {}
923
+
924
+ async seed(options: SeederServiceOptions): Promise<void> {
925
+ const tenantFactory = DataFactory.createForClass(TenantFactory);
926
+ const tenants = tenantFactory.generate(5);
927
+ const savedTenants = await this.tenantRepository.save(tenants);
928
+
929
+ const userFactory = DataFactory.createForClass(UserFactory);
930
+
931
+ // Create users for each tenant
932
+ for (const tenant of savedTenants) {
933
+ const users = userFactory.generate(10, {
934
+ tenantId: tenant.id,
935
+ });
936
+ await this.userRepository.save(users);
937
+ }
938
+
939
+ console.log('✅ Seeded 5 tenants with 10 users each');
940
+ }
941
+
942
+ async drop(options: SeederServiceOptions): Promise<void> {
943
+ await this.userRepository.delete({});
944
+ await this.tenantRepository.delete({});
945
+ }
946
+ }
947
+ ```
948
+
949
+ ## 📚 API Reference
950
+
951
+ ### SeederModule
952
+
953
+ #### `SeederModule.register(options: SeederModuleOptions)`
954
+
955
+ Synchronously register the seeder module.
956
+
957
+ **Options:**
958
+ - `seeders`: Array of seeder providers
959
+ - `imports`: Modules to import
960
+ - `providers`: Additional providers
961
+
962
+ #### `SeederModule.forRootAsync(options: SeederModuleAsyncOptions)`
963
+
964
+ Asynchronously register the seeder module.
965
+
966
+ **Options:**
967
+ - `useFactory`: Factory function for async configuration
968
+ - `useClass`: Configuration class implementing `SeederOptionsFactory`
969
+ - `useExisting`: Existing provider for configuration
970
+ - `imports`: Modules to import
971
+ - `inject`: Dependencies to inject
972
+ - `isGlobal`: Make module global
973
+
974
+ ### Seeder Interface
975
+
976
+ ```typescript
977
+ interface Seeder {
978
+ seed(options: SeederServiceOptions): Promise<any>;
979
+ drop(options: SeederServiceOptions): Promise<any>;
980
+ }
981
+ ```
982
+
983
+ ### SeederServiceOptions
984
+
985
+ ```typescript
986
+ interface SeederServiceOptions {
987
+ name?: string | string[]; // Specific seeders to run
988
+ refresh?: boolean; // Drop before seeding
989
+ dummyData?: boolean; // Flag for conditional logic
990
+ }
991
+ ```
992
+
993
+ ### DataFactory
994
+
995
+ #### `DataFactory.createForClass<T>(target: Type<T>): Factory`
996
+
997
+ Create a factory for a class with `@Factory` decorators.
998
+
999
+ **Returns:** Factory object with `generate()` method
1000
+
1001
+ ```typescript
1002
+ interface Factory {
1003
+ generate(count: number, values?: Record<string, any>): Array<Record<string, any>>;
1004
+ }
1005
+ ```
1006
+
1007
+ ### @Factory Decorator
1008
+
1009
+ ```typescript
1010
+ @Factory(
1011
+ generator: FactoryValueGenerator | FactoryValue,
1012
+ dependsOn?: string[]
1013
+ )
1014
+ ```
1015
+
1016
+ **Parameters:**
1017
+ - `generator`: Function `(faker, ctx) => value` or static value
1018
+ - `dependsOn`: Array of property names this field depends on
1019
+
1020
+ ### SeederService
1021
+
1022
+ #### Methods
1023
+
1024
+ - `run()`: Execute seed or drop+seed based on options
1025
+ - `seed()`: Run seed method on all seeders
1026
+ - `drop()`: Run drop method on all seeders
1027
+ - `getSeederToRun()`: Get list of seeders to run based on options
1028
+
1029
+ ## 📦 Publishing
1030
+
1031
+ This package uses automated GitHub Actions for publishing.
1032
+
1033
+ ### Using CLI Script
1034
+
1035
+ ```bash
1036
+ # Patch version (0.0.1 -> 0.0.2)
1037
+ npm run publish:patch
1038
+
1039
+ # Minor version (0.0.1 -> 0.1.0)
1040
+ npm run publish:minor
1041
+
1042
+ # Major version (0.0.1 -> 1.0.0)
1043
+ npm run publish:major
1044
+ ```
1045
+
1046
+ The script will:
1047
+ 1. Update package version
1048
+ 2. Create git tag
1049
+ 3. Ask to push to remote (triggers GitHub Action)
1050
+ 4. Commit version change
1051
+
1052
+ ### Manual Publishing
1053
+
1054
+ ```bash
1055
+ # Create and push a tag
1056
+ git tag v1.0.0
1057
+ git push origin v1.0.0
1058
+
1059
+ # GitHub Action will automatically publish to npm
1060
+ ```
1061
+
1062
+ ## 🤝 Contributing
1063
+
1064
+ Contributions are welcome! Please feel free to submit a Pull Request.
1065
+
1066
+ ## 📄 License
1067
+
1068
+ This project is licensed under the MIT License.
1069
+
1070
+ ## 🙏 Acknowledgments
1071
+
1072
+ - Built with [NestJS](https://nestjs.com/)
1073
+ - Powered by [Faker.js](https://fakerjs.dev/)
1074
+ - Inspired by database seeding patterns from Laravel and other frameworks
1075
+
1076
+ ## 📮 Support
1077
+
1078
+ If you have any questions or need help, please:
1079
+ - Open an issue on GitHub
1080
+ - Check existing documentation
1081
+ - Review examples in the repository
1082
+
1083
+ ---
1084
+
1085
+ Made with ❤️ for the NestJS community