@aceitadev/adatabase 0.5.0 → 0.5.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 +2 -0
- package/dist/SchemaManager.js +69 -23
- package/package.json +1 -1
package/dist/SchemaManager.d.ts
CHANGED
package/dist/SchemaManager.js
CHANGED
|
@@ -14,22 +14,21 @@ 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
|
-
Logger_1.Logger.schemaLog("", { table: table, status: "started" });
|
|
33
32
|
const { columns, indexes } = this.getSchemaFromModel(model);
|
|
34
33
|
const existing = yield this.getExistingColumns(table);
|
|
35
34
|
if (Object.keys(existing).length === 0) {
|
|
@@ -39,6 +38,28 @@ class SchemaManager {
|
|
|
39
38
|
yield this.updateTable(table, columns, indexes, existing);
|
|
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();
|
|
@@ -75,18 +97,34 @@ class SchemaManager {
|
|
|
75
97
|
}
|
|
76
98
|
updateTable(table, desired, indexes, existing) {
|
|
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
|
+
if (!existing.hasOwnProperty(col)) {
|
|
105
|
+
const sql = `ALTER TABLE \`${table}\` ADD COLUMN \`${col}\` ${type};`;
|
|
83
106
|
yield (0, Database_1.execute)(sql, [], conn);
|
|
84
|
-
|
|
107
|
+
tableChanges.push(`+ ${col} (adicionado)`);
|
|
85
108
|
}
|
|
86
|
-
|
|
87
|
-
|
|
109
|
+
else {
|
|
110
|
+
const normalize = (t) => t.toLowerCase().replace(/\s/g, '').replace('character varying', 'varchar');
|
|
111
|
+
const existingType = normalize(existing[col]);
|
|
112
|
+
const desiredType = normalize(type.split(' ')[0]);
|
|
113
|
+
if (existingType !== desiredType) {
|
|
114
|
+
// NOTE: Type modification is database-specific and can be risky.
|
|
115
|
+
// This implementation assumes MySQL's MODIFY COLUMN syntax.
|
|
116
|
+
const sql = `ALTER TABLE \`${table}\` MODIFY COLUMN \`${col}\` ${type};`;
|
|
117
|
+
yield (0, Database_1.execute)(sql, [], conn);
|
|
118
|
+
tableChanges.push(`~ ${col} (tipo alterado: ${existing[col].toUpperCase()} → ${type.split(' ')[0].toUpperCase()})`);
|
|
119
|
+
}
|
|
88
120
|
}
|
|
89
121
|
}
|
|
122
|
+
if (tableChanges.length > 0) {
|
|
123
|
+
this.changes.set(table, tableChanges);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
finally {
|
|
127
|
+
conn.release();
|
|
90
128
|
}
|
|
91
129
|
});
|
|
92
130
|
}
|
|
@@ -97,15 +135,14 @@ class SchemaManager {
|
|
|
97
135
|
const nullableMeta = (0, Nullable_1.getNullableMeta)(model);
|
|
98
136
|
const adapter = (0, Database_1.getAdapter)();
|
|
99
137
|
if (!colMeta) {
|
|
100
|
-
Logger_1.Logger.log(`No @Column or @Id decorators found on model ${model.name}.`, 'warn');
|
|
101
138
|
return { columns, indexes };
|
|
102
139
|
}
|
|
103
140
|
for (const [prop, opts] of colMeta.entries()) {
|
|
104
|
-
const colName = opts
|
|
141
|
+
const colName = (opts === null || opts === void 0 ? void 0 : opts.name) ? opts.name : camelToSnake(prop);
|
|
105
142
|
if (opts.index) {
|
|
106
143
|
indexes.push(colName);
|
|
107
144
|
}
|
|
108
|
-
if (opts
|
|
145
|
+
if (opts === null || opts === void 0 ? void 0 : opts.id) {
|
|
109
146
|
const type = opts.type || Number;
|
|
110
147
|
if (adapter.type === 'postgres') {
|
|
111
148
|
columns[colName] = "SERIAL PRIMARY KEY";
|
|
@@ -117,7 +154,6 @@ class SchemaManager {
|
|
|
117
154
|
}
|
|
118
155
|
const type = opts.type;
|
|
119
156
|
if (!type) {
|
|
120
|
-
Logger_1.Logger.log(`Type not provided for property '${prop}' on model '${model.name}'.`, 'error');
|
|
121
157
|
continue;
|
|
122
158
|
}
|
|
123
159
|
let sqlType = this.getSqlTypeForClass(type);
|
|
@@ -129,7 +165,7 @@ class SchemaManager {
|
|
|
129
165
|
sqlType = 'DECIMAL(10, 2)';
|
|
130
166
|
}
|
|
131
167
|
}
|
|
132
|
-
if (type === String && opts
|
|
168
|
+
else if (type === String && (opts === null || opts === void 0 ? void 0 : opts.limit)) {
|
|
133
169
|
sqlType = `VARCHAR(${opts.limit})`;
|
|
134
170
|
}
|
|
135
171
|
const isNullable = nullableMeta === null || nullableMeta === void 0 ? void 0 : nullableMeta.get(prop);
|
|
@@ -145,7 +181,7 @@ class SchemaManager {
|
|
|
145
181
|
sqlType += " DEFAULT CURRENT_TIMESTAMP";
|
|
146
182
|
}
|
|
147
183
|
}
|
|
148
|
-
if (opts
|
|
184
|
+
if (opts === null || opts === void 0 ? void 0 : opts.unique)
|
|
149
185
|
sqlType += " UNIQUE";
|
|
150
186
|
columns[colName] = sqlType;
|
|
151
187
|
}
|
|
@@ -178,25 +214,35 @@ class SchemaManager {
|
|
|
178
214
|
try {
|
|
179
215
|
let sql;
|
|
180
216
|
if (adapter.type === 'postgres') {
|
|
181
|
-
sql = `SELECT column_name,
|
|
217
|
+
sql = `SELECT column_name, udt_name || COALESCE('(' || character_maximum_length || ')', '') as column_type
|
|
218
|
+
FROM information_schema.columns
|
|
219
|
+
WHERE table_schema = current_schema() AND table_name = $1`;
|
|
182
220
|
}
|
|
183
221
|
else { // mysql
|
|
184
|
-
sql = `SELECT COLUMN_NAME,
|
|
222
|
+
sql = `SELECT COLUMN_NAME, COLUMN_TYPE
|
|
223
|
+
FROM INFORMATION_SCHEMA.COLUMNS
|
|
224
|
+
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ?`;
|
|
185
225
|
}
|
|
186
226
|
const rows = yield (0, Database_1.query)(sql, [table], conn);
|
|
227
|
+
if (rows.length === 0)
|
|
228
|
+
return {};
|
|
187
229
|
if (adapter.type === 'postgres') {
|
|
188
230
|
for (const r of rows) {
|
|
189
|
-
columns[r.column_name] = r.
|
|
231
|
+
columns[r.column_name] = r.column_type;
|
|
190
232
|
}
|
|
191
233
|
}
|
|
192
234
|
else {
|
|
193
235
|
for (const r of rows) {
|
|
194
|
-
columns[r.COLUMN_NAME] = r.
|
|
236
|
+
columns[r.COLUMN_NAME] = r.COLUMN_TYPE;
|
|
195
237
|
}
|
|
196
238
|
}
|
|
197
239
|
}
|
|
240
|
+
catch (e) {
|
|
241
|
+
return {}; // Table likely does not exist
|
|
242
|
+
}
|
|
198
243
|
finally {
|
|
199
|
-
conn
|
|
244
|
+
if (conn)
|
|
245
|
+
conn.release();
|
|
200
246
|
}
|
|
201
247
|
return columns;
|
|
202
248
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aceitadev/adatabase",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.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",
|