@mlagie/sql-connector 1.4.0 → 1.4.1
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/package.json +1 -1
- package/src/models/Model.js +31 -29
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mlagie/sql-connector",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "Le module sql-connector permet de gérer les connexions à une base de données MySQL, de définir des schémas de tables, et d'interagir avec les données de manière simple et efficace.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
package/src/models/Model.js
CHANGED
|
@@ -155,7 +155,6 @@ class Model {
|
|
|
155
155
|
fs.writeFileSync(backupPath, insertSQL, 'utf-8');
|
|
156
156
|
logs(`Sauvegarde SQL de la table '${dbTable}' effectuée dans '${backupPath}'.`);
|
|
157
157
|
} else {
|
|
158
|
-
fs.writeFileSync(backupPath, '', 'utf-8');
|
|
159
158
|
logs(`Table '${dbTable}' vide, fichier '${backupPath}' créé.`);
|
|
160
159
|
}
|
|
161
160
|
} catch (err) {
|
|
@@ -191,7 +190,7 @@ class Model {
|
|
|
191
190
|
input: process.stdin,
|
|
192
191
|
output: process.stdout
|
|
193
192
|
});
|
|
194
|
-
|
|
193
|
+
|
|
195
194
|
// Demande restauration
|
|
196
195
|
const answer = await new Promise((resolve) => {
|
|
197
196
|
rl.question(
|
|
@@ -201,7 +200,7 @@ class Model {
|
|
|
201
200
|
}
|
|
202
201
|
);
|
|
203
202
|
});
|
|
204
|
-
|
|
203
|
+
|
|
205
204
|
if (answer === 'y') {
|
|
206
205
|
try {
|
|
207
206
|
const sqlContent = fs.readFileSync(latestBackup, 'utf-8');
|
|
@@ -211,7 +210,7 @@ class Model {
|
|
|
211
210
|
error(`Erreur lors de la restauration du backup pour '${model.name}': ${err}`);
|
|
212
211
|
}
|
|
213
212
|
}
|
|
214
|
-
|
|
213
|
+
|
|
215
214
|
// Toujours demander la suppression après restauration ou non
|
|
216
215
|
await new Promise((resolve) => {
|
|
217
216
|
rl.question(
|
|
@@ -231,13 +230,13 @@ class Model {
|
|
|
231
230
|
);
|
|
232
231
|
});
|
|
233
232
|
}
|
|
234
|
-
|
|
233
|
+
|
|
235
234
|
// 2. Synchronise les colonnes (renommage, ajout, suppression)
|
|
236
235
|
const [columns] = await conn.promise().query(
|
|
237
236
|
`SHOW COLUMNS FROM \`${model.name}\``
|
|
238
237
|
);
|
|
239
238
|
let existingCols = columns.map(col => col.Field);
|
|
240
|
-
|
|
239
|
+
|
|
241
240
|
for (const [fieldName, field] of Object.entries(model.schema.schemaDict)) {
|
|
242
241
|
if (existingCols.includes(fieldName)) {
|
|
243
242
|
// 1. Récupère infos colonne
|
|
@@ -245,14 +244,14 @@ class Model {
|
|
|
245
244
|
const [indexes] = await conn.promise().query(
|
|
246
245
|
`SHOW INDEX FROM \`${model.name}\` WHERE Column_name = ?`, [fieldName]
|
|
247
246
|
);
|
|
248
|
-
|
|
247
|
+
|
|
249
248
|
// 2. Vérifie les propriétés principales avec plus de précision
|
|
250
249
|
let needModify = false;
|
|
251
|
-
|
|
250
|
+
|
|
252
251
|
// --- Vérification du TYPE ---
|
|
253
252
|
const fieldType = getFieldType(field);
|
|
254
253
|
let expectedTypeDef;
|
|
255
|
-
|
|
254
|
+
|
|
256
255
|
if (Array.isArray(field.enum) && field.enum.length > 0) {
|
|
257
256
|
// Pour les ENUM, on compare la définition complète
|
|
258
257
|
const enumValues = field.enum.map(v => `'${v.replace(/'/g, "''")}'`).join(", ");
|
|
@@ -260,31 +259,31 @@ class Model {
|
|
|
260
259
|
} else {
|
|
261
260
|
// Pour les autres types
|
|
262
261
|
if (!sqlTypeMap[fieldType]) throw new Error(`Field ${fieldName} has unsupported type ${fieldType}.`);
|
|
263
|
-
|
|
262
|
+
|
|
264
263
|
expectedTypeDef = sqlTypeMap[fieldType];
|
|
265
264
|
if (sqlTypeMap[fieldType] === "VARCHAR" || sqlTypeMap[fieldType] === "INT") {
|
|
266
265
|
const length = field.length > 0 ? field.length : 255;
|
|
267
266
|
expectedTypeDef += `(${length})`;
|
|
268
267
|
}
|
|
269
268
|
}
|
|
270
|
-
|
|
269
|
+
|
|
271
270
|
// Normalisation pour la comparaison (minuscules, suppression des espaces)
|
|
272
271
|
const normalizeType = (typeStr) => {
|
|
273
272
|
return typeStr.toLowerCase().replace(/\s+/g, '').replace(/`/g, '');
|
|
274
273
|
};
|
|
275
|
-
|
|
274
|
+
|
|
276
275
|
const currentTypeNormalized = normalizeType(currentCol.Type);
|
|
277
276
|
const expectedTypeNormalized = normalizeType(expectedTypeDef);
|
|
278
|
-
|
|
277
|
+
|
|
279
278
|
if (currentTypeNormalized !== expectedTypeNormalized) {
|
|
280
279
|
logs(`Type mismatch for ${fieldName}: DB has '${currentCol.Type}', expected '${expectedTypeDef}'`);
|
|
281
280
|
needModify = true;
|
|
282
281
|
}
|
|
283
|
-
|
|
282
|
+
|
|
284
283
|
// --- Vérification NULL/NOT NULL ---
|
|
285
284
|
const shouldBeNotNull = field.required === true || field.primary_key === true;
|
|
286
285
|
const isNullableInDB = currentCol.Null === "YES";
|
|
287
|
-
|
|
286
|
+
|
|
288
287
|
if (shouldBeNotNull && isNullableInDB) {
|
|
289
288
|
logs(`Nullability mismatch for ${fieldName}: DB allows NULL, expected NOT NULL`);
|
|
290
289
|
needModify = true;
|
|
@@ -293,11 +292,11 @@ class Model {
|
|
|
293
292
|
logs(`Nullability mismatch for ${fieldName}: DB is NOT NULL, expected NULL allowed`);
|
|
294
293
|
needModify = true;
|
|
295
294
|
}
|
|
296
|
-
|
|
295
|
+
|
|
297
296
|
// --- Vérification DEFAULT VALUE ---
|
|
298
297
|
const expectedDefault = field.default !== undefined ? field.default : null;
|
|
299
298
|
const currentDefault = currentCol.Default;
|
|
300
|
-
|
|
299
|
+
|
|
301
300
|
// Gestion spéciale pour les valeurs par défaut
|
|
302
301
|
if (expectedDefault !== null && currentDefault === null) {
|
|
303
302
|
logs(`Default value mismatch for ${fieldName}: DB has NULL, expected '${expectedDefault}'`);
|
|
@@ -312,28 +311,28 @@ class Model {
|
|
|
312
311
|
needModify = true;
|
|
313
312
|
}
|
|
314
313
|
}
|
|
315
|
-
|
|
314
|
+
|
|
316
315
|
// --- Vérification UNIQUE constraint ---
|
|
317
316
|
const isUniqueInDB = indexes.some(idx => idx.Non_unique === 0 && idx.Key_name !== 'PRIMARY');
|
|
318
317
|
if (!!field.unique !== isUniqueInDB) {
|
|
319
318
|
logs(`Unique constraint mismatch for ${fieldName}: DB has unique=${isUniqueInDB}, expected=${!!field.unique}`);
|
|
320
319
|
needModify = true;
|
|
321
320
|
}
|
|
322
|
-
|
|
321
|
+
|
|
323
322
|
// --- Vérification PRIMARY KEY ---
|
|
324
323
|
const isPrimaryInDB = indexes.some(idx => idx.Key_name === 'PRIMARY');
|
|
325
324
|
if (!!field.primary_key !== isPrimaryInDB) {
|
|
326
325
|
logs(`Primary key mismatch for ${fieldName}: DB has PK=${isPrimaryInDB}, expected=${!!field.primary_key}`);
|
|
327
326
|
needModify = true;
|
|
328
327
|
}
|
|
329
|
-
|
|
328
|
+
|
|
330
329
|
// --- Vérification AUTO_INCREMENT ---
|
|
331
330
|
const isAutoIncrementInDB = currentCol.Extra.toLowerCase().includes('auto_increment');
|
|
332
331
|
if (!!field.auto_increment !== isAutoIncrementInDB) {
|
|
333
332
|
logs(`Auto increment mismatch for ${fieldName}: DB has AI=${isAutoIncrementInDB}, expected=${!!field.auto_increment}`);
|
|
334
333
|
needModify = true;
|
|
335
334
|
}
|
|
336
|
-
|
|
335
|
+
|
|
337
336
|
// 3. Si différence, on modifie
|
|
338
337
|
if (needModify) {
|
|
339
338
|
try {
|
|
@@ -352,27 +351,27 @@ class Model {
|
|
|
352
351
|
logs(`⚠️ Pensez à retirer la propriété 'oldName' du champ '${fieldName}' dans le schéma JS de '${model.name}' pour éviter des renommages inutiles à l'avenir.`);
|
|
353
352
|
}
|
|
354
353
|
}
|
|
355
|
-
|
|
354
|
+
|
|
356
355
|
// --- Étape 1 : Renommage des colonnes ---
|
|
357
356
|
for (const [fieldName, field] of Object.entries(model.schema.schemaDict)) {
|
|
358
357
|
if (field.oldName && existingCols.includes(field.oldName) && !existingCols.includes(fieldName)) {
|
|
359
358
|
// Génère la définition SQL de la nouvelle colonne
|
|
360
359
|
let colDef = getColumnDefinition(fieldName, field);
|
|
361
|
-
|
|
360
|
+
|
|
362
361
|
// Renomme la colonne
|
|
363
|
-
const alterSQL = `ALTER TABLE \`${model.name}\` CHANGE COLUMN \`${field.oldName}\`
|
|
362
|
+
const alterSQL = `ALTER TABLE \`${model.name}\` CHANGE COLUMN \`${field.oldName}\` ${colDef}`;
|
|
364
363
|
await conn.promise().query(alterSQL);
|
|
365
364
|
logs(`Colonne ${field.oldName} renommée en ${fieldName} dans ${model.name}`);
|
|
366
365
|
// Mets à jour existingCols pour la suite
|
|
367
366
|
existingCols = existingCols.map(col => col === field.oldName ? fieldName : col);
|
|
368
367
|
}
|
|
369
368
|
}
|
|
370
|
-
|
|
369
|
+
|
|
371
370
|
// --- Étape 2 : Ajout des colonnes manquantes ---
|
|
372
371
|
for (const [fieldName, field] of Object.entries(model.schema.schemaDict)) {
|
|
373
372
|
if (!existingCols.includes(fieldName)) {
|
|
374
373
|
let colDef = getColumnDefinition(fieldName, field);
|
|
375
|
-
|
|
374
|
+
|
|
376
375
|
// Ajoute la colonne
|
|
377
376
|
const alterSQL = `ALTER TABLE \`${model.name}\` ADD COLUMN ${colDef}`;
|
|
378
377
|
await conn.promise().query(alterSQL);
|
|
@@ -380,7 +379,7 @@ class Model {
|
|
|
380
379
|
existingCols.push(fieldName);
|
|
381
380
|
}
|
|
382
381
|
}
|
|
383
|
-
|
|
382
|
+
|
|
384
383
|
// --- Étape 3 : Suppression des colonnes orphelines (dangerousSync) ---
|
|
385
384
|
if (dangerousSync) {
|
|
386
385
|
for (const col of existingCols) {
|
|
@@ -459,7 +458,7 @@ class Model {
|
|
|
459
458
|
* @param {Object} [options.where] - Filtres (clé/valeur).
|
|
460
459
|
* @param {Array} [options.order] - Ex: [['points', 'DESC']]
|
|
461
460
|
* @param {number} [options.limit] - Limite de résultats.
|
|
462
|
-
* @returns {Promise<Array<
|
|
461
|
+
* @returns {Promise<Array<ModelInstance>>}
|
|
463
462
|
*/
|
|
464
463
|
async findAll(options = {}) {
|
|
465
464
|
const {
|
|
@@ -481,9 +480,12 @@ class Model {
|
|
|
481
480
|
sql_request += ` LIMIT ${limit}`;
|
|
482
481
|
}
|
|
483
482
|
|
|
483
|
+
logs(sql_request)
|
|
484
|
+
|
|
484
485
|
return new Promise((resolve, reject) => {
|
|
485
486
|
getConnexion().promise().query(sql_request).then(([rows]) => {
|
|
486
|
-
|
|
487
|
+
const instances = rows.map(row => new ModelInstance(this.name, row, this.schema));
|
|
488
|
+
resolve(instances);
|
|
487
489
|
}).catch((err) => {
|
|
488
490
|
error(`Error executing findAll: ${err}`);
|
|
489
491
|
resolve([]);
|