@flusys/nestjs-core 3.0.0 → 4.0.0-rc
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 +1 -1
- package/cjs/config/env-config.service.js +2 -1
- package/cjs/docs/docs.config.js +5 -15
- package/cjs/seeders/data-generator.js +32 -21
- package/cjs/seeders/entity-reader.js +11 -33
- package/cjs/seeders/field-patterns.js +6 -0
- package/cjs/seeders/seed-runner.js +8 -41
- package/config/env-config.service.d.ts +1 -0
- package/fesm/config/env-config.service.js +2 -1
- package/fesm/docs/docs.config.js +7 -21
- package/fesm/seeders/data-generator.js +33 -27
- package/fesm/seeders/entity-reader.js +12 -46
- package/fesm/seeders/field-patterns.js +15 -19
- package/fesm/seeders/seed-runner.js +10 -64
- package/interfaces/database.interface.d.ts +1 -1
- package/package.json +1 -1
- package/seeders/data-generator.d.ts +2 -2
- package/seeders/entity-reader.d.ts +2 -2
- package/seeders/field-patterns.d.ts +1 -1
- package/seeders/seed-runner.d.ts +2 -2
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Core Package Guide
|
|
2
2
|
|
|
3
3
|
> **Package:** `@flusys/nestjs-core`
|
|
4
|
-
> **Version:** 3.0.
|
|
4
|
+
> **Version:** 3.0.1
|
|
5
5
|
> **Type:** Pure TypeScript foundation (zero NestJS dependencies)
|
|
6
6
|
|
|
7
7
|
Foundation layer providing type-safe configuration, database utilities, migration CLI, seeders with intelligent pattern detection, and Swagger setup.
|
|
@@ -133,7 +133,8 @@ let EnvConfigService = class EnvConfigService {
|
|
|
133
133
|
dir: this.getValue('LOG_DIR', false) || 'logs',
|
|
134
134
|
level: this.getValue('LOG_LEVEL', false) || (this.isProduction() ? 'info' : 'debug'),
|
|
135
135
|
maxSize: this.getValue('LOG_MAX_SIZE', false) || '20m',
|
|
136
|
-
maxFiles: this.getValue('LOG_MAX_FILES', false) || '14d'
|
|
136
|
+
maxFiles: this.getValue('LOG_MAX_FILES', false) || '14d',
|
|
137
|
+
disableHttpLogging: this.getValue('DISABLE_HTTP_LOGGING', false).toLowerCase() === 'true'
|
|
137
138
|
};
|
|
138
139
|
}
|
|
139
140
|
getEnv() {
|
package/cjs/docs/docs.config.js
CHANGED
|
@@ -17,9 +17,7 @@ _export(exports, {
|
|
|
17
17
|
}
|
|
18
18
|
});
|
|
19
19
|
const _swagger = require("@nestjs/swagger");
|
|
20
|
-
|
|
21
|
-
* Filter OpenAPI document to exclude schema properties
|
|
22
|
-
*/ function filterSchemaProperties(document, exclusions) {
|
|
20
|
+
function filterSchemaProperties(document, exclusions) {
|
|
23
21
|
if (!exclusions?.length || !document.components?.schemas) {
|
|
24
22
|
return document;
|
|
25
23
|
}
|
|
@@ -54,9 +52,7 @@ const _swagger = require("@nestjs/swagger");
|
|
|
54
52
|
}
|
|
55
53
|
};
|
|
56
54
|
}
|
|
57
|
-
|
|
58
|
-
* Filter OpenAPI document to exclude query parameters from specific endpoints
|
|
59
|
-
*/ function filterQueryParameters(document, exclusions) {
|
|
55
|
+
function filterQueryParameters(document, exclusions) {
|
|
60
56
|
if (!exclusions?.length || !document.paths) {
|
|
61
57
|
return document;
|
|
62
58
|
}
|
|
@@ -102,9 +98,7 @@ const _swagger = require("@nestjs/swagger");
|
|
|
102
98
|
paths: filteredPaths
|
|
103
99
|
};
|
|
104
100
|
}
|
|
105
|
-
|
|
106
|
-
* Filter OpenAPI document to exclude examples from endpoint responses
|
|
107
|
-
*/ function filterExamples(document, exclusions) {
|
|
101
|
+
function filterExamples(document, exclusions) {
|
|
108
102
|
if (!exclusions?.length || !document.paths) {
|
|
109
103
|
return document;
|
|
110
104
|
}
|
|
@@ -161,18 +155,14 @@ const _swagger = require("@nestjs/swagger");
|
|
|
161
155
|
paths: filteredPaths
|
|
162
156
|
};
|
|
163
157
|
}
|
|
164
|
-
|
|
165
|
-
* Check if a path matches a pattern (supports wildcards)
|
|
166
|
-
*/ function pathMatchesPattern(path, pattern) {
|
|
158
|
+
function pathMatchesPattern(path, pattern) {
|
|
167
159
|
// Convert wildcard pattern to regex
|
|
168
160
|
const regexPattern = pattern.replace(/\*/g, '[^/]+') // * matches any characters except /
|
|
169
161
|
.replace(/\*\*/g, '.*'); // ** matches any characters including /
|
|
170
162
|
const regex = new RegExp(`^${regexPattern}$`);
|
|
171
163
|
return regex.test(path);
|
|
172
164
|
}
|
|
173
|
-
|
|
174
|
-
* Filter OpenAPI document to exclude paths and tags based on excludeTags
|
|
175
|
-
*/ function filterDocumentByTags(document, excludeTags) {
|
|
165
|
+
function filterDocumentByTags(document, excludeTags) {
|
|
176
166
|
if (!excludeTags?.length) {
|
|
177
167
|
return document;
|
|
178
168
|
}
|
|
@@ -11,9 +11,7 @@ Object.defineProperty(exports, "DataGenerator", {
|
|
|
11
11
|
const _faker = require("@faker-js/faker");
|
|
12
12
|
const _fieldpatterns = require("./field-patterns");
|
|
13
13
|
let DataGenerator = class DataGenerator {
|
|
14
|
-
|
|
15
|
-
* Generate value for a single column based on its metadata
|
|
16
|
-
*/ generateValue(column) {
|
|
14
|
+
generateValue(column) {
|
|
17
15
|
if (column.isGenerated) return undefined;
|
|
18
16
|
// Handle nullable fields (50% chance of null)
|
|
19
17
|
if (column.isNullable && _faker.faker.datatype.boolean()) return null;
|
|
@@ -30,9 +28,7 @@ let DataGenerator = class DataGenerator {
|
|
|
30
28
|
// Generate based on column type
|
|
31
29
|
return this.generateByType(column);
|
|
32
30
|
}
|
|
33
|
-
|
|
34
|
-
* Generate entity object from column definitions
|
|
35
|
-
*/ generateEntity(columns) {
|
|
31
|
+
generateEntity(columns) {
|
|
36
32
|
const entity = {};
|
|
37
33
|
for (const column of columns){
|
|
38
34
|
const value = this.generateValue(column);
|
|
@@ -42,9 +38,7 @@ let DataGenerator = class DataGenerator {
|
|
|
42
38
|
}
|
|
43
39
|
return entity;
|
|
44
40
|
}
|
|
45
|
-
|
|
46
|
-
* Generate value based on detected field pattern
|
|
47
|
-
*/ generateByPattern(pattern, column) {
|
|
41
|
+
generateByPattern(pattern, column) {
|
|
48
42
|
switch(pattern){
|
|
49
43
|
case 'skip':
|
|
50
44
|
return undefined;
|
|
@@ -125,13 +119,36 @@ let DataGenerator = class DataGenerator {
|
|
|
125
119
|
'authenticated',
|
|
126
120
|
'permission'
|
|
127
121
|
]);
|
|
122
|
+
case 'notificationType':
|
|
123
|
+
return _faker.faker.helpers.arrayElement([
|
|
124
|
+
'INFO',
|
|
125
|
+
'SUCCESS',
|
|
126
|
+
'WARNING',
|
|
127
|
+
'ERROR'
|
|
128
|
+
]);
|
|
129
|
+
case 'languageCode':
|
|
130
|
+
return _faker.faker.helpers.arrayElement([
|
|
131
|
+
'en',
|
|
132
|
+
'ar',
|
|
133
|
+
'bn',
|
|
134
|
+
'es',
|
|
135
|
+
'fr',
|
|
136
|
+
'de',
|
|
137
|
+
'zh',
|
|
138
|
+
'ja',
|
|
139
|
+
'ko',
|
|
140
|
+
'hi'
|
|
141
|
+
]);
|
|
142
|
+
case 'languageDirection':
|
|
143
|
+
return _faker.faker.helpers.arrayElement([
|
|
144
|
+
'ltr',
|
|
145
|
+
'rtl'
|
|
146
|
+
]);
|
|
128
147
|
default:
|
|
129
148
|
return undefined;
|
|
130
149
|
}
|
|
131
150
|
}
|
|
132
|
-
|
|
133
|
-
* Generate value based on column type
|
|
134
|
-
*/ generateByType(column) {
|
|
151
|
+
generateByType(column) {
|
|
135
152
|
const category = (0, _fieldpatterns.detectTypeCategory)(column.type);
|
|
136
153
|
switch(category){
|
|
137
154
|
case 'string':
|
|
@@ -175,9 +192,7 @@ let DataGenerator = class DataGenerator {
|
|
|
175
192
|
return _faker.faker.lorem.word();
|
|
176
193
|
}
|
|
177
194
|
}
|
|
178
|
-
|
|
179
|
-
* Generate string value respecting length constraints
|
|
180
|
-
*/ generateString(column) {
|
|
195
|
+
generateString(column) {
|
|
181
196
|
const maxLength = typeof column.length === 'number' ? column.length : 255;
|
|
182
197
|
const category = (0, _fieldpatterns.getStringLengthCategory)(column.length);
|
|
183
198
|
switch(category){
|
|
@@ -189,15 +204,11 @@ let DataGenerator = class DataGenerator {
|
|
|
189
204
|
return _faker.faker.lorem.paragraph().substring(0, maxLength);
|
|
190
205
|
}
|
|
191
206
|
}
|
|
192
|
-
|
|
193
|
-
* Generate related entity ID (for foreign keys)
|
|
194
|
-
*/ generateRelationId(relatedEntities) {
|
|
207
|
+
generateRelationId(relatedEntities) {
|
|
195
208
|
if (relatedEntities.length === 0) return null;
|
|
196
209
|
return _faker.faker.helpers.arrayElement(relatedEntities).id;
|
|
197
210
|
}
|
|
198
|
-
|
|
199
|
-
* Generate multiple related entity IDs (for many-to-many)
|
|
200
|
-
*/ generateRelationIds(relatedEntities, min = 1, max = 3) {
|
|
211
|
+
generateRelationIds(relatedEntities, min = 1, max = 3) {
|
|
201
212
|
if (relatedEntities.length === 0) return [];
|
|
202
213
|
const count = _faker.faker.number.int({
|
|
203
214
|
min,
|
|
@@ -22,15 +22,10 @@ function _define_property(obj, key, value) {
|
|
|
22
22
|
return obj;
|
|
23
23
|
}
|
|
24
24
|
let EntityReader = class EntityReader {
|
|
25
|
-
|
|
26
|
-
* Get all entity metadata from DataSource
|
|
27
|
-
*/ getAllEntities() {
|
|
25
|
+
getAllEntities() {
|
|
28
26
|
return this.dataSource.entityMetadatas;
|
|
29
27
|
}
|
|
30
|
-
|
|
31
|
-
* Get detailed entity information
|
|
32
|
-
* @param entityName Entity class name or table name
|
|
33
|
-
*/ getEntityInfo(entityName) {
|
|
28
|
+
getEntityInfo(entityName) {
|
|
34
29
|
const metadata = this.findEntityMetadata(entityName);
|
|
35
30
|
if (!metadata) {
|
|
36
31
|
throw new Error(`Entity ${entityName} not found in DataSource`);
|
|
@@ -44,29 +39,22 @@ let EntityReader = class EntityReader {
|
|
|
44
39
|
hasCompany: this.hasCompanyColumn(metadata)
|
|
45
40
|
};
|
|
46
41
|
}
|
|
47
|
-
|
|
48
|
-
* Get seeding order based on foreign key dependencies
|
|
49
|
-
* Returns entity names sorted by dependency (independent entities first)
|
|
50
|
-
*/ getSeedingOrder(skipEntities = []) {
|
|
42
|
+
getSeedingOrder(skipEntities = []) {
|
|
51
43
|
const entities = this.getAllEntities().filter((e)=>!skipEntities.includes(e.name) && !skipEntities.includes(e.tableName));
|
|
52
44
|
const graph = this.buildDependencyGraph(entities);
|
|
53
45
|
return this.topologicalSort(graph);
|
|
54
46
|
}
|
|
55
|
-
|
|
56
|
-
* Find entity metadata by name or table name
|
|
57
|
-
*/ findEntityMetadata(entityName) {
|
|
47
|
+
findEntityMetadata(entityName) {
|
|
58
48
|
return this.getAllEntities().find((e)=>e.name === entityName || e.tableName === entityName);
|
|
59
49
|
}
|
|
60
|
-
|
|
61
|
-
* Extract column information from entity metadata
|
|
62
|
-
*/ extractColumns(metadata) {
|
|
50
|
+
extractColumns(metadata) {
|
|
63
51
|
return metadata.columns.map((col)=>({
|
|
64
52
|
name: col.databaseName,
|
|
65
53
|
propertyName: col.propertyName,
|
|
66
54
|
type: this.getColumnTypeString(col.type),
|
|
67
55
|
length: col.length,
|
|
68
56
|
isNullable: col.isNullable,
|
|
69
|
-
isUnique: col.isUnique === true
|
|
57
|
+
isUnique: 'isUnique' in col ? col.isUnique === true : false,
|
|
70
58
|
isPrimary: col.isPrimary,
|
|
71
59
|
isGenerated: col.isGenerated,
|
|
72
60
|
default: col.default,
|
|
@@ -75,9 +63,7 @@ let EntityReader = class EntityReader {
|
|
|
75
63
|
scale: col.scale ?? undefined
|
|
76
64
|
}));
|
|
77
65
|
}
|
|
78
|
-
|
|
79
|
-
* Extract relation information from entity metadata
|
|
80
|
-
*/ extractRelations(metadata) {
|
|
66
|
+
extractRelations(metadata) {
|
|
81
67
|
return metadata.relations.map((rel)=>({
|
|
82
68
|
propertyName: rel.propertyName,
|
|
83
69
|
type: rel.relationType,
|
|
@@ -86,14 +72,10 @@ let EntityReader = class EntityReader {
|
|
|
86
72
|
joinColumnName: rel.joinColumns?.[0]?.databaseName
|
|
87
73
|
}));
|
|
88
74
|
}
|
|
89
|
-
|
|
90
|
-
* Check if entity has company-related columns
|
|
91
|
-
*/ hasCompanyColumn(metadata) {
|
|
75
|
+
hasCompanyColumn(metadata) {
|
|
92
76
|
return metadata.columns.some((col)=>col.propertyName === 'companyId' || col.databaseName === 'company_id');
|
|
93
77
|
}
|
|
94
|
-
|
|
95
|
-
* Convert TypeORM column type to string
|
|
96
|
-
*/ getColumnTypeString(type) {
|
|
78
|
+
getColumnTypeString(type) {
|
|
97
79
|
if (typeof type === 'string') {
|
|
98
80
|
return type;
|
|
99
81
|
}
|
|
@@ -102,9 +84,7 @@ let EntityReader = class EntityReader {
|
|
|
102
84
|
}
|
|
103
85
|
return 'unknown';
|
|
104
86
|
}
|
|
105
|
-
|
|
106
|
-
* Build dependency graph for entities
|
|
107
|
-
*/ buildDependencyGraph(entities) {
|
|
87
|
+
buildDependencyGraph(entities) {
|
|
108
88
|
const graph = new Map();
|
|
109
89
|
for (const entity of entities){
|
|
110
90
|
const dependencies = [];
|
|
@@ -117,9 +97,7 @@ let EntityReader = class EntityReader {
|
|
|
117
97
|
}
|
|
118
98
|
return graph;
|
|
119
99
|
}
|
|
120
|
-
|
|
121
|
-
* Topological sort for dependency resolution
|
|
122
|
-
*/ topologicalSort(graph) {
|
|
100
|
+
topologicalSort(graph) {
|
|
123
101
|
const sorted = [];
|
|
124
102
|
const visited = new Set();
|
|
125
103
|
const visiting = new Set();
|
|
@@ -120,6 +120,12 @@ function detectFieldPattern(column) {
|
|
|
120
120
|
if (nameLower === 'provider' || nameLower === 'emailprovider') return 'emailProvider';
|
|
121
121
|
// Form access type
|
|
122
122
|
if (nameLower === 'accesstype' || nameLower === 'access_type') return 'formAccessType';
|
|
123
|
+
// Notification type (short varchar for type fields)
|
|
124
|
+
if (nameLower === 'type') return 'notificationType';
|
|
125
|
+
// Language code (short varchar for language codes like 'en', 'ar', 'bn')
|
|
126
|
+
if (nameLower === 'code') return 'languageCode';
|
|
127
|
+
// Language direction (ltr/rtl)
|
|
128
|
+
if (nameLower === 'direction') return 'languageDirection';
|
|
123
129
|
return undefined;
|
|
124
130
|
}
|
|
125
131
|
function detectTypeCategory(type) {
|
|
@@ -38,24 +38,13 @@ const defaultLogger = {
|
|
|
38
38
|
error: (message)=>console.error(message)
|
|
39
39
|
};
|
|
40
40
|
let SeedRunner = class SeedRunner {
|
|
41
|
-
|
|
42
|
-
* Register a custom seeder for specific entity
|
|
43
|
-
* Custom seeders take precedence over generic seeders
|
|
44
|
-
* @param entityName Entity name
|
|
45
|
-
* @param seeder Custom seeder instance
|
|
46
|
-
*/ registerCustomSeeder(entityName, seeder) {
|
|
41
|
+
registerCustomSeeder(entityName, seeder) {
|
|
47
42
|
this.customSeeders.set(entityName, seeder);
|
|
48
43
|
}
|
|
49
|
-
|
|
50
|
-
* Unregister a custom seeder
|
|
51
|
-
* @param entityName Entity name
|
|
52
|
-
*/ unregisterCustomSeeder(entityName) {
|
|
44
|
+
unregisterCustomSeeder(entityName) {
|
|
53
45
|
this.customSeeders.delete(entityName);
|
|
54
46
|
}
|
|
55
|
-
|
|
56
|
-
* Check if entity has custom seeder registered
|
|
57
|
-
* @param entityName Entity name
|
|
58
|
-
*/ hasCustomSeeder(entityName) {
|
|
47
|
+
hasCustomSeeder(entityName) {
|
|
59
48
|
return this.customSeeders.has(entityName);
|
|
60
49
|
}
|
|
61
50
|
getSeeder(entityName, entity, dataSource, entityInfo, batchSize) {
|
|
@@ -64,11 +53,7 @@ let SeedRunner = class SeedRunner {
|
|
|
64
53
|
}
|
|
65
54
|
return new GenericSeeder(dataSource, entity, this.dataGenerator, entityInfo, batchSize);
|
|
66
55
|
}
|
|
67
|
-
|
|
68
|
-
* Run seeds for all entities
|
|
69
|
-
* @param options Seeding options
|
|
70
|
-
* @returns Array of seed results
|
|
71
|
-
*/ async runAll(options = {}) {
|
|
56
|
+
async runAll(options = {}) {
|
|
72
57
|
const results = [];
|
|
73
58
|
const continueOnError = options.continueOnError ?? true;
|
|
74
59
|
// Get all entities
|
|
@@ -111,12 +96,7 @@ let SeedRunner = class SeedRunner {
|
|
|
111
96
|
}
|
|
112
97
|
return results;
|
|
113
98
|
}
|
|
114
|
-
|
|
115
|
-
* Run seed for a single entity
|
|
116
|
-
* @param entityName Entity name to seed
|
|
117
|
-
* @param options Seeding options
|
|
118
|
-
* @returns Seed result
|
|
119
|
-
*/ async runSingle(entityName, options = {}) {
|
|
99
|
+
async runSingle(entityName, options = {}) {
|
|
120
100
|
const queryRunner = this.dataSource.createQueryRunner();
|
|
121
101
|
await queryRunner.connect();
|
|
122
102
|
await queryRunner.startTransaction();
|
|
@@ -180,12 +160,7 @@ let SeedRunner = class SeedRunner {
|
|
|
180
160
|
await queryRunner.release();
|
|
181
161
|
}
|
|
182
162
|
}
|
|
183
|
-
|
|
184
|
-
* Clear all seeded data
|
|
185
|
-
* @param hard If true, hard delete (ignore soft delete)
|
|
186
|
-
* @param continueOnError If true, continue even if an entity fails (default: true)
|
|
187
|
-
* @returns Array of clear results
|
|
188
|
-
*/ async clearAll(hard = false, continueOnError = true) {
|
|
163
|
+
async clearAll(hard = false, continueOnError = true) {
|
|
189
164
|
const results = [];
|
|
190
165
|
// Get all entities
|
|
191
166
|
const allEntities = this.entityReader.getAllEntities();
|
|
@@ -245,10 +220,7 @@ let SeedRunner = class SeedRunner {
|
|
|
245
220
|
}
|
|
246
221
|
return results;
|
|
247
222
|
}
|
|
248
|
-
|
|
249
|
-
* Get status for all entities
|
|
250
|
-
* @returns Array of entity status
|
|
251
|
-
*/ async getStatus() {
|
|
223
|
+
async getStatus() {
|
|
252
224
|
const allEntities = this.entityReader.getAllEntities();
|
|
253
225
|
const status = [];
|
|
254
226
|
for (const metadata of allEntities){
|
|
@@ -282,12 +254,7 @@ let SeedRunner = class SeedRunner {
|
|
|
282
254
|
this.logger = logger ?? defaultLogger;
|
|
283
255
|
}
|
|
284
256
|
};
|
|
285
|
-
|
|
286
|
-
* Generic Seeder Implementation
|
|
287
|
-
*
|
|
288
|
-
* Used by SeedRunner for entities without custom seeders.
|
|
289
|
-
* Generates data based on entity metadata with batch processing support.
|
|
290
|
-
*/ let GenericSeeder = class GenericSeeder extends _baseseeder.BaseSeeder {
|
|
257
|
+
let GenericSeeder = class GenericSeeder extends _baseseeder.BaseSeeder {
|
|
291
258
|
async generate(count) {
|
|
292
259
|
const allSaved = [];
|
|
293
260
|
// Process in batches to optimize memory usage for large datasets
|
|
@@ -82,7 +82,8 @@ let EnvConfigService = class EnvConfigService {
|
|
|
82
82
|
dir: this.getValue('LOG_DIR', false) || 'logs',
|
|
83
83
|
level: this.getValue('LOG_LEVEL', false) || (this.isProduction() ? 'info' : 'debug'),
|
|
84
84
|
maxSize: this.getValue('LOG_MAX_SIZE', false) || '20m',
|
|
85
|
-
maxFiles: this.getValue('LOG_MAX_FILES', false) || '14d'
|
|
85
|
+
maxFiles: this.getValue('LOG_MAX_FILES', false) || '14d',
|
|
86
|
+
disableHttpLogging: this.getValue('DISABLE_HTTP_LOGGING', false).toLowerCase() === 'true'
|
|
86
87
|
};
|
|
87
88
|
}
|
|
88
89
|
getEnv() {
|
package/fesm/docs/docs.config.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
|
2
|
-
|
|
3
|
-
* Filter OpenAPI document to exclude schema properties
|
|
4
|
-
*/ function filterSchemaProperties(document, exclusions) {
|
|
2
|
+
function filterSchemaProperties(document, exclusions) {
|
|
5
3
|
if (!exclusions?.length || !document.components?.schemas) {
|
|
6
4
|
return document;
|
|
7
5
|
}
|
|
@@ -36,9 +34,7 @@ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
|
|
36
34
|
}
|
|
37
35
|
};
|
|
38
36
|
}
|
|
39
|
-
|
|
40
|
-
* Filter OpenAPI document to exclude query parameters from specific endpoints
|
|
41
|
-
*/ function filterQueryParameters(document, exclusions) {
|
|
37
|
+
function filterQueryParameters(document, exclusions) {
|
|
42
38
|
if (!exclusions?.length || !document.paths) {
|
|
43
39
|
return document;
|
|
44
40
|
}
|
|
@@ -84,9 +80,7 @@ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
|
|
84
80
|
paths: filteredPaths
|
|
85
81
|
};
|
|
86
82
|
}
|
|
87
|
-
|
|
88
|
-
* Filter OpenAPI document to exclude examples from endpoint responses
|
|
89
|
-
*/ function filterExamples(document, exclusions) {
|
|
83
|
+
function filterExamples(document, exclusions) {
|
|
90
84
|
if (!exclusions?.length || !document.paths) {
|
|
91
85
|
return document;
|
|
92
86
|
}
|
|
@@ -143,18 +137,14 @@ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
|
|
143
137
|
paths: filteredPaths
|
|
144
138
|
};
|
|
145
139
|
}
|
|
146
|
-
|
|
147
|
-
* Check if a path matches a pattern (supports wildcards)
|
|
148
|
-
*/ function pathMatchesPattern(path, pattern) {
|
|
140
|
+
function pathMatchesPattern(path, pattern) {
|
|
149
141
|
// Convert wildcard pattern to regex
|
|
150
142
|
const regexPattern = pattern.replace(/\*/g, '[^/]+') // * matches any characters except /
|
|
151
143
|
.replace(/\*\*/g, '.*'); // ** matches any characters including /
|
|
152
144
|
const regex = new RegExp(`^${regexPattern}$`);
|
|
153
145
|
return regex.test(path);
|
|
154
146
|
}
|
|
155
|
-
|
|
156
|
-
* Filter OpenAPI document to exclude paths and tags based on excludeTags
|
|
157
|
-
*/ function filterDocumentByTags(document, excludeTags) {
|
|
147
|
+
function filterDocumentByTags(document, excludeTags) {
|
|
158
148
|
if (!excludeTags?.length) {
|
|
159
149
|
return document;
|
|
160
150
|
}
|
|
@@ -197,9 +187,7 @@ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
|
|
197
187
|
tags: filteredTags
|
|
198
188
|
};
|
|
199
189
|
}
|
|
200
|
-
|
|
201
|
-
* Setup Swagger documentation for multiple modules
|
|
202
|
-
*/ export function setupModuleSwaggerDocs(app, configs) {
|
|
190
|
+
export function setupModuleSwaggerDocs(app, configs) {
|
|
203
191
|
configs.forEach((config)=>{
|
|
204
192
|
const builder = new DocumentBuilder().setTitle(config.title).setDescription(config.description).setVersion(config.version || '1.0');
|
|
205
193
|
// Add bearer auth
|
|
@@ -245,8 +233,6 @@ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
|
|
245
233
|
SwaggerModule.setup(config.path, app, document);
|
|
246
234
|
});
|
|
247
235
|
}
|
|
248
|
-
|
|
249
|
-
* Setup Swagger docs with variadic module configs
|
|
250
|
-
*/ export function setupSwaggerDocs(app, ...modules) {
|
|
236
|
+
export function setupSwaggerDocs(app, ...modules) {
|
|
251
237
|
setupModuleSwaggerDocs(app, modules);
|
|
252
238
|
}
|
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
import { faker } from '@faker-js/faker';
|
|
2
2
|
import { detectFieldPattern, detectTypeCategory, getStringLengthCategory, getTokenLength } from './field-patterns';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
*
|
|
6
|
-
* Generates realistic sample data based on column metadata.
|
|
7
|
-
* Uses @faker-js/faker for data generation with intelligent field detection.
|
|
8
|
-
*/ export class DataGenerator {
|
|
9
|
-
/**
|
|
10
|
-
* Generate value for a single column based on its metadata
|
|
11
|
-
*/ generateValue(column) {
|
|
3
|
+
export class DataGenerator {
|
|
4
|
+
generateValue(column) {
|
|
12
5
|
if (column.isGenerated) return undefined;
|
|
13
6
|
// Handle nullable fields (50% chance of null)
|
|
14
7
|
if (column.isNullable && faker.datatype.boolean()) return null;
|
|
@@ -25,9 +18,7 @@ import { detectFieldPattern, detectTypeCategory, getStringLengthCategory, getTok
|
|
|
25
18
|
// Generate based on column type
|
|
26
19
|
return this.generateByType(column);
|
|
27
20
|
}
|
|
28
|
-
|
|
29
|
-
* Generate entity object from column definitions
|
|
30
|
-
*/ generateEntity(columns) {
|
|
21
|
+
generateEntity(columns) {
|
|
31
22
|
const entity = {};
|
|
32
23
|
for (const column of columns){
|
|
33
24
|
const value = this.generateValue(column);
|
|
@@ -37,9 +28,7 @@ import { detectFieldPattern, detectTypeCategory, getStringLengthCategory, getTok
|
|
|
37
28
|
}
|
|
38
29
|
return entity;
|
|
39
30
|
}
|
|
40
|
-
|
|
41
|
-
* Generate value based on detected field pattern
|
|
42
|
-
*/ generateByPattern(pattern, column) {
|
|
31
|
+
generateByPattern(pattern, column) {
|
|
43
32
|
switch(pattern){
|
|
44
33
|
case 'skip':
|
|
45
34
|
return undefined;
|
|
@@ -120,13 +109,36 @@ import { detectFieldPattern, detectTypeCategory, getStringLengthCategory, getTok
|
|
|
120
109
|
'authenticated',
|
|
121
110
|
'permission'
|
|
122
111
|
]);
|
|
112
|
+
case 'notificationType':
|
|
113
|
+
return faker.helpers.arrayElement([
|
|
114
|
+
'INFO',
|
|
115
|
+
'SUCCESS',
|
|
116
|
+
'WARNING',
|
|
117
|
+
'ERROR'
|
|
118
|
+
]);
|
|
119
|
+
case 'languageCode':
|
|
120
|
+
return faker.helpers.arrayElement([
|
|
121
|
+
'en',
|
|
122
|
+
'ar',
|
|
123
|
+
'bn',
|
|
124
|
+
'es',
|
|
125
|
+
'fr',
|
|
126
|
+
'de',
|
|
127
|
+
'zh',
|
|
128
|
+
'ja',
|
|
129
|
+
'ko',
|
|
130
|
+
'hi'
|
|
131
|
+
]);
|
|
132
|
+
case 'languageDirection':
|
|
133
|
+
return faker.helpers.arrayElement([
|
|
134
|
+
'ltr',
|
|
135
|
+
'rtl'
|
|
136
|
+
]);
|
|
123
137
|
default:
|
|
124
138
|
return undefined;
|
|
125
139
|
}
|
|
126
140
|
}
|
|
127
|
-
|
|
128
|
-
* Generate value based on column type
|
|
129
|
-
*/ generateByType(column) {
|
|
141
|
+
generateByType(column) {
|
|
130
142
|
const category = detectTypeCategory(column.type);
|
|
131
143
|
switch(category){
|
|
132
144
|
case 'string':
|
|
@@ -170,9 +182,7 @@ import { detectFieldPattern, detectTypeCategory, getStringLengthCategory, getTok
|
|
|
170
182
|
return faker.lorem.word();
|
|
171
183
|
}
|
|
172
184
|
}
|
|
173
|
-
|
|
174
|
-
* Generate string value respecting length constraints
|
|
175
|
-
*/ generateString(column) {
|
|
185
|
+
generateString(column) {
|
|
176
186
|
const maxLength = typeof column.length === 'number' ? column.length : 255;
|
|
177
187
|
const category = getStringLengthCategory(column.length);
|
|
178
188
|
switch(category){
|
|
@@ -184,15 +194,11 @@ import { detectFieldPattern, detectTypeCategory, getStringLengthCategory, getTok
|
|
|
184
194
|
return faker.lorem.paragraph().substring(0, maxLength);
|
|
185
195
|
}
|
|
186
196
|
}
|
|
187
|
-
|
|
188
|
-
* Generate related entity ID (for foreign keys)
|
|
189
|
-
*/ generateRelationId(relatedEntities) {
|
|
197
|
+
generateRelationId(relatedEntities) {
|
|
190
198
|
if (relatedEntities.length === 0) return null;
|
|
191
199
|
return faker.helpers.arrayElement(relatedEntities).id;
|
|
192
200
|
}
|
|
193
|
-
|
|
194
|
-
* Generate multiple related entity IDs (for many-to-many)
|
|
195
|
-
*/ generateRelationIds(relatedEntities, min = 1, max = 3) {
|
|
201
|
+
generateRelationIds(relatedEntities, min = 1, max = 3) {
|
|
196
202
|
if (relatedEntities.length === 0) return [];
|
|
197
203
|
const count = faker.number.int({
|
|
198
204
|
min,
|
|
@@ -11,28 +11,11 @@ function _define_property(obj, key, value) {
|
|
|
11
11
|
}
|
|
12
12
|
return obj;
|
|
13
13
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
*
|
|
17
|
-
* Extracts metadata from TypeORM entities for seed data generation.
|
|
18
|
-
* Discovers columns, types, constraints, and relationships.
|
|
19
|
-
*
|
|
20
|
-
* Usage:
|
|
21
|
-
* ```typescript
|
|
22
|
-
* const reader = new EntityReader(dataSource);
|
|
23
|
-
* const entities = reader.getAllEntities();
|
|
24
|
-
* const userInfo = reader.getEntityInfo('User');
|
|
25
|
-
* ```
|
|
26
|
-
*/ export class EntityReader {
|
|
27
|
-
/**
|
|
28
|
-
* Get all entity metadata from DataSource
|
|
29
|
-
*/ getAllEntities() {
|
|
14
|
+
export class EntityReader {
|
|
15
|
+
getAllEntities() {
|
|
30
16
|
return this.dataSource.entityMetadatas;
|
|
31
17
|
}
|
|
32
|
-
|
|
33
|
-
* Get detailed entity information
|
|
34
|
-
* @param entityName Entity class name or table name
|
|
35
|
-
*/ getEntityInfo(entityName) {
|
|
18
|
+
getEntityInfo(entityName) {
|
|
36
19
|
const metadata = this.findEntityMetadata(entityName);
|
|
37
20
|
if (!metadata) {
|
|
38
21
|
throw new Error(`Entity ${entityName} not found in DataSource`);
|
|
@@ -46,29 +29,22 @@ function _define_property(obj, key, value) {
|
|
|
46
29
|
hasCompany: this.hasCompanyColumn(metadata)
|
|
47
30
|
};
|
|
48
31
|
}
|
|
49
|
-
|
|
50
|
-
* Get seeding order based on foreign key dependencies
|
|
51
|
-
* Returns entity names sorted by dependency (independent entities first)
|
|
52
|
-
*/ getSeedingOrder(skipEntities = []) {
|
|
32
|
+
getSeedingOrder(skipEntities = []) {
|
|
53
33
|
const entities = this.getAllEntities().filter((e)=>!skipEntities.includes(e.name) && !skipEntities.includes(e.tableName));
|
|
54
34
|
const graph = this.buildDependencyGraph(entities);
|
|
55
35
|
return this.topologicalSort(graph);
|
|
56
36
|
}
|
|
57
|
-
|
|
58
|
-
* Find entity metadata by name or table name
|
|
59
|
-
*/ findEntityMetadata(entityName) {
|
|
37
|
+
findEntityMetadata(entityName) {
|
|
60
38
|
return this.getAllEntities().find((e)=>e.name === entityName || e.tableName === entityName);
|
|
61
39
|
}
|
|
62
|
-
|
|
63
|
-
* Extract column information from entity metadata
|
|
64
|
-
*/ extractColumns(metadata) {
|
|
40
|
+
extractColumns(metadata) {
|
|
65
41
|
return metadata.columns.map((col)=>({
|
|
66
42
|
name: col.databaseName,
|
|
67
43
|
propertyName: col.propertyName,
|
|
68
44
|
type: this.getColumnTypeString(col.type),
|
|
69
45
|
length: col.length,
|
|
70
46
|
isNullable: col.isNullable,
|
|
71
|
-
isUnique: col.isUnique === true
|
|
47
|
+
isUnique: 'isUnique' in col ? col.isUnique === true : false,
|
|
72
48
|
isPrimary: col.isPrimary,
|
|
73
49
|
isGenerated: col.isGenerated,
|
|
74
50
|
default: col.default,
|
|
@@ -77,9 +53,7 @@ function _define_property(obj, key, value) {
|
|
|
77
53
|
scale: col.scale ?? undefined
|
|
78
54
|
}));
|
|
79
55
|
}
|
|
80
|
-
|
|
81
|
-
* Extract relation information from entity metadata
|
|
82
|
-
*/ extractRelations(metadata) {
|
|
56
|
+
extractRelations(metadata) {
|
|
83
57
|
return metadata.relations.map((rel)=>({
|
|
84
58
|
propertyName: rel.propertyName,
|
|
85
59
|
type: rel.relationType,
|
|
@@ -88,14 +62,10 @@ function _define_property(obj, key, value) {
|
|
|
88
62
|
joinColumnName: rel.joinColumns?.[0]?.databaseName
|
|
89
63
|
}));
|
|
90
64
|
}
|
|
91
|
-
|
|
92
|
-
* Check if entity has company-related columns
|
|
93
|
-
*/ hasCompanyColumn(metadata) {
|
|
65
|
+
hasCompanyColumn(metadata) {
|
|
94
66
|
return metadata.columns.some((col)=>col.propertyName === 'companyId' || col.databaseName === 'company_id');
|
|
95
67
|
}
|
|
96
|
-
|
|
97
|
-
* Convert TypeORM column type to string
|
|
98
|
-
*/ getColumnTypeString(type) {
|
|
68
|
+
getColumnTypeString(type) {
|
|
99
69
|
if (typeof type === 'string') {
|
|
100
70
|
return type;
|
|
101
71
|
}
|
|
@@ -104,9 +74,7 @@ function _define_property(obj, key, value) {
|
|
|
104
74
|
}
|
|
105
75
|
return 'unknown';
|
|
106
76
|
}
|
|
107
|
-
|
|
108
|
-
* Build dependency graph for entities
|
|
109
|
-
*/ buildDependencyGraph(entities) {
|
|
77
|
+
buildDependencyGraph(entities) {
|
|
110
78
|
const graph = new Map();
|
|
111
79
|
for (const entity of entities){
|
|
112
80
|
const dependencies = [];
|
|
@@ -119,9 +87,7 @@ function _define_property(obj, key, value) {
|
|
|
119
87
|
}
|
|
120
88
|
return graph;
|
|
121
89
|
}
|
|
122
|
-
|
|
123
|
-
* Topological sort for dependency resolution
|
|
124
|
-
*/ topologicalSort(graph) {
|
|
90
|
+
topologicalSort(graph) {
|
|
125
91
|
const sorted = [];
|
|
126
92
|
const visited = new Set();
|
|
127
93
|
const visiting = new Set();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
export const SYSTEM_FIELDS = [
|
|
2
2
|
'id',
|
|
3
3
|
'createdAt',
|
|
4
4
|
'updatedAt',
|
|
@@ -7,18 +7,18 @@
|
|
|
7
7
|
'updatedById',
|
|
8
8
|
'deletedById'
|
|
9
9
|
];
|
|
10
|
-
|
|
10
|
+
export const AUDIT_FIELDS = [
|
|
11
11
|
'createdbyid',
|
|
12
12
|
'updatedbyid',
|
|
13
13
|
'deletedbyid'
|
|
14
14
|
];
|
|
15
|
-
|
|
15
|
+
export const IDENTITY_FIELDS = [
|
|
16
16
|
'id',
|
|
17
17
|
'createdat',
|
|
18
18
|
'updatedat',
|
|
19
19
|
'deletedat'
|
|
20
20
|
];
|
|
21
|
-
|
|
21
|
+
export const BOOLEAN_KEYWORDS = [
|
|
22
22
|
'verified',
|
|
23
23
|
'active',
|
|
24
24
|
'enabled',
|
|
@@ -26,9 +26,7 @@
|
|
|
26
26
|
'readonly',
|
|
27
27
|
'valid'
|
|
28
28
|
];
|
|
29
|
-
|
|
30
|
-
* Detect field pattern from column name
|
|
31
|
-
*/ export function detectFieldPattern(column) {
|
|
29
|
+
export function detectFieldPattern(column) {
|
|
32
30
|
const nameLower = column.propertyName.toLowerCase();
|
|
33
31
|
const typeLower = column.type.toLowerCase();
|
|
34
32
|
// Identity fields (skip)
|
|
@@ -83,11 +81,15 @@
|
|
|
83
81
|
if (nameLower === 'provider' || nameLower === 'emailprovider') return 'emailProvider';
|
|
84
82
|
// Form access type
|
|
85
83
|
if (nameLower === 'accesstype' || nameLower === 'access_type') return 'formAccessType';
|
|
84
|
+
// Notification type (short varchar for type fields)
|
|
85
|
+
if (nameLower === 'type') return 'notificationType';
|
|
86
|
+
// Language code (short varchar for language codes like 'en', 'ar', 'bn')
|
|
87
|
+
if (nameLower === 'code') return 'languageCode';
|
|
88
|
+
// Language direction (ltr/rtl)
|
|
89
|
+
if (nameLower === 'direction') return 'languageDirection';
|
|
86
90
|
return undefined;
|
|
87
91
|
}
|
|
88
|
-
|
|
89
|
-
* Detect column type category
|
|
90
|
-
*/ export function detectTypeCategory(type) {
|
|
92
|
+
export function detectTypeCategory(type) {
|
|
91
93
|
const typeLower = type.toLowerCase();
|
|
92
94
|
if ([
|
|
93
95
|
'varchar',
|
|
@@ -126,22 +128,16 @@
|
|
|
126
128
|
if (typeLower === 'array') return 'array';
|
|
127
129
|
return 'unknown';
|
|
128
130
|
}
|
|
129
|
-
|
|
130
|
-
* Get string length category for faker generation
|
|
131
|
-
*/ export function getStringLengthCategory(length) {
|
|
131
|
+
export function getStringLengthCategory(length) {
|
|
132
132
|
const maxLength = typeof length === 'number' ? length : 255;
|
|
133
133
|
if (maxLength <= 50) return 'word';
|
|
134
134
|
if (maxLength <= 255) return 'sentence';
|
|
135
135
|
return 'paragraph';
|
|
136
136
|
}
|
|
137
|
-
|
|
138
|
-
* Check if field is a system field
|
|
139
|
-
*/ export function isSystemField(fieldName) {
|
|
137
|
+
export function isSystemField(fieldName) {
|
|
140
138
|
return SYSTEM_FIELDS.includes(fieldName);
|
|
141
139
|
}
|
|
142
|
-
|
|
143
|
-
* Get token max length respecting column constraints
|
|
144
|
-
*/ export function getTokenLength(column) {
|
|
140
|
+
export function getTokenLength(column) {
|
|
145
141
|
const maxLength = typeof column.length === 'number' ? column.length : 64;
|
|
146
142
|
return Math.min(maxLength, 32);
|
|
147
143
|
}
|
|
@@ -15,50 +15,18 @@ import { EntityReader } from './entity-reader';
|
|
|
15
15
|
import { DataGenerator } from './data-generator';
|
|
16
16
|
import { BaseSeeder } from './base-seeder';
|
|
17
17
|
import { seedConfig, getEntityCount, shouldSkipEntity, getSeedingOrder } from './seed-config';
|
|
18
|
-
|
|
19
|
-
* Default console logger implementation
|
|
20
|
-
*/ export const defaultLogger = {
|
|
18
|
+
export const defaultLogger = {
|
|
21
19
|
log: (message)=>console.log(message),
|
|
22
20
|
error: (message)=>console.error(message)
|
|
23
21
|
};
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
*
|
|
27
|
-
* Orchestrates seed data generation across all entities.
|
|
28
|
-
* Handles dependency order, transactions, and error reporting.
|
|
29
|
-
*
|
|
30
|
-
* Usage:
|
|
31
|
-
* ```typescript
|
|
32
|
-
* const runner = new SeedRunner(dataSource);
|
|
33
|
-
* await runner.runAll();
|
|
34
|
-
* await runner.runSingle('User', { count: 50 });
|
|
35
|
-
* await runner.clearAll();
|
|
36
|
-
*
|
|
37
|
-
* // With custom logger
|
|
38
|
-
* const runner = new SeedRunner(dataSource, customLogger);
|
|
39
|
-
*
|
|
40
|
-
* // With custom seeder
|
|
41
|
-
* runner.registerCustomSeeder('User', new UserSeeder(dataSource));
|
|
42
|
-
* ```
|
|
43
|
-
*/ export class SeedRunner {
|
|
44
|
-
/**
|
|
45
|
-
* Register a custom seeder for specific entity
|
|
46
|
-
* Custom seeders take precedence over generic seeders
|
|
47
|
-
* @param entityName Entity name
|
|
48
|
-
* @param seeder Custom seeder instance
|
|
49
|
-
*/ registerCustomSeeder(entityName, seeder) {
|
|
22
|
+
export class SeedRunner {
|
|
23
|
+
registerCustomSeeder(entityName, seeder) {
|
|
50
24
|
this.customSeeders.set(entityName, seeder);
|
|
51
25
|
}
|
|
52
|
-
|
|
53
|
-
* Unregister a custom seeder
|
|
54
|
-
* @param entityName Entity name
|
|
55
|
-
*/ unregisterCustomSeeder(entityName) {
|
|
26
|
+
unregisterCustomSeeder(entityName) {
|
|
56
27
|
this.customSeeders.delete(entityName);
|
|
57
28
|
}
|
|
58
|
-
|
|
59
|
-
* Check if entity has custom seeder registered
|
|
60
|
-
* @param entityName Entity name
|
|
61
|
-
*/ hasCustomSeeder(entityName) {
|
|
29
|
+
hasCustomSeeder(entityName) {
|
|
62
30
|
return this.customSeeders.has(entityName);
|
|
63
31
|
}
|
|
64
32
|
getSeeder(entityName, entity, dataSource, entityInfo, batchSize) {
|
|
@@ -67,11 +35,7 @@ import { seedConfig, getEntityCount, shouldSkipEntity, getSeedingOrder } from '.
|
|
|
67
35
|
}
|
|
68
36
|
return new GenericSeeder(dataSource, entity, this.dataGenerator, entityInfo, batchSize);
|
|
69
37
|
}
|
|
70
|
-
|
|
71
|
-
* Run seeds for all entities
|
|
72
|
-
* @param options Seeding options
|
|
73
|
-
* @returns Array of seed results
|
|
74
|
-
*/ async runAll(options = {}) {
|
|
38
|
+
async runAll(options = {}) {
|
|
75
39
|
const results = [];
|
|
76
40
|
const continueOnError = options.continueOnError ?? true;
|
|
77
41
|
// Get all entities
|
|
@@ -114,12 +78,7 @@ import { seedConfig, getEntityCount, shouldSkipEntity, getSeedingOrder } from '.
|
|
|
114
78
|
}
|
|
115
79
|
return results;
|
|
116
80
|
}
|
|
117
|
-
|
|
118
|
-
* Run seed for a single entity
|
|
119
|
-
* @param entityName Entity name to seed
|
|
120
|
-
* @param options Seeding options
|
|
121
|
-
* @returns Seed result
|
|
122
|
-
*/ async runSingle(entityName, options = {}) {
|
|
81
|
+
async runSingle(entityName, options = {}) {
|
|
123
82
|
const queryRunner = this.dataSource.createQueryRunner();
|
|
124
83
|
await queryRunner.connect();
|
|
125
84
|
await queryRunner.startTransaction();
|
|
@@ -183,12 +142,7 @@ import { seedConfig, getEntityCount, shouldSkipEntity, getSeedingOrder } from '.
|
|
|
183
142
|
await queryRunner.release();
|
|
184
143
|
}
|
|
185
144
|
}
|
|
186
|
-
|
|
187
|
-
* Clear all seeded data
|
|
188
|
-
* @param hard If true, hard delete (ignore soft delete)
|
|
189
|
-
* @param continueOnError If true, continue even if an entity fails (default: true)
|
|
190
|
-
* @returns Array of clear results
|
|
191
|
-
*/ async clearAll(hard = false, continueOnError = true) {
|
|
145
|
+
async clearAll(hard = false, continueOnError = true) {
|
|
192
146
|
const results = [];
|
|
193
147
|
// Get all entities
|
|
194
148
|
const allEntities = this.entityReader.getAllEntities();
|
|
@@ -248,10 +202,7 @@ import { seedConfig, getEntityCount, shouldSkipEntity, getSeedingOrder } from '.
|
|
|
248
202
|
}
|
|
249
203
|
return results;
|
|
250
204
|
}
|
|
251
|
-
|
|
252
|
-
* Get status for all entities
|
|
253
|
-
* @returns Array of entity status
|
|
254
|
-
*/ async getStatus() {
|
|
205
|
+
async getStatus() {
|
|
255
206
|
const allEntities = this.entityReader.getAllEntities();
|
|
256
207
|
const status = [];
|
|
257
208
|
for (const metadata of allEntities){
|
|
@@ -285,12 +236,7 @@ import { seedConfig, getEntityCount, shouldSkipEntity, getSeedingOrder } from '.
|
|
|
285
236
|
this.logger = logger ?? defaultLogger;
|
|
286
237
|
}
|
|
287
238
|
}
|
|
288
|
-
|
|
289
|
-
* Generic Seeder Implementation
|
|
290
|
-
*
|
|
291
|
-
* Used by SeedRunner for entities without custom seeders.
|
|
292
|
-
* Generates data based on entity metadata with batch processing support.
|
|
293
|
-
*/ let GenericSeeder = class GenericSeeder extends BaseSeeder {
|
|
239
|
+
let GenericSeeder = class GenericSeeder extends BaseSeeder {
|
|
294
240
|
async generate(count) {
|
|
295
241
|
const allSaved = [];
|
|
296
242
|
// Process in batches to optimize memory usage for large datasets
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { IColumnInfo } from './entity-reader';
|
|
2
2
|
export declare class DataGenerator {
|
|
3
3
|
constructor(locale?: string);
|
|
4
|
-
generateValue(column: IColumnInfo):
|
|
5
|
-
generateEntity(columns: IColumnInfo[]): Record<string,
|
|
4
|
+
generateValue(column: IColumnInfo): unknown;
|
|
5
|
+
generateEntity(columns: IColumnInfo[]): Record<string, unknown>;
|
|
6
6
|
private generateByPattern;
|
|
7
7
|
private generateByType;
|
|
8
8
|
private generateString;
|
|
@@ -3,7 +3,7 @@ export declare const SYSTEM_FIELDS: string[];
|
|
|
3
3
|
export declare const AUDIT_FIELDS: string[];
|
|
4
4
|
export declare const IDENTITY_FIELDS: string[];
|
|
5
5
|
export declare const BOOLEAN_KEYWORDS: string[];
|
|
6
|
-
export type FieldPatternType = 'skip' | 'null' | 'boolean' | 'token' | 'firstName' | 'lastName' | 'fullName' | 'email' | 'phone' | 'address' | 'street' | 'city' | 'state' | 'country' | 'zipCode' | 'url' | 'domain' | 'slug' | 'description' | 'summary' | 'content' | 'title' | 'username' | 'password' | 'birthdate' | 'futureDate' | 'recentDateOrNull' | 'serial' | 'company' | 'emailProvider' | 'formAccessType';
|
|
6
|
+
export type FieldPatternType = 'skip' | 'null' | 'boolean' | 'token' | 'firstName' | 'lastName' | 'fullName' | 'email' | 'phone' | 'address' | 'street' | 'city' | 'state' | 'country' | 'zipCode' | 'url' | 'domain' | 'slug' | 'description' | 'summary' | 'content' | 'title' | 'username' | 'password' | 'birthdate' | 'futureDate' | 'recentDateOrNull' | 'serial' | 'company' | 'emailProvider' | 'formAccessType' | 'notificationType' | 'languageCode' | 'languageDirection';
|
|
7
7
|
export type ColumnTypeCategory = 'string' | 'integer' | 'decimal' | 'boolean' | 'date' | 'timestamp' | 'time' | 'uuid' | 'json' | 'array' | 'unknown';
|
|
8
8
|
export declare function detectFieldPattern(column: IColumnInfo): FieldPatternType | undefined;
|
|
9
9
|
export declare function detectTypeCategory(type: string): ColumnTypeCategory;
|
package/seeders/seed-runner.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DataSource } from 'typeorm';
|
|
1
|
+
import { DataSource, ObjectLiteral } from 'typeorm';
|
|
2
2
|
import { BaseSeeder } from './base-seeder';
|
|
3
3
|
export interface ISeederLogger {
|
|
4
4
|
log(message: string): void;
|
|
@@ -31,7 +31,7 @@ export declare class SeedRunner {
|
|
|
31
31
|
private logger;
|
|
32
32
|
private customSeeders;
|
|
33
33
|
constructor(dataSource: DataSource, logger?: ISeederLogger);
|
|
34
|
-
registerCustomSeeder(entityName: string, seeder: BaseSeeder<
|
|
34
|
+
registerCustomSeeder(entityName: string, seeder: BaseSeeder<ObjectLiteral>): void;
|
|
35
35
|
unregisterCustomSeeder(entityName: string): void;
|
|
36
36
|
hasCustomSeeder(entityName: string): boolean;
|
|
37
37
|
private getSeeder;
|