@aceitadev/adatabase 0.5.0 → 0.5.6
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 +2 -0
- package/dist/SchemaManager.js +79 -28
- package/package.json +1 -1
package/dist/SchemaManager.d.ts
CHANGED
package/dist/SchemaManager.js
CHANGED
|
@@ -14,31 +14,52 @@ const Table_1 = require("./decorators/Table");
|
|
|
14
14
|
const Column_1 = require("./decorators/Column");
|
|
15
15
|
const Nullable_1 = require("./decorators/Nullable");
|
|
16
16
|
const Database_1 = require("./Database");
|
|
17
|
-
const Logger_1 = require("./Logger");
|
|
18
17
|
function camelToSnake(s) {
|
|
19
18
|
return s.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
|
|
20
19
|
}
|
|
21
20
|
class SchemaManager {
|
|
22
21
|
constructor(models) {
|
|
22
|
+
this.changes = new Map();
|
|
23
23
|
this.models = models;
|
|
24
24
|
}
|
|
25
25
|
migrate() {
|
|
26
26
|
return __awaiter(this, void 0, void 0, function* () {
|
|
27
|
-
|
|
27
|
+
this.changes.clear();
|
|
28
28
|
for (const model of this.models) {
|
|
29
29
|
const table = (0, Table_1.getTableName)(model);
|
|
30
30
|
if (!table)
|
|
31
31
|
continue;
|
|
32
|
-
|
|
33
|
-
const { columns, indexes } = this.getSchemaFromModel(model);
|
|
32
|
+
const { columns, indexes, primaryKey } = this.getSchemaFromModel(model);
|
|
34
33
|
const existing = yield this.getExistingColumns(table);
|
|
35
34
|
if (Object.keys(existing).length === 0) {
|
|
36
35
|
yield this.createTable(table, columns, indexes);
|
|
37
36
|
}
|
|
38
37
|
else {
|
|
39
|
-
yield this.updateTable(table, columns, indexes, existing);
|
|
38
|
+
yield this.updateTable(table, columns, indexes, existing, primaryKey);
|
|
40
39
|
}
|
|
41
40
|
}
|
|
41
|
+
this.printMigrationSummary();
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
printMigrationSummary() {
|
|
45
|
+
if (this.changes.size === 0) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
console.log("Schema atualizado:");
|
|
49
|
+
const tableEntries = Array.from(this.changes.entries());
|
|
50
|
+
tableEntries.forEach(([table, changes], tableIndex) => {
|
|
51
|
+
const isLastTable = tableIndex === tableEntries.length - 1;
|
|
52
|
+
const tablePrefix = isLastTable ? "└─" : "├─";
|
|
53
|
+
if (tableIndex > 0) {
|
|
54
|
+
console.log("│");
|
|
55
|
+
}
|
|
56
|
+
console.log(`${tablePrefix} ${table}`);
|
|
57
|
+
changes.forEach((change, changeIndex) => {
|
|
58
|
+
const isLastChange = changeIndex === changes.length - 1;
|
|
59
|
+
const changeLinePrefix = isLastTable ? " " : "│ ";
|
|
60
|
+
const changeConnector = isLastChange ? "└─" : "├─";
|
|
61
|
+
console.log(` ${changeLinePrefix}${changeConnector} ${change}`);
|
|
62
|
+
});
|
|
42
63
|
});
|
|
43
64
|
}
|
|
44
65
|
createTable(table, columns, indexes) {
|
|
@@ -53,7 +74,8 @@ class SchemaManager {
|
|
|
53
74
|
const conn = yield (0, Database_1.getConnection)();
|
|
54
75
|
try {
|
|
55
76
|
yield (0, Database_1.execute)(sql, [], conn);
|
|
56
|
-
|
|
77
|
+
const columnChanges = Object.keys(columns).map(col => `+ ${col} (adicionado)`);
|
|
78
|
+
this.changes.set(table, columnChanges);
|
|
57
79
|
}
|
|
58
80
|
finally {
|
|
59
81
|
conn.release();
|
|
@@ -73,39 +95,59 @@ class SchemaManager {
|
|
|
73
95
|
}
|
|
74
96
|
});
|
|
75
97
|
}
|
|
76
|
-
updateTable(table, desired, indexes, existing) {
|
|
98
|
+
updateTable(table, desired, indexes, existing, primaryKey) {
|
|
77
99
|
return __awaiter(this, void 0, void 0, function* () {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
100
|
+
const tableChanges = [];
|
|
101
|
+
const conn = yield (0, Database_1.getConnection)();
|
|
102
|
+
try {
|
|
103
|
+
for (const [col, type] of Object.entries(desired)) {
|
|
104
|
+
// Se a coluna for a chave primária, pule a verificação para evitar o erro.
|
|
105
|
+
if (col === primaryKey) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (!existing.hasOwnProperty(col)) {
|
|
109
|
+
const sql = `ALTER TABLE \`${table}\` ADD COLUMN \`${col}\` ${type};`;
|
|
83
110
|
yield (0, Database_1.execute)(sql, [], conn);
|
|
84
|
-
|
|
111
|
+
tableChanges.push(`+ ${col} (adicionado)`);
|
|
85
112
|
}
|
|
86
|
-
|
|
87
|
-
|
|
113
|
+
else {
|
|
114
|
+
const normalize = (t) => t.toLowerCase().replace(/\s/g, '').replace('character varying', 'varchar');
|
|
115
|
+
const existingType = normalize(existing[col]);
|
|
116
|
+
// Compara apenas o tipo base, ignorando extras como NOT NULL
|
|
117
|
+
const desiredType = normalize(type.split(' ')[0]);
|
|
118
|
+
if (existingType !== desiredType) {
|
|
119
|
+
const sql = `ALTER TABLE \`${table}\` MODIFY COLUMN \`${col}\` ${type};`;
|
|
120
|
+
yield (0, Database_1.execute)(sql, [], conn);
|
|
121
|
+
tableChanges.push(`~ ${col} (tipo alterado: ${existing[col].toUpperCase()} → ${type.split(' ')[0].toUpperCase()})`);
|
|
122
|
+
}
|
|
88
123
|
}
|
|
89
124
|
}
|
|
125
|
+
if (tableChanges.length > 0) {
|
|
126
|
+
this.changes.set(table, tableChanges);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
conn.release();
|
|
90
131
|
}
|
|
91
132
|
});
|
|
92
133
|
}
|
|
93
134
|
getSchemaFromModel(model) {
|
|
94
135
|
const columns = {};
|
|
95
136
|
const indexes = [];
|
|
137
|
+
let primaryKey = null;
|
|
96
138
|
const colMeta = (0, Column_1.getColumnMeta)(model);
|
|
97
139
|
const nullableMeta = (0, Nullable_1.getNullableMeta)(model);
|
|
98
140
|
const adapter = (0, Database_1.getAdapter)();
|
|
99
141
|
if (!colMeta) {
|
|
100
|
-
|
|
101
|
-
return { columns, indexes };
|
|
142
|
+
return { columns, indexes, primaryKey };
|
|
102
143
|
}
|
|
103
144
|
for (const [prop, opts] of colMeta.entries()) {
|
|
104
|
-
const colName = opts
|
|
145
|
+
const colName = (opts === null || opts === void 0 ? void 0 : opts.name) ? opts.name : camelToSnake(prop);
|
|
105
146
|
if (opts.index) {
|
|
106
147
|
indexes.push(colName);
|
|
107
148
|
}
|
|
108
|
-
if (opts
|
|
149
|
+
if (opts === null || opts === void 0 ? void 0 : opts.id) {
|
|
150
|
+
primaryKey = colName;
|
|
109
151
|
const type = opts.type || Number;
|
|
110
152
|
if (adapter.type === 'postgres') {
|
|
111
153
|
columns[colName] = "SERIAL PRIMARY KEY";
|
|
@@ -117,7 +159,6 @@ class SchemaManager {
|
|
|
117
159
|
}
|
|
118
160
|
const type = opts.type;
|
|
119
161
|
if (!type) {
|
|
120
|
-
Logger_1.Logger.log(`Type not provided for property '${prop}' on model '${model.name}'.`, 'error');
|
|
121
162
|
continue;
|
|
122
163
|
}
|
|
123
164
|
let sqlType = this.getSqlTypeForClass(type);
|
|
@@ -129,7 +170,7 @@ class SchemaManager {
|
|
|
129
170
|
sqlType = 'DECIMAL(10, 2)';
|
|
130
171
|
}
|
|
131
172
|
}
|
|
132
|
-
if (type === String && opts
|
|
173
|
+
else if (type === String && (opts === null || opts === void 0 ? void 0 : opts.limit)) {
|
|
133
174
|
sqlType = `VARCHAR(${opts.limit})`;
|
|
134
175
|
}
|
|
135
176
|
const isNullable = nullableMeta === null || nullableMeta === void 0 ? void 0 : nullableMeta.get(prop);
|
|
@@ -145,11 +186,11 @@ class SchemaManager {
|
|
|
145
186
|
sqlType += " DEFAULT CURRENT_TIMESTAMP";
|
|
146
187
|
}
|
|
147
188
|
}
|
|
148
|
-
if (opts
|
|
189
|
+
if (opts === null || opts === void 0 ? void 0 : opts.unique)
|
|
149
190
|
sqlType += " UNIQUE";
|
|
150
191
|
columns[colName] = sqlType;
|
|
151
192
|
}
|
|
152
|
-
return { columns, indexes };
|
|
193
|
+
return { columns, indexes, primaryKey };
|
|
153
194
|
}
|
|
154
195
|
getSqlTypeForClass(type) {
|
|
155
196
|
const adapterType = (0, Database_1.getAdapter)().type;
|
|
@@ -178,25 +219,35 @@ class SchemaManager {
|
|
|
178
219
|
try {
|
|
179
220
|
let sql;
|
|
180
221
|
if (adapter.type === 'postgres') {
|
|
181
|
-
sql = `SELECT column_name,
|
|
222
|
+
sql = `SELECT column_name, udt_name || COALESCE('(' || character_maximum_length || ')', '') as column_type
|
|
223
|
+
FROM information_schema.columns
|
|
224
|
+
WHERE table_schema = current_schema() AND table_name = $1`;
|
|
182
225
|
}
|
|
183
226
|
else { // mysql
|
|
184
|
-
sql = `SELECT COLUMN_NAME,
|
|
227
|
+
sql = `SELECT COLUMN_NAME, COLUMN_TYPE
|
|
228
|
+
FROM INFORMATION_SCHEMA.COLUMNS
|
|
229
|
+
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ?`;
|
|
185
230
|
}
|
|
186
231
|
const rows = yield (0, Database_1.query)(sql, [table], conn);
|
|
232
|
+
if (rows.length === 0)
|
|
233
|
+
return {};
|
|
187
234
|
if (adapter.type === 'postgres') {
|
|
188
235
|
for (const r of rows) {
|
|
189
|
-
columns[r.column_name] = r.
|
|
236
|
+
columns[r.column_name] = r.column_type;
|
|
190
237
|
}
|
|
191
238
|
}
|
|
192
239
|
else {
|
|
193
240
|
for (const r of rows) {
|
|
194
|
-
columns[r.COLUMN_NAME] = r.
|
|
241
|
+
columns[r.COLUMN_NAME] = r.COLUMN_TYPE;
|
|
195
242
|
}
|
|
196
243
|
}
|
|
197
244
|
}
|
|
245
|
+
catch (e) {
|
|
246
|
+
return {}; // Table likely does not exist
|
|
247
|
+
}
|
|
198
248
|
finally {
|
|
199
|
-
conn
|
|
249
|
+
if (conn)
|
|
250
|
+
conn.release();
|
|
200
251
|
}
|
|
201
252
|
return columns;
|
|
202
253
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aceitadev/adatabase",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.6",
|
|
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",
|