@flusys/nestjs-core 1.1.0-beta → 1.2.0-rc.1
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/README.md +136 -162
- package/cjs/config/env-config.service.js +14 -10
- package/cjs/docs/docs.config.js +99 -15
- package/cjs/docs/index.js +0 -1
- package/cjs/index.js +0 -1
- package/cjs/interfaces/base-entity.interface.js +5 -3
- package/cjs/interfaces/database.interface.js +1 -3
- package/cjs/migration/datasource.factory.js +1 -3
- package/cjs/migration/index.js +0 -12
- package/cjs/migration/migration.cli.js +1 -17
- package/cjs/migration/migration.runner.js +37 -65
- package/cjs/utils/datasource-config.builder.js +2 -14
- package/config/env-config.service.d.ts +3 -1
- package/docs/docs.config.d.ts +8 -0
- package/docs/index.d.ts +0 -1
- package/fesm/config/env-config.service.js +14 -10
- package/fesm/docs/docs.config.js +89 -15
- package/fesm/docs/index.js +0 -1
- package/fesm/index.js +0 -2
- package/fesm/interfaces/app-config.interfaces.js +1 -3
- package/fesm/interfaces/base-entity.interface.js +5 -5
- package/fesm/interfaces/database.interface.js +1 -5
- package/fesm/migration/cli.js +1 -20
- package/fesm/migration/datasource.factory.js +3 -20
- package/fesm/migration/index.js +0 -14
- package/fesm/migration/migration.cli.js +1 -17
- package/fesm/migration/migration.runner.js +43 -132
- package/fesm/utils/datasource-config.builder.js +2 -13
- package/index.d.ts +0 -1
- package/interfaces/app-config.interfaces.d.ts +1 -0
- package/interfaces/base-entity.interface.d.ts +2 -2
- package/interfaces/database.interface.d.ts +2 -1
- package/package.json +9 -9
- package/utils/datasource-config.builder.d.ts +0 -1
- package/cjs/docs/docs.setup.js +0 -14
- package/cjs/seeders/base-seeder.js +0 -95
- package/cjs/seeders/cli.js +0 -398
- package/cjs/seeders/data-generator.js +0 -247
- package/cjs/seeders/entity-reader.js +0 -168
- package/cjs/seeders/index.js +0 -77
- package/cjs/seeders/seed-config.js +0 -101
- package/cjs/seeders/seed-runner.js +0 -320
- package/cjs/seeders/template-generator.js +0 -297
- package/docs/docs.setup.d.ts +0 -3
- package/fesm/docs/docs.setup.js +0 -4
- package/fesm/seeders/base-seeder.js +0 -110
- package/fesm/seeders/cli.js +0 -366
- package/fesm/seeders/data-generator.js +0 -249
- package/fesm/seeders/entity-reader.js +0 -170
- package/fesm/seeders/index.js +0 -11
- package/fesm/seeders/seed-config.js +0 -85
- package/fesm/seeders/seed-runner.js +0 -323
- package/fesm/seeders/template-generator.js +0 -257
- package/seeders/base-seeder.d.ts +0 -14
- package/seeders/cli.d.ts +0 -3
- package/seeders/data-generator.d.ts +0 -15
- package/seeders/entity-reader.d.ts +0 -45
- package/seeders/index.d.ts +0 -7
- package/seeders/seed-config.d.ts +0 -11
- package/seeders/seed-runner.d.ts +0 -47
- package/seeders/template-generator.d.ts +0 -16
package/cjs/seeders/cli.js
DELETED
|
@@ -1,398 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
Object.defineProperty(exports, "runSeedCli", {
|
|
7
|
-
enumerable: true,
|
|
8
|
-
get: function() {
|
|
9
|
-
return main;
|
|
10
|
-
}
|
|
11
|
-
});
|
|
12
|
-
const _path = /*#__PURE__*/ _interop_require_wildcard(require("path"));
|
|
13
|
-
const _typeorm = require("typeorm");
|
|
14
|
-
const _config = require("../config");
|
|
15
|
-
const _entityreader = require("./entity-reader");
|
|
16
|
-
const _templategenerator = require("./template-generator");
|
|
17
|
-
const _seedrunner = require("./seed-runner");
|
|
18
|
-
const _seedconfig = require("./seed-config");
|
|
19
|
-
function _getRequireWildcardCache(nodeInterop) {
|
|
20
|
-
if (typeof WeakMap !== "function") return null;
|
|
21
|
-
var cacheBabelInterop = new WeakMap();
|
|
22
|
-
var cacheNodeInterop = new WeakMap();
|
|
23
|
-
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
24
|
-
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
25
|
-
})(nodeInterop);
|
|
26
|
-
}
|
|
27
|
-
function _interop_require_wildcard(obj, nodeInterop) {
|
|
28
|
-
if (!nodeInterop && obj && obj.__esModule) {
|
|
29
|
-
return obj;
|
|
30
|
-
}
|
|
31
|
-
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
32
|
-
return {
|
|
33
|
-
default: obj
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
var cache = _getRequireWildcardCache(nodeInterop);
|
|
37
|
-
if (cache && cache.has(obj)) {
|
|
38
|
-
return cache.get(obj);
|
|
39
|
-
}
|
|
40
|
-
var newObj = {
|
|
41
|
-
__proto__: null
|
|
42
|
-
};
|
|
43
|
-
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
44
|
-
for(var key in obj){
|
|
45
|
-
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
46
|
-
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
47
|
-
if (desc && (desc.get || desc.set)) {
|
|
48
|
-
Object.defineProperty(newObj, key, desc);
|
|
49
|
-
} else {
|
|
50
|
-
newObj[key] = obj[key];
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
newObj.default = obj;
|
|
55
|
-
if (cache) {
|
|
56
|
-
cache.set(obj, newObj);
|
|
57
|
-
}
|
|
58
|
-
return newObj;
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Show help message
|
|
62
|
-
*/ function showHelp() {
|
|
63
|
-
console.log(`
|
|
64
|
-
Seed Data CLI
|
|
65
|
-
|
|
66
|
-
Usage:
|
|
67
|
-
npm run seed:<command> [options]
|
|
68
|
-
|
|
69
|
-
Commands:
|
|
70
|
-
generate Generate seeder template files
|
|
71
|
-
run Execute seeders for all entities
|
|
72
|
-
run:all Execute seeders for all tenants (multi-tenant mode)
|
|
73
|
-
clear Clear all seeded data
|
|
74
|
-
status Show seeding status
|
|
75
|
-
|
|
76
|
-
Options:
|
|
77
|
-
--config=<path> Migration config file (default: src/persistence/migration.config.ts)
|
|
78
|
-
--count=<number> Number of records per entity (default: from seed-config)
|
|
79
|
-
--clear Clear existing data before seeding
|
|
80
|
-
--entity=<name> Seed only specific entity
|
|
81
|
-
--hard Hard delete when clearing (ignore soft delete)
|
|
82
|
-
--tenant=<id> Target specific tenant (multi-tenant mode)
|
|
83
|
-
|
|
84
|
-
Environment:
|
|
85
|
-
MIGRATION_CONFIG Default config path (overrides auto-detection)
|
|
86
|
-
|
|
87
|
-
Examples:
|
|
88
|
-
npm run seed:generate
|
|
89
|
-
npm run seed:run
|
|
90
|
-
npm run seed:run -- --count=50 --clear
|
|
91
|
-
npm run seed:run -- --entity=User --count=100
|
|
92
|
-
npm run seed:run -- --config=src/persistence/migration.config.ts
|
|
93
|
-
npm run seed:clear
|
|
94
|
-
npm run seed:clear -- --hard
|
|
95
|
-
npm run seed:status
|
|
96
|
-
npm run seed:run:all
|
|
97
|
-
`);
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Parse command-line arguments
|
|
101
|
-
*/ function parseArgs() {
|
|
102
|
-
const args = process.argv.slice(2);
|
|
103
|
-
let command;
|
|
104
|
-
let count;
|
|
105
|
-
let clear = false;
|
|
106
|
-
let entity;
|
|
107
|
-
let hard = false;
|
|
108
|
-
let tenant;
|
|
109
|
-
let configPath;
|
|
110
|
-
for(let i = 0; i < args.length; i++){
|
|
111
|
-
const arg = args[i];
|
|
112
|
-
if (arg.startsWith('--count=')) {
|
|
113
|
-
count = parseInt(arg.split('=')[1], 10);
|
|
114
|
-
} else if (arg === '--clear') {
|
|
115
|
-
clear = true;
|
|
116
|
-
} else if (arg.startsWith('--entity=')) {
|
|
117
|
-
entity = arg.split('=')[1];
|
|
118
|
-
} else if (arg === '--hard') {
|
|
119
|
-
hard = true;
|
|
120
|
-
} else if (arg.startsWith('--tenant=')) {
|
|
121
|
-
tenant = arg.split('=')[1];
|
|
122
|
-
} else if (arg.startsWith('--config=')) {
|
|
123
|
-
configPath = arg.split('=')[1];
|
|
124
|
-
} else if (!arg.startsWith('-') && !command) {
|
|
125
|
-
command = arg;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
return {
|
|
129
|
-
command,
|
|
130
|
-
count,
|
|
131
|
-
clear,
|
|
132
|
-
entity,
|
|
133
|
-
hard,
|
|
134
|
-
tenant,
|
|
135
|
-
configPath
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
// Resolved config path (set once during CLI initialization)
|
|
139
|
-
let resolvedConfigPath;
|
|
140
|
-
/**
|
|
141
|
-
* Resolve migration config path with auto-detection
|
|
142
|
-
*/ async function resolveConfigPath(explicitPath) {
|
|
143
|
-
if (resolvedConfigPath) return resolvedConfigPath;
|
|
144
|
-
// Try paths in order: explicit, env var, then common defaults
|
|
145
|
-
const envConfigPath = _config.envConfig.tryGetValue('MIGRATION_CONFIG');
|
|
146
|
-
const defaultPaths = [
|
|
147
|
-
explicitPath,
|
|
148
|
-
envConfigPath,
|
|
149
|
-
'src/persistence/migration.config.ts',
|
|
150
|
-
'src/persistence/migration.config.js',
|
|
151
|
-
'persistence/migration.config.ts',
|
|
152
|
-
'persistence/migration.config.js'
|
|
153
|
-
].filter(Boolean);
|
|
154
|
-
for (const tryPath of defaultPaths){
|
|
155
|
-
const absolutePath = _path.isAbsolute(tryPath) ? tryPath : _path.resolve(process.cwd(), tryPath);
|
|
156
|
-
try {
|
|
157
|
-
await Promise.resolve(absolutePath).then((p)=>/*#__PURE__*/ _interop_require_wildcard(require(p)));
|
|
158
|
-
resolvedConfigPath = absolutePath;
|
|
159
|
-
return absolutePath;
|
|
160
|
-
} catch {
|
|
161
|
-
// Try next path
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
console.error('❌ Config not found. Use --config=<path> or set MIGRATION_CONFIG env var');
|
|
165
|
-
console.error(' Tried paths:', defaultPaths.join(', '));
|
|
166
|
-
process.exit(1);
|
|
167
|
-
}
|
|
168
|
-
/**
|
|
169
|
-
* Load DataSource configuration
|
|
170
|
-
*/ async function loadDataSource(tenantId, configPath) {
|
|
171
|
-
const resolvedPath = await resolveConfigPath(configPath);
|
|
172
|
-
try {
|
|
173
|
-
const module1 = await Promise.resolve(resolvedPath).then((p)=>/*#__PURE__*/ _interop_require_wildcard(require(p)));
|
|
174
|
-
const migrationConfig = module1.migrationConfig || module1.default?.migrationConfig || module1;
|
|
175
|
-
// Get database config for tenant
|
|
176
|
-
const dbConfig = tenantId ? migrationConfig.tenants?.find((t)=>t.tenantId === tenantId || t.id === tenantId) : migrationConfig.defaultDatabaseConfig || migrationConfig.database;
|
|
177
|
-
if (!dbConfig) {
|
|
178
|
-
throw new Error(`Database configuration not found${tenantId ? ` for tenant: ${tenantId}` : ''}`);
|
|
179
|
-
}
|
|
180
|
-
// Get entities - handle both function and array
|
|
181
|
-
const entities = typeof migrationConfig.entities === 'function' ? migrationConfig.entities() : migrationConfig.entities || [];
|
|
182
|
-
// Create DataSource
|
|
183
|
-
const dataSource = new _typeorm.DataSource({
|
|
184
|
-
type: dbConfig.type || 'mysql',
|
|
185
|
-
host: dbConfig.host,
|
|
186
|
-
port: dbConfig.port,
|
|
187
|
-
username: dbConfig.username,
|
|
188
|
-
password: dbConfig.password,
|
|
189
|
-
database: dbConfig.database,
|
|
190
|
-
entities,
|
|
191
|
-
synchronize: false,
|
|
192
|
-
logging: false
|
|
193
|
-
});
|
|
194
|
-
await dataSource.initialize();
|
|
195
|
-
return dataSource;
|
|
196
|
-
} catch (error) {
|
|
197
|
-
console.error('❌ Failed to load DataSource configuration');
|
|
198
|
-
console.error(' Error:', error instanceof Error ? error.message : String(error));
|
|
199
|
-
throw error;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
/**
|
|
203
|
-
* Get all tenant IDs from configuration
|
|
204
|
-
*/ async function getAllTenantIds(configPath) {
|
|
205
|
-
const resolvedPath = await resolveConfigPath(configPath);
|
|
206
|
-
try {
|
|
207
|
-
const module1 = await Promise.resolve(resolvedPath).then((p)=>/*#__PURE__*/ _interop_require_wildcard(require(p)));
|
|
208
|
-
const migrationConfig = module1.migrationConfig || module1.default?.migrationConfig || module1;
|
|
209
|
-
if (migrationConfig.bootstrapAppConfig?.databaseMode !== 'multi-tenant' || !migrationConfig.tenants) {
|
|
210
|
-
throw new Error('Multi-tenant mode is not configured');
|
|
211
|
-
}
|
|
212
|
-
return migrationConfig.tenants.map((t)=>t.tenantId || t.id);
|
|
213
|
-
} catch (error) {
|
|
214
|
-
console.error('❌ Failed to load tenant configuration');
|
|
215
|
-
throw error;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
/**
|
|
219
|
-
* Generate seeder template files
|
|
220
|
-
*/ async function generateCommand(configPath) {
|
|
221
|
-
console.log('🔍 Discovering entities...\n');
|
|
222
|
-
const dataSource = await loadDataSource(undefined, configPath);
|
|
223
|
-
try {
|
|
224
|
-
const reader = new _entityreader.EntityReader(dataSource);
|
|
225
|
-
const generator = new _templategenerator.TemplateGenerator();
|
|
226
|
-
const entities = reader.getAllEntities();
|
|
227
|
-
const outputDir = _path.resolve(process.cwd(), 'src/seeders/generators');
|
|
228
|
-
console.log(`📝 Generating seeder files in ${outputDir}\n`);
|
|
229
|
-
let generatedCount = 0;
|
|
230
|
-
const entityInfos = [];
|
|
231
|
-
for (const metadata of entities){
|
|
232
|
-
if ((0, _seedconfig.shouldSkipEntity)(metadata.name)) {
|
|
233
|
-
continue;
|
|
234
|
-
}
|
|
235
|
-
try {
|
|
236
|
-
const entityInfo = reader.getEntityInfo(metadata.name);
|
|
237
|
-
entityInfos.push(entityInfo);
|
|
238
|
-
const filePath = generator.generateSeederFile(entityInfo, outputDir);
|
|
239
|
-
console.log(`✓ Generated: ${_path.basename(filePath)}`);
|
|
240
|
-
generatedCount++;
|
|
241
|
-
} catch (error) {
|
|
242
|
-
console.error(`✗ Failed to generate ${metadata.name}:`, error instanceof Error ? error.message : String(error));
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
// Generate index file
|
|
246
|
-
const indexPath = generator.generateIndexFile(entityInfos, outputDir);
|
|
247
|
-
console.log(`✓ Generated: ${_path.basename(indexPath)}`);
|
|
248
|
-
console.log(`\n✓ Generated ${generatedCount} seeder files\n`);
|
|
249
|
-
} finally{
|
|
250
|
-
await dataSource.destroy();
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
/**
|
|
254
|
-
* Run seeds for single database
|
|
255
|
-
*/ async function runCommand(options, configPath) {
|
|
256
|
-
const dataSource = await loadDataSource(undefined, configPath);
|
|
257
|
-
try {
|
|
258
|
-
const runner = new _seedrunner.SeedRunner(dataSource);
|
|
259
|
-
if (options.entity) {
|
|
260
|
-
console.log(`🌱 Seeding entity: ${options.entity}\n`);
|
|
261
|
-
const result = await runner.runSingle(options.entity, options);
|
|
262
|
-
if (result.success) {
|
|
263
|
-
console.log(`\n✓ ${result.entity}: ${result.count} records created\n`);
|
|
264
|
-
} else {
|
|
265
|
-
console.error(`\n✗ ${result.entity}: ${result.error}\n`);
|
|
266
|
-
process.exit(1);
|
|
267
|
-
}
|
|
268
|
-
} else {
|
|
269
|
-
const results = await runner.runAll(options);
|
|
270
|
-
const failedCount = results.filter((r)=>!r.success).length;
|
|
271
|
-
if (failedCount > 0) {
|
|
272
|
-
process.exit(1);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
} finally{
|
|
276
|
-
await dataSource.destroy();
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
/**
|
|
280
|
-
* Run seeds for all tenants
|
|
281
|
-
*/ async function runAllTenantsCommand(options, configPath) {
|
|
282
|
-
console.log('🏢 Running seeds for all tenants...\n');
|
|
283
|
-
const tenantIds = await getAllTenantIds(configPath);
|
|
284
|
-
let successCount = 0;
|
|
285
|
-
let failCount = 0;
|
|
286
|
-
for (const tenantId of tenantIds){
|
|
287
|
-
console.log(`\n📦 Tenant: ${tenantId}`);
|
|
288
|
-
console.log('─'.repeat(50));
|
|
289
|
-
const dataSource = await loadDataSource(tenantId, configPath);
|
|
290
|
-
try {
|
|
291
|
-
const runner = new _seedrunner.SeedRunner(dataSource);
|
|
292
|
-
const results = await runner.runAll(options);
|
|
293
|
-
const failed = results.filter((r)=>!r.success).length;
|
|
294
|
-
if (failed === 0) {
|
|
295
|
-
successCount++;
|
|
296
|
-
} else {
|
|
297
|
-
failCount++;
|
|
298
|
-
}
|
|
299
|
-
} catch (error) {
|
|
300
|
-
console.error(`✗ Failed to seed tenant ${tenantId}:`, error);
|
|
301
|
-
failCount++;
|
|
302
|
-
} finally{
|
|
303
|
-
await dataSource.destroy();
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
console.log('\n' + '='.repeat(50));
|
|
307
|
-
console.log(`\n✓ Completed: ${successCount} tenants seeded`);
|
|
308
|
-
if (failCount > 0) {
|
|
309
|
-
console.log(`✗ Failed: ${failCount} tenants\n`);
|
|
310
|
-
process.exit(1);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
/**
|
|
314
|
-
* Clear all seeded data
|
|
315
|
-
*/ async function clearCommand(hard = false, configPath) {
|
|
316
|
-
const dataSource = await loadDataSource(undefined, configPath);
|
|
317
|
-
try {
|
|
318
|
-
const runner = new _seedrunner.SeedRunner(dataSource);
|
|
319
|
-
await runner.clearAll(hard);
|
|
320
|
-
} finally{
|
|
321
|
-
await dataSource.destroy();
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
/**
|
|
325
|
-
* Show seeding status
|
|
326
|
-
*/ async function statusCommand(configPath) {
|
|
327
|
-
const dataSource = await loadDataSource(undefined, configPath);
|
|
328
|
-
try {
|
|
329
|
-
const runner = new _seedrunner.SeedRunner(dataSource);
|
|
330
|
-
const status = await runner.getStatus();
|
|
331
|
-
console.log('\nSeed Status:');
|
|
332
|
-
console.log('┌────────────────────────────┬───────────┬─────────┐');
|
|
333
|
-
console.log('│ Entity │ Records │ Status │');
|
|
334
|
-
console.log('├────────────────────────────┼───────────┼─────────┤');
|
|
335
|
-
for (const item of status){
|
|
336
|
-
const entityName = item.entity.padEnd(26);
|
|
337
|
-
const count = item.count.toString().padEnd(9);
|
|
338
|
-
const statusIcon = item.isEmpty ? '⚠ Empty' : '✓ Ready ';
|
|
339
|
-
console.log(`│ ${entityName} │ ${count} │ ${statusIcon} │`);
|
|
340
|
-
}
|
|
341
|
-
console.log('└────────────────────────────┴───────────┴─────────┘\n');
|
|
342
|
-
} finally{
|
|
343
|
-
await dataSource.destroy();
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
/**
|
|
347
|
-
* Main CLI entry point
|
|
348
|
-
*/ async function main() {
|
|
349
|
-
const args = parseArgs();
|
|
350
|
-
if (!args.command) {
|
|
351
|
-
showHelp();
|
|
352
|
-
return;
|
|
353
|
-
}
|
|
354
|
-
// Initialize config path for all commands
|
|
355
|
-
if (args.configPath) {
|
|
356
|
-
await resolveConfigPath(args.configPath);
|
|
357
|
-
}
|
|
358
|
-
try {
|
|
359
|
-
switch(args.command){
|
|
360
|
-
case 'generate':
|
|
361
|
-
await generateCommand(args.configPath);
|
|
362
|
-
break;
|
|
363
|
-
case 'run':
|
|
364
|
-
await runCommand({
|
|
365
|
-
count: args.count,
|
|
366
|
-
clear: args.clear,
|
|
367
|
-
entity: args.entity
|
|
368
|
-
}, args.configPath);
|
|
369
|
-
break;
|
|
370
|
-
case 'run:all':
|
|
371
|
-
await runAllTenantsCommand({
|
|
372
|
-
count: args.count,
|
|
373
|
-
clear: args.clear
|
|
374
|
-
}, args.configPath);
|
|
375
|
-
break;
|
|
376
|
-
case 'clear':
|
|
377
|
-
await clearCommand(args.hard, args.configPath);
|
|
378
|
-
break;
|
|
379
|
-
case 'status':
|
|
380
|
-
await statusCommand(args.configPath);
|
|
381
|
-
break;
|
|
382
|
-
default:
|
|
383
|
-
console.error(`❌ Unknown command: ${args.command}`);
|
|
384
|
-
showHelp();
|
|
385
|
-
process.exit(1);
|
|
386
|
-
}
|
|
387
|
-
} catch (error) {
|
|
388
|
-
console.error('\n❌ CLI Error:', error instanceof Error ? error.message : String(error));
|
|
389
|
-
process.exit(1);
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
// Run CLI if called directly
|
|
393
|
-
if (require.main === module) {
|
|
394
|
-
main().catch((error)=>{
|
|
395
|
-
console.error('Fatal error:', error);
|
|
396
|
-
process.exit(1);
|
|
397
|
-
});
|
|
398
|
-
}
|
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
value: true
|
|
4
|
-
});
|
|
5
|
-
Object.defineProperty(exports, "DataGenerator", {
|
|
6
|
-
enumerable: true,
|
|
7
|
-
get: function() {
|
|
8
|
-
return DataGenerator;
|
|
9
|
-
}
|
|
10
|
-
});
|
|
11
|
-
const _faker = require("@faker-js/faker");
|
|
12
|
-
let DataGenerator = class DataGenerator {
|
|
13
|
-
/**
|
|
14
|
-
* Generate value for a single column based on its metadata
|
|
15
|
-
*/ generateValue(column) {
|
|
16
|
-
// Skip generated fields
|
|
17
|
-
if (column.isGenerated) {
|
|
18
|
-
return undefined;
|
|
19
|
-
}
|
|
20
|
-
// Handle nullable fields (50% chance of null)
|
|
21
|
-
if (column.isNullable && _faker.faker.datatype.boolean()) {
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
// Check for enum
|
|
25
|
-
if (column.enum && column.enum.length > 0) {
|
|
26
|
-
return _faker.faker.helpers.arrayElement(column.enum);
|
|
27
|
-
}
|
|
28
|
-
// Generate based on column name pattern
|
|
29
|
-
const nameLower = column.propertyName.toLowerCase();
|
|
30
|
-
const value = this.generateByName(nameLower, column);
|
|
31
|
-
if (value !== undefined) {
|
|
32
|
-
return value;
|
|
33
|
-
}
|
|
34
|
-
// Generate based on column type
|
|
35
|
-
return this.generateByType(column);
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Generate entity object from column definitions
|
|
39
|
-
*/ generateEntity(columns) {
|
|
40
|
-
const entity = {};
|
|
41
|
-
for (const column of columns){
|
|
42
|
-
const value = this.generateValue(column);
|
|
43
|
-
if (value !== undefined) {
|
|
44
|
-
entity[column.propertyName] = value;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
return entity;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Generate value based on column name patterns
|
|
51
|
-
*/ generateByName(nameLower, column) {
|
|
52
|
-
// Identity fields (skip, handled by database)
|
|
53
|
-
if ([
|
|
54
|
-
'id',
|
|
55
|
-
'createdat',
|
|
56
|
-
'updatedat',
|
|
57
|
-
'deletedat'
|
|
58
|
-
].includes(nameLower)) {
|
|
59
|
-
return undefined;
|
|
60
|
-
}
|
|
61
|
-
// Audit fields (skip, handled by interceptors)
|
|
62
|
-
if ([
|
|
63
|
-
'createdbyid',
|
|
64
|
-
'updatedbyid',
|
|
65
|
-
'deletedbyid'
|
|
66
|
-
].includes(nameLower)) {
|
|
67
|
-
return null;
|
|
68
|
-
}
|
|
69
|
-
// Name fields
|
|
70
|
-
if (nameLower.includes('firstname')) return _faker.faker.person.firstName();
|
|
71
|
-
if (nameLower.includes('lastname')) return _faker.faker.person.lastName();
|
|
72
|
-
if (nameLower.includes('fullname') || nameLower === 'name') {
|
|
73
|
-
return _faker.faker.person.fullName();
|
|
74
|
-
}
|
|
75
|
-
// Contact fields
|
|
76
|
-
if (nameLower.includes('email')) return _faker.faker.internet.email().toLowerCase();
|
|
77
|
-
if (nameLower.includes('phone')) return _faker.faker.phone.number();
|
|
78
|
-
if (nameLower.includes('mobile')) return _faker.faker.phone.number();
|
|
79
|
-
// Location fields
|
|
80
|
-
if (nameLower.includes('address')) return _faker.faker.location.streetAddress();
|
|
81
|
-
if (nameLower.includes('street')) return _faker.faker.location.street();
|
|
82
|
-
if (nameLower.includes('city')) return _faker.faker.location.city();
|
|
83
|
-
if (nameLower.includes('state')) return _faker.faker.location.state();
|
|
84
|
-
if (nameLower.includes('country')) return _faker.faker.location.country();
|
|
85
|
-
if (nameLower.includes('zipcode') || nameLower.includes('postalcode')) {
|
|
86
|
-
return _faker.faker.location.zipCode();
|
|
87
|
-
}
|
|
88
|
-
// URL/Web fields
|
|
89
|
-
if (nameLower.includes('url')) return _faker.faker.internet.url();
|
|
90
|
-
if (nameLower.includes('website')) return _faker.faker.internet.url();
|
|
91
|
-
if (nameLower.includes('domain')) return _faker.faker.internet.domainName();
|
|
92
|
-
if (nameLower.includes('slug')) {
|
|
93
|
-
return _faker.faker.helpers.slugify(_faker.faker.lorem.words(3)).toLowerCase();
|
|
94
|
-
}
|
|
95
|
-
// Text fields
|
|
96
|
-
if (nameLower.includes('description')) return _faker.faker.lorem.paragraph();
|
|
97
|
-
if (nameLower.includes('summary')) return _faker.faker.lorem.sentence();
|
|
98
|
-
if (nameLower.includes('content')) return _faker.faker.lorem.paragraphs(3);
|
|
99
|
-
if (nameLower.includes('title')) return _faker.faker.lorem.sentence();
|
|
100
|
-
// User fields
|
|
101
|
-
if (nameLower.includes('username')) return _faker.faker.internet.username();
|
|
102
|
-
if (nameLower.includes('password')) return '$2b$12$dummy.hashed.password.value'; // Dummy bcrypt hash
|
|
103
|
-
// Status/Active fields
|
|
104
|
-
if (nameLower.includes('isactive')) return _faker.faker.datatype.boolean();
|
|
105
|
-
if (nameLower.includes('isenabled')) return _faker.faker.datatype.boolean();
|
|
106
|
-
if (nameLower.includes('ispublic')) return _faker.faker.datatype.boolean();
|
|
107
|
-
if (nameLower.includes('isverified')) return _faker.faker.datatype.boolean();
|
|
108
|
-
// Date fields
|
|
109
|
-
if (nameLower.includes('birthdate') || nameLower.includes('dateofbirth')) {
|
|
110
|
-
return _faker.faker.date.birthdate({
|
|
111
|
-
min: 18,
|
|
112
|
-
max: 80,
|
|
113
|
-
mode: 'age'
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
if (nameLower.includes('expiresat') || nameLower.includes('expirydate')) {
|
|
117
|
-
return _faker.faker.date.future();
|
|
118
|
-
}
|
|
119
|
-
if (nameLower.includes('verifiedat')) {
|
|
120
|
-
return _faker.faker.datatype.boolean() ? _faker.faker.date.recent() : null;
|
|
121
|
-
}
|
|
122
|
-
// Serial/Order fields
|
|
123
|
-
if (nameLower.includes('serial') || nameLower.includes('order')) {
|
|
124
|
-
return _faker.faker.number.int({
|
|
125
|
-
min: 1,
|
|
126
|
-
max: 100
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
// Company/Organization
|
|
130
|
-
if (nameLower.includes('company') && !nameLower.includes('id')) {
|
|
131
|
-
return _faker.faker.company.name();
|
|
132
|
-
}
|
|
133
|
-
return undefined;
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* Generate value based on column type
|
|
137
|
-
*/ generateByType(column) {
|
|
138
|
-
const type = column.type.toLowerCase();
|
|
139
|
-
switch(type){
|
|
140
|
-
// String types
|
|
141
|
-
case 'varchar':
|
|
142
|
-
case 'character varying':
|
|
143
|
-
case 'text':
|
|
144
|
-
case 'string':
|
|
145
|
-
return this.generateString(column);
|
|
146
|
-
// Number types
|
|
147
|
-
case 'int':
|
|
148
|
-
case 'integer':
|
|
149
|
-
case 'smallint':
|
|
150
|
-
case 'bigint':
|
|
151
|
-
return _faker.faker.number.int({
|
|
152
|
-
min: 1,
|
|
153
|
-
max: 1000
|
|
154
|
-
});
|
|
155
|
-
case 'decimal':
|
|
156
|
-
case 'numeric':
|
|
157
|
-
case 'float':
|
|
158
|
-
case 'double':
|
|
159
|
-
case 'real':
|
|
160
|
-
return _faker.faker.number.float({
|
|
161
|
-
min: 0,
|
|
162
|
-
max: 10000,
|
|
163
|
-
fractionDigits: column.scale || 2
|
|
164
|
-
});
|
|
165
|
-
// Boolean
|
|
166
|
-
case 'boolean':
|
|
167
|
-
case 'bool':
|
|
168
|
-
return _faker.faker.datatype.boolean();
|
|
169
|
-
// Date/Time
|
|
170
|
-
case 'date':
|
|
171
|
-
return _faker.faker.date.recent({
|
|
172
|
-
days: 30
|
|
173
|
-
});
|
|
174
|
-
case 'timestamp':
|
|
175
|
-
case 'datetime':
|
|
176
|
-
return _faker.faker.date.recent({
|
|
177
|
-
days: 30
|
|
178
|
-
});
|
|
179
|
-
case 'time':
|
|
180
|
-
return _faker.faker.date.recent().toTimeString().split(' ')[0];
|
|
181
|
-
// UUID
|
|
182
|
-
case 'uuid':
|
|
183
|
-
return _faker.faker.string.uuid();
|
|
184
|
-
// JSON
|
|
185
|
-
case 'json':
|
|
186
|
-
case 'jsonb':
|
|
187
|
-
return {
|
|
188
|
-
key1: _faker.faker.lorem.word(),
|
|
189
|
-
key2: _faker.faker.number.int({
|
|
190
|
-
min: 1,
|
|
191
|
-
max: 100
|
|
192
|
-
})
|
|
193
|
-
};
|
|
194
|
-
// Array
|
|
195
|
-
case 'array':
|
|
196
|
-
return [
|
|
197
|
-
_faker.faker.lorem.word(),
|
|
198
|
-
_faker.faker.lorem.word()
|
|
199
|
-
];
|
|
200
|
-
// Default
|
|
201
|
-
default:
|
|
202
|
-
return _faker.faker.lorem.word();
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
/**
|
|
206
|
-
* Generate string value respecting length constraints
|
|
207
|
-
*/ generateString(column) {
|
|
208
|
-
const maxLength = typeof column.length === 'number' ? column.length : 255;
|
|
209
|
-
if (maxLength <= 50) {
|
|
210
|
-
return _faker.faker.lorem.word().substring(0, maxLength);
|
|
211
|
-
} else if (maxLength <= 255) {
|
|
212
|
-
return _faker.faker.lorem.sentence().substring(0, maxLength);
|
|
213
|
-
} else {
|
|
214
|
-
return _faker.faker.lorem.paragraph().substring(0, maxLength);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
/**
|
|
218
|
-
* Generate related entity ID (for foreign keys)
|
|
219
|
-
* @param relatedEntities Array of entities to pick from
|
|
220
|
-
*/ generateRelationId(relatedEntities) {
|
|
221
|
-
if (relatedEntities.length === 0) {
|
|
222
|
-
return null;
|
|
223
|
-
}
|
|
224
|
-
return _faker.faker.helpers.arrayElement(relatedEntities).id;
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* Generate multiple related entity IDs (for many-to-many)
|
|
228
|
-
* @param relatedEntities Array of entities to pick from
|
|
229
|
-
* @param min Minimum number of relations
|
|
230
|
-
* @param max Maximum number of relations
|
|
231
|
-
*/ generateRelationIds(relatedEntities, min = 1, max = 3) {
|
|
232
|
-
if (relatedEntities.length === 0) {
|
|
233
|
-
return [];
|
|
234
|
-
}
|
|
235
|
-
const count = _faker.faker.number.int({
|
|
236
|
-
min,
|
|
237
|
-
max: Math.min(max, relatedEntities.length)
|
|
238
|
-
});
|
|
239
|
-
const selected = _faker.faker.helpers.arrayElements(relatedEntities, count);
|
|
240
|
-
return selected.map((e)=>e.id);
|
|
241
|
-
}
|
|
242
|
-
constructor(locale = 'en'){
|
|
243
|
-
// Note: faker v8+ uses faker.locale instead of setLocale
|
|
244
|
-
// For v8+: faker.locale = locale;
|
|
245
|
-
// Locale is set globally, not needed for basic usage
|
|
246
|
-
}
|
|
247
|
-
};
|