@mlagie/sql-connector 1.4.0 → 1.4.2

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/models/Model.js +33 -35
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mlagie/sql-connector",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
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": {
@@ -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}\` \`${fieldName}\` ${colDef}`;
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<Object>>}
461
+ * @returns {Promise<Array<ModelInstance>>}
463
462
  */
464
463
  async findAll(options = {}) {
465
464
  const {
@@ -483,7 +482,8 @@ class Model {
483
482
 
484
483
  return new Promise((resolve, reject) => {
485
484
  getConnexion().promise().query(sql_request).then(([rows]) => {
486
- resolve(rows);
485
+ const instances = rows.map(row => new ModelInstance(this.name, row, this.schema));
486
+ resolve(instances);
487
487
  }).catch((err) => {
488
488
  error(`Error executing findAll: ${err}`);
489
489
  resolve([]);
@@ -501,13 +501,12 @@ class Model {
501
501
  const sql_request = `SELECT ${fields.join(", ")} FROM ${this.name} WHERE ${generateCondition(formatObject(filter))}`;
502
502
 
503
503
  return new Promise((resolve, reject) => {
504
- getConnexion().promise().query(sql_request).then((rows) => {
505
- if (rows.length == 0) return resolve(0);
506
-
507
- resolve(new ModelInstance(this.name, Object.values(rows[0])[0], this.schema));
504
+ getConnexion().promise().query(sql_request).then(([rows]) => {
505
+ if (!rows || rows.length === 0) return resolve(0);
506
+ resolve(new ModelInstance(this.name, rows[0], this.schema));
508
507
  }).catch((err) => {
509
508
  error(`Error executing query: ${err}`);
510
- return 0;
509
+ return resolve(0);
511
510
  });
512
511
  });
513
512
  }
@@ -589,7 +588,6 @@ class Model {
589
588
  */
590
589
  async delete(filter) {
591
590
  const sql_request = `DELETE FROM ${this.name} WHERE ${generateCondition(formatObject(filter))}`;
592
-
593
591
  return new Promise((resolve, reject) => {
594
592
  getConnexion().promise().query(sql_request).then((rows) => {
595
593
  if (rows[1] != undefined) return resolve(0);