@aceitadev/adatabase 0.6.7 → 0.8.0

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.
@@ -6,6 +6,7 @@ export declare class SchemaManager {
6
6
  private printMigrationSummary;
7
7
  private createTable;
8
8
  private updateTable;
9
+ private getExistingConstraints;
9
10
  private getSchemaFromModel;
10
11
  private getSqlTypeForClass;
11
12
  private getExistingColumns;
@@ -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.updateTable(table, columns, indexes, existing, primaryKey);
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
- const sql = `CREATE TABLE \`${table}\` (${colsSql}${indexSql});`;
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} (adicionado)`);
78
- this.changes.set(table, columnChanges);
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} (adicionado)`);
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} (tipo alterado: ${existing[col].toUpperCase()} → ${type.split(' ')[0].toUpperCase()})`);
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);
@@ -166,11 +223,9 @@ class SchemaManager {
166
223
  let sqlType = this.getSqlTypeForClass(type);
167
224
  if (type === Number && opts.decimal) {
168
225
  if (Array.isArray(opts.decimal) && opts.decimal.length === 2) {
169
- // CORREÇÃO: Removido o espaço após a vírgula
170
226
  sqlType = `DECIMAL(${opts.decimal[0]},${opts.decimal[1]})`;
171
227
  }
172
228
  else {
173
- // CORREÇÃO: Removido o espaço após a vírgula
174
229
  sqlType = 'DECIMAL(10,2)';
175
230
  }
176
231
  }
@@ -194,7 +249,37 @@ class SchemaManager {
194
249
  sqlType += " UNIQUE";
195
250
  columns[colName] = sqlType;
196
251
  }
197
- return { columns, indexes, primaryKey };
252
+ if (belongsToMeta) {
253
+ for (const [prop, opts] of belongsToMeta.entries()) {
254
+ const fkProp = opts.foreignKey;
255
+ const targetModel = opts.model();
256
+ const targetTable = (0, Table_1.getTableName)(targetModel);
257
+ if (!targetTable)
258
+ continue;
259
+ // Find the column name for the foreign key property
260
+ const colOpts = colMeta.get(fkProp);
261
+ const fkColName = (colOpts === null || colOpts === void 0 ? void 0 : colOpts.name) ? colOpts.name : camelToSnake(fkProp);
262
+ // Find primary key of target model
263
+ let targetPk = 'id';
264
+ const targetColMeta = (0, Column_1.getColumnMeta)(targetModel);
265
+ if (targetColMeta) {
266
+ for (const [tProp, tOpts] of targetColMeta.entries()) {
267
+ if (tOpts.id) {
268
+ targetPk = tOpts.name ? tOpts.name : camelToSnake(tProp);
269
+ break;
270
+ }
271
+ }
272
+ }
273
+ const constraintName = `fk_${tableName}_${fkColName}`;
274
+ foreignKeys.push({
275
+ constraintName,
276
+ column: fkColName,
277
+ referenceTable: targetTable,
278
+ referenceColumn: targetPk
279
+ });
280
+ }
281
+ }
282
+ return { columns, indexes, primaryKey, foreignKeys };
198
283
  }
199
284
  getSqlTypeForClass(type) {
200
285
  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.6.7",
3
+ "version": "0.8.0",
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",