@aceitadev/adatabase 0.4.5 → 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/Logger.js CHANGED
@@ -19,30 +19,25 @@ class Logger {
19
19
  }
20
20
  }
21
21
  static schemaLog(message, details) {
22
- if (!details) {
23
- Logger.log(message);
24
- return;
25
- }
26
- let logOutput = `${Logger.PREFIX} ${message}`;
27
- if (details.table) {
28
- logOutput += `
29
- |`;
30
- logOutput += `
31
- |–– Table '${details.table}'`;
32
- if (details.status) {
33
- logOutput += ` (${details.status})`;
22
+ const PREFIX = `[aDatabase]`;
23
+ if (details && details.table && !details.column) {
24
+ if (details.status === 'started') {
25
+ process.stdout.write(`${PREFIX} Synchronizing table '${details.table}'...`);
26
+ }
27
+ else if (details.status === 'created') {
28
+ process.stdout.write(` Done.
29
+ `);
34
30
  }
35
31
  }
36
- if (details.column) {
37
- logOutput += `
38
- `;
39
- logOutput += `
40
- \_ Column '${details.column}'`;
41
- if (details.status) {
42
- logOutput += ` (${details.status})`;
32
+ else if (details && details.table && details.column) {
33
+ if (details.status === 'added') {
34
+ console.log(`
35
+ ${PREFIX} Column '${details.column}' added to table '${details.table}'.`);
43
36
  }
44
37
  }
45
- console.log(`${logOutput}`); // Green for schema logs
38
+ else {
39
+ console.log(`${PREFIX} ${message}`);
40
+ }
46
41
  }
47
42
  }
48
43
  exports.Logger = Logger;
@@ -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,21 +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
+ this.changes.clear();
27
28
  for (const model of this.models) {
28
29
  const table = (0, Table_1.getTableName)(model);
29
30
  if (!table)
30
31
  continue;
31
- Logger_1.Logger.schemaLog("Synchronizing database schema...", { table: table, status: "started" });
32
32
  const { columns, indexes } = this.getSchemaFromModel(model);
33
33
  const existing = yield this.getExistingColumns(table);
34
34
  if (Object.keys(existing).length === 0) {
@@ -38,6 +38,28 @@ class SchemaManager {
38
38
  yield this.updateTable(table, columns, indexes, existing);
39
39
  }
40
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
+ });
41
63
  });
42
64
  }
43
65
  createTable(table, columns, indexes) {
@@ -52,7 +74,8 @@ class SchemaManager {
52
74
  const conn = yield (0, Database_1.getConnection)();
53
75
  try {
54
76
  yield (0, Database_1.execute)(sql, [], conn);
55
- Logger_1.Logger.schemaLog("Table created", { table: table, status: "created" });
77
+ const columnChanges = Object.keys(columns).map(col => `+ ${col} (adicionado)`);
78
+ this.changes.set(table, columnChanges);
56
79
  }
57
80
  finally {
58
81
  conn.release();
@@ -74,18 +97,34 @@ class SchemaManager {
74
97
  }
75
98
  updateTable(table, desired, indexes, existing) {
76
99
  return __awaiter(this, void 0, void 0, function* () {
77
- for (const [col, type] of Object.entries(desired)) {
78
- if (!existing.hasOwnProperty(col)) {
79
- const sql = `ALTER TABLE \`${table}\` ADD COLUMN \`${col}\` ${type};`;
80
- const conn = yield (0, Database_1.getConnection)();
81
- 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};`;
82
106
  yield (0, Database_1.execute)(sql, [], conn);
83
- Logger_1.Logger.schemaLog("Column added", { table: table, column: col, status: "added" });
107
+ tableChanges.push(`+ ${col} (adicionado)`);
84
108
  }
85
- finally {
86
- 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
+ }
87
120
  }
88
121
  }
122
+ if (tableChanges.length > 0) {
123
+ this.changes.set(table, tableChanges);
124
+ }
125
+ }
126
+ finally {
127
+ conn.release();
89
128
  }
90
129
  });
91
130
  }
@@ -96,15 +135,14 @@ class SchemaManager {
96
135
  const nullableMeta = (0, Nullable_1.getNullableMeta)(model);
97
136
  const adapter = (0, Database_1.getAdapter)();
98
137
  if (!colMeta) {
99
- Logger_1.Logger.log(`No @Column or @Id decorators found on model ${model.name}.`, 'warn');
100
138
  return { columns, indexes };
101
139
  }
102
140
  for (const [prop, opts] of colMeta.entries()) {
103
- 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);
104
142
  if (opts.index) {
105
143
  indexes.push(colName);
106
144
  }
107
- if (opts && opts.id) {
145
+ if (opts === null || opts === void 0 ? void 0 : opts.id) {
108
146
  const type = opts.type || Number;
109
147
  if (adapter.type === 'postgres') {
110
148
  columns[colName] = "SERIAL PRIMARY KEY";
@@ -116,7 +154,6 @@ class SchemaManager {
116
154
  }
117
155
  const type = opts.type;
118
156
  if (!type) {
119
- Logger_1.Logger.log(`Type not provided for property '${prop}' on model '${model.name}'.`, 'error');
120
157
  continue;
121
158
  }
122
159
  let sqlType = this.getSqlTypeForClass(type);
@@ -128,7 +165,7 @@ class SchemaManager {
128
165
  sqlType = 'DECIMAL(10, 2)';
129
166
  }
130
167
  }
131
- if (type === String && opts && opts.limit) {
168
+ else if (type === String && (opts === null || opts === void 0 ? void 0 : opts.limit)) {
132
169
  sqlType = `VARCHAR(${opts.limit})`;
133
170
  }
134
171
  const isNullable = nullableMeta === null || nullableMeta === void 0 ? void 0 : nullableMeta.get(prop);
@@ -144,7 +181,7 @@ class SchemaManager {
144
181
  sqlType += " DEFAULT CURRENT_TIMESTAMP";
145
182
  }
146
183
  }
147
- if (opts && opts.unique)
184
+ if (opts === null || opts === void 0 ? void 0 : opts.unique)
148
185
  sqlType += " UNIQUE";
149
186
  columns[colName] = sqlType;
150
187
  }
@@ -177,25 +214,35 @@ class SchemaManager {
177
214
  try {
178
215
  let sql;
179
216
  if (adapter.type === 'postgres') {
180
- 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`;
181
220
  }
182
221
  else { // mysql
183
- 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 = ?`;
184
225
  }
185
226
  const rows = yield (0, Database_1.query)(sql, [table], conn);
227
+ if (rows.length === 0)
228
+ return {};
186
229
  if (adapter.type === 'postgres') {
187
230
  for (const r of rows) {
188
- columns[r.column_name] = r.data_type;
231
+ columns[r.column_name] = r.column_type;
189
232
  }
190
233
  }
191
234
  else {
192
235
  for (const r of rows) {
193
- columns[r.COLUMN_NAME] = r.DATA_TYPE;
236
+ columns[r.COLUMN_NAME] = r.COLUMN_TYPE;
194
237
  }
195
238
  }
196
239
  }
240
+ catch (e) {
241
+ return {}; // Table likely does not exist
242
+ }
197
243
  finally {
198
- conn.release();
244
+ if (conn)
245
+ conn.release();
199
246
  }
200
247
  return columns;
201
248
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aceitadev/adatabase",
3
- "version": "0.4.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",