@flusys/nestjs-core 1.0.0-beta ā 1.0.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.
- package/README.md +507 -61
- package/cjs/config/env-config.service.js +1 -1
- package/cjs/docs/docs.config.js +77 -3
- package/cjs/docs/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/seeders/base-seeder.js +6 -25
- package/cjs/seeders/cli.js +65 -172
- package/cjs/seeders/data-generator.js +96 -142
- package/cjs/seeders/entity-reader.js +0 -17
- package/cjs/seeders/field-patterns.js +172 -0
- package/cjs/seeders/index.js +16 -8
- package/cjs/seeders/seed-config.js +9 -48
- package/cjs/seeders/seed-runner.js +8 -14
- package/cjs/utils/datasource-config.builder.js +2 -14
- package/docs/docs.config.d.ts +7 -0
- package/docs/index.d.ts +0 -1
- package/fesm/config/env-config.service.js +1 -1
- package/fesm/docs/docs.config.js +68 -0
- package/fesm/docs/index.js +0 -1
- 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/seeders/base-seeder.js +7 -51
- package/fesm/seeders/cli.js +65 -182
- package/fesm/seeders/data-generator.js +96 -149
- package/fesm/seeders/entity-reader.js +0 -17
- package/fesm/seeders/field-patterns.js +143 -0
- package/fesm/seeders/index.js +3 -7
- package/fesm/seeders/seed-config.js +9 -59
- package/fesm/seeders/seed-runner.js +8 -14
- package/fesm/utils/datasource-config.builder.js +2 -13
- package/interfaces/base-entity.interface.d.ts +3 -0
- package/package.json +2 -2
- package/seeders/data-generator.d.ts +1 -1
- package/seeders/entity-reader.d.ts +0 -1
- package/seeders/field-patterns.d.ts +12 -0
- package/seeders/index.d.ts +3 -3
- package/seeders/seed-config.d.ts +1 -0
- package/seeders/seed-runner.d.ts +1 -0
- package/utils/datasource-config.builder.d.ts +0 -1
- package/cjs/docs/docs.setup.js +0 -14
- 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/template-generator.js +0 -257
- package/seeders/template-generator.d.ts +0 -16
package/cjs/seeders/cli.js
CHANGED
|
@@ -12,10 +12,7 @@ Object.defineProperty(exports, "runSeedCli", {
|
|
|
12
12
|
const _path = /*#__PURE__*/ _interop_require_wildcard(require("path"));
|
|
13
13
|
const _typeorm = require("typeorm");
|
|
14
14
|
const _config = require("../config");
|
|
15
|
-
const _entityreader = require("./entity-reader");
|
|
16
|
-
const _templategenerator = require("./template-generator");
|
|
17
15
|
const _seedrunner = require("./seed-runner");
|
|
18
|
-
const _seedconfig = require("./seed-config");
|
|
19
16
|
function _getRequireWildcardCache(nodeInterop) {
|
|
20
17
|
if (typeof WeakMap !== "function") return null;
|
|
21
18
|
var cacheBabelInterop = new WeakMap();
|
|
@@ -57,9 +54,7 @@ function _interop_require_wildcard(obj, nodeInterop) {
|
|
|
57
54
|
}
|
|
58
55
|
return newObj;
|
|
59
56
|
}
|
|
60
|
-
|
|
61
|
-
* Show help message
|
|
62
|
-
*/ function showHelp() {
|
|
57
|
+
function showHelp() {
|
|
63
58
|
console.log(`
|
|
64
59
|
Seed Data CLI
|
|
65
60
|
|
|
@@ -67,7 +62,6 @@ Usage:
|
|
|
67
62
|
npm run seed:<command> [options]
|
|
68
63
|
|
|
69
64
|
Commands:
|
|
70
|
-
generate Generate seeder template files
|
|
71
65
|
run Execute seeders for all entities
|
|
72
66
|
run:all Execute seeders for all tenants (multi-tenant mode)
|
|
73
67
|
clear Clear all seeded data
|
|
@@ -81,24 +75,17 @@ Options:
|
|
|
81
75
|
--hard Hard delete when clearing (ignore soft delete)
|
|
82
76
|
--tenant=<id> Target specific tenant (multi-tenant mode)
|
|
83
77
|
|
|
84
|
-
Environment:
|
|
85
|
-
MIGRATION_CONFIG Default config path (overrides auto-detection)
|
|
86
|
-
|
|
87
78
|
Examples:
|
|
88
|
-
npm run seed:generate
|
|
89
79
|
npm run seed:run
|
|
90
80
|
npm run seed:run -- --count=50 --clear
|
|
91
81
|
npm run seed:run -- --entity=User --count=100
|
|
92
|
-
npm run seed:run -- --config=src/persistence/migration.config.ts
|
|
93
82
|
npm run seed:clear
|
|
94
83
|
npm run seed:clear -- --hard
|
|
95
84
|
npm run seed:status
|
|
96
85
|
npm run seed:run:all
|
|
97
86
|
`);
|
|
98
87
|
}
|
|
99
|
-
|
|
100
|
-
* Parse command-line arguments
|
|
101
|
-
*/ function parseArgs() {
|
|
88
|
+
function parseArgs() {
|
|
102
89
|
const args = process.argv.slice(2);
|
|
103
90
|
let command;
|
|
104
91
|
let count;
|
|
@@ -107,8 +94,7 @@ Examples:
|
|
|
107
94
|
let hard = false;
|
|
108
95
|
let tenant;
|
|
109
96
|
let configPath;
|
|
110
|
-
for(
|
|
111
|
-
const arg = args[i];
|
|
97
|
+
for (const arg of args){
|
|
112
98
|
if (arg.startsWith('--count=')) {
|
|
113
99
|
count = parseInt(arg.split('=')[1], 10);
|
|
114
100
|
} else if (arg === '--clear') {
|
|
@@ -135,21 +121,15 @@ Examples:
|
|
|
135
121
|
configPath
|
|
136
122
|
};
|
|
137
123
|
}
|
|
138
|
-
// Resolved config path (set once during CLI initialization)
|
|
139
124
|
let resolvedConfigPath;
|
|
140
|
-
|
|
141
|
-
* Resolve migration config path with auto-detection
|
|
142
|
-
*/ async function resolveConfigPath(explicitPath) {
|
|
125
|
+
async function resolveConfigPath(explicitPath) {
|
|
143
126
|
if (resolvedConfigPath) return resolvedConfigPath;
|
|
144
|
-
// Try paths in order: explicit, env var, then common defaults
|
|
145
127
|
const envConfigPath = _config.envConfig.tryGetValue('MIGRATION_CONFIG');
|
|
146
128
|
const defaultPaths = [
|
|
147
129
|
explicitPath,
|
|
148
130
|
envConfigPath,
|
|
149
131
|
'src/persistence/migration.config.ts',
|
|
150
|
-
'src/persistence/migration.config.js'
|
|
151
|
-
'persistence/migration.config.ts',
|
|
152
|
-
'persistence/migration.config.js'
|
|
132
|
+
'src/persistence/migration.config.js'
|
|
153
133
|
].filter(Boolean);
|
|
154
134
|
for (const tryPath of defaultPaths){
|
|
155
135
|
const absolutePath = _path.isAbsolute(tryPath) ? tryPath : _path.resolve(process.cwd(), tryPath);
|
|
@@ -162,97 +142,41 @@ let resolvedConfigPath;
|
|
|
162
142
|
}
|
|
163
143
|
}
|
|
164
144
|
console.error('ā Config not found. Use --config=<path> or set MIGRATION_CONFIG env var');
|
|
165
|
-
console.error(' Tried paths:', defaultPaths.join(', '));
|
|
166
145
|
process.exit(1);
|
|
167
146
|
}
|
|
168
|
-
|
|
169
|
-
* Load DataSource configuration
|
|
170
|
-
*/ async function loadDataSource(tenantId, configPath) {
|
|
147
|
+
async function loadDataSource(tenantId, configPath) {
|
|
171
148
|
const resolvedPath = await resolveConfigPath(configPath);
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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;
|
|
149
|
+
const module1 = await Promise.resolve(resolvedPath).then((p)=>/*#__PURE__*/ _interop_require_wildcard(require(p)));
|
|
150
|
+
const migrationConfig = module1.migrationConfig || module1.default?.migrationConfig || module1;
|
|
151
|
+
const dbConfig = tenantId ? migrationConfig.tenants?.find((t)=>t.tenantId === tenantId || t.id === tenantId) : migrationConfig.defaultDatabaseConfig || migrationConfig.database;
|
|
152
|
+
if (!dbConfig) {
|
|
153
|
+
throw new Error(`Database configuration not found${tenantId ? ` for tenant: ${tenantId}` : ''}`);
|
|
200
154
|
}
|
|
155
|
+
const entities = typeof migrationConfig.entities === 'function' ? migrationConfig.entities() : migrationConfig.entities || [];
|
|
156
|
+
const dataSource = new _typeorm.DataSource({
|
|
157
|
+
type: dbConfig.type || 'mysql',
|
|
158
|
+
host: dbConfig.host,
|
|
159
|
+
port: dbConfig.port,
|
|
160
|
+
username: dbConfig.username,
|
|
161
|
+
password: dbConfig.password,
|
|
162
|
+
database: dbConfig.database,
|
|
163
|
+
entities,
|
|
164
|
+
synchronize: false,
|
|
165
|
+
logging: false
|
|
166
|
+
});
|
|
167
|
+
await dataSource.initialize();
|
|
168
|
+
return dataSource;
|
|
201
169
|
}
|
|
202
|
-
|
|
203
|
-
* Get all tenant IDs from configuration
|
|
204
|
-
*/ async function getAllTenantIds(configPath) {
|
|
170
|
+
async function getAllTenantIds(configPath) {
|
|
205
171
|
const resolvedPath = await resolveConfigPath(configPath);
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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;
|
|
172
|
+
const module1 = await Promise.resolve(resolvedPath).then((p)=>/*#__PURE__*/ _interop_require_wildcard(require(p)));
|
|
173
|
+
const migrationConfig = module1.migrationConfig || module1.default?.migrationConfig || module1;
|
|
174
|
+
if (migrationConfig.bootstrapAppConfig?.databaseMode !== 'multi-tenant' || !migrationConfig.tenants) {
|
|
175
|
+
throw new Error('Multi-tenant mode is not configured');
|
|
216
176
|
}
|
|
177
|
+
return migrationConfig.tenants.map((t)=>t.tenantId || t.id);
|
|
217
178
|
}
|
|
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) {
|
|
179
|
+
async function runCommand(options, configPath) {
|
|
256
180
|
const dataSource = await loadDataSource(undefined, configPath);
|
|
257
181
|
try {
|
|
258
182
|
const runner = new _seedrunner.SeedRunner(dataSource);
|
|
@@ -267,18 +191,13 @@ let resolvedConfigPath;
|
|
|
267
191
|
}
|
|
268
192
|
} else {
|
|
269
193
|
const results = await runner.runAll(options);
|
|
270
|
-
|
|
271
|
-
if (failedCount > 0) {
|
|
272
|
-
process.exit(1);
|
|
273
|
-
}
|
|
194
|
+
if (results.some((r)=>!r.success)) process.exit(1);
|
|
274
195
|
}
|
|
275
196
|
} finally{
|
|
276
197
|
await dataSource.destroy();
|
|
277
198
|
}
|
|
278
199
|
}
|
|
279
|
-
|
|
280
|
-
* Run seeds for all tenants
|
|
281
|
-
*/ async function runAllTenantsCommand(options, configPath) {
|
|
200
|
+
async function runAllTenantsCommand(options, configPath) {
|
|
282
201
|
console.log('š¢ Running seeds for all tenants...\n');
|
|
283
202
|
const tenantIds = await getAllTenantIds(configPath);
|
|
284
203
|
let successCount = 0;
|
|
@@ -290,12 +209,7 @@ let resolvedConfigPath;
|
|
|
290
209
|
try {
|
|
291
210
|
const runner = new _seedrunner.SeedRunner(dataSource);
|
|
292
211
|
const results = await runner.runAll(options);
|
|
293
|
-
|
|
294
|
-
if (failed === 0) {
|
|
295
|
-
successCount++;
|
|
296
|
-
} else {
|
|
297
|
-
failCount++;
|
|
298
|
-
}
|
|
212
|
+
results.some((r)=>!r.success) ? failCount++ : successCount++;
|
|
299
213
|
} catch (error) {
|
|
300
214
|
console.error(`ā Failed to seed tenant ${tenantId}:`, error);
|
|
301
215
|
failCount++;
|
|
@@ -310,86 +224,65 @@ let resolvedConfigPath;
|
|
|
310
224
|
process.exit(1);
|
|
311
225
|
}
|
|
312
226
|
}
|
|
313
|
-
|
|
314
|
-
* Clear all seeded data
|
|
315
|
-
*/ async function clearCommand(hard = false, configPath) {
|
|
227
|
+
async function clearCommand(hard = false, configPath) {
|
|
316
228
|
const dataSource = await loadDataSource(undefined, configPath);
|
|
317
229
|
try {
|
|
318
|
-
|
|
319
|
-
await runner.clearAll(hard);
|
|
230
|
+
await new _seedrunner.SeedRunner(dataSource).clearAll(hard);
|
|
320
231
|
} finally{
|
|
321
232
|
await dataSource.destroy();
|
|
322
233
|
}
|
|
323
234
|
}
|
|
324
|
-
|
|
325
|
-
* Show seeding status
|
|
326
|
-
*/ async function statusCommand(configPath) {
|
|
235
|
+
async function statusCommand(configPath) {
|
|
327
236
|
const dataSource = await loadDataSource(undefined, configPath);
|
|
328
237
|
try {
|
|
329
|
-
const
|
|
330
|
-
const status = await runner.getStatus();
|
|
238
|
+
const status = await new _seedrunner.SeedRunner(dataSource).getStatus();
|
|
331
239
|
console.log('\nSeed Status:');
|
|
332
240
|
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāā¬āāāāāāāāāā');
|
|
333
241
|
console.log('ā Entity ā Records ā Status ā');
|
|
334
242
|
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāā¼āāāāāāāāāā¤');
|
|
335
243
|
for (const item of status){
|
|
336
|
-
|
|
337
|
-
const count = item.count.toString().padEnd(9);
|
|
338
|
-
const statusIcon = item.isEmpty ? 'ā Empty' : 'ā Ready ';
|
|
339
|
-
console.log(`ā ${entityName} ā ${count} ā ${statusIcon} ā`);
|
|
244
|
+
console.log(`ā ${item.entity.padEnd(26)} ā ${item.count.toString().padEnd(9)} ā ${item.isEmpty ? 'ā Empty' : 'ā Ready '} ā`);
|
|
340
245
|
}
|
|
341
246
|
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāā“āāāāāāāāāāāā“āāāāāāāāāā\n');
|
|
342
247
|
} finally{
|
|
343
248
|
await dataSource.destroy();
|
|
344
249
|
}
|
|
345
250
|
}
|
|
346
|
-
|
|
347
|
-
* Main CLI entry point
|
|
348
|
-
*/ async function main() {
|
|
251
|
+
async function main() {
|
|
349
252
|
const args = parseArgs();
|
|
350
253
|
if (!args.command) {
|
|
351
254
|
showHelp();
|
|
352
255
|
return;
|
|
353
256
|
}
|
|
354
|
-
// Initialize config path for all commands
|
|
355
257
|
if (args.configPath) {
|
|
356
258
|
await resolveConfigPath(args.configPath);
|
|
357
259
|
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
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);
|
|
260
|
+
switch(args.command){
|
|
261
|
+
case 'run':
|
|
262
|
+
await runCommand({
|
|
263
|
+
count: args.count,
|
|
264
|
+
clear: args.clear,
|
|
265
|
+
entity: args.entity
|
|
266
|
+
}, args.configPath);
|
|
267
|
+
break;
|
|
268
|
+
case 'run:all':
|
|
269
|
+
await runAllTenantsCommand({
|
|
270
|
+
count: args.count,
|
|
271
|
+
clear: args.clear
|
|
272
|
+
}, args.configPath);
|
|
273
|
+
break;
|
|
274
|
+
case 'clear':
|
|
275
|
+
await clearCommand(args.hard, args.configPath);
|
|
276
|
+
break;
|
|
277
|
+
case 'status':
|
|
278
|
+
await statusCommand(args.configPath);
|
|
279
|
+
break;
|
|
280
|
+
default:
|
|
281
|
+
console.error(`ā Unknown command: ${args.command}`);
|
|
282
|
+
showHelp();
|
|
283
|
+
process.exit(1);
|
|
390
284
|
}
|
|
391
285
|
}
|
|
392
|
-
// Run CLI if called directly
|
|
393
286
|
if (require.main === module) {
|
|
394
287
|
main().catch((error)=>{
|
|
395
288
|
console.error('Fatal error:', error);
|