@aceitadev/adatabase 0.7.0 → 0.8.5
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/dist/SchemaManager.d.ts +1 -0
- package/dist/SchemaManager.js +103 -15
- package/dist/decorators/Column.d.ts +1 -0
- package/package.json +1 -1
package/dist/SchemaManager.d.ts
CHANGED
package/dist/SchemaManager.js
CHANGED
|
@@ -13,6 +13,7 @@ exports.SchemaManager = void 0;
|
|
|
13
13
|
const Table_1 = require("./decorators/Table");
|
|
14
14
|
const Column_1 = require("./decorators/Column");
|
|
15
15
|
const Nullable_1 = require("./decorators/Nullable");
|
|
16
|
+
const BelongsTo_1 = require("./decorators/BelongsTo");
|
|
16
17
|
const Database_1 = require("./Database");
|
|
17
18
|
function camelToSnake(s) {
|
|
18
19
|
return s.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
|
|
@@ -29,13 +30,14 @@ class SchemaManager {
|
|
|
29
30
|
const table = (0, Table_1.getTableName)(model);
|
|
30
31
|
if (!table)
|
|
31
32
|
continue;
|
|
32
|
-
const { columns, indexes, primaryKey } = this.getSchemaFromModel(model);
|
|
33
|
+
const { columns, indexes, primaryKey, foreignKeys } = this.getSchemaFromModel(model);
|
|
33
34
|
const existing = yield this.getExistingColumns(table);
|
|
34
35
|
if (Object.keys(existing).length === 0) {
|
|
35
|
-
yield this.createTable(table, columns, indexes);
|
|
36
|
+
yield this.createTable(table, columns, indexes, foreignKeys);
|
|
36
37
|
}
|
|
37
38
|
else {
|
|
38
|
-
yield this.
|
|
39
|
+
const existingConstraints = yield this.getExistingConstraints(table);
|
|
40
|
+
yield this.updateTable(table, columns, indexes, existing, primaryKey, foreignKeys, existingConstraints);
|
|
39
41
|
}
|
|
40
42
|
}
|
|
41
43
|
this.printMigrationSummary();
|
|
@@ -62,7 +64,7 @@ class SchemaManager {
|
|
|
62
64
|
});
|
|
63
65
|
});
|
|
64
66
|
}
|
|
65
|
-
createTable(table, columns, indexes) {
|
|
67
|
+
createTable(table, columns, indexes, foreignKeys) {
|
|
66
68
|
return __awaiter(this, void 0, void 0, function* () {
|
|
67
69
|
const adapter = (0, Database_1.getAdapter)();
|
|
68
70
|
const colsSql = Object.entries(columns).map(([k, v]) => `\`${k}\` ${v}`).join(", ");
|
|
@@ -70,12 +72,17 @@ class SchemaManager {
|
|
|
70
72
|
if (adapter.type === 'mysql' && indexes.length > 0) {
|
|
71
73
|
indexSql = ", " + indexes.map(col => `INDEX \`${col}\` (\`${col}\`)`).join(", ");
|
|
72
74
|
}
|
|
73
|
-
|
|
75
|
+
let fkSql = "";
|
|
76
|
+
if (foreignKeys.length > 0) {
|
|
77
|
+
fkSql = ", " + foreignKeys.map(fk => `CONSTRAINT \`${fk.constraintName}\` FOREIGN KEY (\`${fk.column}\`) REFERENCES \`${fk.referenceTable}\` (\`${fk.referenceColumn}\`)`).join(", ");
|
|
78
|
+
}
|
|
79
|
+
const sql = `CREATE TABLE \`${table}\` (${colsSql}${indexSql}${fkSql});`;
|
|
74
80
|
const conn = yield (0, Database_1.getConnection)();
|
|
75
81
|
try {
|
|
76
82
|
yield (0, Database_1.execute)(sql, [], conn);
|
|
77
|
-
const columnChanges = Object.keys(columns).map(col => `+ ${col} (
|
|
78
|
-
|
|
83
|
+
const columnChanges = Object.keys(columns).map(col => `+ ${col} (added)`);
|
|
84
|
+
const fkChanges = foreignKeys.map(fk => `+ FK ${fk.constraintName} (added)`);
|
|
85
|
+
this.changes.set(table, [...columnChanges, ...fkChanges]);
|
|
79
86
|
}
|
|
80
87
|
finally {
|
|
81
88
|
conn.release();
|
|
@@ -95,7 +102,7 @@ class SchemaManager {
|
|
|
95
102
|
}
|
|
96
103
|
});
|
|
97
104
|
}
|
|
98
|
-
updateTable(table, desired, indexes, existing, primaryKey) {
|
|
105
|
+
updateTable(table, desired, indexes, existing, primaryKey, foreignKeys, existingConstraints) {
|
|
99
106
|
return __awaiter(this, void 0, void 0, function* () {
|
|
100
107
|
const tableChanges = [];
|
|
101
108
|
const conn = yield (0, Database_1.getConnection)();
|
|
@@ -107,7 +114,7 @@ class SchemaManager {
|
|
|
107
114
|
if (!existing.hasOwnProperty(col)) {
|
|
108
115
|
const sql = `ALTER TABLE \`${table}\` ADD COLUMN \`${col}\` ${type};`;
|
|
109
116
|
yield (0, Database_1.execute)(sql, [], conn);
|
|
110
|
-
tableChanges.push(`+ ${col} (
|
|
117
|
+
tableChanges.push(`+ ${col} (added)`);
|
|
111
118
|
}
|
|
112
119
|
else {
|
|
113
120
|
const normalize = (t) => {
|
|
@@ -120,7 +127,17 @@ class SchemaManager {
|
|
|
120
127
|
if (existingType !== desiredType) {
|
|
121
128
|
const sql = `ALTER TABLE \`${table}\` MODIFY COLUMN \`${col}\` ${type};`;
|
|
122
129
|
yield (0, Database_1.execute)(sql, [], conn);
|
|
123
|
-
tableChanges.push(`~ ${col} (
|
|
130
|
+
tableChanges.push(`~ ${col} (type changed: ${existing[col].toUpperCase()} → ${type.split(' ')[0].toUpperCase()})`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// Check for missing foreign keys
|
|
135
|
+
if (foreignKeys && foreignKeys.length > 0) {
|
|
136
|
+
for (const fk of foreignKeys) {
|
|
137
|
+
if (!existingConstraints.includes(fk.constraintName)) {
|
|
138
|
+
const sql = `ALTER TABLE \`${table}\` ADD CONSTRAINT \`${fk.constraintName}\` FOREIGN KEY (\`${fk.column}\`) REFERENCES \`${fk.referenceTable}\` (\`${fk.referenceColumn}\`);`;
|
|
139
|
+
yield (0, Database_1.execute)(sql, [], conn);
|
|
140
|
+
tableChanges.push(`+ FK ${fk.constraintName} (added)`);
|
|
124
141
|
}
|
|
125
142
|
}
|
|
126
143
|
}
|
|
@@ -133,15 +150,55 @@ class SchemaManager {
|
|
|
133
150
|
}
|
|
134
151
|
});
|
|
135
152
|
}
|
|
153
|
+
getExistingConstraints(table) {
|
|
154
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
155
|
+
const conn = yield (0, Database_1.getConnection)();
|
|
156
|
+
const adapter = (0, Database_1.getAdapter)();
|
|
157
|
+
const constraints = [];
|
|
158
|
+
try {
|
|
159
|
+
let sql;
|
|
160
|
+
if (adapter.type === 'postgres') {
|
|
161
|
+
sql = `SELECT constraint_name
|
|
162
|
+
FROM information_schema.table_constraints
|
|
163
|
+
WHERE table_schema = current_schema() AND table_name = $1 AND constraint_type = 'FOREIGN KEY'`;
|
|
164
|
+
}
|
|
165
|
+
else { // mysql
|
|
166
|
+
sql = `SELECT CONSTRAINT_NAME
|
|
167
|
+
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
|
|
168
|
+
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND CONSTRAINT_TYPE = 'FOREIGN KEY'`;
|
|
169
|
+
}
|
|
170
|
+
const rows = yield (0, Database_1.query)(sql, [table], conn);
|
|
171
|
+
if (rows.length > 0) {
|
|
172
|
+
if (adapter.type === 'postgres') {
|
|
173
|
+
rows.forEach((r) => constraints.push(r.constraint_name));
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
rows.forEach((r) => constraints.push(r.CONSTRAINT_NAME));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
catch (e) {
|
|
181
|
+
return [];
|
|
182
|
+
}
|
|
183
|
+
finally {
|
|
184
|
+
if (conn)
|
|
185
|
+
conn.release();
|
|
186
|
+
}
|
|
187
|
+
return constraints;
|
|
188
|
+
});
|
|
189
|
+
}
|
|
136
190
|
getSchemaFromModel(model) {
|
|
137
191
|
const columns = {};
|
|
138
192
|
const indexes = [];
|
|
193
|
+
const foreignKeys = [];
|
|
139
194
|
let primaryKey = null;
|
|
140
195
|
const colMeta = (0, Column_1.getColumnMeta)(model);
|
|
141
196
|
const nullableMeta = (0, Nullable_1.getNullableMeta)(model);
|
|
197
|
+
const belongsToMeta = (0, BelongsTo_1.getBelongsToMeta)(model);
|
|
142
198
|
const adapter = (0, Database_1.getAdapter)();
|
|
199
|
+
const tableName = (0, Table_1.getTableName)(model);
|
|
143
200
|
if (!colMeta) {
|
|
144
|
-
return { columns, indexes, primaryKey };
|
|
201
|
+
return { columns, indexes, primaryKey, foreignKeys };
|
|
145
202
|
}
|
|
146
203
|
for (const [prop, opts] of colMeta.entries()) {
|
|
147
204
|
const colName = (opts === null || opts === void 0 ? void 0 : opts.name) ? opts.name : camelToSnake(prop);
|
|
@@ -164,13 +221,14 @@ class SchemaManager {
|
|
|
164
221
|
continue;
|
|
165
222
|
}
|
|
166
223
|
let sqlType = this.getSqlTypeForClass(type);
|
|
167
|
-
if (
|
|
224
|
+
if (opts === null || opts === void 0 ? void 0 : opts.text) {
|
|
225
|
+
sqlType = "TEXT";
|
|
226
|
+
}
|
|
227
|
+
else if (type === Number && opts.decimal) {
|
|
168
228
|
if (Array.isArray(opts.decimal) && opts.decimal.length === 2) {
|
|
169
|
-
// CORREÇÃO: Removido o espaço após a vírgula
|
|
170
229
|
sqlType = `DECIMAL(${opts.decimal[0]},${opts.decimal[1]})`;
|
|
171
230
|
}
|
|
172
231
|
else {
|
|
173
|
-
// CORREÇÃO: Removido o espaço após a vírgula
|
|
174
232
|
sqlType = 'DECIMAL(10,2)';
|
|
175
233
|
}
|
|
176
234
|
}
|
|
@@ -194,7 +252,37 @@ class SchemaManager {
|
|
|
194
252
|
sqlType += " UNIQUE";
|
|
195
253
|
columns[colName] = sqlType;
|
|
196
254
|
}
|
|
197
|
-
|
|
255
|
+
if (belongsToMeta) {
|
|
256
|
+
for (const [prop, opts] of belongsToMeta.entries()) {
|
|
257
|
+
const fkProp = opts.foreignKey;
|
|
258
|
+
const targetModel = opts.model();
|
|
259
|
+
const targetTable = (0, Table_1.getTableName)(targetModel);
|
|
260
|
+
if (!targetTable)
|
|
261
|
+
continue;
|
|
262
|
+
// Find the column name for the foreign key property
|
|
263
|
+
const colOpts = colMeta.get(fkProp);
|
|
264
|
+
const fkColName = (colOpts === null || colOpts === void 0 ? void 0 : colOpts.name) ? colOpts.name : camelToSnake(fkProp);
|
|
265
|
+
// Find primary key of target model
|
|
266
|
+
let targetPk = 'id';
|
|
267
|
+
const targetColMeta = (0, Column_1.getColumnMeta)(targetModel);
|
|
268
|
+
if (targetColMeta) {
|
|
269
|
+
for (const [tProp, tOpts] of targetColMeta.entries()) {
|
|
270
|
+
if (tOpts.id) {
|
|
271
|
+
targetPk = tOpts.name ? tOpts.name : camelToSnake(tProp);
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
const constraintName = `fk_${tableName}_${fkColName}`;
|
|
277
|
+
foreignKeys.push({
|
|
278
|
+
constraintName,
|
|
279
|
+
column: fkColName,
|
|
280
|
+
referenceTable: targetTable,
|
|
281
|
+
referenceColumn: targetPk
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return { columns, indexes, primaryKey, foreignKeys };
|
|
198
286
|
}
|
|
199
287
|
getSqlTypeForClass(type) {
|
|
200
288
|
const adapterType = (0, Database_1.getAdapter)().type;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aceitadev/adatabase",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.5",
|
|
4
4
|
"description": "Uma biblioteca para facilitar a interação com bancos de dados MySQL e PostgreSQL em projetos TypeScript/Node.js.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|