@dbcube/core 5.1.13 → 5.2.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/dist/index.cjs CHANGED
@@ -34,6 +34,7 @@ __export(index_exports, {
34
34
  Binary: () => Binary,
35
35
  ComputedFieldProcessor: () => ComputedFieldProcessor,
36
36
  Config: () => Config,
37
+ DaemonClient: () => DaemonClient,
37
38
  DbConfig: () => DbConfig,
38
39
  Engine: () => Engine,
39
40
  FileLogger: () => FileLogger,
@@ -44,7 +45,7 @@ __export(index_exports, {
44
45
  module.exports = __toCommonJS(index_exports);
45
46
 
46
47
  // src/lib/Engine.ts
47
- var import_path3 = __toESM(require("path"));
48
+ var import_path4 = __toESM(require("path"));
48
49
 
49
50
  // src/lib/Arquitecture.ts
50
51
  var os = __toESM(require("os"));
@@ -391,7 +392,7 @@ var Downloader = class {
391
392
  }
392
393
  this.mainSpinner.text = import_chalk.default.blue(`Updating ${binariesToDownload.length} binary(ies)...`);
393
394
  try {
394
- await Promise.all(binariesToDownload.map(async (binary) => {
395
+ const results = await Promise.allSettled(binariesToDownload.map(async (binary) => {
395
396
  const maxRetries = 3;
396
397
  let attempt = 0;
397
398
  while (attempt <= maxRetries) {
@@ -419,6 +420,11 @@ var Downloader = class {
419
420
  }
420
421
  }
421
422
  }));
423
+ const failures = results.filter((r) => r.status === "rejected");
424
+ if (failures.length > 0) {
425
+ const messages = failures.map((f) => f.reason instanceof Error ? f.reason.message : String(f.reason));
426
+ throw new Error(messages.join(" | "));
427
+ }
422
428
  this.mainSpinner.succeed(import_chalk.default.green("Binaries updated successfully"));
423
429
  } catch (error) {
424
430
  const errorMessage = error instanceof Error ? error.message : "Unknown error";
@@ -483,8 +489,7 @@ var Downloader = class {
483
489
  }
484
490
  });
485
491
  response.on("end", () => {
486
- file.end();
487
- resolve5();
492
+ file.end(() => resolve5());
488
493
  });
489
494
  response.on("error", (err) => {
490
495
  file.close();
@@ -711,7 +716,6 @@ var Config = class {
711
716
  /**
712
717
  * Obtiene un valor de configuración
713
718
  * @param key - Clave de configuración
714
- * @returns Valor de configuración
715
719
  */
716
720
  get(key) {
717
721
  return this.data[key];
@@ -719,14 +723,12 @@ var Config = class {
719
723
  /**
720
724
  * Obtiene la configuración de una base de datos específica
721
725
  * @param dbName - Nombre de la base de datos
722
- * @returns Configuración de la base de datos o null
723
726
  */
724
727
  getDatabase(dbName) {
725
728
  return this.databases[dbName] || null;
726
729
  }
727
730
  /**
728
731
  * Obtiene todas las bases de datos configuradas
729
- * @returns Todas las configuraciones de bases de datos
730
732
  */
731
733
  getAllDatabases() {
732
734
  return this.databases;
@@ -734,14 +736,258 @@ var Config = class {
734
736
  };
735
737
 
736
738
  // src/lib/Engine.ts
737
- var import_child_process = require("child_process");
739
+ var import_child_process2 = require("child_process");
738
740
  var import_module = require("module");
741
+
742
+ // src/lib/DaemonClient.ts
743
+ var import_net = __toESM(require("net"));
744
+ var import_fs = __toESM(require("fs"));
745
+ var import_path3 = __toESM(require("path"));
746
+ var import_child_process = require("child_process");
747
+ var DaemonClient = class _DaemonClient {
748
+ static registry = /* @__PURE__ */ new Map();
749
+ name;
750
+ binaryPath;
751
+ engineArgs;
752
+ socket = null;
753
+ buffer = "";
754
+ pending = [];
755
+ starting = null;
756
+ requestTimeout;
757
+ constructor(name, binaryPath, engineArgs, requestTimeout = 3e4) {
758
+ this.name = name;
759
+ this.binaryPath = binaryPath;
760
+ this.engineArgs = engineArgs;
761
+ this.requestTimeout = requestTimeout;
762
+ }
763
+ static get(name, binaryPath, engineArgs) {
764
+ let client = this.registry.get(name);
765
+ if (!client) {
766
+ client = new _DaemonClient(name, binaryPath, engineArgs);
767
+ this.registry.set(name, client);
768
+ }
769
+ return client;
770
+ }
771
+ static isEnabled() {
772
+ const flag = process.env.DBCUBE_DAEMON;
773
+ if (flag === "0" || flag === "false") return false;
774
+ return true;
775
+ }
776
+ portfilePath() {
777
+ return import_path3.default.join(process.cwd(), ".dbcube", "daemon", `${this.name}.json`);
778
+ }
779
+ lockfilePath() {
780
+ return import_path3.default.join(process.cwd(), ".dbcube", "daemon", `${this.name}.lock`);
781
+ }
782
+ /**
783
+ * Exclusive-create lock so two processes never spawn two daemons for the
784
+ * same database at once. Stale locks (crashed starter) expire after 15s.
785
+ */
786
+ acquireSpawnLock() {
787
+ const lockPath = this.lockfilePath();
788
+ try {
789
+ import_fs.default.mkdirSync(import_path3.default.dirname(lockPath), { recursive: true });
790
+ const fd = import_fs.default.openSync(lockPath, "wx");
791
+ import_fs.default.writeSync(fd, String(process.pid));
792
+ import_fs.default.closeSync(fd);
793
+ return true;
794
+ } catch {
795
+ try {
796
+ const age = Date.now() - import_fs.default.statSync(lockPath).mtimeMs;
797
+ if (age > 15e3) {
798
+ import_fs.default.unlinkSync(lockPath);
799
+ return this.acquireSpawnLock();
800
+ }
801
+ } catch {
802
+ }
803
+ return false;
804
+ }
805
+ }
806
+ releaseSpawnLock() {
807
+ try {
808
+ import_fs.default.unlinkSync(this.lockfilePath());
809
+ } catch {
810
+ }
811
+ }
812
+ /**
813
+ * Ensures a usable daemon connection. Returns false when the daemon
814
+ * can't be used (old binary, startup failure) so callers fall back
815
+ * to one-shot spawn mode.
816
+ */
817
+ async ensure() {
818
+ if (this.socket && !this.socket.destroyed) return true;
819
+ if (this.starting) return this.starting;
820
+ this.starting = this.connectOrStart().catch(() => false);
821
+ const result = await this.starting;
822
+ this.starting = null;
823
+ return result;
824
+ }
825
+ async connectOrStart() {
826
+ const port = this.readPortfile();
827
+ if (port && await this.tryConnect(port)) return true;
828
+ const gotLock = this.acquireSpawnLock();
829
+ try {
830
+ if (gotLock) {
831
+ try {
832
+ import_fs.default.unlinkSync(this.portfilePath());
833
+ } catch {
834
+ }
835
+ this.spawnDaemon();
836
+ }
837
+ const deadline = Date.now() + 1e4;
838
+ while (Date.now() < deadline) {
839
+ await new Promise((r) => setTimeout(r, 150));
840
+ const newPort = this.readPortfile();
841
+ if (newPort && await this.tryConnect(newPort)) return true;
842
+ }
843
+ return false;
844
+ } finally {
845
+ if (gotLock) this.releaseSpawnLock();
846
+ }
847
+ }
848
+ readPortfile() {
849
+ try {
850
+ const raw = import_fs.default.readFileSync(this.portfilePath(), "utf8");
851
+ const info = JSON.parse(raw);
852
+ const port = info?.port;
853
+ return Number.isInteger(port) && port > 0 && port <= 65535 ? port : null;
854
+ } catch {
855
+ return null;
856
+ }
857
+ }
858
+ spawnDaemon() {
859
+ const child = (0, import_child_process.spawn)(this.binaryPath, [...this.engineArgs, "--action", "server", "--tcp-port", "9944"], {
860
+ detached: true,
861
+ stdio: "ignore",
862
+ cwd: process.cwd()
863
+ });
864
+ child.unref();
865
+ }
866
+ tryConnect(port) {
867
+ return new Promise((resolve5) => {
868
+ const socket = import_net.default.createConnection({ host: "127.0.0.1", port }, async () => {
869
+ socket.setNoDelay(true);
870
+ this.attach(socket);
871
+ try {
872
+ const pong = await this.send({ action: "ping" }, 2e3);
873
+ resolve5(pong.status === 200);
874
+ } catch {
875
+ this.detach();
876
+ resolve5(false);
877
+ }
878
+ });
879
+ socket.once("error", () => resolve5(false));
880
+ socket.setTimeout(3e3, () => {
881
+ socket.destroy();
882
+ resolve5(false);
883
+ });
884
+ });
885
+ }
886
+ attach(socket) {
887
+ this.socket = socket;
888
+ this.buffer = "";
889
+ socket.setTimeout(0);
890
+ socket.on("data", (chunk) => this.onData(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
891
+ socket.on("close", () => this.detach());
892
+ socket.on("error", () => this.detach());
893
+ }
894
+ detach() {
895
+ if (this.socket) {
896
+ this.socket.removeAllListeners();
897
+ this.socket.destroy();
898
+ this.socket = null;
899
+ }
900
+ for (const req of this.pending.splice(0)) {
901
+ clearTimeout(req.timer);
902
+ req.reject(new Error("Daemon connection lost"));
903
+ }
904
+ }
905
+ onData(chunk) {
906
+ this.buffer += chunk.toString("utf8");
907
+ let idx;
908
+ while ((idx = this.buffer.indexOf("\n")) !== -1) {
909
+ const line = this.buffer.slice(0, idx).trim();
910
+ this.buffer = this.buffer.slice(idx + 1);
911
+ if (!line) continue;
912
+ const marker = line.indexOf("PROCESS_RESPONSE:");
913
+ if (marker === -1) continue;
914
+ const jsonPart = line.slice(marker + "PROCESS_RESPONSE:".length);
915
+ const req = this.pending.shift();
916
+ if (!req) continue;
917
+ clearTimeout(req.timer);
918
+ try {
919
+ req.resolve(JSON.parse(jsonPart));
920
+ } catch (e) {
921
+ req.reject(new Error(`Invalid daemon response: ${e.message}`));
922
+ }
923
+ }
924
+ }
925
+ /**
926
+ * Sends a request to the daemon. Responses arrive in FIFO order on the
927
+ * single socket, so pending requests resolve in send order.
928
+ */
929
+ send(payload, timeoutMs) {
930
+ return new Promise((resolve5, reject) => {
931
+ if (!this.socket || this.socket.destroyed) {
932
+ reject(new Error("Daemon not connected"));
933
+ return;
934
+ }
935
+ const timer = setTimeout(() => {
936
+ const i = this.pending.findIndex((p) => p.timer === timer);
937
+ if (i !== -1) this.pending.splice(i, 1);
938
+ reject(new Error("Daemon request timeout"));
939
+ this.detach();
940
+ }, timeoutMs ?? this.requestTimeout);
941
+ this.pending.push({ resolve: resolve5, reject, timer });
942
+ this.socket.write(JSON.stringify(payload) + "\n");
943
+ });
944
+ }
945
+ async execute(dml, txId) {
946
+ const payload = { action: "execute", dml: JSON.stringify(dml) };
947
+ if (txId) payload.tx_id = txId;
948
+ return this.send(payload);
949
+ }
950
+ async raw(query, params = [], txId) {
951
+ const payload = { action: "raw", query, params };
952
+ if (txId) payload.tx_id = txId;
953
+ return this.send(payload);
954
+ }
955
+ async begin() {
956
+ const res = await this.send({ action: "begin" });
957
+ if (res.status !== 200 || !res.data?.tx_id) {
958
+ throw new Error(res.message || "Failed to begin transaction");
959
+ }
960
+ return res.data.tx_id;
961
+ }
962
+ async commit(txId) {
963
+ const res = await this.send({ action: "commit", tx_id: txId });
964
+ if (res.status !== 200) throw new Error(res.message || "Failed to commit transaction");
965
+ }
966
+ async rollback(txId) {
967
+ const res = await this.send({ action: "rollback", tx_id: txId });
968
+ if (res.status !== 200) throw new Error(res.message || "Failed to rollback transaction");
969
+ }
970
+ async shutdown() {
971
+ try {
972
+ await this.send({ action: "shutdown" });
973
+ } catch {
974
+ }
975
+ this.detach();
976
+ try {
977
+ import_fs.default.unlinkSync(this.portfilePath());
978
+ } catch {
979
+ }
980
+ }
981
+ };
982
+
983
+ // src/lib/Engine.ts
739
984
  var Engine = class {
740
985
  name;
741
986
  config;
742
987
  arguments;
743
988
  binary = null;
744
989
  timeout;
990
+ daemonFailed = false;
745
991
  constructor(name, timeout = 3e4) {
746
992
  this.name = name;
747
993
  this.config = this.setConfig(name);
@@ -753,6 +999,77 @@ var Engine = class {
753
999
  this.binary = await Binary.get();
754
1000
  }
755
1001
  }
1002
+ /**
1003
+ * Returns a connected DaemonClient for this database, or null when
1004
+ * daemon mode is disabled/unavailable (then callers use spawn mode).
1005
+ */
1006
+ async getDaemon() {
1007
+ if (this.daemonFailed || !DaemonClient.isEnabled()) return null;
1008
+ await this.initializeBinary();
1009
+ if (!this.binary) return null;
1010
+ const binaryPath = this.binary["query_engine"];
1011
+ if (!binaryPath) return null;
1012
+ const client = DaemonClient.get(this.name, binaryPath, this.arguments);
1013
+ const ok = await client.ensure();
1014
+ if (!ok) {
1015
+ this.daemonFailed = true;
1016
+ return null;
1017
+ }
1018
+ return client;
1019
+ }
1020
+ /**
1021
+ * Executes a DML plan. Uses the persistent daemon (sub-millisecond
1022
+ * overhead) when available; falls back to one-shot spawn otherwise.
1023
+ */
1024
+ async executeDml(dml, txId) {
1025
+ const daemon = await this.getDaemon();
1026
+ if (daemon) {
1027
+ try {
1028
+ return await daemon.execute(dml, txId);
1029
+ } catch (error) {
1030
+ if (txId) throw error;
1031
+ }
1032
+ }
1033
+ if (txId) {
1034
+ throw new Error("Transactions require daemon mode. Make sure the query-engine binary is up to date (npx dbcube update).");
1035
+ }
1036
+ return this.run("query_engine", ["--action", "execute", "--dml", JSON.stringify(dml)]);
1037
+ }
1038
+ /**
1039
+ * Executes raw SQL (or a MongoDB command document) with bound parameters.
1040
+ */
1041
+ async rawQuery(query, params = [], txId) {
1042
+ const daemon = await this.getDaemon();
1043
+ if (daemon) {
1044
+ try {
1045
+ return await daemon.raw(query, params, txId);
1046
+ } catch (error) {
1047
+ if (txId) throw error;
1048
+ }
1049
+ }
1050
+ if (txId) {
1051
+ throw new Error("Transactions require daemon mode. Make sure the query-engine binary is up to date (npx dbcube update).");
1052
+ }
1053
+ return this.run("query_engine", ["--action", "raw", "--query", query, "--params", JSON.stringify(params)]);
1054
+ }
1055
+ /** Starts a transaction (daemon mode only). Returns the transaction id. */
1056
+ async beginTransaction() {
1057
+ const daemon = await this.getDaemon();
1058
+ if (!daemon) {
1059
+ throw new Error("Transactions require daemon mode. Make sure the query-engine binary is up to date (npx dbcube update).");
1060
+ }
1061
+ return daemon.begin();
1062
+ }
1063
+ async commitTransaction(txId) {
1064
+ const daemon = await this.getDaemon();
1065
+ if (!daemon) throw new Error("Daemon connection lost during transaction");
1066
+ return daemon.commit(txId);
1067
+ }
1068
+ async rollbackTransaction(txId) {
1069
+ const daemon = await this.getDaemon();
1070
+ if (!daemon) throw new Error("Daemon connection lost during transaction");
1071
+ return daemon.rollback(txId);
1072
+ }
756
1073
  setArguments() {
757
1074
  let args = [];
758
1075
  if (this.config.type == "sqlite") {
@@ -777,21 +1094,23 @@ var Engine = class {
777
1094
  "--host",
778
1095
  this.config.config.HOST,
779
1096
  "--port",
780
- this.config.config.PORT,
781
- "--user",
782
- this.config.config.USER,
783
- "--password",
784
- this.config.config.PASSWORD,
1097
+ String(this.config.config.PORT),
785
1098
  "--motor",
786
1099
  this.config.type
787
1100
  ];
1101
+ if (this.config.config.USER != null && this.config.config.USER !== "") {
1102
+ args.push("--user", this.config.config.USER);
1103
+ }
1104
+ if (this.config.config.PASSWORD != null && this.config.config.PASSWORD !== "") {
1105
+ args.push("--password", this.config.config.PASSWORD);
1106
+ }
788
1107
  }
789
1108
  return args;
790
1109
  }
791
1110
  setConfig(name) {
792
1111
  const configInstance = new Config();
793
1112
  try {
794
- const configFilePath = import_path3.default.resolve(process.cwd(), "dbcube.config.js");
1113
+ const configFilePath = import_path4.default.resolve(process.cwd(), "dbcube.config.js");
795
1114
  const requireUrl = typeof __filename !== "undefined" ? __filename : process.cwd();
796
1115
  const require2 = (0, import_module.createRequire)(requireUrl);
797
1116
  if (require2.cache && require2.resolve) {
@@ -824,7 +1143,7 @@ var Engine = class {
824
1143
  throw new Error("Binary not initialized");
825
1144
  }
826
1145
  return new Promise((resolve5, reject) => {
827
- const child = (0, import_child_process.spawn)(this.binary[binary], [...this.arguments, ...args]);
1146
+ const child = (0, import_child_process2.spawn)(this.binary[binary], [...this.arguments, ...args]);
828
1147
  let stdoutBuffer = "";
829
1148
  let stderrBuffer = "";
830
1149
  let isResolved = false;
@@ -843,8 +1162,10 @@ var Engine = class {
843
1162
  }
844
1163
  };
845
1164
  child.stdout.on("data", (data) => {
846
- stdoutBuffer += data.toString();
847
- console.log(stdoutBuffer);
1165
+ const text = data.toString();
1166
+ stdoutBuffer += text;
1167
+ const visible = text.split("\n").filter((l) => l.trim() && !l.includes("PROCESS_RESPONSE:")).join("\n");
1168
+ if (visible) console.log(visible);
848
1169
  const match = stdoutBuffer.match(/PROCESS_RESPONSE:(\{.*\})/);
849
1170
  if (match) {
850
1171
  try {
@@ -864,8 +1185,10 @@ var Engine = class {
864
1185
  }
865
1186
  });
866
1187
  child.stderr.on("data", (data) => {
867
- stderrBuffer += data.toString();
868
- console.log(stderrBuffer);
1188
+ const text = data.toString();
1189
+ stderrBuffer += text;
1190
+ const visible = text.split("\n").filter((l) => l.trim() && !l.includes("PROCESS_RESPONSE:")).join("\n");
1191
+ if (visible) console.log(visible);
869
1192
  const match = stderrBuffer.match(/PROCESS_RESPONSE:(\{.*\})/);
870
1193
  if (match) {
871
1194
  try {
@@ -910,16 +1233,15 @@ var Engine = class {
910
1233
  };
911
1234
 
912
1235
  // src/lib/QueryEngine.ts
913
- var import_path4 = __toESM(require("path"));
1236
+ var import_path5 = __toESM(require("path"));
914
1237
  var import_module2 = require("module");
915
- var net = __toESM(require("net"));
916
- var import_child_process2 = require("child_process");
1238
+ var net2 = __toESM(require("net"));
1239
+ var import_child_process3 = require("child_process");
917
1240
  var globalTcpServers = /* @__PURE__ */ new Map();
918
1241
  var globalTcpConnections = /* @__PURE__ */ new Map();
919
1242
  var connectionQueues = /* @__PURE__ */ new Map();
920
1243
  var connectionProcessing = /* @__PURE__ */ new Map();
921
1244
  var queryCache = /* @__PURE__ */ new Map();
922
- var cacheSize = 0;
923
1245
  var MAX_CACHE_SIZE = 500;
924
1246
  var QueryEngine = class {
925
1247
  name;
@@ -933,7 +1255,7 @@ var QueryEngine = class {
933
1255
  this.name = name;
934
1256
  this.config = this.setConfig(name);
935
1257
  this.arguments = this.setArguments();
936
- this.timeout = timeout;
1258
+ this.timeout = this.config?.daemon?.requestTimeoutMs ?? timeout;
937
1259
  this.connectionId = `${name}_query_engine_${this.config.type}_${this.config.config.DATABASE}_${this.config.config.HOST || "localhost"}`;
938
1260
  this.tcpPort = this.generatePort();
939
1261
  }
@@ -950,7 +1272,7 @@ var QueryEngine = class {
950
1272
  }
951
1273
  isPortAvailable(port) {
952
1274
  return new Promise((resolve5) => {
953
- const tester = net.createServer();
1275
+ const tester = net2.createServer();
954
1276
  tester.once("error", () => resolve5(false));
955
1277
  tester.once("listening", () => {
956
1278
  tester.close();
@@ -988,21 +1310,34 @@ var QueryEngine = class {
988
1310
  "--host",
989
1311
  this.config.config.HOST,
990
1312
  "--port",
991
- this.config.config.PORT,
992
- "--user",
993
- this.config.config.USER,
994
- "--password",
995
- this.config.config.PASSWORD,
1313
+ String(this.config.config.PORT),
996
1314
  "--motor",
997
1315
  this.config.type
998
1316
  ];
1317
+ if (this.config.config.USER != null && this.config.config.USER !== "") {
1318
+ args.push("--user", this.config.config.USER);
1319
+ }
1320
+ if (this.config.config.PASSWORD != null && this.config.config.PASSWORD !== "") {
1321
+ args.push("--password", this.config.config.PASSWORD);
1322
+ }
999
1323
  }
1324
+ const pool = this.config.pool ?? {};
1325
+ if (pool.maxConnections != null) args.push("--max-connections", String(pool.maxConnections));
1326
+ if (pool.minConnections != null) args.push("--min-connections", String(pool.minConnections));
1327
+ if (pool.acquireTimeoutMs != null) args.push("--acquire-timeout-ms", String(pool.acquireTimeoutMs));
1328
+ if (pool.idleTimeoutMs != null) args.push("--idle-timeout-ms", String(pool.idleTimeoutMs));
1000
1329
  return args;
1001
1330
  }
1331
+ /** El daemon puede desactivarse por config (daemon.enabled=false) o por env (DBCUBE_DAEMON=0). */
1332
+ daemonEnabled() {
1333
+ const flag = process.env.DBCUBE_DAEMON;
1334
+ if (flag === "0" || flag === "false") return false;
1335
+ return this.config?.daemon?.enabled !== false;
1336
+ }
1002
1337
  setConfig(name) {
1003
1338
  const configInstance = new Config();
1004
1339
  try {
1005
- const configFilePath = import_path4.default.resolve(process.cwd(), "dbcube.config.js");
1340
+ const configFilePath = import_path5.default.resolve(process.cwd(), "dbcube.config.js");
1006
1341
  const requireUrl = typeof __filename !== "undefined" ? __filename : process.cwd();
1007
1342
  const require2 = (0, import_module2.createRequire)(requireUrl);
1008
1343
  if (require2.cache && require2.resolve) {
@@ -1034,18 +1369,71 @@ var QueryEngine = class {
1034
1369
  const isExecuteAction = actionIndex !== -1 && args[actionIndex + 1] === "execute";
1035
1370
  const isQueryEngine = binary === "query_engine";
1036
1371
  if (isQueryEngine && isExecuteAction) {
1037
- return this.executeWithTcpServer(args);
1372
+ return this.executeWithTcpServer(this.argsToCommand(args));
1038
1373
  } else {
1039
1374
  return this.createProcess(binary, args);
1040
1375
  }
1041
1376
  }
1042
- async executeWithTcpServer(args) {
1377
+ argsToCommand(args) {
1378
+ const command = {};
1379
+ for (let i = 0; i < args.length; i += 2) {
1380
+ if (args[i].startsWith("--")) {
1381
+ command[args[i].substring(2)] = args[i + 1];
1382
+ }
1383
+ }
1384
+ return command;
1385
+ }
1386
+ /**
1387
+ * Executes a DML plan over the persistent TCP server.
1388
+ * Pass txId to run it inside an active transaction.
1389
+ */
1390
+ async executeDml(dml, txId) {
1391
+ const command = { action: "execute", dml: JSON.stringify(dml) };
1392
+ if (txId) command.tx_id = txId;
1393
+ return this.executeWithTcpServer(command);
1394
+ }
1395
+ /**
1396
+ * Executes raw SQL (or a MongoDB command document) with bound parameters
1397
+ * over the persistent TCP server.
1398
+ */
1399
+ async rawQuery(query, params = [], txId) {
1400
+ const command = { action: "raw", query, params };
1401
+ if (txId) command.tx_id = txId;
1402
+ return this.executeWithTcpServer(command);
1403
+ }
1404
+ /** Starts a server-side transaction and returns its id. */
1405
+ async beginTransaction() {
1406
+ const res = await this.executeWithTcpServer({ action: "begin" });
1407
+ if (res.status !== 200 || !res.data?.tx_id) {
1408
+ throw new Error(String(res.message || "Failed to begin transaction (update the query-engine binary: npx dbcube update)"));
1409
+ }
1410
+ return res.data.tx_id;
1411
+ }
1412
+ async commitTransaction(txId) {
1413
+ const res = await this.executeWithTcpServer({ action: "commit", tx_id: txId });
1414
+ if (res.status !== 200) throw new Error(String(res.message || "Failed to commit transaction"));
1415
+ }
1416
+ async rollbackTransaction(txId) {
1417
+ const res = await this.executeWithTcpServer({ action: "rollback", tx_id: txId });
1418
+ if (res.status !== 200) throw new Error(String(res.message || "Failed to rollback transaction"));
1419
+ }
1420
+ async executeWithTcpServer(command) {
1421
+ if (!this.daemonEnabled()) {
1422
+ if (command.tx_id || ["begin", "commit", "rollback"].includes(command.action)) {
1423
+ throw new Error("Transactions require daemon mode. Remove daemon.enabled=false from dbcube.config.js (or unset DBCUBE_DAEMON=0).");
1424
+ }
1425
+ const args = [];
1426
+ for (const [key, value] of Object.entries(command)) {
1427
+ args.push(`--${key.replace(/_/g, "-")}`, typeof value === "string" ? value : JSON.stringify(value));
1428
+ }
1429
+ return this.createProcess("query_engine", args);
1430
+ }
1043
1431
  const serverInfo = globalTcpServers.get(this.connectionId);
1044
1432
  if (!serverInfo || !serverInfo.process || serverInfo.process.killed) {
1045
1433
  await this.startTcpServer();
1046
1434
  await this.waitForServerReady();
1047
1435
  }
1048
- return this.sendTcpRequestFast(args);
1436
+ return this.sendTcpRequestFast(command);
1049
1437
  }
1050
1438
  async waitForServerReady() {
1051
1439
  const maxRetries = 10;
@@ -1064,7 +1452,7 @@ var QueryEngine = class {
1064
1452
  }
1065
1453
  async isServerResponding(port) {
1066
1454
  return new Promise((resolve5) => {
1067
- const client = new net.Socket();
1455
+ const client = new net2.Socket();
1068
1456
  const timeout = setTimeout(() => {
1069
1457
  client.destroy();
1070
1458
  resolve5(false);
@@ -1088,10 +1476,11 @@ var QueryEngine = class {
1088
1476
  return queryCache.get(dmlJson);
1089
1477
  }
1090
1478
  const parsed = JSON.parse(dmlJson);
1091
- if (cacheSize < MAX_CACHE_SIZE) {
1092
- queryCache.set(dmlJson, parsed);
1093
- cacheSize++;
1479
+ if (queryCache.size >= MAX_CACHE_SIZE) {
1480
+ const oldest = queryCache.keys().next().value;
1481
+ if (oldest !== void 0) queryCache.delete(oldest);
1094
1482
  }
1483
+ queryCache.set(dmlJson, parsed);
1095
1484
  return parsed;
1096
1485
  }
1097
1486
  async startTcpServer() {
@@ -1102,7 +1491,7 @@ var QueryEngine = class {
1102
1491
  this.tcpPort = await this.findAvailablePort(this.tcpPort);
1103
1492
  return new Promise((resolve5, reject) => {
1104
1493
  const serverArgs = [...this.arguments, "--action", "server", "--tcp-port", this.tcpPort.toString()];
1105
- const serverProcess = (0, import_child_process2.spawn)(this.binary["query_engine"], serverArgs);
1494
+ const serverProcess = (0, import_child_process3.spawn)(this.binary["query_engine"], serverArgs);
1106
1495
  let started = false;
1107
1496
  const timeout = setTimeout(() => {
1108
1497
  if (!started) {
@@ -1138,14 +1527,14 @@ var QueryEngine = class {
1138
1527
  });
1139
1528
  });
1140
1529
  }
1141
- async sendTcpRequestFast(args) {
1530
+ async sendTcpRequestFast(command) {
1142
1531
  return new Promise((resolve5, reject) => {
1143
1532
  let queue = connectionQueues.get(this.connectionId);
1144
1533
  if (!queue) {
1145
1534
  queue = [];
1146
1535
  connectionQueues.set(this.connectionId, queue);
1147
1536
  }
1148
- queue.push({ args, resolve: resolve5, reject });
1537
+ queue.push({ command, resolve: resolve5, reject });
1149
1538
  this.processQueue();
1150
1539
  });
1151
1540
  }
@@ -1172,9 +1561,16 @@ var QueryEngine = class {
1172
1561
  connection = await this.createNewConnection(serverInfo.port);
1173
1562
  globalTcpConnections.set(this.connectionId, connection);
1174
1563
  }
1175
- const result = await this.executeOnConnection(connection, request.args);
1564
+ const result = await this.executeOnConnection(connection, request.command);
1176
1565
  request.resolve(result);
1177
1566
  } catch (error) {
1567
+ const staleConnection = globalTcpConnections.get(this.connectionId);
1568
+ if (staleConnection) {
1569
+ try {
1570
+ staleConnection.destroy();
1571
+ } catch {
1572
+ }
1573
+ }
1178
1574
  globalTcpConnections.delete(this.connectionId);
1179
1575
  request.reject(error);
1180
1576
  }
@@ -1185,7 +1581,7 @@ var QueryEngine = class {
1185
1581
  }
1186
1582
  async createNewConnection(port) {
1187
1583
  return new Promise((resolve5, reject) => {
1188
- const client = new net.Socket();
1584
+ const client = new net2.Socket();
1189
1585
  client.setNoDelay(true);
1190
1586
  client.setKeepAlive(true, 6e4);
1191
1587
  const timeout = setTimeout(() => {
@@ -1202,16 +1598,8 @@ var QueryEngine = class {
1202
1598
  });
1203
1599
  });
1204
1600
  }
1205
- async executeOnConnection(connection, args) {
1601
+ async executeOnConnection(connection, command) {
1206
1602
  return new Promise((resolve5, reject) => {
1207
- const command = {};
1208
- for (let i = 0; i < args.length; i += 2) {
1209
- if (args[i].startsWith("--")) {
1210
- const key = args[i].substring(2);
1211
- const value = args[i + 1];
1212
- command[key] = value;
1213
- }
1214
- }
1215
1603
  let responseBuffer = "";
1216
1604
  let isResolved = false;
1217
1605
  const timeout = setTimeout(() => {
@@ -1253,7 +1641,7 @@ var QueryEngine = class {
1253
1641
  };
1254
1642
  connection.on("data", onData);
1255
1643
  connection.on("error", onError);
1256
- connection.write(JSON.stringify(command));
1644
+ connection.write(JSON.stringify(command) + "\n");
1257
1645
  });
1258
1646
  }
1259
1647
  async createProcess(binary, args) {
@@ -1262,7 +1650,7 @@ var QueryEngine = class {
1262
1650
  throw new Error("Binary not initialized");
1263
1651
  }
1264
1652
  return new Promise((resolve5, reject) => {
1265
- const child = (0, import_child_process2.spawn)(this.binary[binary], [...this.arguments, ...args]);
1653
+ const child = (0, import_child_process3.spawn)(this.binary[binary], [...this.arguments, ...args]);
1266
1654
  let stdoutBuffer = "";
1267
1655
  let stderrBuffer = "";
1268
1656
  let isResolved = false;
@@ -1369,15 +1757,15 @@ var QueryEngine = class {
1369
1757
  };
1370
1758
 
1371
1759
  // src/lib/SqliteExecutor.ts
1372
- var import_child_process3 = require("child_process");
1373
- var path5 = __toESM(require("path"));
1374
- var fs3 = __toESM(require("fs"));
1760
+ var import_child_process4 = require("child_process");
1761
+ var path6 = __toESM(require("path"));
1762
+ var fs4 = __toESM(require("fs"));
1375
1763
  var import_util = require("util");
1376
1764
  var import_module3 = require("module");
1377
1765
  var import_url3 = require("url");
1378
- var import_path5 = require("path");
1766
+ var import_path6 = require("path");
1379
1767
  var import_meta3 = {};
1380
- var execAsync = (0, import_util.promisify)(import_child_process3.exec);
1768
+ var execAsync = (0, import_util.promisify)(import_child_process4.exec);
1381
1769
  var SqliteExecutor = class {
1382
1770
  binaryPath;
1383
1771
  dbPath;
@@ -1387,13 +1775,13 @@ var SqliteExecutor = class {
1387
1775
  }
1388
1776
  findVersionedBinary(binDir, platform2) {
1389
1777
  try {
1390
- const files = fs3.readdirSync(binDir);
1778
+ const files = fs4.readdirSync(binDir);
1391
1779
  const extension = platform2 === "win32" ? ".exe" : "";
1392
1780
  const platformName = platform2 === "win32" ? "windows" : platform2 === "darwin" ? "macos" : "linux";
1393
1781
  const pattern = new RegExp(`^sqlite-engine-v\\d+\\.\\d+\\.\\d+-${platformName}-x64${extension.replace(".", "\\.")}$`);
1394
1782
  const matchingFile = files.find((f) => pattern.test(f));
1395
1783
  if (matchingFile) {
1396
- return path5.join(binDir, matchingFile);
1784
+ return path6.join(binDir, matchingFile);
1397
1785
  }
1398
1786
  } catch (error) {
1399
1787
  }
@@ -1401,36 +1789,36 @@ var SqliteExecutor = class {
1401
1789
  }
1402
1790
  getBinaryPath() {
1403
1791
  const __filename2 = typeof import_meta3 !== "undefined" && import_meta3.url ? (0, import_url3.fileURLToPath)(import_meta3.url) : "";
1404
- const __dirname = __filename2 ? (0, import_path5.dirname)(__filename2) : process.cwd();
1792
+ const __dirname = __filename2 ? (0, import_path6.dirname)(__filename2) : process.cwd();
1405
1793
  const possibleDirs = [
1406
- path5.resolve(process.cwd(), ".dbcube", "bin"),
1407
- path5.resolve(process.cwd(), "node_modules", ".dbcube", "bin"),
1408
- path5.resolve(__dirname, "..", "bin")
1794
+ path6.resolve(process.cwd(), ".dbcube", "bin"),
1795
+ path6.resolve(process.cwd(), "node_modules", ".dbcube", "bin"),
1796
+ path6.resolve(__dirname, "..", "bin")
1409
1797
  ];
1410
1798
  const platform2 = process.platform;
1411
1799
  const extension = platform2 === "win32" ? ".exe" : "";
1412
1800
  const platformName = platform2 === "win32" ? "windows" : platform2 === "darwin" ? "macos" : "linux";
1413
1801
  for (const dir of possibleDirs) {
1414
1802
  const versionedPath = this.findVersionedBinary(dir, platform2);
1415
- if (versionedPath && fs3.existsSync(versionedPath)) {
1803
+ if (versionedPath && fs4.existsSync(versionedPath)) {
1416
1804
  return versionedPath;
1417
1805
  }
1418
1806
  }
1419
1807
  const binaryName = `sqlite-engine-${platformName}-x64${extension}`;
1420
1808
  for (const dir of possibleDirs) {
1421
- const fullPath = path5.join(dir, binaryName);
1422
- if (fs3.existsSync(fullPath)) {
1809
+ const fullPath = path6.join(dir, binaryName);
1810
+ if (fs4.existsSync(fullPath)) {
1423
1811
  return fullPath;
1424
1812
  }
1425
1813
  }
1426
1814
  const fallbackName = `sqlite-engine${extension}`;
1427
1815
  for (const dir of possibleDirs) {
1428
- const fullPath = path5.join(dir, fallbackName);
1429
- if (fs3.existsSync(fullPath)) {
1816
+ const fullPath = path6.join(dir, fallbackName);
1817
+ if (fs4.existsSync(fullPath)) {
1430
1818
  return fullPath;
1431
1819
  }
1432
1820
  }
1433
- return path5.join(possibleDirs[0], binaryName);
1821
+ return path6.join(possibleDirs[0], binaryName);
1434
1822
  }
1435
1823
  async executeBinary(args) {
1436
1824
  const escapedArgs = args.map((arg) => {
@@ -1581,9 +1969,9 @@ var SqliteExecutor = class {
1581
1969
  };
1582
1970
 
1583
1971
  // src/lib/DbConfig.ts
1584
- var path6 = __toESM(require("path"));
1585
- var import_fs = __toESM(require("fs"));
1586
- var rootPath = path6.resolve(process.cwd(), ".dbcube");
1972
+ var path7 = __toESM(require("path"));
1973
+ var import_fs2 = __toESM(require("fs"));
1974
+ var rootPath = path7.resolve(process.cwd(), ".dbcube");
1587
1975
  var SQLite = class {
1588
1976
  executor = null;
1589
1977
  database;
@@ -1593,11 +1981,11 @@ var SQLite = class {
1593
1981
  async ifExist() {
1594
1982
  if (this.database) {
1595
1983
  const dbPath = this.database || ":memory:";
1596
- const configPath = path6.join(rootPath, dbPath + ".db");
1597
- if (!import_fs.default.existsSync(rootPath)) {
1598
- import_fs.default.mkdirSync(rootPath, { recursive: true });
1984
+ const configPath = path7.join(rootPath, dbPath + ".db");
1985
+ if (!import_fs2.default.existsSync(rootPath)) {
1986
+ import_fs2.default.mkdirSync(rootPath, { recursive: true });
1599
1987
  }
1600
- if (import_fs.default.existsSync(configPath)) {
1988
+ if (import_fs2.default.existsSync(configPath)) {
1601
1989
  return true;
1602
1990
  }
1603
1991
  if (!this.executor) {
@@ -1612,9 +2000,9 @@ var SQLite = class {
1612
2000
  try {
1613
2001
  if (!this.executor) {
1614
2002
  const dbPath = this.database || ":memory:";
1615
- const configPath = path6.join(rootPath, dbPath + ".db");
1616
- if (!import_fs.default.existsSync(rootPath)) {
1617
- import_fs.default.mkdirSync(rootPath, { recursive: true });
2003
+ const configPath = path7.join(rootPath, dbPath + ".db");
2004
+ if (!import_fs2.default.existsSync(rootPath)) {
2005
+ import_fs2.default.mkdirSync(rootPath, { recursive: true });
1618
2006
  }
1619
2007
  this.executor = new SqliteExecutor(configPath);
1620
2008
  const connected = await this.executor.connect();
@@ -1796,8 +2184,8 @@ var DbConfig = new SQLite({ DATABASE: "config" });
1796
2184
  var DbConfig_default = DbConfig;
1797
2185
 
1798
2186
  // src/lib/FileLogger.ts
1799
- var fs5 = __toESM(require("fs"));
1800
- var path7 = __toESM(require("path"));
2187
+ var fs6 = __toESM(require("fs"));
2188
+ var path8 = __toESM(require("path"));
1801
2189
  var import_events = require("events");
1802
2190
  var FileLogger = class _FileLogger extends import_events.EventEmitter {
1803
2191
  static watchers = /* @__PURE__ */ new Map();
@@ -1812,9 +2200,9 @@ var FileLogger = class _FileLogger extends import_events.EventEmitter {
1812
2200
  */
1813
2201
  static async write(filePath, message, level = "INFO", append = true) {
1814
2202
  try {
1815
- const dir = path7.dirname(filePath);
1816
- if (!fs5.existsSync(dir)) {
1817
- fs5.mkdirSync(dir, { recursive: true });
2203
+ const dir = path8.dirname(filePath);
2204
+ if (!fs6.existsSync(dir)) {
2205
+ fs6.mkdirSync(dir, { recursive: true });
1818
2206
  }
1819
2207
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
1820
2208
  const formattedMessage = `[${timestamp}] [${level}] ${message}
@@ -1824,9 +2212,9 @@ var FileLogger = class _FileLogger extends import_events.EventEmitter {
1824
2212
  return true;
1825
2213
  }
1826
2214
  if (append) {
1827
- await fs5.promises.appendFile(filePath, formattedMessage, "utf8");
2215
+ await fs6.promises.appendFile(filePath, formattedMessage, "utf8");
1828
2216
  } else {
1829
- await fs5.promises.writeFile(filePath, formattedMessage, "utf8");
2217
+ await fs6.promises.writeFile(filePath, formattedMessage, "utf8");
1830
2218
  }
1831
2219
  return true;
1832
2220
  } catch (error) {
@@ -1851,12 +2239,12 @@ var FileLogger = class _FileLogger extends import_events.EventEmitter {
1851
2239
  const buffer = _FileLogger.buffers.get(filePath);
1852
2240
  if (buffer && buffer.length > 0) {
1853
2241
  try {
1854
- const dir = path7.dirname(filePath);
1855
- if (!fs5.existsSync(dir)) {
1856
- fs5.mkdirSync(dir, { recursive: true });
2242
+ const dir = path8.dirname(filePath);
2243
+ if (!fs6.existsSync(dir)) {
2244
+ fs6.mkdirSync(dir, { recursive: true });
1857
2245
  }
1858
2246
  const content = buffer.join("");
1859
- await fs5.promises.appendFile(filePath, content, "utf8");
2247
+ await fs6.promises.appendFile(filePath, content, "utf8");
1860
2248
  _FileLogger.buffers.delete(filePath);
1861
2249
  return true;
1862
2250
  } catch (error) {
@@ -1992,10 +2380,10 @@ var FileLogger = class _FileLogger extends import_events.EventEmitter {
1992
2380
  // Si debe retornar como array de líneas
1993
2381
  } = options;
1994
2382
  try {
1995
- if (!fs5.existsSync(filePath)) {
2383
+ if (!fs6.existsSync(filePath)) {
1996
2384
  return asArray ? [] : "";
1997
2385
  }
1998
- let content = await fs5.promises.readFile(filePath, "utf8");
2386
+ let content = await fs6.promises.readFile(filePath, "utf8");
1999
2387
  if (asArray) {
2000
2388
  let linesArray = content.split("\n").filter((line) => line.trim() !== "");
2001
2389
  if (lines !== null) {
@@ -2038,15 +2426,15 @@ var FileLogger = class _FileLogger extends import_events.EventEmitter {
2038
2426
  } = options;
2039
2427
  let lastSize = 0;
2040
2428
  let lastPosition = 0;
2041
- if (fs5.existsSync(filePath)) {
2042
- const stats = fs5.statSync(filePath);
2429
+ if (fs6.existsSync(filePath)) {
2430
+ const stats = fs6.statSync(filePath);
2043
2431
  lastSize = stats.size;
2044
2432
  lastPosition = fromEnd ? stats.size : 0;
2045
2433
  }
2046
2434
  const listener = async (curr, prev) => {
2047
2435
  try {
2048
2436
  if (curr.size > lastSize) {
2049
- const stream = fs5.createReadStream(filePath, {
2437
+ const stream = fs6.createReadStream(filePath, {
2050
2438
  start: lastPosition,
2051
2439
  end: curr.size - 1,
2052
2440
  encoding: "utf8"
@@ -2074,7 +2462,7 @@ var FileLogger = class _FileLogger extends import_events.EventEmitter {
2074
2462
  console.error("Error en watcher:", error);
2075
2463
  }
2076
2464
  };
2077
- fs5.watchFile(filePath, { persistent, interval }, listener);
2465
+ fs6.watchFile(filePath, { persistent, interval }, listener);
2078
2466
  const watcherId = `${filePath}_${Date.now()}`;
2079
2467
  _FileLogger.watchers.set(watcherId, listener);
2080
2468
  return {
@@ -2082,7 +2470,7 @@ var FileLogger = class _FileLogger extends import_events.EventEmitter {
2082
2470
  stop: () => {
2083
2471
  const storedListener = _FileLogger.watchers.get(watcherId);
2084
2472
  if (storedListener) {
2085
- fs5.unwatchFile(filePath, storedListener);
2473
+ fs6.unwatchFile(filePath, storedListener);
2086
2474
  _FileLogger.watchers.delete(watcherId);
2087
2475
  }
2088
2476
  },
@@ -2095,7 +2483,7 @@ var FileLogger = class _FileLogger extends import_events.EventEmitter {
2095
2483
  static stopAllWatchers() {
2096
2484
  for (const [watcherId] of _FileLogger.watchers) {
2097
2485
  const filePath = watcherId.split("_")[0];
2098
- fs5.unwatchFile(filePath);
2486
+ fs6.unwatchFile(filePath);
2099
2487
  }
2100
2488
  _FileLogger.watchers.clear();
2101
2489
  }
@@ -2125,7 +2513,7 @@ var FileLogger = class _FileLogger extends import_events.EventEmitter {
2125
2513
  if (lines.length > maxLines) {
2126
2514
  const keepLines = lines.slice(-maxLines);
2127
2515
  const content = keepLines.join("\n") + "\n";
2128
- await fs5.promises.writeFile(filePath, content, "utf8");
2516
+ await fs6.promises.writeFile(filePath, content, "utf8");
2129
2517
  return lines.length - maxLines;
2130
2518
  }
2131
2519
  return 0;
@@ -2140,8 +2528,8 @@ var FileLogger = class _FileLogger extends import_events.EventEmitter {
2140
2528
  */
2141
2529
  static async deleteLogFile(filePath) {
2142
2530
  try {
2143
- if (fs5.existsSync(filePath)) {
2144
- await fs5.promises.unlink(filePath);
2531
+ if (fs6.existsSync(filePath)) {
2532
+ await fs6.promises.unlink(filePath);
2145
2533
  return true;
2146
2534
  }
2147
2535
  return false;
@@ -2178,7 +2566,7 @@ var ComputedFieldProcessor = class {
2178
2566
  const tableExistsQuery = `SELECT name FROM sqlite_master WHERE type='table' AND name='dbcube_computes_config'`;
2179
2567
  const tableExistsResult = await DbConfig_default.query(tableExistsQuery);
2180
2568
  if (tableExistsResult.status === "success" && tableExistsResult.data && tableExistsResult.data.length > 0) {
2181
- const queryComputes = await DbConfig_default.query(`SELECT * FROM dbcube_computes_config WHERE database_ref='${name}'`);
2569
+ const queryComputes = await DbConfig_default.queryWithParameters(`SELECT * FROM dbcube_computes_config WHERE database_ref=?`, [name]);
2182
2570
  computedFields = queryComputes.data;
2183
2571
  } else {
2184
2572
  computedFields = [];
@@ -2209,21 +2597,10 @@ var ComputedFieldProcessor = class {
2209
2597
  }
2210
2598
  functionBody = functionBody.replace(/@column\(([^)]+)\)/g, (_match, columnName) => {
2211
2599
  const cleanColumnName = columnName.trim().replace(/['"]/g, "");
2212
- const value = rowData[cleanColumnName];
2213
- if (value === null || value === void 0) {
2214
- return "null";
2215
- } else if (typeof value === "string") {
2216
- return `"${value.replace(/"/g, '\\"')}"`;
2217
- } else if (typeof value === "number" || typeof value === "boolean") {
2218
- return value.toString();
2219
- } else if (value instanceof Date) {
2220
- return `new Date("${value.toISOString()}")`;
2221
- } else {
2222
- return JSON.stringify(value);
2223
- }
2600
+ return `__row[${JSON.stringify(cleanColumnName)}]`;
2224
2601
  });
2225
- const computeFunction = new Function(functionBody);
2226
- return computeFunction();
2602
+ const computeFunction = new Function("__row", functionBody);
2603
+ return computeFunction(rowData);
2227
2604
  } catch (error) {
2228
2605
  console.error("Error processing computed field:", error);
2229
2606
  return null;
@@ -2266,14 +2643,7 @@ var ComputedFieldProcessor = class {
2266
2643
  /@column\(([^)]+)\)/g,
2267
2644
  (match, columnName) => {
2268
2645
  const cleanColumnName = columnName.replace(/['"]/g, "");
2269
- const value = processedItem[cleanColumnName];
2270
- if (typeof value === "string") {
2271
- return `"${value}"`;
2272
- } else if (value === null || value === void 0) {
2273
- return "null";
2274
- } else {
2275
- return String(value);
2276
- }
2646
+ return `__row[${JSON.stringify(cleanColumnName)}]`;
2277
2647
  }
2278
2648
  );
2279
2649
  const computeMatch = processedExpression.match(/@compute\s*\(\s*\(\s*\)\s*=>\s*\{(.*)\}\s*\)/s);
@@ -2281,8 +2651,8 @@ var ComputedFieldProcessor = class {
2281
2651
  throw new Error(`Formato de @compute inv\xE1lido para campo ${fieldName}`);
2282
2652
  }
2283
2653
  const functionBody = computeMatch[1];
2284
- const computeFunction = new Function(functionBody);
2285
- let result = computeFunction();
2654
+ const computeFunction = new Function("__row", functionBody);
2655
+ let result = computeFunction(processedItem);
2286
2656
  result = convertToType(result, type2);
2287
2657
  processedItem[fieldName] = result;
2288
2658
  } catch (error) {
@@ -2474,14 +2844,14 @@ var TableProcessor = class {
2474
2844
  if (await DbConfig_default.ifExist()) {
2475
2845
  await DbConfig_default.connect();
2476
2846
  try {
2477
- const tableExistsQuery = `SELECT name FROM sqlite_master WHERE type='table' AND name='dbcube_computes_config'`;
2847
+ const tableExistsQuery = `SELECT name FROM sqlite_master WHERE type='table' AND name='dbcube_schemas_config'`;
2478
2848
  const tableExistsResult = await DbConfig_default.query(tableExistsQuery);
2479
2849
  if (tableExistsResult.status === "success" && tableExistsResult.data && tableExistsResult.data.length > 0) {
2480
- const queryComputes = await DbConfig_default.query(`SELECT * FROM dbcube_schemas_config WHERE table_ref='${tableName}' AND database_ref='${database_ref}'`);
2850
+ const queryComputes = await DbConfig_default.queryWithParameters(`SELECT * FROM dbcube_schemas_config WHERE table_ref=? AND database_ref=?`, [tableName, database_ref]);
2481
2851
  const oldQuery = queryComputes.data[0];
2482
2852
  if (!oldQuery || !oldQuery.struct) {
2483
- console.error("No exist a previus schema please execute the refresh first...", oldQuery);
2484
- return [];
2853
+ await DbConfig_default.disconnect();
2854
+ return [nowQuery];
2485
2855
  }
2486
2856
  const nowSchema = parseCreateTableQuery(nowQuery, dbType);
2487
2857
  const oldSchema = parseCreateTableQuery(oldQuery.struct, dbType);
@@ -2516,7 +2886,7 @@ var TableProcessor = class {
2516
2886
  if (await DbConfig_default.ifExist()) {
2517
2887
  await DbConfig_default.connect();
2518
2888
  try {
2519
- await DbConfig_default.query(`DELETE FROM dbcube_schemas_config WHERE table_ref='${table_ref}' AND database_ref='${database_ref}'`);
2889
+ await DbConfig_default.queryWithParameters(`DELETE FROM dbcube_schemas_config WHERE table_ref=? AND database_ref=?`, [table_ref, database_ref]);
2520
2890
  const tableExistsQuery = `INSERT INTO dbcube_schemas_config (table_ref, database_ref, struct) VALUES (?, ?, ?)`;
2521
2891
  await DbConfig_default.queryWithParameters(tableExistsQuery, [table_ref, database_ref, struct]);
2522
2892
  } catch (error) {
@@ -2535,7 +2905,7 @@ var TriggerProcessor = class {
2535
2905
  const tableExistsQuery = `SELECT name FROM sqlite_master WHERE type='table' AND name='dbcube_triggers_config'`;
2536
2906
  const tableExistsResult = await DbConfig_default.query(tableExistsQuery);
2537
2907
  if (tableExistsResult.status === "success" && tableExistsResult.data && tableExistsResult.data.length > 0) {
2538
- const queryComputes = await DbConfig_default.query(`SELECT * FROM dbcube_triggers_config WHERE database_ref='${name}'`);
2908
+ const queryComputes = await DbConfig_default.queryWithParameters(`SELECT * FROM dbcube_triggers_config WHERE database_ref=?`, [name]);
2539
2909
  triggers = queryComputes.data;
2540
2910
  } else {
2541
2911
  triggers = [];
@@ -2572,6 +2942,7 @@ function convertToType(value, type2) {
2572
2942
  Binary,
2573
2943
  ComputedFieldProcessor,
2574
2944
  Config,
2945
+ DaemonClient,
2575
2946
  DbConfig,
2576
2947
  Engine,
2577
2948
  FileLogger,