@flusys/nestjs-core 4.1.0 → 5.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.
@@ -1,216 +0,0 @@
1
- import { faker } from '@faker-js/faker';
2
- import { detectFieldPattern, detectTypeCategory, getStringLengthCategory, getTokenLength } from './field-patterns';
3
- export class DataGenerator {
4
- generateValue(column) {
5
- if (column.isGenerated) return undefined;
6
- // Handle nullable fields (50% chance of null)
7
- if (column.isNullable && faker.datatype.boolean()) return null;
8
- // Check for enum
9
- if (column.enum && column.enum.length > 0) {
10
- return faker.helpers.arrayElement(column.enum);
11
- }
12
- // Generate based on field pattern
13
- const pattern = detectFieldPattern(column);
14
- if (pattern) {
15
- const value = this.generateByPattern(pattern, column);
16
- if (value !== undefined) return value;
17
- }
18
- // Generate based on column type
19
- return this.generateByType(column);
20
- }
21
- generateEntity(columns) {
22
- const entity = {};
23
- for (const column of columns){
24
- const value = this.generateValue(column);
25
- if (value !== undefined) {
26
- entity[column.propertyName] = value;
27
- }
28
- }
29
- return entity;
30
- }
31
- generateByPattern(pattern, column) {
32
- switch(pattern){
33
- case 'skip':
34
- return undefined;
35
- case 'null':
36
- return null;
37
- case 'boolean':
38
- return faker.datatype.boolean();
39
- case 'token':
40
- return faker.string.alphanumeric(getTokenLength(column));
41
- case 'firstName':
42
- return faker.person.firstName();
43
- case 'lastName':
44
- return faker.person.lastName();
45
- case 'fullName':
46
- return faker.person.fullName();
47
- case 'email':
48
- return faker.internet.email().toLowerCase();
49
- case 'phone':
50
- return faker.phone.number();
51
- case 'address':
52
- return faker.location.streetAddress();
53
- case 'street':
54
- return faker.location.street();
55
- case 'city':
56
- return faker.location.city();
57
- case 'state':
58
- return faker.location.state();
59
- case 'country':
60
- return faker.location.country();
61
- case 'zipCode':
62
- return faker.location.zipCode();
63
- case 'url':
64
- return faker.internet.url();
65
- case 'domain':
66
- return faker.internet.domainName();
67
- case 'slug':
68
- return faker.helpers.slugify(faker.lorem.words(3)).toLowerCase();
69
- case 'description':
70
- return faker.lorem.paragraph();
71
- case 'summary':
72
- return faker.lorem.sentence();
73
- case 'content':
74
- return faker.lorem.paragraphs(3);
75
- case 'title':
76
- return faker.lorem.sentence();
77
- case 'username':
78
- return faker.internet.username();
79
- case 'password':
80
- return '$2b$12$dummy.hashed.password.value';
81
- case 'birthdate':
82
- return faker.date.birthdate({
83
- min: 18,
84
- max: 80,
85
- mode: 'age'
86
- });
87
- case 'futureDate':
88
- return faker.date.future();
89
- case 'recentDateOrNull':
90
- return faker.datatype.boolean() ? faker.date.recent() : null;
91
- case 'serial':
92
- return faker.number.int({
93
- min: 1,
94
- max: 100
95
- });
96
- case 'company':
97
- return faker.company.name();
98
- case 'emailProvider':
99
- return faker.helpers.arrayElement([
100
- 'smtp',
101
- 'sendgrid',
102
- 'mailgun',
103
- 'ses',
104
- 'postmark'
105
- ]);
106
- case 'formAccessType':
107
- return faker.helpers.arrayElement([
108
- 'public',
109
- 'authenticated',
110
- 'permission'
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
- ]);
137
- default:
138
- return undefined;
139
- }
140
- }
141
- generateByType(column) {
142
- const category = detectTypeCategory(column.type);
143
- switch(category){
144
- case 'string':
145
- return this.generateString(column);
146
- case 'integer':
147
- return faker.number.int({
148
- min: 1,
149
- max: 1000
150
- });
151
- case 'decimal':
152
- return faker.number.float({
153
- min: 0,
154
- max: 10000,
155
- fractionDigits: column.scale || 2
156
- });
157
- case 'boolean':
158
- return faker.datatype.boolean();
159
- case 'date':
160
- case 'timestamp':
161
- return faker.date.recent({
162
- days: 30
163
- });
164
- case 'time':
165
- return faker.date.recent().toTimeString().split(' ')[0];
166
- case 'uuid':
167
- return faker.string.uuid();
168
- case 'json':
169
- return {
170
- key1: faker.lorem.word(),
171
- key2: faker.number.int({
172
- min: 1,
173
- max: 100
174
- })
175
- };
176
- case 'array':
177
- return [
178
- faker.lorem.word(),
179
- faker.lorem.word()
180
- ];
181
- default:
182
- return faker.lorem.word();
183
- }
184
- }
185
- generateString(column) {
186
- const maxLength = typeof column.length === 'number' ? column.length : 255;
187
- const category = getStringLengthCategory(column.length);
188
- switch(category){
189
- case 'word':
190
- return faker.lorem.word().substring(0, maxLength);
191
- case 'sentence':
192
- return faker.lorem.sentence().substring(0, maxLength);
193
- case 'paragraph':
194
- return faker.lorem.paragraph().substring(0, maxLength);
195
- }
196
- }
197
- generateRelationId(relatedEntities) {
198
- if (relatedEntities.length === 0) return null;
199
- return faker.helpers.arrayElement(relatedEntities).id;
200
- }
201
- generateRelationIds(relatedEntities, min = 1, max = 3) {
202
- if (relatedEntities.length === 0) return [];
203
- const count = faker.number.int({
204
- min,
205
- max: Math.min(max, relatedEntities.length)
206
- });
207
- return faker.helpers.arrayElements(relatedEntities, count).map((e)=>e.id);
208
- }
209
- constructor(locale = 'en'){
210
- faker.setDefaultRefDate(new Date());
211
- if (locale !== 'en') {
212
- // @ts-expect-error - faker locale property access
213
- faker.locale = locale;
214
- }
215
- }
216
- }
@@ -1,119 +0,0 @@
1
- function _define_property(obj, key, value) {
2
- if (key in obj) {
3
- Object.defineProperty(obj, key, {
4
- value: value,
5
- enumerable: true,
6
- configurable: true,
7
- writable: true
8
- });
9
- } else {
10
- obj[key] = value;
11
- }
12
- return obj;
13
- }
14
- export class EntityReader {
15
- getAllEntities() {
16
- return this.dataSource.entityMetadatas;
17
- }
18
- getEntityInfo(entityName) {
19
- const metadata = this.findEntityMetadata(entityName);
20
- if (!metadata) {
21
- throw new Error(`Entity ${entityName} not found in DataSource`);
22
- }
23
- return {
24
- name: metadata.name,
25
- tableName: metadata.tableName,
26
- columns: this.extractColumns(metadata),
27
- relations: this.extractRelations(metadata),
28
- hasSoftDelete: metadata.deleteDateColumn !== undefined,
29
- hasCompany: this.hasCompanyColumn(metadata)
30
- };
31
- }
32
- getSeedingOrder(skipEntities = []) {
33
- const entities = this.getAllEntities().filter((e)=>!skipEntities.includes(e.name) && !skipEntities.includes(e.tableName));
34
- const graph = this.buildDependencyGraph(entities);
35
- return this.topologicalSort(graph);
36
- }
37
- findEntityMetadata(entityName) {
38
- return this.getAllEntities().find((e)=>e.name === entityName || e.tableName === entityName);
39
- }
40
- extractColumns(metadata) {
41
- return metadata.columns.map((col)=>({
42
- name: col.databaseName,
43
- propertyName: col.propertyName,
44
- type: this.getColumnTypeString(col.type),
45
- length: col.length,
46
- isNullable: col.isNullable,
47
- isUnique: 'isUnique' in col ? col.isUnique === true : false,
48
- isPrimary: col.isPrimary,
49
- isGenerated: col.isGenerated,
50
- default: col.default,
51
- enum: col.enum ? Object.values(col.enum) : undefined,
52
- precision: col.precision ?? undefined,
53
- scale: col.scale ?? undefined
54
- }));
55
- }
56
- extractRelations(metadata) {
57
- return metadata.relations.map((rel)=>({
58
- propertyName: rel.propertyName,
59
- type: rel.relationType,
60
- targetEntity: rel.inverseEntityMetadata.name,
61
- isNullable: rel.isNullable,
62
- joinColumnName: rel.joinColumns?.[0]?.databaseName
63
- }));
64
- }
65
- hasCompanyColumn(metadata) {
66
- return metadata.columns.some((col)=>col.propertyName === 'companyId' || col.databaseName === 'company_id');
67
- }
68
- getColumnTypeString(type) {
69
- if (typeof type === 'string') {
70
- return type;
71
- }
72
- if (typeof type === 'function') {
73
- return type.name.toLowerCase();
74
- }
75
- return 'unknown';
76
- }
77
- buildDependencyGraph(entities) {
78
- const graph = new Map();
79
- for (const entity of entities){
80
- const dependencies = [];
81
- for (const relation of entity.relations){
82
- if (relation.relationType === 'many-to-one' && !relation.isNullable) {
83
- dependencies.push(relation.inverseEntityMetadata.name);
84
- }
85
- }
86
- graph.set(entity.name, dependencies);
87
- }
88
- return graph;
89
- }
90
- topologicalSort(graph) {
91
- const sorted = [];
92
- const visited = new Set();
93
- const visiting = new Set();
94
- const visit = (node)=>{
95
- if (visited.has(node)) return;
96
- if (visiting.has(node)) {
97
- throw new Error(`Circular dependency detected involving ${node}`);
98
- }
99
- visiting.add(node);
100
- const dependencies = graph.get(node) || [];
101
- for (const dep of dependencies){
102
- if (graph.has(dep)) {
103
- visit(dep);
104
- }
105
- }
106
- visiting.delete(node);
107
- visited.add(node);
108
- sorted.push(node);
109
- };
110
- for (const node of graph.keys()){
111
- visit(node);
112
- }
113
- return sorted;
114
- }
115
- constructor(dataSource){
116
- _define_property(this, "dataSource", void 0);
117
- this.dataSource = dataSource;
118
- }
119
- }
@@ -1,143 +0,0 @@
1
- export const SYSTEM_FIELDS = [
2
- 'id',
3
- 'createdAt',
4
- 'updatedAt',
5
- 'deletedAt',
6
- 'createdById',
7
- 'updatedById',
8
- 'deletedById'
9
- ];
10
- export const AUDIT_FIELDS = [
11
- 'createdbyid',
12
- 'updatedbyid',
13
- 'deletedbyid'
14
- ];
15
- export const IDENTITY_FIELDS = [
16
- 'id',
17
- 'createdat',
18
- 'updatedat',
19
- 'deletedat'
20
- ];
21
- export const BOOLEAN_KEYWORDS = [
22
- 'verified',
23
- 'active',
24
- 'enabled',
25
- 'public',
26
- 'readonly',
27
- 'valid'
28
- ];
29
- export function detectFieldPattern(column) {
30
- const nameLower = column.propertyName.toLowerCase();
31
- const typeLower = column.type.toLowerCase();
32
- // Identity fields (skip)
33
- if (IDENTITY_FIELDS.includes(nameLower)) return 'skip';
34
- // Audit fields (null)
35
- if (AUDIT_FIELDS.includes(nameLower)) return 'null';
36
- // Boolean fields with specific keywords
37
- if ((typeLower === 'boolean' || typeLower === 'bool') && BOOLEAN_KEYWORDS.some((k)=>nameLower.includes(k))) {
38
- return 'boolean';
39
- }
40
- // Token fields
41
- if (nameLower.includes('token')) return 'token';
42
- // Name fields
43
- if (nameLower.includes('firstname')) return 'firstName';
44
- if (nameLower.includes('lastname')) return 'lastName';
45
- if (nameLower.includes('fullname') || nameLower === 'name') return 'fullName';
46
- // Contact fields
47
- if (nameLower.includes('email') && typeLower !== 'boolean') return 'email';
48
- if (nameLower.includes('phone') || nameLower.includes('mobile')) return 'phone';
49
- // Location fields
50
- if (nameLower.includes('address')) return 'address';
51
- if (nameLower.includes('street')) return 'street';
52
- if (nameLower.includes('city')) return 'city';
53
- if (nameLower.includes('state')) return 'state';
54
- if (nameLower.includes('country')) return 'country';
55
- if (nameLower.includes('zipcode') || nameLower.includes('postalcode')) return 'zipCode';
56
- // URL/Web fields
57
- if (nameLower.includes('url') || nameLower.includes('website')) return 'url';
58
- if (nameLower.includes('domain')) return 'domain';
59
- if (nameLower.includes('slug')) return 'slug';
60
- // Text fields
61
- if (nameLower.includes('description')) return 'description';
62
- if (nameLower.includes('summary')) return 'summary';
63
- if (nameLower.includes('content')) return 'content';
64
- if (nameLower.includes('title')) return 'title';
65
- // User fields
66
- if (nameLower.includes('username')) return 'username';
67
- if (nameLower.includes('password')) return 'password';
68
- // Boolean status fields (fallback)
69
- if (nameLower.includes('isactive') || nameLower.includes('isenabled') || nameLower.includes('ispublic') || nameLower.includes('isverified')) {
70
- return 'boolean';
71
- }
72
- // Date fields
73
- if (nameLower.includes('birthdate') || nameLower.includes('dateofbirth')) return 'birthdate';
74
- if (nameLower.includes('expiresat') || nameLower.includes('expirydate')) return 'futureDate';
75
- if (nameLower.includes('verifiedat')) return 'recentDateOrNull';
76
- // Serial/Order fields
77
- if (nameLower.includes('serial') || nameLower.includes('order')) return 'serial';
78
- // Company
79
- if (nameLower.includes('company') && !nameLower.includes('id')) return 'company';
80
- // Email provider type
81
- if (nameLower === 'provider' || nameLower === 'emailprovider') return 'emailProvider';
82
- // Form access type
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';
90
- return undefined;
91
- }
92
- export function detectTypeCategory(type) {
93
- const typeLower = type.toLowerCase();
94
- if ([
95
- 'varchar',
96
- 'character varying',
97
- 'text',
98
- 'string'
99
- ].includes(typeLower)) return 'string';
100
- if ([
101
- 'int',
102
- 'integer',
103
- 'smallint',
104
- 'bigint'
105
- ].includes(typeLower)) return 'integer';
106
- if ([
107
- 'decimal',
108
- 'numeric',
109
- 'float',
110
- 'double',
111
- 'real'
112
- ].includes(typeLower)) return 'decimal';
113
- if ([
114
- 'boolean',
115
- 'bool'
116
- ].includes(typeLower)) return 'boolean';
117
- if (typeLower === 'date') return 'date';
118
- if ([
119
- 'timestamp',
120
- 'datetime'
121
- ].includes(typeLower)) return 'timestamp';
122
- if (typeLower === 'time') return 'time';
123
- if (typeLower === 'uuid') return 'uuid';
124
- if ([
125
- 'json',
126
- 'jsonb'
127
- ].includes(typeLower)) return 'json';
128
- if (typeLower === 'array') return 'array';
129
- return 'unknown';
130
- }
131
- export function getStringLengthCategory(length) {
132
- const maxLength = typeof length === 'number' ? length : 255;
133
- if (maxLength <= 50) return 'word';
134
- if (maxLength <= 255) return 'sentence';
135
- return 'paragraph';
136
- }
137
- export function isSystemField(fieldName) {
138
- return SYSTEM_FIELDS.includes(fieldName);
139
- }
140
- export function getTokenLength(column) {
141
- const maxLength = typeof column.length === 'number' ? column.length : 64;
142
- return Math.min(maxLength, 32);
143
- }
@@ -1,7 +0,0 @@
1
- export { BaseSeeder } from './base-seeder';
2
- export { EntityReader, IEntityInfo, IColumnInfo, IRelationInfo } from './entity-reader';
3
- export { DataGenerator } from './data-generator';
4
- export { SeedRunner, ISeedResult, ISeedOptions, ISeederLogger, defaultLogger } from './seed-runner';
5
- export { seedConfig, ISeedConfig, getEntityCount, shouldSkipEntity, getSeedingOrder, configureSeedConfig } from './seed-config';
6
- export { SYSTEM_FIELDS, isSystemField, detectFieldPattern, detectTypeCategory } from './field-patterns';
7
- export { runSeedCli } from './cli';
@@ -1,35 +0,0 @@
1
- export const seedConfig = {
2
- counts: {},
3
- order: [],
4
- skipEntities: [
5
- 'migrations',
6
- 'typeorm_metadata',
7
- 'Migration',
8
- 'Typeorm_Metadata'
9
- ],
10
- locale: 'en',
11
- respectSoftDelete: true
12
- };
13
- export function configureSeedConfig(config) {
14
- Object.assign(seedConfig, config);
15
- }
16
- export function getEntityCount(entityName, config = seedConfig) {
17
- return config.counts[entityName] || 10;
18
- }
19
- export function shouldSkipEntity(entityName, config = seedConfig) {
20
- return config.skipEntities.some((skip)=>skip.toLowerCase() === entityName.toLowerCase());
21
- }
22
- export function getSeedingOrder(availableEntities, config = seedConfig) {
23
- const ordered = [];
24
- for (const entityName of config.order){
25
- if (availableEntities.includes(entityName) && !shouldSkipEntity(entityName, config)) {
26
- ordered.push(entityName);
27
- }
28
- }
29
- for (const entityName of availableEntities){
30
- if (!ordered.includes(entityName) && !shouldSkipEntity(entityName, config)) {
31
- ordered.push(entityName);
32
- }
33
- }
34
- return ordered;
35
- }