@bkmj/node-red-contrib-odbcmj 2.1.0 → 2.1.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.
Files changed (2) hide show
  1. package/odbc.js +86 -66
  2. package/package.json +1 -1
package/odbc.js CHANGED
@@ -257,14 +257,23 @@ module.exports = function (RED) {
257
257
  return newMsg;
258
258
  };
259
259
 
260
- this.executeStreamQuery = async (dbConnection, queryString, queryParams, msg, send, done) => {
260
+ // =================================================================
261
+ // DEBUT DE LA SECTION CORRIGÉE
262
+ // =================================================================
263
+
264
+ this.executeStreamQuery = async (queryString, queryParams, msg, send, done) => {
261
265
  const chunkSize = parseInt(this.config.streamChunkSize) || 1;
262
266
  let cursor;
263
267
  let rowCount = 0;
264
268
  let chunk = [];
265
269
 
266
270
  try {
267
- cursor = await dbConnection.cursor(queryString, queryParams);
271
+ // CORRECTION : Appeler .cursor() sur le pool, pas sur une connexion individuelle.
272
+ if (!this.poolNode || !this.poolNode.pool) {
273
+ throw new Error("Le pool de connexions n'est pas initialisé pour le streaming.");
274
+ }
275
+ cursor = await this.poolNode.pool.cursor(queryString, queryParams);
276
+
268
277
  this.status({ fill: "blue", shape: "dot", text: "streaming rows..." });
269
278
  let row = await cursor.fetch();
270
279
  while (row) {
@@ -294,6 +303,7 @@ module.exports = function (RED) {
294
303
  this.status({ fill: "green", shape: "dot", text: `success (${rowCount} rows)` });
295
304
  if(done) done();
296
305
  } catch(err) {
306
+ // L'erreur sera transmise à l'appelant (runQuery)
297
307
  throw err;
298
308
  }
299
309
  finally {
@@ -302,10 +312,10 @@ module.exports = function (RED) {
302
312
  };
303
313
 
304
314
  this.runQuery = async (msg, send, done) => {
305
- let isPreparedStatement = false;
306
- let connectionFromPool = null;
315
+ let isPreparedStatement = false;
316
+ let connectionFromPool = null;
307
317
 
308
- try {
318
+ try {
309
319
  this.status({ fill: "blue", shape: "dot", text: "preparing..." });
310
320
  this.config.outputObj = msg?.output || this.config?.outputObj || "payload";
311
321
 
@@ -314,18 +324,16 @@ module.exports = function (RED) {
314
324
  const paramsSourceType = this.config.paramsSourceType || 'msg';
315
325
  const paramsSource = this.config.paramsSource || 'parameters';
316
326
 
317
- let currentQueryParams = await new Promise((resolve, reject) => {
327
+ let currentQueryParams = await new Promise((resolve) => {
318
328
  RED.util.evaluateNodeProperty(paramsSource, paramsSourceType, this, msg, (err, value) => {
319
- if (err) { resolve(undefined); }
320
- else { resolve(value); }
329
+ resolve(err ? undefined : value);
321
330
  });
322
331
  });
323
332
 
324
- let currentQueryString = await new Promise((resolve, reject) => {
333
+ let currentQueryString = await new Promise((resolve) => {
325
334
  RED.util.evaluateNodeProperty(querySource, querySourceType, this, msg, (err, value) => {
326
- if (err) { resolve(undefined); }
327
- else { resolve(value || this.config.query || ""); }
328
- });
335
+ resolve(err ? undefined : (value || this.config.query || ""));
336
+ });
329
337
  });
330
338
 
331
339
  if (!currentQueryString) { throw new Error("No query to execute"); }
@@ -340,71 +348,79 @@ module.exports = function (RED) {
340
348
  currentQueryString = mustache.render(currentQueryString, msg);
341
349
  }
342
350
 
343
- const execute = async (conn) => {
344
- if (this.config.streaming) {
345
- await this.executeStreamQuery(conn, currentQueryString, currentQueryParams, msg, send, done);
346
- } else {
351
+ // CORRECTION : Logique séparée pour streaming et non-streaming
352
+ if (this.config.streaming) {
353
+ // Le mode Streaming appelle directement la fonction corrigée
354
+ await this.executeStreamQuery(currentQueryString, currentQueryParams, msg, send, done);
355
+
356
+ } else {
357
+ // Le mode non-streaming utilise la logique de connexion/retry existante
358
+ const executeNonQuery = async (conn) => {
347
359
  const processedMsg = await this.executeQueryAndProcess(conn, currentQueryString, currentQueryParams, isPreparedStatement, msg);
348
360
  this.status({ fill: "green", shape: "dot", text: "success" });
349
361
  send(processedMsg);
350
362
  if(done) done();
363
+ };
364
+
365
+ let firstAttemptError = null;
366
+ try {
367
+ connectionFromPool = await this.poolNode.connect();
368
+ await executeNonQuery(connectionFromPool);
369
+ return;
370
+ } catch (err) {
371
+ firstAttemptError = this.enhanceError(err, currentQueryString, currentQueryParams, "Query failed with pooled connection");
372
+ this.warn(`First attempt failed: ${firstAttemptError.message}`);
373
+ } finally {
374
+ if (connectionFromPool) await connectionFromPool.close();
351
375
  }
352
- };
353
-
354
- let firstAttemptError = null;
355
- try {
356
- connectionFromPool = await this.poolNode.connect();
357
- await execute(connectionFromPool);
358
- return;
359
- } catch (err) {
360
- firstAttemptError = this.enhanceError(err, currentQueryString, currentQueryParams, "Query failed with pooled connection");
361
- this.warn(`First attempt failed: ${firstAttemptError.message}`);
362
- } finally {
363
- if (connectionFromPool) await connectionFromPool.close();
364
- }
365
376
 
366
- if (firstAttemptError) {
367
- if (this.poolNode && this.poolNode.config.retryFreshConnection) {
368
- this.log("Attempting retry with a fresh connection.");
369
- this.status({ fill: "yellow", shape: "dot", text: "Retrying (fresh)..." });
370
- let freshConnection = null;
371
- try {
372
- const freshConnectConfig = this.poolNode.getFreshConnectionConfig();
373
- freshConnection = await odbcModule.connect(freshConnectConfig);
374
- this.log("Fresh connection established for retry.");
375
- await execute(freshConnection);
376
- this.log("Query successful with fresh connection. Resetting pool.");
377
- await this.poolNode.resetPool();
378
- return;
379
- } catch (freshError) {
380
- this.warn(`Retry with fresh connection also failed: ${freshError.message}`);
381
- const retryDelay = parseInt(this.poolNode.config.retryDelay) || 0;
382
- if (retryDelay > 0) {
383
- this.isAwaitingRetry = true;
384
- this.status({ fill: "red", shape: "ring", text: `Retry in ${retryDelay}s...` });
385
- this.log(`Scheduling retry in ${retryDelay} seconds.`);
386
- this.retryTimer = setTimeout(() => {
387
- this.isAwaitingRetry = false;
388
- this.log("Timer expired. Triggering scheduled retry.");
389
- this.receive(msg);
390
- }, retryDelay * 1000);
391
- if (done) done();
392
- } else {
393
- throw this.enhanceError(freshError, currentQueryString, currentQueryParams, "Query failed on fresh connection retry");
377
+ if (firstAttemptError) {
378
+ if (this.poolNode && this.poolNode.config.retryFreshConnection) {
379
+ this.log("Attempting retry with a fresh connection.");
380
+ this.status({ fill: "yellow", shape: "dot", text: "Retrying (fresh)..." });
381
+ let freshConnection = null;
382
+ try {
383
+ const freshConnectConfig = this.poolNode.getFreshConnectionConfig();
384
+ freshConnection = await odbcModule.connect(freshConnectConfig);
385
+ this.log("Fresh connection established for retry.");
386
+ await executeNonQuery(freshConnection);
387
+ this.log("Query successful with fresh connection. Resetting pool.");
388
+ await this.poolNode.resetPool();
389
+ return;
390
+ } catch (freshError) {
391
+ this.warn(`Retry with fresh connection also failed: ${freshError.message}`);
392
+ const retryDelay = parseInt(this.poolNode.config.retryDelay) || 0;
393
+ if (retryDelay > 0) {
394
+ this.isAwaitingRetry = true;
395
+ this.status({ fill: "red", shape: "ring", text: `Retry in ${retryDelay}s...` });
396
+ this.log(`Scheduling retry in ${retryDelay} seconds.`);
397
+ this.retryTimer = setTimeout(() => {
398
+ this.isAwaitingRetry = false;
399
+ this.log("Timer expired. Triggering scheduled retry.");
400
+ this.receive(msg);
401
+ }, retryDelay * 1000);
402
+ if (done) done();
403
+ } else {
404
+ throw this.enhanceError(freshError, currentQueryString, currentQueryParams, "Query failed on fresh connection retry");
405
+ }
406
+ } finally {
407
+ if (freshConnection) await freshConnection.close();
394
408
  }
395
- } finally {
396
- if (freshConnection) await freshConnection.close();
409
+ } else {
410
+ throw firstAttemptError;
397
411
  }
398
- } else {
399
- throw firstAttemptError;
400
412
  }
401
413
  }
402
- } catch (err) {
403
- const finalError = err instanceof Error ? err : new Error(String(err));
404
- this.status({ fill: "red", shape: "ring", text: "query error" });
405
- if (done) { done(finalError); } else { this.error(finalError, msg); }
406
- }
414
+ } catch (err) {
415
+ const finalError = err instanceof Error ? err : new Error(String(err));
416
+ this.status({ fill: "red", shape: "ring", text: "query error" });
417
+ if (done) { done(finalError); } else { this.error(finalError, msg); }
418
+ }
407
419
  };
420
+
421
+ // =================================================================
422
+ // FIN DE LA SECTION CORRIGÉE
423
+ // =================================================================
408
424
 
409
425
  this.checkPool = async function (msg, send, done) {
410
426
  try {
@@ -420,6 +436,10 @@ module.exports = function (RED) {
420
436
  }, 1000);
421
437
  return;
422
438
  }
439
+ // S'assure que le pool est créé avant toute requête, y compris en streaming
440
+ if (!this.poolNode.pool) {
441
+ await this.poolNode.connect().then(c => c.close()); // Etablit le pool s'il n'existe pas
442
+ }
423
443
  await this.runQuery(msg, send, done);
424
444
  } catch (err) {
425
445
  const finalError = err instanceof Error ? err : new Error(String(err));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bkmj/node-red-contrib-odbcmj",
3
- "version": "2.1.0",
3
+ "version": "2.1.1",
4
4
  "description": "A powerful Node-RED node to connect to any ODBC data source, with connection pooling, advanced retry logic, and result streaming.",
5
5
  "keywords": [
6
6
  "node-red",