@dbcube/core 5.1.15 → 5.2.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.
- package/README.md +29 -0
- package/dist/bin.cjs +7 -3
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +7 -3
- package/dist/bin.js.map +1 -1
- package/dist/index.cjs +213 -133
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +113 -47
- package/dist/index.d.ts +113 -47
- package/dist/index.js +213 -133
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -345,7 +345,7 @@ var Downloader = class {
|
|
|
345
345
|
}
|
|
346
346
|
this.mainSpinner.text = chalk.blue(`Updating ${binariesToDownload.length} binary(ies)...`);
|
|
347
347
|
try {
|
|
348
|
-
await Promise.
|
|
348
|
+
const results = await Promise.allSettled(binariesToDownload.map(async (binary) => {
|
|
349
349
|
const maxRetries = 3;
|
|
350
350
|
let attempt = 0;
|
|
351
351
|
while (attempt <= maxRetries) {
|
|
@@ -373,6 +373,11 @@ var Downloader = class {
|
|
|
373
373
|
}
|
|
374
374
|
}
|
|
375
375
|
}));
|
|
376
|
+
const failures = results.filter((r) => r.status === "rejected");
|
|
377
|
+
if (failures.length > 0) {
|
|
378
|
+
const messages = failures.map((f) => f.reason instanceof Error ? f.reason.message : String(f.reason));
|
|
379
|
+
throw new Error(messages.join(" | "));
|
|
380
|
+
}
|
|
376
381
|
this.mainSpinner.succeed(chalk.green("Binaries updated successfully"));
|
|
377
382
|
} catch (error) {
|
|
378
383
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
@@ -437,8 +442,7 @@ var Downloader = class {
|
|
|
437
442
|
}
|
|
438
443
|
});
|
|
439
444
|
response.on("end", () => {
|
|
440
|
-
file.end();
|
|
441
|
-
resolve5();
|
|
445
|
+
file.end(() => resolve5());
|
|
442
446
|
});
|
|
443
447
|
response.on("error", (err) => {
|
|
444
448
|
file.close();
|
|
@@ -664,7 +668,6 @@ var Config = class {
|
|
|
664
668
|
/**
|
|
665
669
|
* Obtiene un valor de configuración
|
|
666
670
|
* @param key - Clave de configuración
|
|
667
|
-
* @returns Valor de configuración
|
|
668
671
|
*/
|
|
669
672
|
get(key) {
|
|
670
673
|
return this.data[key];
|
|
@@ -672,14 +675,12 @@ var Config = class {
|
|
|
672
675
|
/**
|
|
673
676
|
* Obtiene la configuración de una base de datos específica
|
|
674
677
|
* @param dbName - Nombre de la base de datos
|
|
675
|
-
* @returns Configuración de la base de datos o null
|
|
676
678
|
*/
|
|
677
679
|
getDatabase(dbName) {
|
|
678
680
|
return this.databases[dbName] || null;
|
|
679
681
|
}
|
|
680
682
|
/**
|
|
681
683
|
* Obtiene todas las bases de datos configuradas
|
|
682
|
-
* @returns Todas las configuraciones de bases de datos
|
|
683
684
|
*/
|
|
684
685
|
getAllDatabases() {
|
|
685
686
|
return this.databases;
|
|
@@ -727,6 +728,39 @@ var DaemonClient = class _DaemonClient {
|
|
|
727
728
|
portfilePath() {
|
|
728
729
|
return path3.join(process.cwd(), ".dbcube", "daemon", `${this.name}.json`);
|
|
729
730
|
}
|
|
731
|
+
lockfilePath() {
|
|
732
|
+
return path3.join(process.cwd(), ".dbcube", "daemon", `${this.name}.lock`);
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* Exclusive-create lock so two processes never spawn two daemons for the
|
|
736
|
+
* same database at once. Stale locks (crashed starter) expire after 15s.
|
|
737
|
+
*/
|
|
738
|
+
acquireSpawnLock() {
|
|
739
|
+
const lockPath = this.lockfilePath();
|
|
740
|
+
try {
|
|
741
|
+
fs3.mkdirSync(path3.dirname(lockPath), { recursive: true });
|
|
742
|
+
const fd = fs3.openSync(lockPath, "wx");
|
|
743
|
+
fs3.writeSync(fd, String(process.pid));
|
|
744
|
+
fs3.closeSync(fd);
|
|
745
|
+
return true;
|
|
746
|
+
} catch {
|
|
747
|
+
try {
|
|
748
|
+
const age = Date.now() - fs3.statSync(lockPath).mtimeMs;
|
|
749
|
+
if (age > 15e3) {
|
|
750
|
+
fs3.unlinkSync(lockPath);
|
|
751
|
+
return this.acquireSpawnLock();
|
|
752
|
+
}
|
|
753
|
+
} catch {
|
|
754
|
+
}
|
|
755
|
+
return false;
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
releaseSpawnLock() {
|
|
759
|
+
try {
|
|
760
|
+
fs3.unlinkSync(this.lockfilePath());
|
|
761
|
+
} catch {
|
|
762
|
+
}
|
|
763
|
+
}
|
|
730
764
|
/**
|
|
731
765
|
* Ensures a usable daemon connection. Returns false when the daemon
|
|
732
766
|
* can't be used (old binary, startup failure) so callers fall back
|
|
@@ -743,24 +777,32 @@ var DaemonClient = class _DaemonClient {
|
|
|
743
777
|
async connectOrStart() {
|
|
744
778
|
const port = this.readPortfile();
|
|
745
779
|
if (port && await this.tryConnect(port)) return true;
|
|
780
|
+
const gotLock = this.acquireSpawnLock();
|
|
746
781
|
try {
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
const
|
|
755
|
-
|
|
782
|
+
if (gotLock) {
|
|
783
|
+
try {
|
|
784
|
+
fs3.unlinkSync(this.portfilePath());
|
|
785
|
+
} catch {
|
|
786
|
+
}
|
|
787
|
+
this.spawnDaemon();
|
|
788
|
+
}
|
|
789
|
+
const deadline = Date.now() + 1e4;
|
|
790
|
+
while (Date.now() < deadline) {
|
|
791
|
+
await new Promise((r) => setTimeout(r, 150));
|
|
792
|
+
const newPort = this.readPortfile();
|
|
793
|
+
if (newPort && await this.tryConnect(newPort)) return true;
|
|
794
|
+
}
|
|
795
|
+
return false;
|
|
796
|
+
} finally {
|
|
797
|
+
if (gotLock) this.releaseSpawnLock();
|
|
756
798
|
}
|
|
757
|
-
return false;
|
|
758
799
|
}
|
|
759
800
|
readPortfile() {
|
|
760
801
|
try {
|
|
761
802
|
const raw = fs3.readFileSync(this.portfilePath(), "utf8");
|
|
762
803
|
const info = JSON.parse(raw);
|
|
763
|
-
|
|
804
|
+
const port = info?.port;
|
|
805
|
+
return Number.isInteger(port) && port > 0 && port <= 65535 ? port : null;
|
|
764
806
|
} catch {
|
|
765
807
|
return null;
|
|
766
808
|
}
|
|
@@ -779,7 +821,7 @@ var DaemonClient = class _DaemonClient {
|
|
|
779
821
|
socket.setNoDelay(true);
|
|
780
822
|
this.attach(socket);
|
|
781
823
|
try {
|
|
782
|
-
const pong = await this.send({ action: "ping" });
|
|
824
|
+
const pong = await this.send({ action: "ping" }, 2e3);
|
|
783
825
|
resolve5(pong.status === 200);
|
|
784
826
|
} catch {
|
|
785
827
|
this.detach();
|
|
@@ -836,7 +878,7 @@ var DaemonClient = class _DaemonClient {
|
|
|
836
878
|
* Sends a request to the daemon. Responses arrive in FIFO order on the
|
|
837
879
|
* single socket, so pending requests resolve in send order.
|
|
838
880
|
*/
|
|
839
|
-
send(payload) {
|
|
881
|
+
send(payload, timeoutMs) {
|
|
840
882
|
return new Promise((resolve5, reject) => {
|
|
841
883
|
if (!this.socket || this.socket.destroyed) {
|
|
842
884
|
reject(new Error("Daemon not connected"));
|
|
@@ -846,7 +888,8 @@ var DaemonClient = class _DaemonClient {
|
|
|
846
888
|
const i = this.pending.findIndex((p) => p.timer === timer);
|
|
847
889
|
if (i !== -1) this.pending.splice(i, 1);
|
|
848
890
|
reject(new Error("Daemon request timeout"));
|
|
849
|
-
|
|
891
|
+
this.detach();
|
|
892
|
+
}, timeoutMs ?? this.requestTimeout);
|
|
850
893
|
this.pending.push({ resolve: resolve5, reject, timer });
|
|
851
894
|
this.socket.write(JSON.stringify(payload) + "\n");
|
|
852
895
|
});
|
|
@@ -1003,14 +1046,16 @@ var Engine = class {
|
|
|
1003
1046
|
"--host",
|
|
1004
1047
|
this.config.config.HOST,
|
|
1005
1048
|
"--port",
|
|
1006
|
-
this.config.config.PORT,
|
|
1007
|
-
"--user",
|
|
1008
|
-
this.config.config.USER,
|
|
1009
|
-
"--password",
|
|
1010
|
-
this.config.config.PASSWORD,
|
|
1049
|
+
String(this.config.config.PORT),
|
|
1011
1050
|
"--motor",
|
|
1012
1051
|
this.config.type
|
|
1013
1052
|
];
|
|
1053
|
+
if (this.config.config.USER != null && this.config.config.USER !== "") {
|
|
1054
|
+
args.push("--user", this.config.config.USER);
|
|
1055
|
+
}
|
|
1056
|
+
if (this.config.config.PASSWORD != null && this.config.config.PASSWORD !== "") {
|
|
1057
|
+
args.push("--password", this.config.config.PASSWORD);
|
|
1058
|
+
}
|
|
1014
1059
|
}
|
|
1015
1060
|
return args;
|
|
1016
1061
|
}
|
|
@@ -1068,13 +1113,15 @@ var Engine = class {
|
|
|
1068
1113
|
resolve5(response);
|
|
1069
1114
|
}
|
|
1070
1115
|
};
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1116
|
+
const tryParseLines = (buffer) => {
|
|
1117
|
+
let idx;
|
|
1118
|
+
while ((idx = buffer.indexOf("\n")) !== -1) {
|
|
1119
|
+
const line = buffer.slice(0, idx);
|
|
1120
|
+
buffer = buffer.slice(idx + 1);
|
|
1121
|
+
const marker = line.indexOf("PROCESS_RESPONSE:");
|
|
1122
|
+
if (marker === -1) continue;
|
|
1076
1123
|
try {
|
|
1077
|
-
const response = JSON.parse(
|
|
1124
|
+
const response = JSON.parse(line.slice(marker + "PROCESS_RESPONSE:".length));
|
|
1078
1125
|
resolveOnce({
|
|
1079
1126
|
status: response.status,
|
|
1080
1127
|
message: response.message,
|
|
@@ -1088,27 +1135,19 @@ var Engine = class {
|
|
|
1088
1135
|
});
|
|
1089
1136
|
}
|
|
1090
1137
|
}
|
|
1138
|
+
return buffer;
|
|
1139
|
+
};
|
|
1140
|
+
child.stdout.on("data", (data) => {
|
|
1141
|
+
const text = data.toString();
|
|
1142
|
+
const visible = text.split("\n").filter((l) => l.trim() && !l.includes("PROCESS_RESPONSE:")).join("\n");
|
|
1143
|
+
if (visible) console.log(visible);
|
|
1144
|
+
stdoutBuffer = tryParseLines(stdoutBuffer + text);
|
|
1091
1145
|
});
|
|
1092
1146
|
child.stderr.on("data", (data) => {
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
try {
|
|
1098
|
-
const response = JSON.parse(match[1]);
|
|
1099
|
-
resolveOnce({
|
|
1100
|
-
status: response.status,
|
|
1101
|
-
message: response.message,
|
|
1102
|
-
data: response.data
|
|
1103
|
-
});
|
|
1104
|
-
} catch (error) {
|
|
1105
|
-
resolveOnce({
|
|
1106
|
-
status: 500,
|
|
1107
|
-
message: "Failed to parse response JSON",
|
|
1108
|
-
data: null
|
|
1109
|
-
});
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1147
|
+
const text = data.toString();
|
|
1148
|
+
const visible = text.split("\n").filter((l) => l.trim() && !l.includes("PROCESS_RESPONSE:")).join("\n");
|
|
1149
|
+
if (visible) console.log(visible);
|
|
1150
|
+
stderrBuffer = tryParseLines(stderrBuffer + text);
|
|
1112
1151
|
});
|
|
1113
1152
|
child.on("close", (code) => {
|
|
1114
1153
|
clearTimeout(timeoutId);
|
|
@@ -1145,7 +1184,6 @@ var globalTcpConnections = /* @__PURE__ */ new Map();
|
|
|
1145
1184
|
var connectionQueues = /* @__PURE__ */ new Map();
|
|
1146
1185
|
var connectionProcessing = /* @__PURE__ */ new Map();
|
|
1147
1186
|
var queryCache = /* @__PURE__ */ new Map();
|
|
1148
|
-
var cacheSize = 0;
|
|
1149
1187
|
var MAX_CACHE_SIZE = 500;
|
|
1150
1188
|
var QueryEngine = class {
|
|
1151
1189
|
name;
|
|
@@ -1159,7 +1197,7 @@ var QueryEngine = class {
|
|
|
1159
1197
|
this.name = name;
|
|
1160
1198
|
this.config = this.setConfig(name);
|
|
1161
1199
|
this.arguments = this.setArguments();
|
|
1162
|
-
this.timeout = timeout;
|
|
1200
|
+
this.timeout = this.config?.daemon?.requestTimeoutMs ?? timeout;
|
|
1163
1201
|
this.connectionId = `${name}_query_engine_${this.config.type}_${this.config.config.DATABASE}_${this.config.config.HOST || "localhost"}`;
|
|
1164
1202
|
this.tcpPort = this.generatePort();
|
|
1165
1203
|
}
|
|
@@ -1214,17 +1252,30 @@ var QueryEngine = class {
|
|
|
1214
1252
|
"--host",
|
|
1215
1253
|
this.config.config.HOST,
|
|
1216
1254
|
"--port",
|
|
1217
|
-
this.config.config.PORT,
|
|
1218
|
-
"--user",
|
|
1219
|
-
this.config.config.USER,
|
|
1220
|
-
"--password",
|
|
1221
|
-
this.config.config.PASSWORD,
|
|
1255
|
+
String(this.config.config.PORT),
|
|
1222
1256
|
"--motor",
|
|
1223
1257
|
this.config.type
|
|
1224
1258
|
];
|
|
1259
|
+
if (this.config.config.USER != null && this.config.config.USER !== "") {
|
|
1260
|
+
args.push("--user", this.config.config.USER);
|
|
1261
|
+
}
|
|
1262
|
+
if (this.config.config.PASSWORD != null && this.config.config.PASSWORD !== "") {
|
|
1263
|
+
args.push("--password", this.config.config.PASSWORD);
|
|
1264
|
+
}
|
|
1225
1265
|
}
|
|
1266
|
+
const pool = this.config.pool ?? {};
|
|
1267
|
+
if (pool.maxConnections != null) args.push("--max-connections", String(pool.maxConnections));
|
|
1268
|
+
if (pool.minConnections != null) args.push("--min-connections", String(pool.minConnections));
|
|
1269
|
+
if (pool.acquireTimeoutMs != null) args.push("--acquire-timeout-ms", String(pool.acquireTimeoutMs));
|
|
1270
|
+
if (pool.idleTimeoutMs != null) args.push("--idle-timeout-ms", String(pool.idleTimeoutMs));
|
|
1226
1271
|
return args;
|
|
1227
1272
|
}
|
|
1273
|
+
/** El daemon puede desactivarse por config (daemon.enabled=false) o por env (DBCUBE_DAEMON=0). */
|
|
1274
|
+
daemonEnabled() {
|
|
1275
|
+
const flag = process.env.DBCUBE_DAEMON;
|
|
1276
|
+
if (flag === "0" || flag === "false") return false;
|
|
1277
|
+
return this.config?.daemon?.enabled !== false;
|
|
1278
|
+
}
|
|
1228
1279
|
setConfig(name) {
|
|
1229
1280
|
const configInstance = new Config();
|
|
1230
1281
|
try {
|
|
@@ -1260,18 +1311,71 @@ var QueryEngine = class {
|
|
|
1260
1311
|
const isExecuteAction = actionIndex !== -1 && args[actionIndex + 1] === "execute";
|
|
1261
1312
|
const isQueryEngine = binary === "query_engine";
|
|
1262
1313
|
if (isQueryEngine && isExecuteAction) {
|
|
1263
|
-
return this.executeWithTcpServer(args);
|
|
1314
|
+
return this.executeWithTcpServer(this.argsToCommand(args));
|
|
1264
1315
|
} else {
|
|
1265
1316
|
return this.createProcess(binary, args);
|
|
1266
1317
|
}
|
|
1267
1318
|
}
|
|
1268
|
-
|
|
1319
|
+
argsToCommand(args) {
|
|
1320
|
+
const command = {};
|
|
1321
|
+
for (let i = 0; i < args.length; i += 2) {
|
|
1322
|
+
if (args[i].startsWith("--")) {
|
|
1323
|
+
command[args[i].substring(2)] = args[i + 1];
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
return command;
|
|
1327
|
+
}
|
|
1328
|
+
/**
|
|
1329
|
+
* Executes a DML plan over the persistent TCP server.
|
|
1330
|
+
* Pass txId to run it inside an active transaction.
|
|
1331
|
+
*/
|
|
1332
|
+
async executeDml(dml, txId) {
|
|
1333
|
+
const command = { action: "execute", dml: JSON.stringify(dml) };
|
|
1334
|
+
if (txId) command.tx_id = txId;
|
|
1335
|
+
return this.executeWithTcpServer(command);
|
|
1336
|
+
}
|
|
1337
|
+
/**
|
|
1338
|
+
* Executes raw SQL (or a MongoDB command document) with bound parameters
|
|
1339
|
+
* over the persistent TCP server.
|
|
1340
|
+
*/
|
|
1341
|
+
async rawQuery(query, params = [], txId) {
|
|
1342
|
+
const command = { action: "raw", query, params };
|
|
1343
|
+
if (txId) command.tx_id = txId;
|
|
1344
|
+
return this.executeWithTcpServer(command);
|
|
1345
|
+
}
|
|
1346
|
+
/** Starts a server-side transaction and returns its id. */
|
|
1347
|
+
async beginTransaction() {
|
|
1348
|
+
const res = await this.executeWithTcpServer({ action: "begin" });
|
|
1349
|
+
if (res.status !== 200 || !res.data?.tx_id) {
|
|
1350
|
+
throw new Error(String(res.message || "Failed to begin transaction (update the query-engine binary: npx dbcube update)"));
|
|
1351
|
+
}
|
|
1352
|
+
return res.data.tx_id;
|
|
1353
|
+
}
|
|
1354
|
+
async commitTransaction(txId) {
|
|
1355
|
+
const res = await this.executeWithTcpServer({ action: "commit", tx_id: txId });
|
|
1356
|
+
if (res.status !== 200) throw new Error(String(res.message || "Failed to commit transaction"));
|
|
1357
|
+
}
|
|
1358
|
+
async rollbackTransaction(txId) {
|
|
1359
|
+
const res = await this.executeWithTcpServer({ action: "rollback", tx_id: txId });
|
|
1360
|
+
if (res.status !== 200) throw new Error(String(res.message || "Failed to rollback transaction"));
|
|
1361
|
+
}
|
|
1362
|
+
async executeWithTcpServer(command) {
|
|
1363
|
+
if (!this.daemonEnabled()) {
|
|
1364
|
+
if (command.tx_id || ["begin", "commit", "rollback"].includes(command.action)) {
|
|
1365
|
+
throw new Error("Transactions require daemon mode. Remove daemon.enabled=false from dbcube.config.js (or unset DBCUBE_DAEMON=0).");
|
|
1366
|
+
}
|
|
1367
|
+
const args = [];
|
|
1368
|
+
for (const [key, value] of Object.entries(command)) {
|
|
1369
|
+
args.push(`--${key.replace(/_/g, "-")}`, typeof value === "string" ? value : JSON.stringify(value));
|
|
1370
|
+
}
|
|
1371
|
+
return this.createProcess("query_engine", args);
|
|
1372
|
+
}
|
|
1269
1373
|
const serverInfo = globalTcpServers.get(this.connectionId);
|
|
1270
1374
|
if (!serverInfo || !serverInfo.process || serverInfo.process.killed) {
|
|
1271
1375
|
await this.startTcpServer();
|
|
1272
1376
|
await this.waitForServerReady();
|
|
1273
1377
|
}
|
|
1274
|
-
return this.sendTcpRequestFast(
|
|
1378
|
+
return this.sendTcpRequestFast(command);
|
|
1275
1379
|
}
|
|
1276
1380
|
async waitForServerReady() {
|
|
1277
1381
|
const maxRetries = 10;
|
|
@@ -1314,10 +1418,11 @@ var QueryEngine = class {
|
|
|
1314
1418
|
return queryCache.get(dmlJson);
|
|
1315
1419
|
}
|
|
1316
1420
|
const parsed = JSON.parse(dmlJson);
|
|
1317
|
-
if (
|
|
1318
|
-
queryCache.
|
|
1319
|
-
|
|
1421
|
+
if (queryCache.size >= MAX_CACHE_SIZE) {
|
|
1422
|
+
const oldest = queryCache.keys().next().value;
|
|
1423
|
+
if (oldest !== void 0) queryCache.delete(oldest);
|
|
1320
1424
|
}
|
|
1425
|
+
queryCache.set(dmlJson, parsed);
|
|
1321
1426
|
return parsed;
|
|
1322
1427
|
}
|
|
1323
1428
|
async startTcpServer() {
|
|
@@ -1364,14 +1469,14 @@ var QueryEngine = class {
|
|
|
1364
1469
|
});
|
|
1365
1470
|
});
|
|
1366
1471
|
}
|
|
1367
|
-
async sendTcpRequestFast(
|
|
1472
|
+
async sendTcpRequestFast(command) {
|
|
1368
1473
|
return new Promise((resolve5, reject) => {
|
|
1369
1474
|
let queue = connectionQueues.get(this.connectionId);
|
|
1370
1475
|
if (!queue) {
|
|
1371
1476
|
queue = [];
|
|
1372
1477
|
connectionQueues.set(this.connectionId, queue);
|
|
1373
1478
|
}
|
|
1374
|
-
queue.push({
|
|
1479
|
+
queue.push({ command, resolve: resolve5, reject });
|
|
1375
1480
|
this.processQueue();
|
|
1376
1481
|
});
|
|
1377
1482
|
}
|
|
@@ -1398,9 +1503,16 @@ var QueryEngine = class {
|
|
|
1398
1503
|
connection = await this.createNewConnection(serverInfo.port);
|
|
1399
1504
|
globalTcpConnections.set(this.connectionId, connection);
|
|
1400
1505
|
}
|
|
1401
|
-
const result = await this.executeOnConnection(connection, request.
|
|
1506
|
+
const result = await this.executeOnConnection(connection, request.command);
|
|
1402
1507
|
request.resolve(result);
|
|
1403
1508
|
} catch (error) {
|
|
1509
|
+
const staleConnection = globalTcpConnections.get(this.connectionId);
|
|
1510
|
+
if (staleConnection) {
|
|
1511
|
+
try {
|
|
1512
|
+
staleConnection.destroy();
|
|
1513
|
+
} catch {
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1404
1516
|
globalTcpConnections.delete(this.connectionId);
|
|
1405
1517
|
request.reject(error);
|
|
1406
1518
|
}
|
|
@@ -1428,16 +1540,8 @@ var QueryEngine = class {
|
|
|
1428
1540
|
});
|
|
1429
1541
|
});
|
|
1430
1542
|
}
|
|
1431
|
-
async executeOnConnection(connection,
|
|
1543
|
+
async executeOnConnection(connection, command) {
|
|
1432
1544
|
return new Promise((resolve5, reject) => {
|
|
1433
|
-
const command = {};
|
|
1434
|
-
for (let i = 0; i < args.length; i += 2) {
|
|
1435
|
-
if (args[i].startsWith("--")) {
|
|
1436
|
-
const key = args[i].substring(2);
|
|
1437
|
-
const value = args[i + 1];
|
|
1438
|
-
command[key] = value;
|
|
1439
|
-
}
|
|
1440
|
-
}
|
|
1441
1545
|
let responseBuffer = "";
|
|
1442
1546
|
let isResolved = false;
|
|
1443
1547
|
const timeout = setTimeout(() => {
|
|
@@ -1450,14 +1554,18 @@ var QueryEngine = class {
|
|
|
1450
1554
|
}, this.timeout);
|
|
1451
1555
|
const onData = (data) => {
|
|
1452
1556
|
responseBuffer += data.toString();
|
|
1453
|
-
|
|
1454
|
-
|
|
1557
|
+
let idx;
|
|
1558
|
+
while ((idx = responseBuffer.indexOf("\n")) !== -1 && !isResolved) {
|
|
1559
|
+
const line = responseBuffer.slice(0, idx);
|
|
1560
|
+
responseBuffer = responseBuffer.slice(idx + 1);
|
|
1561
|
+
const marker = line.indexOf("PROCESS_RESPONSE:");
|
|
1562
|
+
if (marker === -1) continue;
|
|
1455
1563
|
isResolved = true;
|
|
1456
1564
|
clearTimeout(timeout);
|
|
1457
1565
|
connection.removeListener("data", onData);
|
|
1458
1566
|
connection.removeListener("error", onError);
|
|
1459
1567
|
try {
|
|
1460
|
-
const response = JSON.parse(
|
|
1568
|
+
const response = JSON.parse(line.slice(marker + "PROCESS_RESPONSE:".length));
|
|
1461
1569
|
resolve5({
|
|
1462
1570
|
status: response.status,
|
|
1463
1571
|
message: response.message,
|
|
@@ -1479,7 +1587,7 @@ var QueryEngine = class {
|
|
|
1479
1587
|
};
|
|
1480
1588
|
connection.on("data", onData);
|
|
1481
1589
|
connection.on("error", onError);
|
|
1482
|
-
connection.write(JSON.stringify(command));
|
|
1590
|
+
connection.write(JSON.stringify(command) + "\n");
|
|
1483
1591
|
});
|
|
1484
1592
|
}
|
|
1485
1593
|
async createProcess(binary, args) {
|
|
@@ -1506,12 +1614,15 @@ var QueryEngine = class {
|
|
|
1506
1614
|
resolve5(response);
|
|
1507
1615
|
}
|
|
1508
1616
|
};
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1617
|
+
const tryParseLines = (buffer) => {
|
|
1618
|
+
let idx;
|
|
1619
|
+
while ((idx = buffer.indexOf("\n")) !== -1) {
|
|
1620
|
+
const line = buffer.slice(0, idx);
|
|
1621
|
+
buffer = buffer.slice(idx + 1);
|
|
1622
|
+
const marker = line.indexOf("PROCESS_RESPONSE:");
|
|
1623
|
+
if (marker === -1) continue;
|
|
1513
1624
|
try {
|
|
1514
|
-
const response = JSON.parse(
|
|
1625
|
+
const response = JSON.parse(line.slice(marker + "PROCESS_RESPONSE:".length));
|
|
1515
1626
|
resolveOnce({
|
|
1516
1627
|
status: response.status,
|
|
1517
1628
|
message: response.message,
|
|
@@ -1525,26 +1636,13 @@ var QueryEngine = class {
|
|
|
1525
1636
|
});
|
|
1526
1637
|
}
|
|
1527
1638
|
}
|
|
1639
|
+
return buffer;
|
|
1640
|
+
};
|
|
1641
|
+
child.stdout.on("data", (data) => {
|
|
1642
|
+
stdoutBuffer = tryParseLines(stdoutBuffer + data.toString());
|
|
1528
1643
|
});
|
|
1529
1644
|
child.stderr.on("data", (data) => {
|
|
1530
|
-
stderrBuffer
|
|
1531
|
-
const match = stderrBuffer.match(/PROCESS_RESPONSE:(\{.*\})/);
|
|
1532
|
-
if (match) {
|
|
1533
|
-
try {
|
|
1534
|
-
const response = JSON.parse(match[1]);
|
|
1535
|
-
resolveOnce({
|
|
1536
|
-
status: response.status,
|
|
1537
|
-
message: response.message,
|
|
1538
|
-
data: response.data
|
|
1539
|
-
});
|
|
1540
|
-
} catch (error) {
|
|
1541
|
-
resolveOnce({
|
|
1542
|
-
status: 500,
|
|
1543
|
-
message: "Failed to parse response JSON",
|
|
1544
|
-
data: null
|
|
1545
|
-
});
|
|
1546
|
-
}
|
|
1547
|
-
}
|
|
1645
|
+
stderrBuffer = tryParseLines(stderrBuffer + data.toString());
|
|
1548
1646
|
});
|
|
1549
1647
|
child.on("close", (code) => {
|
|
1550
1648
|
clearTimeout(timeoutId);
|
|
@@ -2403,7 +2501,7 @@ var ComputedFieldProcessor = class {
|
|
|
2403
2501
|
const tableExistsQuery = `SELECT name FROM sqlite_master WHERE type='table' AND name='dbcube_computes_config'`;
|
|
2404
2502
|
const tableExistsResult = await DbConfig_default.query(tableExistsQuery);
|
|
2405
2503
|
if (tableExistsResult.status === "success" && tableExistsResult.data && tableExistsResult.data.length > 0) {
|
|
2406
|
-
const queryComputes = await DbConfig_default.
|
|
2504
|
+
const queryComputes = await DbConfig_default.queryWithParameters(`SELECT * FROM dbcube_computes_config WHERE database_ref=?`, [name]);
|
|
2407
2505
|
computedFields = queryComputes.data;
|
|
2408
2506
|
} else {
|
|
2409
2507
|
computedFields = [];
|
|
@@ -2434,21 +2532,10 @@ var ComputedFieldProcessor = class {
|
|
|
2434
2532
|
}
|
|
2435
2533
|
functionBody = functionBody.replace(/@column\(([^)]+)\)/g, (_match, columnName) => {
|
|
2436
2534
|
const cleanColumnName = columnName.trim().replace(/['"]/g, "");
|
|
2437
|
-
|
|
2438
|
-
if (value === null || value === void 0) {
|
|
2439
|
-
return "null";
|
|
2440
|
-
} else if (typeof value === "string") {
|
|
2441
|
-
return `"${value.replace(/"/g, '\\"')}"`;
|
|
2442
|
-
} else if (typeof value === "number" || typeof value === "boolean") {
|
|
2443
|
-
return value.toString();
|
|
2444
|
-
} else if (value instanceof Date) {
|
|
2445
|
-
return `new Date("${value.toISOString()}")`;
|
|
2446
|
-
} else {
|
|
2447
|
-
return JSON.stringify(value);
|
|
2448
|
-
}
|
|
2535
|
+
return `__row[${JSON.stringify(cleanColumnName)}]`;
|
|
2449
2536
|
});
|
|
2450
|
-
const computeFunction = new Function(functionBody);
|
|
2451
|
-
return computeFunction();
|
|
2537
|
+
const computeFunction = new Function("__row", functionBody);
|
|
2538
|
+
return computeFunction(rowData);
|
|
2452
2539
|
} catch (error) {
|
|
2453
2540
|
console.error("Error processing computed field:", error);
|
|
2454
2541
|
return null;
|
|
@@ -2491,14 +2578,7 @@ var ComputedFieldProcessor = class {
|
|
|
2491
2578
|
/@column\(([^)]+)\)/g,
|
|
2492
2579
|
(match, columnName) => {
|
|
2493
2580
|
const cleanColumnName = columnName.replace(/['"]/g, "");
|
|
2494
|
-
|
|
2495
|
-
if (typeof value === "string") {
|
|
2496
|
-
return `"${value}"`;
|
|
2497
|
-
} else if (value === null || value === void 0) {
|
|
2498
|
-
return "null";
|
|
2499
|
-
} else {
|
|
2500
|
-
return String(value);
|
|
2501
|
-
}
|
|
2581
|
+
return `__row[${JSON.stringify(cleanColumnName)}]`;
|
|
2502
2582
|
}
|
|
2503
2583
|
);
|
|
2504
2584
|
const computeMatch = processedExpression.match(/@compute\s*\(\s*\(\s*\)\s*=>\s*\{(.*)\}\s*\)/s);
|
|
@@ -2506,8 +2586,8 @@ var ComputedFieldProcessor = class {
|
|
|
2506
2586
|
throw new Error(`Formato de @compute inv\xE1lido para campo ${fieldName}`);
|
|
2507
2587
|
}
|
|
2508
2588
|
const functionBody = computeMatch[1];
|
|
2509
|
-
const computeFunction = new Function(functionBody);
|
|
2510
|
-
let result = computeFunction();
|
|
2589
|
+
const computeFunction = new Function("__row", functionBody);
|
|
2590
|
+
let result = computeFunction(processedItem);
|
|
2511
2591
|
result = convertToType(result, type2);
|
|
2512
2592
|
processedItem[fieldName] = result;
|
|
2513
2593
|
} catch (error) {
|
|
@@ -2699,14 +2779,14 @@ var TableProcessor = class {
|
|
|
2699
2779
|
if (await DbConfig_default.ifExist()) {
|
|
2700
2780
|
await DbConfig_default.connect();
|
|
2701
2781
|
try {
|
|
2702
|
-
const tableExistsQuery = `SELECT name FROM sqlite_master WHERE type='table' AND name='
|
|
2782
|
+
const tableExistsQuery = `SELECT name FROM sqlite_master WHERE type='table' AND name='dbcube_schemas_config'`;
|
|
2703
2783
|
const tableExistsResult = await DbConfig_default.query(tableExistsQuery);
|
|
2704
2784
|
if (tableExistsResult.status === "success" && tableExistsResult.data && tableExistsResult.data.length > 0) {
|
|
2705
|
-
const queryComputes = await DbConfig_default.
|
|
2785
|
+
const queryComputes = await DbConfig_default.queryWithParameters(`SELECT * FROM dbcube_schemas_config WHERE table_ref=? AND database_ref=?`, [tableName, database_ref]);
|
|
2706
2786
|
const oldQuery = queryComputes.data[0];
|
|
2707
2787
|
if (!oldQuery || !oldQuery.struct) {
|
|
2708
|
-
|
|
2709
|
-
return [];
|
|
2788
|
+
await DbConfig_default.disconnect();
|
|
2789
|
+
return [nowQuery];
|
|
2710
2790
|
}
|
|
2711
2791
|
const nowSchema = parseCreateTableQuery(nowQuery, dbType);
|
|
2712
2792
|
const oldSchema = parseCreateTableQuery(oldQuery.struct, dbType);
|
|
@@ -2741,7 +2821,7 @@ var TableProcessor = class {
|
|
|
2741
2821
|
if (await DbConfig_default.ifExist()) {
|
|
2742
2822
|
await DbConfig_default.connect();
|
|
2743
2823
|
try {
|
|
2744
|
-
await DbConfig_default.
|
|
2824
|
+
await DbConfig_default.queryWithParameters(`DELETE FROM dbcube_schemas_config WHERE table_ref=? AND database_ref=?`, [table_ref, database_ref]);
|
|
2745
2825
|
const tableExistsQuery = `INSERT INTO dbcube_schemas_config (table_ref, database_ref, struct) VALUES (?, ?, ?)`;
|
|
2746
2826
|
await DbConfig_default.queryWithParameters(tableExistsQuery, [table_ref, database_ref, struct]);
|
|
2747
2827
|
} catch (error) {
|
|
@@ -2760,7 +2840,7 @@ var TriggerProcessor = class {
|
|
|
2760
2840
|
const tableExistsQuery = `SELECT name FROM sqlite_master WHERE type='table' AND name='dbcube_triggers_config'`;
|
|
2761
2841
|
const tableExistsResult = await DbConfig_default.query(tableExistsQuery);
|
|
2762
2842
|
if (tableExistsResult.status === "success" && tableExistsResult.data && tableExistsResult.data.length > 0) {
|
|
2763
|
-
const queryComputes = await DbConfig_default.
|
|
2843
|
+
const queryComputes = await DbConfig_default.queryWithParameters(`SELECT * FROM dbcube_triggers_config WHERE database_ref=?`, [name]);
|
|
2764
2844
|
triggers = queryComputes.data;
|
|
2765
2845
|
} else {
|
|
2766
2846
|
triggers = [];
|