@carbonorm/carbonnode 3.0.13 → 3.0.15

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/index.esm.js CHANGED
@@ -2,6 +2,8 @@ import axios from 'axios';
2
2
  import Qs from 'qs';
3
3
  import { __assign, __awaiter, __generator, __extends, __spreadArray } from 'tslib';
4
4
  import { toast } from 'react-toastify';
5
+ import namedPlaceholders from 'named-placeholders';
6
+ import { Buffer as Buffer$1 } from 'buffer';
5
7
 
6
8
  var C6Constants = {
7
9
  // try to 1=1 match the Rest abstract class
@@ -66,6 +68,7 @@ var C6Constants = {
66
68
  LOCALTIMESTAMP: 'LOCALTIMESTAMP',
67
69
  MAKEDATE: 'MAKEDATE',
68
70
  MAKETIME: 'MAKETIME',
71
+ MATCH_AGAINST: 'MATCH_AGAINST',
69
72
  MONTHNAME: 'MONTHNAME',
70
73
  MICROSECOND: 'MICROSECOND',
71
74
  MINUTE: 'MINUTE',
@@ -440,203 +443,400 @@ var Executor = /** @class */ (function () {
440
443
  var SqlBuilder = /** @class */ (function (_super) {
441
444
  __extends(SqlBuilder, _super);
442
445
  function SqlBuilder() {
443
- return _super !== null && _super.apply(this, arguments) || this;
446
+ var _this = _super !== null && _super.apply(this, arguments) || this;
447
+ /** Flag to determine if named placeholders should be used */
448
+ _this.useNamedParams = false;
449
+ return _this;
444
450
  }
445
- /** Generate nested WHERE/JOIN conditions with parameter binding */
451
+ SqlBuilder.prototype.convertHexIfBinary = function (col, val) {
452
+ var _a;
453
+ var columnDef = (_a = this.config.C6.TABLES[this.config.restModel.TABLE_NAME].TYPE_VALIDATION) === null || _a === void 0 ? void 0 : _a[col];
454
+ if (typeof val === 'string' &&
455
+ /^[0-9a-fA-F]{32}$/.test(val) &&
456
+ typeof columnDef === 'object' &&
457
+ columnDef.MYSQL_TYPE.toUpperCase().includes('BINARY')) {
458
+ return Buffer.from(val, 'hex');
459
+ }
460
+ return val;
461
+ };
462
+ /** Generate nested WHERE/ON conditions with parameter binding (supports AND/OR/NOT) */
446
463
  SqlBuilder.prototype.buildBooleanJoinedConditions = function (set, andMode, params) {
464
+ var _this = this;
447
465
  if (andMode === void 0) { andMode = true; }
448
466
  if (params === void 0) { params = []; }
449
467
  var booleanOperator = andMode ? 'AND' : 'OR';
450
- var OPERATORS = ['=', '!=', '<', '<=', '>', '>=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'IS', 'IS NOT'];
451
- var isAggregateArray = function (value) {
452
- return Array.isArray(value) && typeof value[0] === 'string' && OPERATORS.includes(value[0]);
453
- };
468
+ var OPERATORS = [
469
+ '=', '!=', '<', '<=', '>', '>=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'IS', 'IS NOT',
470
+ 'BETWEEN', 'NOT BETWEEN', C6Constants.MATCH_AGAINST
471
+ ];
454
472
  var isNumericKeyed = function (obj) {
455
473
  return Array.isArray(obj) && Object.keys(obj).every(function (k) { return /^\d+$/.test(k); });
456
474
  };
475
+ // Helper to add a single condition with proper parameter binding
457
476
  var addCondition = function (column, op, value) {
458
477
  var clause;
459
- /*if (Buffer.isBuffer(value)) { // TODO - I want this as a parameterized option, for now default to faster
460
- params.push(value.toString('hex')); // Or use UNHEX(?) in SQL
461
- clause = `(${column} = UNHEX(?))`;
462
- } else {*/
463
- params.push(value);
464
- clause = "( ".concat(column, " ").concat(op, " ? )");
465
- //}
466
- isVerbose() && console.log("[WHERE] \u2795 ".concat(clause, " ->"), value);
478
+ // If using named parameters, generate a unique key; otherwise use positional placeholder
479
+ var addParam = function (val) {
480
+ if (Array.isArray(params)) {
481
+ // Positional (unnamed) parameter
482
+ params.push(_this.convertHexIfBinary(column, val));
483
+ return '?';
484
+ }
485
+ else {
486
+ // Named parameter mode
487
+ var key = "param".concat(Object.keys(params).length);
488
+ params[key] = _this.convertHexIfBinary(column, val);
489
+ return ":".concat(key);
490
+ }
491
+ };
492
+ if ((op === 'IN' || op === 'NOT IN') && Array.isArray(value)) {
493
+ if (value.length === 0) {
494
+ // Edge case: empty IN list - use a condition that's always false
495
+ clause = "( ".concat(column, " ").concat(op, " (NULL) )");
496
+ isVerbose() && console.warn("[WHERE] Empty list for ".concat(op, " on ").concat(column));
497
+ }
498
+ else {
499
+ var placeholders = value.map(function (val) { return addParam(val); }).join(', ');
500
+ clause = "( ".concat(column, " ").concat(op, " (").concat(placeholders, ") )");
501
+ }
502
+ }
503
+ else if ((op === 'BETWEEN' || op === 'NOT BETWEEN') && Array.isArray(value) && value.length === 2) {
504
+ // BETWEEN expects exactly two values [min, max]
505
+ var minVal = value[0], maxVal = value[1];
506
+ var ph1 = addParam(minVal);
507
+ var ph2 = addParam(maxVal);
508
+ clause = "( ".concat(column, " ").concat(op, " ").concat(ph1, " AND ").concat(ph2, " )");
509
+ }
510
+ else {
511
+ // Default case for single-value operators (including IS, IS NOT, =, etc.)
512
+ // Note: If value is null and op is 'IS' or 'IS NOT', the placeholder will safely bind null.
513
+ var ph = addParam(value);
514
+ clause = "( ".concat(column, " ").concat(op, " ").concat(ph, " )");
515
+ }
516
+ isVerbose() && console.log("[WHERE] \u2795 ".concat(clause));
467
517
  return clause;
468
518
  };
469
519
  var sql;
470
520
  if (isNumericKeyed(set)) {
471
- isVerbose() && console.log("[WHERE] Numeric keyed condition:", set);
472
- switch (set.length) {
473
- case 2:
474
- sql = addCondition(set[0], '=', set[1]);
475
- break;
476
- case 3:
477
- if (!OPERATORS.includes(set[1]))
478
- throw new Error("Invalid operator: ".concat(set[1]));
479
- sql = addCondition(set[0], set[1], set[2]);
480
- break;
481
- default:
482
- throw new Error("Invalid array condition: ".concat(JSON.stringify(set)));
521
+ // Array of conditions, use opposite boolean mode for combining (AND/OR swap)
522
+ isVerbose() && console.log("[WHERE] Grouping conditions (array) in ".concat(andMode ? 'AND' : 'OR', " mode:"), set);
523
+ if (set.length === 0) {
524
+ sql = ''; // no conditions
525
+ }
526
+ else if (set.length === 1) {
527
+ // Single element array, just build it normally (no boolean operator needed)
528
+ sql = this.buildBooleanJoinedConditions(set[0], true, params);
529
+ }
530
+ else {
531
+ // Multiple conditions: join them with the opposite of current mode
532
+ var subClauses = set.map(function (item) { return _this.buildBooleanJoinedConditions(item, true, params); });
533
+ var op = andMode ? 'OR' : 'AND';
534
+ sql = subClauses.map(function (sc) { return "(".concat(sc, ")"); }).join(" ".concat(op, " "));
483
535
  }
484
536
  }
485
- else {
537
+ else if (typeof set === 'object') {
486
538
  var parts = [];
487
539
  for (var _i = 0, _a = Object.entries(set); _i < _a.length; _i++) {
488
540
  var _b = _a[_i], key = _b[0], value = _b[1];
489
541
  if (/^\d+$/.test(key)) {
542
+ // Numeric object keys (should not happen because numeric arrays handled above)
490
543
  parts.push(this.buildBooleanJoinedConditions(value, !andMode, params));
491
544
  }
492
- else if (!Array.isArray(value) || isAggregateArray(value)) {
493
- parts.push(addCondition(key, '=', value));
545
+ else if (key.toUpperCase() === 'NOT') {
546
+ // NOT operator: negate the inner condition(s)
547
+ var negated = this.buildBooleanJoinedConditions(value, true, params);
548
+ parts.push("NOT (".concat(negated, ")"));
549
+ isVerbose() && console.log("[WHERE] NOT block: (".concat(negated, ")"));
550
+ }
551
+ else if (!Array.isArray(value)) {
552
+ if (typeof value === 'object' && value !== null && Object.keys(value).length === 1) {
553
+ var _c = Object.entries(value)[0], op = _c[0], val = _c[1];
554
+ if (OPERATORS.includes(op.toUpperCase())) {
555
+ if (value !== null &&
556
+ C6Constants.MATCH_AGAINST in value &&
557
+ Array.isArray(value[C6Constants.MATCH_AGAINST])) {
558
+ var _d = value[C6Constants.MATCH_AGAINST], search = _d[0], mode = _d[1];
559
+ var paramName = "param".concat(Object.keys(params).length);
560
+ params[paramName] = search;
561
+ var againstClause = void 0;
562
+ switch (mode === null || mode === void 0 ? void 0 : mode.toUpperCase()) {
563
+ case 'BOOLEAN':
564
+ againstClause = "AGAINST(:".concat(paramName, " IN BOOLEAN MODE)");
565
+ break;
566
+ case 'WITH QUERY EXPANSION':
567
+ againstClause = "AGAINST(:".concat(paramName, " WITH QUERY EXPANSION)");
568
+ break;
569
+ case 'NATURAL':
570
+ case undefined:
571
+ case null:
572
+ againstClause = "AGAINST(:".concat(paramName, ")"); // default natural language mode
573
+ break;
574
+ default:
575
+ throw new Error("Unsupported MATCH_AGAINST mode: ".concat(mode));
576
+ }
577
+ parts.push("(MATCH(".concat(key, ") ").concat(againstClause, ")"));
578
+ continue;
579
+ }
580
+ parts.push(addCondition(key, op.toUpperCase(), val));
581
+ }
582
+ else {
583
+ throw new Error("Unsupported operator '".concat(op, "' for key '").concat(key, "'"));
584
+ }
585
+ }
586
+ else {
587
+ // Fallback: treat as simple equality
588
+ parts.push(addCondition(key, '=', value));
589
+ }
494
590
  }
495
591
  else if (value.length === 2 && OPERATORS.includes(value[0])) {
592
+ // Two-element array, first is an operator (like ['>', 5])
496
593
  parts.push(addCondition(key, value[0], value[1]));
497
594
  }
595
+ else if (value.length === 3 && OPERATORS.includes(value[0])) {
596
+ // Three-element array, e.g. ['BETWEEN', min, max]
597
+ parts.push(addCondition(key, value[0], value.slice(1)));
598
+ }
498
599
  else {
499
600
  throw new Error("Invalid condition for ".concat(key, ": ").concat(JSON.stringify(value)));
500
601
  }
501
602
  }
502
- sql = parts.join(" ".concat(booleanOperator, " "));
603
+ sql = parts.length ? parts.join(" ".concat(booleanOperator, " ")) : '';
604
+ }
605
+ else {
606
+ // Primitive type (should not happen normally), treat it as a boolean expression string
607
+ sql = String(set);
503
608
  }
504
- isVerbose() && console.log("[WHERE] Final: (".concat(sql, ")"));
505
- return "(".concat(sql, ")");
609
+ // Wrap the final combined condition in parentheses to maintain correct precedence
610
+ return sql ? "(".concat(sql, ")") : '';
506
611
  };
507
- /** Translate array or function calls into SQL expressions */
612
+ /** Translate array or function call definitions into SQL expressions (supports nested calls) */
508
613
  SqlBuilder.prototype.buildAggregateField = function (field) {
509
- if (typeof field === 'string')
614
+ var _this = this;
615
+ if (typeof field === 'string') {
510
616
  return field;
511
- if (!Array.isArray(field))
512
- throw new Error('Invalid SELECT entry');
617
+ }
618
+ if (!Array.isArray(field) || field.length === 0) {
619
+ throw new Error('Invalid SELECT field entry');
620
+ }
621
+ // e.g. field = [ 'ROUND', [ 'SQRT', 'age' ], 2, 'AS', 'roundedRootAge' ]
513
622
  var fn = field[0], args = field.slice(1);
514
623
  var alias;
515
- if (args.length >= 2 && args[args.length - 2] === 'AS') {
516
- alias = String(args.pop());
517
- args.pop();
624
+ // Handle alias if present in array (e.g. ... 'AS', 'aliasName')
625
+ if (args.length >= 2 && String(args[args.length - 2]).toUpperCase() === 'AS') {
626
+ alias = String(args.pop()); // last element is alias name
627
+ args.pop(); // remove the 'AS'
518
628
  }
519
629
  var F = String(fn).toUpperCase();
520
- var p = args.join(', ');
521
- isVerbose() && console.log("[SELECT] ".concat(F, "(").concat(p, ")").concat(alias ? " AS ".concat(alias) : ''));
630
+ // Map each argument to SQL string, handling nested function arrays recursively
631
+ var argList = args.map(function (arg) {
632
+ if (Array.isArray(arg)) {
633
+ return _this.buildAggregateField(arg);
634
+ }
635
+ else {
636
+ return arg;
637
+ }
638
+ }).join(', ');
639
+ var expr;
522
640
  switch (F) {
523
641
  case 'DATE_ADD':
524
- return "DATE_ADD(".concat(args[0], ", ").concat(args[1], ")").concat(alias ? " AS ".concat(alias) : '');
525
642
  case 'DATE_SUB':
526
- return "DATE_SUB(".concat(args[0], ", ").concat(args[1], ")").concat(alias ? " AS ".concat(alias) : '');
643
+ // Functions with comma-separated interval, assume args like [ date, interval_expression ]
644
+ expr = "".concat(F, "(").concat(argList, ")");
645
+ break;
527
646
  case 'YEAR':
528
- return "YEAR(".concat(args[0], ")").concat(alias ? " AS ".concat(alias) : '');
529
647
  case 'MONTH':
530
- return "MONTH(".concat(args[0], ")").concat(alias ? " AS ".concat(alias) : '');
531
648
  case 'DAY':
532
- return "DAY(".concat(args[0], ")").concat(alias ? " AS ".concat(alias) : '');
533
649
  case 'ROUND':
534
650
  case 'CEIL':
535
651
  case 'FLOOR':
536
652
  case 'ABS':
537
653
  case 'SQRT':
538
- return "".concat(F, "(").concat(p, ")").concat(alias ? " AS ".concat(alias) : '');
654
+ case 'UPPER':
655
+ case 'LOWER':
656
+ case 'COALESCE':
657
+ case 'CONCAT':
658
+ case 'IFNULL':
659
+ case 'IF':
660
+ case 'COUNT':
661
+ case 'SUM':
662
+ case 'MIN':
663
+ case 'MAX':
664
+ case 'AVG':
665
+ // Common SQL functions – just format as F(arg1, arg2, ...)
666
+ expr = "".concat(F, "(").concat(argList, ")");
667
+ break;
539
668
  case 'ST_DISTANCE':
540
- return "ST_Distance(".concat(p, ")").concat(alias ? " AS ".concat(alias) : '');
669
+ expr = "ST_Distance(".concat(argList, ")");
670
+ break;
541
671
  default:
542
- if (/^[A-Z_]+$/.test(F))
543
- return "".concat(F, "(").concat(p, ")").concat(alias ? " AS ".concat(alias) : '');
544
- throw new Error("Unsupported function: ".concat(F));
672
+ if (/^[A-Z_]+$/.test(F)) {
673
+ // Allow any other SQL function by name (assuming it's a valid function)
674
+ expr = "".concat(F, "(").concat(argList, ")");
675
+ }
676
+ else {
677
+ throw new Error("Unsupported function: ".concat(F));
678
+ }
679
+ }
680
+ if (alias) {
681
+ expr += " AS ".concat(alias);
682
+ }
683
+ isVerbose() && console.log("[SELECT] ".concat(expr));
684
+ return expr;
685
+ };
686
+ SqlBuilder.prototype.buildJoinClauses = function (joinArgs, params) {
687
+ var sql = '';
688
+ for (var joinType in joinArgs) {
689
+ var jk = joinType.replace('_', ' ').toUpperCase();
690
+ for (var joinTable in joinArgs[joinType]) {
691
+ var onConditions = joinArgs[joinType][joinTable];
692
+ var onClause = this.buildBooleanJoinedConditions(onConditions, true, params);
693
+ sql += " ".concat(jk, " JOIN `").concat(joinTable, "` ON ").concat(onClause);
694
+ isVerbose() && console.log("[JOIN] ".concat(jk, " JOIN ").concat(joinTable, " ON ").concat(onClause));
695
+ }
545
696
  }
697
+ return sql;
698
+ };
699
+ SqlBuilder.prototype.buildPaginationClause = function (pagination, _params) {
700
+ var _a;
701
+ var sql = '';
702
+ if (pagination === null || pagination === void 0 ? void 0 : pagination[C6Constants.ORDER]) {
703
+ var orderParts = Object.entries(pagination[C6Constants.ORDER])
704
+ .map(function (_a) {
705
+ var col = _a[0], dir = _a[1];
706
+ return "".concat(col, " ").concat(String(dir).toUpperCase());
707
+ });
708
+ sql += " ORDER BY ".concat(orderParts.join(', '));
709
+ isVerbose() && console.log("[ORDER BY] ".concat(orderParts));
710
+ }
711
+ if ((pagination === null || pagination === void 0 ? void 0 : pagination[C6Constants.LIMIT]) != null) {
712
+ var lim = parseInt(pagination[C6Constants.LIMIT], 10);
713
+ var page = parseInt((_a = pagination[C6Constants.PAGE]) !== null && _a !== void 0 ? _a : 1, 10);
714
+ var offset = (page - 1) * lim;
715
+ sql += " LIMIT ".concat(offset, ", ").concat(lim);
716
+ isVerbose() && console.log("[LIMIT] ".concat(offset, ", ").concat(lim));
717
+ }
718
+ return sql;
719
+ };
720
+ SqlBuilder.prototype.buildWhereClause = function (whereArg, params) {
721
+ var whereClause = this.buildBooleanJoinedConditions(whereArg, true, params);
722
+ if (whereClause) {
723
+ var trimmed = whereClause.replace(/^\((.*)\)$/, '$1');
724
+ isVerbose() && console.log("[WHERE] ".concat(trimmed));
725
+ return " WHERE ".concat(trimmed);
726
+ }
727
+ return '';
546
728
  };
547
- /** Compose a parameterized SELECT query with optional JOIN/WHERE/GROUP/HAVING/PAGINATION */
548
729
  SqlBuilder.prototype.buildSelectQuery = function (table, primary, args, isSubSelect) {
549
730
  var _this = this;
550
- var _a, _b, _c, _d;
731
+ var _a, _b, _c;
551
732
  if (isSubSelect === void 0) { isSubSelect = false; }
552
733
  var model = this.config.C6.TABLES[table];
553
- var params = [];
554
- // SELECT
734
+ var params = this.useNamedParams ? {} : [];
555
735
  var selectList = (_a = args === null || args === void 0 ? void 0 : args[C6Constants.SELECT]) !== null && _a !== void 0 ? _a : ['*'];
556
736
  var selectFields = Array.isArray(selectList)
557
737
  ? selectList.map(function (f) { return _this.buildAggregateField(f); }).join(', ')
558
- : '*';
738
+ : String(selectList);
559
739
  var sql = "SELECT ".concat(selectFields, " FROM ").concat(table);
560
- isVerbose() && console.log("[SELECT]", selectFields);
561
- // JOIN
562
740
  if (args === null || args === void 0 ? void 0 : args[C6Constants.JOIN]) {
563
- for (var jt in args[C6Constants.JOIN]) {
564
- var jk = jt.replace('_', ' ').toUpperCase();
565
- for (var jn in args[C6Constants.JOIN][jt]) {
566
- var on = this.buildBooleanJoinedConditions(args[C6Constants.JOIN][jt][jn], true, params);
567
- sql += " ".concat(jk, " JOIN `").concat(jn, "` ON ").concat(on);
568
- isVerbose() && console.log("[JOIN]", jk, jn, on);
569
- }
570
- }
741
+ sql += this.buildJoinClauses(args[C6Constants.JOIN], params);
571
742
  }
572
- // WHERE
573
743
  if (args === null || args === void 0 ? void 0 : args[C6Constants.WHERE]) {
574
- var wc = this.buildBooleanJoinedConditions(args[C6Constants.WHERE], true, params);
575
- // Trim leading and trailing parentheses if they fully wrap the condition
576
- while (wc.startsWith('(') && wc.endsWith(')')) {
577
- wc = wc.slice(1, -1).trim();
578
- }
579
- sql += " WHERE ".concat(wc);
744
+ sql += this.buildWhereClause(args[C6Constants.WHERE], params);
580
745
  }
581
- // GROUP BY
582
746
  if (args === null || args === void 0 ? void 0 : args[C6Constants.GROUP_BY]) {
583
747
  var gb = Array.isArray(args[C6Constants.GROUP_BY])
584
748
  ? args[C6Constants.GROUP_BY].join(', ')
585
749
  : args[C6Constants.GROUP_BY];
586
750
  sql += " GROUP BY ".concat(gb);
587
- isVerbose() && console.log("[GROUP BY]", gb);
751
+ isVerbose() && console.log("[GROUP BY] ".concat(gb));
588
752
  }
589
- // HAVING
590
753
  if (args === null || args === void 0 ? void 0 : args[C6Constants.HAVING]) {
591
- var hc = this.buildBooleanJoinedConditions(args[C6Constants.HAVING], true, params);
592
- sql += " HAVING ".concat(hc);
754
+ var havingClause = this.buildBooleanJoinedConditions(args[C6Constants.HAVING], true, params);
755
+ if (havingClause) {
756
+ sql += " HAVING ".concat(havingClause);
757
+ }
593
758
  }
594
- // PAGINATION
595
759
  if (args === null || args === void 0 ? void 0 : args[C6Constants.PAGINATION]) {
596
- var p = args[C6Constants.PAGINATION];
597
- if (p[C6Constants.ORDER]) {
598
- var ord = Object.entries(p[C6Constants.ORDER]).map(function (_a) {
599
- var c = _a[0], d = _a[1];
600
- return "".concat(c, " ").concat(String(d).toUpperCase());
601
- });
602
- sql += " ORDER BY ".concat(ord.join(', '));
603
- isVerbose() && console.log("[ORDER BY]", ord);
604
- }
605
- if (p[C6Constants.LIMIT] != null) {
606
- var lim = parseInt(p[C6Constants.LIMIT], 10);
607
- var pg = parseInt((_b = p[C6Constants.PAGE]) !== null && _b !== void 0 ? _b : 1, 10);
608
- var off = (pg - 1) * lim;
609
- sql += " LIMIT ".concat(off, ", ").concat(lim);
610
- isVerbose() && console.log("[LIMIT]", off, lim);
611
- }
760
+ sql += this.buildPaginationClause(args[C6Constants.PAGINATION], params);
612
761
  }
613
- // Fallback ORDER/LIMIT
614
762
  else if (!isSubSelect) {
615
- var ok = void 0;
616
- if (primary)
617
- ok = primary;
618
- else if ((_c = model === null || model === void 0 ? void 0 : model.PRIMARY_SHORT) === null || _c === void 0 ? void 0 : _c[0])
619
- ok = model.PRIMARY_SHORT[0];
620
- else
621
- for (var _i = 0, _e = ['created_at', 'updated_at']; _i < _e.length; _i++) {
622
- var ts = _e[_i];
623
- if ((_d = model === null || model === void 0 ? void 0 : model.COLUMNS) === null || _d === void 0 ? void 0 : _d["".concat(table, ".").concat(ts)]) {
624
- ok = ts;
763
+ var orderKey = primary || ((_b = model === null || model === void 0 ? void 0 : model.PRIMARY_SHORT) === null || _b === void 0 ? void 0 : _b[0]);
764
+ if (!orderKey) {
765
+ for (var _i = 0, _d = ['created_at', 'updated_at']; _i < _d.length; _i++) {
766
+ var ts = _d[_i];
767
+ if ((_c = model === null || model === void 0 ? void 0 : model.COLUMNS) === null || _c === void 0 ? void 0 : _c["".concat(table, ".").concat(ts)]) {
768
+ orderKey = ts;
625
769
  break;
626
770
  }
627
771
  }
628
- if (ok) {
772
+ }
773
+ if (orderKey) {
629
774
  var dir = primary ? 'ASC' : 'DESC';
630
- var lim = primary ? 1 : 100;
631
- sql += " ORDER BY ".concat(ok, " ").concat(dir, " LIMIT ").concat(lim);
632
- isVerbose() && console.log("[ORDER]", ok, dir, lim);
775
+ sql += " ORDER BY ".concat(orderKey, " ").concat(dir, " LIMIT ").concat(primary ? 1 : 100);
776
+ isVerbose() && console.log("[DEFAULT ORDER] ".concat(orderKey, " ").concat(dir));
633
777
  }
634
778
  else {
635
779
  sql += " LIMIT 100";
636
- isVerbose() && console.warn("[ORDER] fallback LIMIT 100");
780
+ isVerbose() && console.warn("[DEFAULT LIMIT] 100 (no order key found)");
781
+ }
782
+ }
783
+ isVerbose() && console.log("[SQL SELECT]", sql, params);
784
+ return { sql: sql, params: params };
785
+ };
786
+ SqlBuilder.prototype.buildUpdateQuery = function (table, data, args) {
787
+ if (args === void 0) { args = {}; }
788
+ var params = this.useNamedParams ? {} : [];
789
+ var sql = "UPDATE ".concat(table);
790
+ if (args[C6Constants.JOIN]) {
791
+ sql += this.buildJoinClauses(args[C6Constants.JOIN], params);
792
+ }
793
+ var setClauses = [];
794
+ for (var _i = 0, _a = Object.entries(data); _i < _a.length; _i++) {
795
+ var _b = _a[_i], col = _b[0], val = _b[1];
796
+ if (Array.isArray(val)) {
797
+ var expr = this.buildAggregateField(val);
798
+ setClauses.push("`".concat(col, "` = ").concat(expr));
799
+ }
800
+ else {
801
+ var key = "param".concat(Array.isArray(params) ? params.length : Object.keys(params).length);
802
+ if (Array.isArray(params)) {
803
+ params.push(val);
804
+ setClauses.push("`".concat(col, "` = ?"));
805
+ }
806
+ else {
807
+ params[key] = val;
808
+ setClauses.push("`".concat(col, "` = :").concat(key));
809
+ }
637
810
  }
638
811
  }
639
- isVerbose() && console.log("[SQL]", sql, params);
812
+ sql += " SET ".concat(setClauses.join(', '));
813
+ isVerbose() && console.log("[SET] ".concat(setClauses));
814
+ if (args[C6Constants.WHERE]) {
815
+ sql += this.buildWhereClause(args[C6Constants.WHERE], params);
816
+ }
817
+ if (args[C6Constants.PAGINATION]) {
818
+ sql += this.buildPaginationClause(args[C6Constants.PAGINATION], params);
819
+ }
820
+ isVerbose() && console.log("[SQL UPDATE]", sql, params);
821
+ return { sql: sql, params: params };
822
+ };
823
+ /** Compose a DELETE query with optional JOIN and WHERE clauses */
824
+ SqlBuilder.prototype.buildDeleteQuery = function (table, args) {
825
+ if (args === void 0) { args = {}; }
826
+ var params = this.useNamedParams ? {} : [];
827
+ var sql = args[C6Constants.JOIN]
828
+ ? "DELETE ".concat(table, " FROM ").concat(table)
829
+ : "DELETE FROM ".concat(table);
830
+ if (args[C6Constants.JOIN]) {
831
+ sql += this.buildJoinClauses(args[C6Constants.JOIN], params);
832
+ }
833
+ if (args[C6Constants.WHERE]) {
834
+ sql += this.buildWhereClause(args[C6Constants.WHERE], params);
835
+ }
836
+ if (args[C6Constants.PAGINATION]) {
837
+ sql += this.buildPaginationClause(args[C6Constants.PAGINATION], params);
838
+ }
839
+ isVerbose() && console.log("[SQL DELETE]", sql, params);
640
840
  return { sql: sql, params: params };
641
841
  };
642
842
  return SqlBuilder;
@@ -1363,7 +1563,12 @@ var HttpExecutor$1 = /*#__PURE__*/Object.freeze({
1363
1563
  var SqlExecutor = /** @class */ (function (_super) {
1364
1564
  __extends(SqlExecutor, _super);
1365
1565
  function SqlExecutor() {
1366
- return _super !== null && _super.apply(this, arguments) || this;
1566
+ var _this = _super !== null && _super.apply(this, arguments) || this;
1567
+ _this.serialize = function (row) { return Object.fromEntries(Object.entries(row).map(function (_a) {
1568
+ var k = _a[0], v = _a[1];
1569
+ return [k, Buffer$1.isBuffer(v) ? v.toString('hex').toUpperCase() : v];
1570
+ })); };
1571
+ return _this;
1367
1572
  }
1368
1573
  SqlExecutor.prototype.execute = function () {
1369
1574
  return __awaiter(this, void 0, void 0, function () {
@@ -1387,7 +1592,7 @@ var SqlExecutor = /** @class */ (function (_super) {
1387
1592
  case 2:
1388
1593
  rest = _b.sent();
1389
1594
  console.log("[SQL EXECUTOR] \u2705 GET result:", rest);
1390
- return [2 /*return*/, { rest: rest }];
1595
+ return [2 /*return*/, rest];
1391
1596
  case 3: return [4 /*yield*/, this.insert(TABLE_NAME, this.request)];
1392
1597
  case 4:
1393
1598
  result = _b.sent();
@@ -1398,11 +1603,7 @@ var SqlExecutor = /** @class */ (function (_super) {
1398
1603
  case 6:
1399
1604
  result = _b.sent();
1400
1605
  console.log("[SQL EXECUTOR] \u2705 PUT result:", result);
1401
- updated = {
1402
- rest: result,
1403
- updated: true,
1404
- rowCount: result.affectedRows
1405
- };
1606
+ updated = __assign(__assign({}, result), { updated: true, rowCount: result.rest.affectedRows });
1406
1607
  return [2 /*return*/, updated];
1407
1608
  case 7: return [4 /*yield*/, this.delete(TABLE_NAME, [], this.request)];
1408
1609
  case 8:
@@ -1411,7 +1612,7 @@ var SqlExecutor = /** @class */ (function (_super) {
1411
1612
  deleted = {
1412
1613
  rest: result,
1413
1614
  deleted: true,
1414
- rowCount: result.affectedRows
1615
+ rowCount: result.rest.affectedRows
1415
1616
  };
1416
1617
  return [2 /*return*/, deleted];
1417
1618
  case 9: throw new Error("Unsupported request method: ".concat(method));
@@ -1446,28 +1647,36 @@ var SqlExecutor = /** @class */ (function (_super) {
1446
1647
  };
1447
1648
  SqlExecutor.prototype.select = function (table, primary, args) {
1448
1649
  return __awaiter(this, void 0, void 0, function () {
1449
- var sql, formatted;
1650
+ var QueryResult, formatted, toUnnamed, _a, sql, values;
1450
1651
  var _this = this;
1451
- return __generator(this, function (_a) {
1452
- switch (_a.label) {
1652
+ return __generator(this, function (_b) {
1653
+ switch (_b.label) {
1453
1654
  case 0:
1454
- sql = this.buildSelectQuery(table, primary, args);
1455
- console.log("[SQL EXECUTOR] \uD83E\uDDE0 Generated SELECT SQL:", sql);
1456
- formatted = this.formatSQLWithParams(sql.sql, sql.params);
1655
+ QueryResult = this.buildSelectQuery(table, primary, args);
1656
+ console.log("[SQL EXECUTOR] \uD83E\uDDE0 Generated SELECT SQL:", QueryResult);
1657
+ formatted = this.formatSQLWithParams(QueryResult.sql, QueryResult.params);
1457
1658
  console.log("[SQL EXECUTOR] \uD83E\uDDE0 Formatted SELECT SQL:", formatted);
1659
+ toUnnamed = namedPlaceholders();
1660
+ _a = toUnnamed(QueryResult.sql, QueryResult.params), sql = _a[0], values = _a[1];
1458
1661
  return [4 /*yield*/, this.withConnection(function (conn) { return __awaiter(_this, void 0, void 0, function () {
1459
1662
  var rows;
1460
1663
  return __generator(this, function (_a) {
1461
1664
  switch (_a.label) {
1462
- case 0: return [4 /*yield*/, conn.query(sql.sql, sql.params)];
1665
+ case 0: return [4 /*yield*/, conn.query(sql, values)];
1463
1666
  case 1:
1464
1667
  rows = (_a.sent())[0];
1465
1668
  console.log("[SQL EXECUTOR] \uD83D\uDCE6 Rows fetched:", rows);
1466
- return [2 /*return*/, rows];
1669
+ return [2 /*return*/, {
1670
+ rest: rows.map(this.serialize),
1671
+ sql: {
1672
+ sql: sql,
1673
+ values: values
1674
+ }
1675
+ }];
1467
1676
  }
1468
1677
  });
1469
1678
  }); })];
1470
- case 1: return [2 /*return*/, _a.sent()];
1679
+ case 1: return [2 /*return*/, _b.sent()];
1471
1680
  }
1472
1681
  });
1473
1682
  });
@@ -1482,7 +1691,7 @@ var SqlExecutor = /** @class */ (function (_super) {
1482
1691
  keys = Object.keys(data);
1483
1692
  values = keys.map(function (k) { return data[k]; });
1484
1693
  placeholders = keys.map(function () { return '?'; }).join(', ');
1485
- sql = "INSERT INTO `".concat(table, "` (").concat(keys.join(', '), ") VALUES (").concat(placeholders, ")");
1694
+ sql = "INSERT INTO `".concat(table, "` (").concat(keys.join(', '), ")\n VALUES (").concat(placeholders, ")");
1486
1695
  console.log("[SQL EXECUTOR] \uD83E\uDDE0 Generated INSERT SQL:", sql);
1487
1696
  console.log("[SQL EXECUTOR] \uD83D\uDD22 Values:", values);
1488
1697
  return [4 /*yield*/, this.withConnection(function (conn) { return __awaiter(_this, void 0, void 0, function () {
@@ -1492,7 +1701,13 @@ var SqlExecutor = /** @class */ (function (_super) {
1492
1701
  case 0: return [4 /*yield*/, conn.execute(sql, values)];
1493
1702
  case 1:
1494
1703
  result = (_a.sent())[0];
1495
- return [2 /*return*/, result];
1704
+ return [2 /*return*/, {
1705
+ rest: result,
1706
+ sql: {
1707
+ sql: sql,
1708
+ placeholders: placeholders
1709
+ }
1710
+ }];
1496
1711
  }
1497
1712
  });
1498
1713
  }); })];
@@ -1513,7 +1728,7 @@ var SqlExecutor = /** @class */ (function (_super) {
1513
1728
  keys = Object.keys(data);
1514
1729
  values = keys.map(function (k) { return data[k]; });
1515
1730
  updates = keys.map(function (k) { return "`".concat(k, "` = ?"); }).join(', ');
1516
- sql = "UPDATE `".concat(table, "` SET ").concat(updates, " WHERE `").concat(primary[0], "` = ?");
1731
+ sql = "UPDATE `".concat(table, "`\n SET ").concat(updates, "\n WHERE `").concat(primary[0], "` = ?");
1517
1732
  values.push(data[primary[0]]);
1518
1733
  console.log("[SQL EXECUTOR] \uD83E\uDDE0 Generated UPDATE SQL:", sql);
1519
1734
  console.log("[SQL EXECUTOR] \uD83D\uDD22 Values:", values);
@@ -1524,7 +1739,13 @@ var SqlExecutor = /** @class */ (function (_super) {
1524
1739
  case 0: return [4 /*yield*/, conn.execute(sql, values)];
1525
1740
  case 1:
1526
1741
  result = (_a.sent())[0];
1527
- return [2 /*return*/, result];
1742
+ return [2 /*return*/, {
1743
+ rest: result,
1744
+ sql: {
1745
+ sql: sql,
1746
+ values: values
1747
+ }
1748
+ }];
1528
1749
  }
1529
1750
  });
1530
1751
  }); })];
@@ -1543,7 +1764,7 @@ var SqlExecutor = /** @class */ (function (_super) {
1543
1764
  key = primary === null || primary === void 0 ? void 0 : primary[0];
1544
1765
  if (!key || !(args === null || args === void 0 ? void 0 : args[key]))
1545
1766
  throw new Error('Primary key and value required for delete');
1546
- sql = "DELETE FROM `".concat(table, "` WHERE `").concat(key, "` = ?");
1767
+ sql = "DELETE\n FROM `".concat(table, "`\n WHERE `").concat(key, "` = ?");
1547
1768
  console.log("[SQL EXECUTOR] \uD83E\uDDE0 Generated DELETE SQL:", sql);
1548
1769
  console.log("[SQL EXECUTOR] \uD83D\uDD22 Value:", args[key]);
1549
1770
  return [4 /*yield*/, this.withConnection(function (conn) { return __awaiter(_this, void 0, void 0, function () {
@@ -1553,7 +1774,13 @@ var SqlExecutor = /** @class */ (function (_super) {
1553
1774
  case 0: return [4 /*yield*/, conn.execute(sql, [args[key]])];
1554
1775
  case 1:
1555
1776
  result = (_a.sent())[0];
1556
- return [2 /*return*/, result];
1777
+ return [2 /*return*/, {
1778
+ rest: result,
1779
+ sql: {
1780
+ sql: sql,
1781
+ args: args
1782
+ }
1783
+ }];
1557
1784
  }
1558
1785
  });
1559
1786
  }); })];
@@ -1563,23 +1790,35 @@ var SqlExecutor = /** @class */ (function (_super) {
1563
1790
  });
1564
1791
  };
1565
1792
  SqlExecutor.prototype.formatSQLWithParams = function (sql, params) {
1566
- var index = 0;
1567
- return sql.replace(/\?/g, function () {
1568
- if (index >= params.length)
1569
- return '?'; // fallback if params are missing
1570
- var val = params[index++];
1571
- if (val === null || val === undefined)
1572
- return 'NULL';
1573
- if (Buffer.isBuffer(val))
1574
- return "UNHEX('".concat(val.toString('hex'), "')");
1575
- if (typeof val === 'string')
1576
- return "'".concat(val.replace(/'/g, "''"), "'");
1577
- if (typeof val === 'number')
1578
- return val.toString();
1579
- if (val instanceof Date)
1580
- return "'".concat(val.toISOString().slice(0, 19).replace('T', ' '), "'");
1581
- return "'".concat(JSON.stringify(val), "'");
1582
- });
1793
+ var _this = this;
1794
+ if (Array.isArray(params)) {
1795
+ var index_1 = 0;
1796
+ return sql.replace(/\?/g, function () {
1797
+ if (index_1 >= params.length)
1798
+ return '?';
1799
+ var val = params[index_1++];
1800
+ return _this.formatValue(val);
1801
+ });
1802
+ }
1803
+ else {
1804
+ return sql.replace(/:([a-zA-Z0-9_]+)/g, function (_, key) {
1805
+ var val = params[key];
1806
+ return _this.formatValue(val);
1807
+ });
1808
+ }
1809
+ };
1810
+ SqlExecutor.prototype.formatValue = function (val) {
1811
+ if (val === null || val === undefined)
1812
+ return 'NULL';
1813
+ if (Buffer$1.isBuffer(val))
1814
+ return "UNHEX('".concat(val.toString('hex'), "')");
1815
+ if (typeof val === 'string')
1816
+ return "'".concat(val.replace(/'/g, "''"), "'");
1817
+ if (typeof val === 'number')
1818
+ return val.toString();
1819
+ if (val instanceof Date)
1820
+ return "'".concat(val.toISOString().slice(0, 19).replace('T', ' '), "'");
1821
+ return "'".concat(JSON.stringify(val), "'");
1583
1822
  };
1584
1823
  return SqlExecutor;
1585
1824
  }(SqlBuilder));
@@ -1633,11 +1872,11 @@ function ExpressHandler(_a) {
1633
1872
  })(payload)];
1634
1873
  case 1:
1635
1874
  response = _a.sent();
1636
- console.log('response', JSON.stringify(response));
1637
1875
  res.status(200).json(__assign({ success: true }, response));
1638
1876
  return [3 /*break*/, 3];
1639
1877
  case 2:
1640
1878
  err_1 = _a.sent();
1879
+ res.status(500).json({ success: false });
1641
1880
  next(err_1);
1642
1881
  return [3 /*break*/, 3];
1643
1882
  case 3: return [2 /*return*/];