@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.
@@ -1,7 +1,9 @@
1
1
  export declare class SchemaManager {
2
2
  private models;
3
+ private changes;
3
4
  constructor(models: Function[]);
4
5
  migrate(): Promise<void>;
6
+ private printMigrationSummary;
5
7
  private createTable;
6
8
  private updateTable;
7
9
  private getSchemaFromModel;
@@ -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
- Logger_1.Logger.schemaLog("Synchronizing database schema...");
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
- Logger_1.Logger.schemaLog("", { table: table, status: "created" });
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
- for (const [col, type] of Object.entries(desired)) {
79
- if (!existing.hasOwnProperty(col)) {
80
- const sql = `ALTER TABLE \`${table}\` ADD COLUMN \`${col}\` ${type};`;
81
- const conn = yield (0, Database_1.getConnection)();
82
- try {
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
- Logger_1.Logger.schemaLog("", { table: table, column: col, status: "added" });
107
+ tableChanges.push(`+ ${col} (adicionado)`);
85
108
  }
86
- finally {
87
- conn.release();
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 && opts.name ? opts.name : camelToSnake(prop);
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 && opts.id) {
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 && opts.limit) {
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 && opts.unique)
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, data_type FROM information_schema.columns WHERE table_schema = current_schema() AND table_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, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_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.data_type;
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.DATA_TYPE;
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.release();
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.0",
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",