@ackplus/nest-dynamic-templates 1.1.12 → 1.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -10
- package/examples/post.seeder.example.ts +0 -65
- package/examples/product.factory.example.ts +0 -84
- package/examples/seed.script.example.ts +0 -32
- package/examples/seeder.config.example.ts +0 -50
- package/examples/user.factory.example.ts +0 -59
- package/examples/user.seeder.example.ts +0 -55
package/package.json
CHANGED
|
@@ -1,23 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ackplus/nest-dynamic-templates",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.13",
|
|
4
4
|
"description": "A powerful and flexible dynamic template rendering library for NestJS applications with support for Nunjucks, Handlebars, EJS, MJML, and more.",
|
|
5
5
|
"author": "AckPlus",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"types": "dist/index.d.ts",
|
|
9
|
-
"exports": {
|
|
10
|
-
".": {
|
|
11
|
-
"types": "./dist/index.d.ts",
|
|
12
|
-
"require": "./dist/index.js",
|
|
13
|
-
"default": "./dist/index.js"
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
9
|
"files": [
|
|
17
10
|
"dist",
|
|
18
11
|
"README.md",
|
|
19
|
-
"
|
|
20
|
-
"examples"
|
|
12
|
+
"LICENSE"
|
|
21
13
|
],
|
|
22
14
|
"keywords": [
|
|
23
15
|
"nestjs",
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
// Example: Seeder with relationships (Post depends on User)
|
|
2
|
-
import { Injectable } from '@nestjs/common';
|
|
3
|
-
import { InjectRepository } from '@nestjs/typeorm';
|
|
4
|
-
import { Repository } from 'typeorm';
|
|
5
|
-
import { Seeder, SeederServiceOptions, DataFactory } from '@ackplus/nest-dynamic-templates';
|
|
6
|
-
import { Post } from '../entities/post.entity';
|
|
7
|
-
import { User } from '../entities/user.entity';
|
|
8
|
-
import { PostFactory } from '../factories/post.factory';
|
|
9
|
-
|
|
10
|
-
@Injectable()
|
|
11
|
-
export class PostSeeder implements Seeder {
|
|
12
|
-
constructor(
|
|
13
|
-
@InjectRepository(Post)
|
|
14
|
-
private readonly postRepository: Repository<Post>,
|
|
15
|
-
@InjectRepository(User)
|
|
16
|
-
private readonly userRepository: Repository<User>,
|
|
17
|
-
) {}
|
|
18
|
-
|
|
19
|
-
async seed(options: SeederServiceOptions): Promise<void> {
|
|
20
|
-
console.log('🌱 Seeding posts...');
|
|
21
|
-
|
|
22
|
-
// Get existing users
|
|
23
|
-
const users = await this.userRepository.find();
|
|
24
|
-
|
|
25
|
-
if (users.length === 0) {
|
|
26
|
-
console.warn('⚠️ No users found. Please run UserSeeder first.');
|
|
27
|
-
console.log('💡 Run: npm run seed -- --name UserSeeder');
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Check if posts already exist
|
|
32
|
-
const existingCount = await this.postRepository.count();
|
|
33
|
-
if (existingCount > 0 && !options.refresh) {
|
|
34
|
-
console.log(`⏭️ ${existingCount} posts already exist, skipping...`);
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const factory = DataFactory.createForClass(PostFactory);
|
|
39
|
-
const postsPerUser = options.dummyData ? 10 : 3;
|
|
40
|
-
let totalPosts = 0;
|
|
41
|
-
|
|
42
|
-
// Generate posts for each user
|
|
43
|
-
for (const user of users) {
|
|
44
|
-
const posts = factory.generate(postsPerUser, {
|
|
45
|
-
authorId: user.id,
|
|
46
|
-
authorName: `${user.firstName} ${user.lastName}`,
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
await this.postRepository.save(posts);
|
|
50
|
-
totalPosts += posts.length;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
console.log(`✅ Successfully seeded ${totalPosts} posts for ${users.length} users`);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
async drop(options: SeederServiceOptions): Promise<void> {
|
|
57
|
-
console.log('🗑️ Dropping posts...');
|
|
58
|
-
|
|
59
|
-
const count = await this.postRepository.count();
|
|
60
|
-
await this.postRepository.delete({});
|
|
61
|
-
|
|
62
|
-
console.log(`✅ Dropped ${count} posts`);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
// Example: Product Factory with complex data structures
|
|
2
|
-
import { Factory } from '@ackplus/nest-dynamic-templates';
|
|
3
|
-
|
|
4
|
-
export class ProductFactory {
|
|
5
|
-
@Factory((faker) => faker.commerce.productName())
|
|
6
|
-
name: string;
|
|
7
|
-
|
|
8
|
-
@Factory((faker) => faker.commerce.productDescription())
|
|
9
|
-
description: string;
|
|
10
|
-
|
|
11
|
-
// Generate slug from name
|
|
12
|
-
@Factory((faker, ctx) => {
|
|
13
|
-
return ctx.name
|
|
14
|
-
.toLowerCase()
|
|
15
|
-
.replace(/[^a-z0-9]+/g, '-')
|
|
16
|
-
.replace(/^-|-$/g, '');
|
|
17
|
-
}, ['name'])
|
|
18
|
-
slug: string;
|
|
19
|
-
|
|
20
|
-
// Price as number
|
|
21
|
-
@Factory((faker) => parseFloat(faker.commerce.price({ min: 10, max: 1000 })))
|
|
22
|
-
price: number;
|
|
23
|
-
|
|
24
|
-
// Stock quantity
|
|
25
|
-
@Factory((faker) => faker.number.int({ min: 0, max: 1000 }))
|
|
26
|
-
stock: number;
|
|
27
|
-
|
|
28
|
-
// Category
|
|
29
|
-
@Factory((faker) => faker.helpers.arrayElement([
|
|
30
|
-
'electronics',
|
|
31
|
-
'clothing',
|
|
32
|
-
'food',
|
|
33
|
-
'books',
|
|
34
|
-
'toys',
|
|
35
|
-
'sports',
|
|
36
|
-
]))
|
|
37
|
-
category: string;
|
|
38
|
-
|
|
39
|
-
// Rating
|
|
40
|
-
@Factory((faker) => faker.number.float({ min: 1, max: 5, precision: 0.1 }))
|
|
41
|
-
rating: number;
|
|
42
|
-
|
|
43
|
-
// Image URLs array
|
|
44
|
-
@Factory((faker) => {
|
|
45
|
-
const count = faker.number.int({ min: 1, max: 5 });
|
|
46
|
-
return Array.from({ length: count }, () => faker.image.url());
|
|
47
|
-
})
|
|
48
|
-
images: string[];
|
|
49
|
-
|
|
50
|
-
// Complex metadata object
|
|
51
|
-
@Factory((faker) => ({
|
|
52
|
-
weight: faker.number.float({ min: 0.1, max: 100, precision: 0.1 }),
|
|
53
|
-
dimensions: {
|
|
54
|
-
width: faker.number.int({ min: 1, max: 100 }),
|
|
55
|
-
height: faker.number.int({ min: 1, max: 100 }),
|
|
56
|
-
depth: faker.number.int({ min: 1, max: 100 }),
|
|
57
|
-
},
|
|
58
|
-
material: faker.commerce.productMaterial(),
|
|
59
|
-
color: faker.color.human(),
|
|
60
|
-
}))
|
|
61
|
-
metadata: object;
|
|
62
|
-
|
|
63
|
-
// Tags array
|
|
64
|
-
@Factory((faker) => faker.helpers.arrayElements(
|
|
65
|
-
['new', 'sale', 'featured', 'bestseller', 'limited'],
|
|
66
|
-
{ min: 0, max: 3 }
|
|
67
|
-
))
|
|
68
|
-
tags: string[];
|
|
69
|
-
|
|
70
|
-
// Boolean flags
|
|
71
|
-
@Factory((faker) => faker.datatype.boolean())
|
|
72
|
-
isActive: boolean;
|
|
73
|
-
|
|
74
|
-
@Factory((faker) => faker.datatype.boolean())
|
|
75
|
-
isFeatured: boolean;
|
|
76
|
-
|
|
77
|
-
// Dates
|
|
78
|
-
@Factory((faker) => faker.date.past())
|
|
79
|
-
createdAt: Date;
|
|
80
|
-
|
|
81
|
-
@Factory((faker) => faker.date.recent())
|
|
82
|
-
updatedAt: Date;
|
|
83
|
-
}
|
|
84
|
-
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
// Example: Programmatic seeding script
|
|
2
|
-
import { NestFactory } from '@nestjs/core';
|
|
3
|
-
import { SeederService } from '@ackplus/nest-dynamic-templates';
|
|
4
|
-
import { AppModule } from './app.module';
|
|
5
|
-
|
|
6
|
-
async function bootstrap() {
|
|
7
|
-
console.log('🚀 Starting database seeding...\n');
|
|
8
|
-
|
|
9
|
-
// Create NestJS application context
|
|
10
|
-
const app = await NestFactory.createApplicationContext(AppModule, {
|
|
11
|
-
logger: ['error', 'warn'],
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
try {
|
|
15
|
-
// Get the seeder service
|
|
16
|
-
const seeder = app.get(SeederService);
|
|
17
|
-
|
|
18
|
-
// Run all seeders
|
|
19
|
-
await seeder.run();
|
|
20
|
-
|
|
21
|
-
console.log('\n✅ Database seeding completed successfully!');
|
|
22
|
-
} catch (error) {
|
|
23
|
-
console.error('\n❌ Database seeding failed:');
|
|
24
|
-
console.error(error);
|
|
25
|
-
process.exit(1);
|
|
26
|
-
} finally {
|
|
27
|
-
await app.close();
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
bootstrap();
|
|
32
|
-
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
// Example: Seeder configuration file for CLI
|
|
2
|
-
import { TypeOrmModule } from '@nestjs/typeorm';
|
|
3
|
-
import { ConfigModule, ConfigService } from '@nestjs/config';
|
|
4
|
-
|
|
5
|
-
// Import entities
|
|
6
|
-
import { User } from '../entities/user.entity';
|
|
7
|
-
import { Post } from '../entities/post.entity';
|
|
8
|
-
import { Comment } from '../entities/comment.entity';
|
|
9
|
-
|
|
10
|
-
// Import seeders
|
|
11
|
-
import { UserSeeder } from '../seeders/user.seeder';
|
|
12
|
-
import { PostSeeder } from '../seeders/post.seeder';
|
|
13
|
-
import { CommentSeeder } from '../seeders/comment.seeder';
|
|
14
|
-
|
|
15
|
-
export default {
|
|
16
|
-
imports: [
|
|
17
|
-
// Load environment variables
|
|
18
|
-
ConfigModule.forRoot({
|
|
19
|
-
isGlobal: true,
|
|
20
|
-
envFilePath: '.env',
|
|
21
|
-
}),
|
|
22
|
-
|
|
23
|
-
// Configure TypeORM
|
|
24
|
-
TypeOrmModule.forRootAsync({
|
|
25
|
-
imports: [ConfigModule],
|
|
26
|
-
inject: [ConfigService],
|
|
27
|
-
useFactory: (config: ConfigService) => ({
|
|
28
|
-
type: 'postgres',
|
|
29
|
-
host: config.get('DB_HOST', 'localhost'),
|
|
30
|
-
port: config.get('DB_PORT', 5432),
|
|
31
|
-
username: config.get('DB_USERNAME', 'postgres'),
|
|
32
|
-
password: config.get('DB_PASSWORD', 'postgres'),
|
|
33
|
-
database: config.get('DB_DATABASE', 'mydb'),
|
|
34
|
-
entities: [User, Post, Comment],
|
|
35
|
-
synchronize: config.get('DB_SYNCHRONIZE', true),
|
|
36
|
-
}),
|
|
37
|
-
}),
|
|
38
|
-
|
|
39
|
-
// Register entities
|
|
40
|
-
TypeOrmModule.forFeature([User, Post, Comment]),
|
|
41
|
-
],
|
|
42
|
-
|
|
43
|
-
// Register seeders in order of execution
|
|
44
|
-
seeders: [
|
|
45
|
-
UserSeeder, // Run first (no dependencies)
|
|
46
|
-
PostSeeder, // Run second (depends on users)
|
|
47
|
-
CommentSeeder, // Run third (depends on posts and users)
|
|
48
|
-
],
|
|
49
|
-
};
|
|
50
|
-
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
// Example: Complete User Factory with all features
|
|
2
|
-
import { Factory } from '@ackplus/nest-dynamic-templates';
|
|
3
|
-
|
|
4
|
-
export class UserFactory {
|
|
5
|
-
// Simple faker-based generation
|
|
6
|
-
@Factory((faker) => faker.internet.email())
|
|
7
|
-
email: string;
|
|
8
|
-
|
|
9
|
-
@Factory((faker) => faker.person.firstName())
|
|
10
|
-
firstName: string;
|
|
11
|
-
|
|
12
|
-
@Factory((faker) => faker.person.lastName())
|
|
13
|
-
lastName: string;
|
|
14
|
-
|
|
15
|
-
// Dependent field - uses firstName and lastName
|
|
16
|
-
@Factory((faker, ctx) => {
|
|
17
|
-
return `${ctx.firstName}.${ctx.lastName}@example.com`.toLowerCase();
|
|
18
|
-
}, ['firstName', 'lastName'])
|
|
19
|
-
username: string;
|
|
20
|
-
|
|
21
|
-
// Static value
|
|
22
|
-
@Factory('user')
|
|
23
|
-
role: string;
|
|
24
|
-
|
|
25
|
-
// Random boolean
|
|
26
|
-
@Factory((faker) => faker.datatype.boolean())
|
|
27
|
-
isActive: boolean;
|
|
28
|
-
|
|
29
|
-
// Password with specific length
|
|
30
|
-
@Factory((faker) => faker.internet.password({ length: 12 }))
|
|
31
|
-
password: string;
|
|
32
|
-
|
|
33
|
-
// Phone number
|
|
34
|
-
@Factory((faker) => faker.phone.number())
|
|
35
|
-
phone: string;
|
|
36
|
-
|
|
37
|
-
// Date in the past
|
|
38
|
-
@Factory((faker) => faker.date.past({ years: 2 }))
|
|
39
|
-
createdAt: Date;
|
|
40
|
-
|
|
41
|
-
// Random from array
|
|
42
|
-
@Factory((faker) => faker.helpers.arrayElement(['pending', 'active', 'suspended']))
|
|
43
|
-
status: string;
|
|
44
|
-
|
|
45
|
-
// Complex object
|
|
46
|
-
@Factory((faker) => ({
|
|
47
|
-
street: faker.location.streetAddress(),
|
|
48
|
-
city: faker.location.city(),
|
|
49
|
-
state: faker.location.state(),
|
|
50
|
-
zipCode: faker.location.zipCode(),
|
|
51
|
-
country: faker.location.country(),
|
|
52
|
-
}))
|
|
53
|
-
address: object;
|
|
54
|
-
|
|
55
|
-
// Array of values
|
|
56
|
-
@Factory((faker) => faker.helpers.arrayElements(['reading', 'gaming', 'sports', 'music'], { min: 1, max: 3 }))
|
|
57
|
-
interests: string[];
|
|
58
|
-
}
|
|
59
|
-
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
// Example: Complete User Seeder with TypeORM
|
|
2
|
-
import { Injectable } from '@nestjs/common';
|
|
3
|
-
import { InjectRepository } from '@nestjs/typeorm';
|
|
4
|
-
import { Repository } from 'typeorm';
|
|
5
|
-
import { Seeder, SeederServiceOptions, DataFactory } from '@ackplus/nest-dynamic-templates';
|
|
6
|
-
import { User } from '../entities/user.entity';
|
|
7
|
-
import { UserFactory } from '../factories/user.factory';
|
|
8
|
-
|
|
9
|
-
@Injectable()
|
|
10
|
-
export class UserSeeder implements Seeder {
|
|
11
|
-
constructor(
|
|
12
|
-
@InjectRepository(User)
|
|
13
|
-
private readonly userRepository: Repository<User>,
|
|
14
|
-
) {}
|
|
15
|
-
|
|
16
|
-
async seed(options: SeederServiceOptions): Promise<void> {
|
|
17
|
-
console.log('🌱 Seeding users...');
|
|
18
|
-
|
|
19
|
-
// Check if users already exist (unless refresh mode)
|
|
20
|
-
const existingCount = await this.userRepository.count();
|
|
21
|
-
if (existingCount > 0 && !options.refresh) {
|
|
22
|
-
console.log(`⏭️ ${existingCount} users already exist, skipping...`);
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Create factory
|
|
27
|
-
const factory = DataFactory.createForClass(UserFactory);
|
|
28
|
-
|
|
29
|
-
// Generate different amounts based on options
|
|
30
|
-
const count = options.dummyData ? 100 : 10;
|
|
31
|
-
|
|
32
|
-
// Generate users
|
|
33
|
-
const users = factory.generate(count);
|
|
34
|
-
|
|
35
|
-
// Insert in batches for better performance
|
|
36
|
-
const batchSize = 50;
|
|
37
|
-
for (let i = 0; i < users.length; i += batchSize) {
|
|
38
|
-
const batch = users.slice(i, i + batchSize);
|
|
39
|
-
await this.userRepository.save(batch);
|
|
40
|
-
console.log(` 📦 Inserted batch ${Math.floor(i / batchSize) + 1}/${Math.ceil(users.length / batchSize)}`);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
console.log(`✅ Successfully seeded ${users.length} users`);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async drop(options: SeederServiceOptions): Promise<void> {
|
|
47
|
-
console.log('🗑️ Dropping users...');
|
|
48
|
-
|
|
49
|
-
const count = await this.userRepository.count();
|
|
50
|
-
await this.userRepository.delete({});
|
|
51
|
-
|
|
52
|
-
console.log(`✅ Dropped ${count} users`);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|