@currentjs/gen 0.5.0 → 0.5.2
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/CHANGELOG.md +19 -0
- package/README.md +374 -996
- package/dist/cli.js +28 -10
- package/dist/commands/createModel.d.ts +1 -0
- package/dist/commands/createModel.js +764 -0
- package/dist/commands/createModule.js +13 -0
- package/dist/commands/generateAll.d.ts +1 -0
- package/dist/commands/generateAll.js +1 -1
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/{createApp.js → init.js} +2 -2
- package/dist/commands/migrateCommit.js +33 -68
- package/dist/generators/controllerGenerator.d.ts +7 -0
- package/dist/generators/controllerGenerator.js +56 -17
- package/dist/generators/domainLayerGenerator.js +51 -8
- package/dist/generators/dtoGenerator.js +13 -8
- package/dist/generators/serviceGenerator.d.ts +6 -0
- package/dist/generators/serviceGenerator.js +219 -23
- package/dist/generators/storeGenerator.d.ts +4 -0
- package/dist/generators/storeGenerator.js +116 -9
- package/dist/generators/templateGenerator.d.ts +1 -0
- package/dist/generators/templateGenerator.js +8 -2
- package/dist/generators/templates/appTemplates.js +1 -1
- package/dist/generators/templates/data/cursorRulesTemplate +11 -755
- package/dist/generators/templates/data/frontendScriptTemplate +11 -4
- package/dist/generators/templates/data/mainViewTemplate +1 -0
- package/dist/generators/templates/storeTemplates.d.ts +1 -1
- package/dist/generators/templates/storeTemplates.js +3 -26
- package/dist/generators/useCaseGenerator.js +6 -3
- package/dist/types/configTypes.d.ts +6 -0
- package/dist/utils/migrationUtils.d.ts +9 -19
- package/dist/utils/migrationUtils.js +80 -110
- package/dist/utils/promptUtils.d.ts +37 -0
- package/dist/utils/promptUtils.js +149 -0
- package/dist/utils/typeUtils.d.ts +4 -0
- package/dist/utils/typeUtils.js +7 -0
- package/package.json +1 -1
- package/dist/commands/createApp.d.ts +0 -1
- package/dist/commands/migratePush.d.ts +0 -1
- package/dist/commands/migratePush.js +0 -135
- package/dist/commands/migrateUpdate.d.ts +0 -1
- package/dist/commands/migrateUpdate.js +0 -147
- package/dist/commands/newGenerateAll.d.ts +0 -4
- package/dist/commands/newGenerateAll.js +0 -336
- package/dist/generators/domainModelGenerator.d.ts +0 -41
- package/dist/generators/domainModelGenerator.js +0 -242
- package/dist/generators/newControllerGenerator.d.ts +0 -55
- package/dist/generators/newControllerGenerator.js +0 -644
- package/dist/generators/newServiceGenerator.d.ts +0 -19
- package/dist/generators/newServiceGenerator.js +0 -266
- package/dist/generators/newStoreGenerator.d.ts +0 -39
- package/dist/generators/newStoreGenerator.js +0 -408
- package/dist/generators/newTemplateGenerator.d.ts +0 -29
- package/dist/generators/newTemplateGenerator.js +0 -510
- package/dist/generators/storeGeneratorV2.d.ts +0 -31
- package/dist/generators/storeGeneratorV2.js +0 -190
- package/dist/generators/templates/controllerTemplates.d.ts +0 -43
- package/dist/generators/templates/controllerTemplates.js +0 -82
- package/dist/generators/templates/newStoreTemplates.d.ts +0 -5
- package/dist/generators/templates/newStoreTemplates.js +0 -141
- package/dist/generators/templates/serviceTemplates.d.ts +0 -16
- package/dist/generators/templates/serviceTemplates.js +0 -59
- package/dist/generators/templates/validationTemplates.d.ts +0 -25
- package/dist/generators/templates/validationTemplates.js +0 -66
- package/dist/generators/templates/viewTemplates.d.ts +0 -25
- package/dist/generators/templates/viewTemplates.js +0 -491
- package/dist/generators/validationGenerator.d.ts +0 -29
- package/dist/generators/validationGenerator.js +0 -250
- package/dist/utils/new_parts_of_migrationUtils.d.ts +0 -0
- package/dist/utils/new_parts_of_migrationUtils.js +0 -164
- package/howto.md +0 -667
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.ValidationGenerator = void 0;
|
|
37
|
-
const fs = __importStar(require("fs"));
|
|
38
|
-
const path = __importStar(require("path"));
|
|
39
|
-
const yaml_1 = require("yaml");
|
|
40
|
-
const validationTemplates_1 = require("./templates/validationTemplates");
|
|
41
|
-
const generationRegistry_1 = require("../utils/generationRegistry");
|
|
42
|
-
const colors_1 = require("../utils/colors");
|
|
43
|
-
const constants_1 = require("../utils/constants");
|
|
44
|
-
class ValidationGenerator {
|
|
45
|
-
constructor() {
|
|
46
|
-
this.availableModels = new Set();
|
|
47
|
-
}
|
|
48
|
-
setAvailableModels(models) {
|
|
49
|
-
this.availableModels.clear();
|
|
50
|
-
models.forEach(model => {
|
|
51
|
-
this.availableModels.add(model.name);
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
isRelationshipField(field) {
|
|
55
|
-
return this.availableModels.has(field.type);
|
|
56
|
-
}
|
|
57
|
-
getForeignKeyFieldName(field) {
|
|
58
|
-
// Convention: fieldName + 'Id' (e.g., owner -> ownerId)
|
|
59
|
-
return field.name + 'Id';
|
|
60
|
-
}
|
|
61
|
-
replaceTemplateVars(template, variables) {
|
|
62
|
-
let result = template;
|
|
63
|
-
Object.entries(variables).forEach(([key, value]) => {
|
|
64
|
-
const regex = new RegExp(`{{${key}}}`, 'g');
|
|
65
|
-
result = result.replace(regex, value);
|
|
66
|
-
});
|
|
67
|
-
return result;
|
|
68
|
-
}
|
|
69
|
-
getTypeScriptType(yamlType) {
|
|
70
|
-
return validationTemplates_1.typeMapping[yamlType] || 'any';
|
|
71
|
-
}
|
|
72
|
-
generateInterfaceField(field, isCreate) {
|
|
73
|
-
// For relationship fields, use the foreign key field instead
|
|
74
|
-
if (this.isRelationshipField(field)) {
|
|
75
|
-
const foreignKeyName = this.getForeignKeyFieldName(field);
|
|
76
|
-
const tsType = 'number'; // Foreign keys are always numbers
|
|
77
|
-
if (isCreate) {
|
|
78
|
-
const optional = !field.required ? '?' : '';
|
|
79
|
-
return ` ${foreignKeyName}${optional}: ${tsType};`;
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
return ` ${foreignKeyName}?: ${tsType};`;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
const tsType = this.getTypeScriptType(field.type);
|
|
86
|
-
if (isCreate) {
|
|
87
|
-
if (field.auto || field.name === 'id') {
|
|
88
|
-
return '';
|
|
89
|
-
}
|
|
90
|
-
const optional = !field.required ? '?' : '';
|
|
91
|
-
return ` ${field.name}${optional}: ${tsType};`;
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
if (field.name === 'id' || field.auto) {
|
|
95
|
-
return '';
|
|
96
|
-
}
|
|
97
|
-
return ` ${field.name}?: ${tsType};`;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
generateValidationLogic(field, isCreate) {
|
|
101
|
-
// For relationship fields, validate the foreign key
|
|
102
|
-
if (this.isRelationshipField(field)) {
|
|
103
|
-
const foreignKeyName = this.getForeignKeyFieldName(field);
|
|
104
|
-
const isRequired = isCreate && field.required;
|
|
105
|
-
const template = isRequired ? validationTemplates_1.validationTemplates.requiredNumberValidation : validationTemplates_1.validationTemplates.optionalNumberValidation;
|
|
106
|
-
return this.replaceTemplateVars(template, { FIELD_NAME: foreignKeyName });
|
|
107
|
-
}
|
|
108
|
-
const fieldName = field.name;
|
|
109
|
-
if (field.auto || field.name === 'id') {
|
|
110
|
-
return '';
|
|
111
|
-
}
|
|
112
|
-
let template = '';
|
|
113
|
-
const isRequired = isCreate && field.required;
|
|
114
|
-
switch (field.type) {
|
|
115
|
-
case 'string':
|
|
116
|
-
template = isRequired ? validationTemplates_1.validationTemplates.requiredStringValidation : validationTemplates_1.validationTemplates.optionalStringValidation;
|
|
117
|
-
break;
|
|
118
|
-
case 'number':
|
|
119
|
-
template = isRequired ? validationTemplates_1.validationTemplates.requiredNumberValidation : validationTemplates_1.validationTemplates.optionalNumberValidation;
|
|
120
|
-
break;
|
|
121
|
-
case 'boolean':
|
|
122
|
-
template = isRequired ? validationTemplates_1.validationTemplates.requiredBooleanValidation : validationTemplates_1.validationTemplates.optionalBooleanValidation;
|
|
123
|
-
break;
|
|
124
|
-
case 'datetime':
|
|
125
|
-
template = isRequired ? validationTemplates_1.validationTemplates.requiredDateValidation : validationTemplates_1.validationTemplates.optionalDateValidation;
|
|
126
|
-
break;
|
|
127
|
-
default:
|
|
128
|
-
template = isRequired ? validationTemplates_1.validationTemplates.requiredComplexValidation : validationTemplates_1.validationTemplates.optionalComplexValidation;
|
|
129
|
-
break;
|
|
130
|
-
}
|
|
131
|
-
return this.replaceTemplateVars(template, { FIELD_NAME: fieldName });
|
|
132
|
-
}
|
|
133
|
-
generateDtoField(field, isCreate) {
|
|
134
|
-
// For relationship fields, use the foreign key field instead
|
|
135
|
-
if (this.isRelationshipField(field)) {
|
|
136
|
-
const foreignKeyName = this.getForeignKeyFieldName(field);
|
|
137
|
-
const tsType = 'number'; // Foreign keys are always numbers
|
|
138
|
-
if (isCreate) {
|
|
139
|
-
const optional = !field.required ? '?' : '';
|
|
140
|
-
return ` ${foreignKeyName}${optional}: ${tsType};`;
|
|
141
|
-
}
|
|
142
|
-
else {
|
|
143
|
-
return ` ${foreignKeyName}?: ${tsType};`;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
const tsType = this.getTypeScriptType(field.type);
|
|
147
|
-
if (isCreate) {
|
|
148
|
-
if (field.auto || field.name === 'id') {
|
|
149
|
-
return '';
|
|
150
|
-
}
|
|
151
|
-
const optional = !field.required ? '?' : '';
|
|
152
|
-
return ` ${field.name}${optional}: ${tsType};`;
|
|
153
|
-
}
|
|
154
|
-
else {
|
|
155
|
-
if (field.name === 'id' || field.auto) {
|
|
156
|
-
return '';
|
|
157
|
-
}
|
|
158
|
-
return ` ${field.name}?: ${tsType};`;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
generateDtoInterface(entityName, fields, isCreate) {
|
|
162
|
-
const dtoName = `${entityName}DTO`;
|
|
163
|
-
const dtoFields = fields
|
|
164
|
-
.map(field => this.generateDtoField(field, isCreate))
|
|
165
|
-
.filter(field => field !== '')
|
|
166
|
-
.join('\n');
|
|
167
|
-
return this.replaceTemplateVars(validationTemplates_1.validationTemplates.dtoInterface, {
|
|
168
|
-
DTO_NAME: dtoName,
|
|
169
|
-
DTO_FIELDS: dtoFields
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
generateInputInterface(entityName, fields, isCreate) {
|
|
173
|
-
const interfaceName = `${isCreate ? 'Create' : 'Update'}${entityName}Input`;
|
|
174
|
-
const interfaceFields = fields
|
|
175
|
-
.map(field => this.generateInterfaceField(field, isCreate))
|
|
176
|
-
.filter(field => field !== '')
|
|
177
|
-
.join('\n');
|
|
178
|
-
return this.replaceTemplateVars(validationTemplates_1.validationTemplates.inputInterface, {
|
|
179
|
-
INTERFACE_NAME: interfaceName,
|
|
180
|
-
INTERFACE_FIELDS: interfaceFields
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
generateValidationFunction(entityName, fields, isCreate) {
|
|
184
|
-
const functionName = `validate${isCreate ? 'Create' : 'Update'}${entityName}`;
|
|
185
|
-
const dtoParam = `${entityName.toLowerCase()}Data: ${entityName}DTO`;
|
|
186
|
-
const validationLogic = fields
|
|
187
|
-
.map(field => this.generateValidationLogic(field, isCreate))
|
|
188
|
-
.filter(logic => logic !== '')
|
|
189
|
-
.join('\n');
|
|
190
|
-
return this.replaceTemplateVars(validationTemplates_1.validationTemplates.validationFunction, {
|
|
191
|
-
FUNCTION_NAME: functionName,
|
|
192
|
-
VALIDATION_LOGIC: validationLogic
|
|
193
|
-
}).replace('(data: any)', `(${dtoParam})`).replace(/data\./g, `${entityName.toLowerCase()}Data.`);
|
|
194
|
-
}
|
|
195
|
-
generateValidation(entityName, fields) {
|
|
196
|
-
const dtoInterface = this.generateDtoInterface(entityName, fields, true);
|
|
197
|
-
const createValidation = this.generateValidationFunction(entityName, fields, true);
|
|
198
|
-
const updateValidation = this.generateValidationFunction(entityName, fields, false);
|
|
199
|
-
const validationFunctions = `${createValidation}\n\n${updateValidation}`;
|
|
200
|
-
return this.replaceTemplateVars(validationTemplates_1.validationTemplates.validationFileTemplate, {
|
|
201
|
-
ENTITY_NAME: entityName,
|
|
202
|
-
DTO_INTERFACES: dtoInterface,
|
|
203
|
-
VALIDATION_FUNCTIONS: validationFunctions
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
generateFromYamlFile(yamlFilePath) {
|
|
207
|
-
const yamlContent = fs.readFileSync(yamlFilePath, 'utf8');
|
|
208
|
-
const config = (0, yaml_1.parse)(yamlContent);
|
|
209
|
-
const validations = {};
|
|
210
|
-
if (config.modules) {
|
|
211
|
-
Object.values(config.modules).forEach(moduleConfig => {
|
|
212
|
-
if (moduleConfig.models && moduleConfig.models.length > 0) {
|
|
213
|
-
// Set available models for relationship detection
|
|
214
|
-
this.setAvailableModels(moduleConfig.models);
|
|
215
|
-
moduleConfig.models.forEach(model => {
|
|
216
|
-
const validationCode = this.generateValidation(model.name, model.fields);
|
|
217
|
-
validations[model.name] = validationCode;
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
else if (config.models) {
|
|
223
|
-
const module = config;
|
|
224
|
-
if (module.models) {
|
|
225
|
-
// Set available models for relationship detection
|
|
226
|
-
this.setAvailableModels(module.models);
|
|
227
|
-
module.models.forEach(model => {
|
|
228
|
-
const validationCode = this.generateValidation(model.name, model.fields);
|
|
229
|
-
validations[model.name] = validationCode;
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
return validations;
|
|
234
|
-
}
|
|
235
|
-
async generateAndSaveFiles(yamlFilePath = constants_1.COMMON_FILES.APP_YAML, outputDir = 'application', opts) {
|
|
236
|
-
const validations = this.generateFromYamlFile(yamlFilePath);
|
|
237
|
-
const validationDir = path.join(outputDir, 'validation');
|
|
238
|
-
fs.mkdirSync(validationDir, { recursive: true });
|
|
239
|
-
for (const [entityName, validationCode] of Object.entries(validations)) {
|
|
240
|
-
const fileName = `${entityName}Validation.ts`;
|
|
241
|
-
const filePath = path.join(validationDir, fileName);
|
|
242
|
-
// Sequential to avoid multiple prompts overlapping
|
|
243
|
-
// eslint-disable-next-line no-await-in-loop
|
|
244
|
-
await (0, generationRegistry_1.writeGeneratedFile)(filePath, validationCode, { force: !!(opts === null || opts === void 0 ? void 0 : opts.force), skipOnConflict: !!(opts === null || opts === void 0 ? void 0 : opts.skipOnConflict) });
|
|
245
|
-
}
|
|
246
|
-
// eslint-disable-next-line no-console
|
|
247
|
-
console.log('\n' + colors_1.colors.green('Validation files generated successfully!') + '\n');
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
exports.ValidationGenerator = ValidationGenerator;
|
|
File without changes
|
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*
|
|
3
|
-
export async function connectToDatabase(): Promise<mysql.Connection> {
|
|
4
|
-
const config = {
|
|
5
|
-
host: process.env.DB_HOST || 'localhost',
|
|
6
|
-
port: parseInt(process.env.DB_PORT || '3306'),
|
|
7
|
-
user: process.env.DB_USER || 'root',
|
|
8
|
-
password: process.env.DB_PASSWORD || '',
|
|
9
|
-
database: process.env.DB_NAME || 'test',
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
try {
|
|
13
|
-
const connection = await mysql.createConnection(config);
|
|
14
|
-
return connection;
|
|
15
|
-
} catch (error) {
|
|
16
|
-
throw new Error(`Failed to connect to database: ${error instanceof Error ? error.message : String(error)}`);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export async function getTableNames(connection: mysql.Connection): Promise<string[]> {
|
|
21
|
-
const [rows] = await connection.query('SHOW TABLES');
|
|
22
|
-
const tableKey = Object.keys(rows[0] as object)[0];
|
|
23
|
-
return (rows as any[]).map(row => row[tableKey]);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export async function getTableSchema(connection: mysql.Connection, tableName: string): Promise<ColumnInfo[]> {
|
|
27
|
-
const [rows] = await connection.query(`DESCRIBE ${tableName}`);
|
|
28
|
-
return rows as ColumnInfo[];
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export async function getForeignKeys(connection: mysql.Connection, tableName: string): Promise<ForeignKeyInfo[]> {
|
|
32
|
-
const [rows] = await connection.query(
|
|
33
|
-
`SELECT
|
|
34
|
-
CONSTRAINT_NAME,
|
|
35
|
-
COLUMN_NAME,
|
|
36
|
-
REFERENCED_TABLE_NAME,
|
|
37
|
-
REFERENCED_COLUMN_NAME
|
|
38
|
-
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
|
|
39
|
-
WHERE TABLE_SCHEMA = DATABASE()
|
|
40
|
-
AND TABLE_NAME = ?
|
|
41
|
-
AND REFERENCED_TABLE_NAME IS NOT NULL`,
|
|
42
|
-
[tableName]
|
|
43
|
-
);
|
|
44
|
-
return rows as ForeignKeyInfo[];
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
export function sqlTypeToYamlType(sqlType: string): string {
|
|
49
|
-
const upperType = sqlType.toUpperCase();
|
|
50
|
-
|
|
51
|
-
if (upperType.includes('VARCHAR') || upperType.includes('TEXT') || upperType.includes('CHAR')) {
|
|
52
|
-
return 'string';
|
|
53
|
-
}
|
|
54
|
-
if (upperType.includes('INT') || upperType.includes('DECIMAL') || upperType.includes('FLOAT') || upperType.includes('DOUBLE')) {
|
|
55
|
-
return 'number';
|
|
56
|
-
}
|
|
57
|
-
if (upperType.includes('TINYINT(1)') || upperType.includes('BOOLEAN')) {
|
|
58
|
-
return 'boolean';
|
|
59
|
-
}
|
|
60
|
-
if (upperType.includes('DATETIME') || upperType.includes('TIMESTAMP') || upperType.includes('DATE')) {
|
|
61
|
-
return 'datetime';
|
|
62
|
-
}
|
|
63
|
-
if (upperType.includes('JSON')) {
|
|
64
|
-
return 'json';
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return 'string'; // Default
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
export async function extractSchemaFromDatabase(connection: mysql.Connection): Promise<ModelConfig[]> {
|
|
72
|
-
const models: ModelConfig[] = [];
|
|
73
|
-
const tables = await getTableNames(connection);
|
|
74
|
-
|
|
75
|
-
for (const table of tables) {
|
|
76
|
-
// Skip migration log table
|
|
77
|
-
if (table === 'migration_log') {
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const columns = await getTableSchema(connection, table);
|
|
82
|
-
const foreignKeys = await getForeignKeys(connection, table);
|
|
83
|
-
|
|
84
|
-
// Convert table name to model name (e.g., cats -> Cat)
|
|
85
|
-
const modelName = table.slice(0, -1).charAt(0).toUpperCase() + table.slice(1, -1);
|
|
86
|
-
|
|
87
|
-
const fields: FieldConfig[] = [];
|
|
88
|
-
|
|
89
|
-
for (const column of columns) {
|
|
90
|
-
// Skip standard columns
|
|
91
|
-
if (['id', 'created_at', 'updated_at', 'deleted_at'].includes(column.Field)) {
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Check if this is a foreign key
|
|
96
|
-
const fk = foreignKeys.find(fk => fk.COLUMN_NAME === column.Field);
|
|
97
|
-
|
|
98
|
-
if (fk) {
|
|
99
|
-
// This is a foreign key - extract the relationship field name
|
|
100
|
-
const fieldName = column.Field.endsWith('Id')
|
|
101
|
-
? column.Field.slice(0, -2)
|
|
102
|
-
: column.Field;
|
|
103
|
-
|
|
104
|
-
// Convert referenced table to model name
|
|
105
|
-
const refModelName = fk.REFERENCED_TABLE_NAME.slice(0, -1).charAt(0).toUpperCase() +
|
|
106
|
-
fk.REFERENCED_TABLE_NAME.slice(1, -1);
|
|
107
|
-
|
|
108
|
-
fields.push({
|
|
109
|
-
name: fieldName,
|
|
110
|
-
type: refModelName,
|
|
111
|
-
required: column.Null === 'NO'
|
|
112
|
-
});
|
|
113
|
-
} else {
|
|
114
|
-
// Regular field
|
|
115
|
-
fields.push({
|
|
116
|
-
name: column.Field,
|
|
117
|
-
type: sqlTypeToYamlType(column.Type),
|
|
118
|
-
required: column.Null === 'NO'
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
models.push({
|
|
124
|
-
name: modelName,
|
|
125
|
-
fields
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return models;
|
|
130
|
-
}
|
|
131
|
-
*/
|
|
132
|
-
/*
|
|
133
|
-
export async function executeMigration(connection: mysql.Connection, migrationSQL: string): Promise<void> {
|
|
134
|
-
// Split by semicolons and execute each statement
|
|
135
|
-
const statements = migrationSQL
|
|
136
|
-
.split(';')
|
|
137
|
-
.map(s => s.trim())
|
|
138
|
-
.filter(s => s.length > 0 && !s.startsWith('--'));
|
|
139
|
-
|
|
140
|
-
for (const statement of statements) {
|
|
141
|
-
await connection.query(statement);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
export async function ensureMigrationLogTable(connection: mysql.Connection): Promise<void> {
|
|
146
|
-
await connection.query(`
|
|
147
|
-
CREATE TABLE IF NOT EXISTS migration_log (
|
|
148
|
-
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
149
|
-
filename VARCHAR(255) NOT NULL UNIQUE,
|
|
150
|
-
applied_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
151
|
-
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
152
|
-
`);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
export async function getAppliedMigrations(connection: mysql.Connection): Promise<string[]> {
|
|
156
|
-
await ensureMigrationLogTable(connection);
|
|
157
|
-
const [rows] = await connection.query('SELECT filename FROM migration_log ORDER BY applied_at');
|
|
158
|
-
return (rows as any[]).map(row => row.filename);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
export async function recordMigration(connection: mysql.Connection, filename: string): Promise<void> {
|
|
162
|
-
await connection.query('INSERT INTO migration_log (filename) VALUES (?)', [filename]);
|
|
163
|
-
}
|
|
164
|
-
*/
|