@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.cjs
CHANGED
|
@@ -392,7 +392,7 @@ var Downloader = class {
|
|
|
392
392
|
}
|
|
393
393
|
this.mainSpinner.text = import_chalk.default.blue(`Updating ${binariesToDownload.length} binary(ies)...`);
|
|
394
394
|
try {
|
|
395
|
-
await Promise.
|
|
395
|
+
const results = await Promise.allSettled(binariesToDownload.map(async (binary) => {
|
|
396
396
|
const maxRetries = 3;
|
|
397
397
|
let attempt = 0;
|
|
398
398
|
while (attempt <= maxRetries) {
|
|
@@ -420,6 +420,11 @@ var Downloader = class {
|
|
|
420
420
|
}
|
|
421
421
|
}
|
|
422
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
|
+
}
|
|
423
428
|
this.mainSpinner.succeed(import_chalk.default.green("Binaries updated successfully"));
|
|
424
429
|
} catch (error) {
|
|
425
430
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
@@ -484,8 +489,7 @@ var Downloader = class {
|
|
|
484
489
|
}
|
|
485
490
|
});
|
|
486
491
|
response.on("end", () => {
|
|
487
|
-
file.end();
|
|
488
|
-
resolve5();
|
|
492
|
+
file.end(() => resolve5());
|
|
489
493
|
});
|
|
490
494
|
response.on("error", (err) => {
|
|
491
495
|
file.close();
|
|
@@ -712,7 +716,6 @@ var Config = class {
|
|
|
712
716
|
/**
|
|
713
717
|
* Obtiene un valor de configuración
|
|
714
718
|
* @param key - Clave de configuración
|
|
715
|
-
* @returns Valor de configuración
|
|
716
719
|
*/
|
|
717
720
|
get(key) {
|
|
718
721
|
return this.data[key];
|
|
@@ -720,14 +723,12 @@ var Config = class {
|
|
|
720
723
|
/**
|
|
721
724
|
* Obtiene la configuración de una base de datos específica
|
|
722
725
|
* @param dbName - Nombre de la base de datos
|
|
723
|
-
* @returns Configuración de la base de datos o null
|
|
724
726
|
*/
|
|
725
727
|
getDatabase(dbName) {
|
|
726
728
|
return this.databases[dbName] || null;
|
|
727
729
|
}
|
|
728
730
|
/**
|
|
729
731
|
* Obtiene todas las bases de datos configuradas
|
|
730
|
-
* @returns Todas las configuraciones de bases de datos
|
|
731
732
|
*/
|
|
732
733
|
getAllDatabases() {
|
|
733
734
|
return this.databases;
|
|
@@ -775,6 +776,39 @@ var DaemonClient = class _DaemonClient {
|
|
|
775
776
|
portfilePath() {
|
|
776
777
|
return import_path3.default.join(process.cwd(), ".dbcube", "daemon", `${this.name}.json`);
|
|
777
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
|
+
}
|
|
778
812
|
/**
|
|
779
813
|
* Ensures a usable daemon connection. Returns false when the daemon
|
|
780
814
|
* can't be used (old binary, startup failure) so callers fall back
|
|
@@ -791,24 +825,32 @@ var DaemonClient = class _DaemonClient {
|
|
|
791
825
|
async connectOrStart() {
|
|
792
826
|
const port = this.readPortfile();
|
|
793
827
|
if (port && await this.tryConnect(port)) return true;
|
|
828
|
+
const gotLock = this.acquireSpawnLock();
|
|
794
829
|
try {
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
const
|
|
803
|
-
|
|
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();
|
|
804
846
|
}
|
|
805
|
-
return false;
|
|
806
847
|
}
|
|
807
848
|
readPortfile() {
|
|
808
849
|
try {
|
|
809
850
|
const raw = import_fs.default.readFileSync(this.portfilePath(), "utf8");
|
|
810
851
|
const info = JSON.parse(raw);
|
|
811
|
-
|
|
852
|
+
const port = info?.port;
|
|
853
|
+
return Number.isInteger(port) && port > 0 && port <= 65535 ? port : null;
|
|
812
854
|
} catch {
|
|
813
855
|
return null;
|
|
814
856
|
}
|
|
@@ -827,7 +869,7 @@ var DaemonClient = class _DaemonClient {
|
|
|
827
869
|
socket.setNoDelay(true);
|
|
828
870
|
this.attach(socket);
|
|
829
871
|
try {
|
|
830
|
-
const pong = await this.send({ action: "ping" });
|
|
872
|
+
const pong = await this.send({ action: "ping" }, 2e3);
|
|
831
873
|
resolve5(pong.status === 200);
|
|
832
874
|
} catch {
|
|
833
875
|
this.detach();
|
|
@@ -884,7 +926,7 @@ var DaemonClient = class _DaemonClient {
|
|
|
884
926
|
* Sends a request to the daemon. Responses arrive in FIFO order on the
|
|
885
927
|
* single socket, so pending requests resolve in send order.
|
|
886
928
|
*/
|
|
887
|
-
send(payload) {
|
|
929
|
+
send(payload, timeoutMs) {
|
|
888
930
|
return new Promise((resolve5, reject) => {
|
|
889
931
|
if (!this.socket || this.socket.destroyed) {
|
|
890
932
|
reject(new Error("Daemon not connected"));
|
|
@@ -894,7 +936,8 @@ var DaemonClient = class _DaemonClient {
|
|
|
894
936
|
const i = this.pending.findIndex((p) => p.timer === timer);
|
|
895
937
|
if (i !== -1) this.pending.splice(i, 1);
|
|
896
938
|
reject(new Error("Daemon request timeout"));
|
|
897
|
-
|
|
939
|
+
this.detach();
|
|
940
|
+
}, timeoutMs ?? this.requestTimeout);
|
|
898
941
|
this.pending.push({ resolve: resolve5, reject, timer });
|
|
899
942
|
this.socket.write(JSON.stringify(payload) + "\n");
|
|
900
943
|
});
|
|
@@ -1051,14 +1094,16 @@ var Engine = class {
|
|
|
1051
1094
|
"--host",
|
|
1052
1095
|
this.config.config.HOST,
|
|
1053
1096
|
"--port",
|
|
1054
|
-
this.config.config.PORT,
|
|
1055
|
-
"--user",
|
|
1056
|
-
this.config.config.USER,
|
|
1057
|
-
"--password",
|
|
1058
|
-
this.config.config.PASSWORD,
|
|
1097
|
+
String(this.config.config.PORT),
|
|
1059
1098
|
"--motor",
|
|
1060
1099
|
this.config.type
|
|
1061
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
|
+
}
|
|
1062
1107
|
}
|
|
1063
1108
|
return args;
|
|
1064
1109
|
}
|
|
@@ -1116,13 +1161,15 @@ var Engine = class {
|
|
|
1116
1161
|
resolve5(response);
|
|
1117
1162
|
}
|
|
1118
1163
|
};
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1164
|
+
const tryParseLines = (buffer) => {
|
|
1165
|
+
let idx;
|
|
1166
|
+
while ((idx = buffer.indexOf("\n")) !== -1) {
|
|
1167
|
+
const line = buffer.slice(0, idx);
|
|
1168
|
+
buffer = buffer.slice(idx + 1);
|
|
1169
|
+
const marker = line.indexOf("PROCESS_RESPONSE:");
|
|
1170
|
+
if (marker === -1) continue;
|
|
1124
1171
|
try {
|
|
1125
|
-
const response = JSON.parse(
|
|
1172
|
+
const response = JSON.parse(line.slice(marker + "PROCESS_RESPONSE:".length));
|
|
1126
1173
|
resolveOnce({
|
|
1127
1174
|
status: response.status,
|
|
1128
1175
|
message: response.message,
|
|
@@ -1136,27 +1183,19 @@ var Engine = class {
|
|
|
1136
1183
|
});
|
|
1137
1184
|
}
|
|
1138
1185
|
}
|
|
1186
|
+
return buffer;
|
|
1187
|
+
};
|
|
1188
|
+
child.stdout.on("data", (data) => {
|
|
1189
|
+
const text = data.toString();
|
|
1190
|
+
const visible = text.split("\n").filter((l) => l.trim() && !l.includes("PROCESS_RESPONSE:")).join("\n");
|
|
1191
|
+
if (visible) console.log(visible);
|
|
1192
|
+
stdoutBuffer = tryParseLines(stdoutBuffer + text);
|
|
1139
1193
|
});
|
|
1140
1194
|
child.stderr.on("data", (data) => {
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
try {
|
|
1146
|
-
const response = JSON.parse(match[1]);
|
|
1147
|
-
resolveOnce({
|
|
1148
|
-
status: response.status,
|
|
1149
|
-
message: response.message,
|
|
1150
|
-
data: response.data
|
|
1151
|
-
});
|
|
1152
|
-
} catch (error) {
|
|
1153
|
-
resolveOnce({
|
|
1154
|
-
status: 500,
|
|
1155
|
-
message: "Failed to parse response JSON",
|
|
1156
|
-
data: null
|
|
1157
|
-
});
|
|
1158
|
-
}
|
|
1159
|
-
}
|
|
1195
|
+
const text = data.toString();
|
|
1196
|
+
const visible = text.split("\n").filter((l) => l.trim() && !l.includes("PROCESS_RESPONSE:")).join("\n");
|
|
1197
|
+
if (visible) console.log(visible);
|
|
1198
|
+
stderrBuffer = tryParseLines(stderrBuffer + text);
|
|
1160
1199
|
});
|
|
1161
1200
|
child.on("close", (code) => {
|
|
1162
1201
|
clearTimeout(timeoutId);
|
|
@@ -1193,7 +1232,6 @@ var globalTcpConnections = /* @__PURE__ */ new Map();
|
|
|
1193
1232
|
var connectionQueues = /* @__PURE__ */ new Map();
|
|
1194
1233
|
var connectionProcessing = /* @__PURE__ */ new Map();
|
|
1195
1234
|
var queryCache = /* @__PURE__ */ new Map();
|
|
1196
|
-
var cacheSize = 0;
|
|
1197
1235
|
var MAX_CACHE_SIZE = 500;
|
|
1198
1236
|
var QueryEngine = class {
|
|
1199
1237
|
name;
|
|
@@ -1207,7 +1245,7 @@ var QueryEngine = class {
|
|
|
1207
1245
|
this.name = name;
|
|
1208
1246
|
this.config = this.setConfig(name);
|
|
1209
1247
|
this.arguments = this.setArguments();
|
|
1210
|
-
this.timeout = timeout;
|
|
1248
|
+
this.timeout = this.config?.daemon?.requestTimeoutMs ?? timeout;
|
|
1211
1249
|
this.connectionId = `${name}_query_engine_${this.config.type}_${this.config.config.DATABASE}_${this.config.config.HOST || "localhost"}`;
|
|
1212
1250
|
this.tcpPort = this.generatePort();
|
|
1213
1251
|
}
|
|
@@ -1262,17 +1300,30 @@ var QueryEngine = class {
|
|
|
1262
1300
|
"--host",
|
|
1263
1301
|
this.config.config.HOST,
|
|
1264
1302
|
"--port",
|
|
1265
|
-
this.config.config.PORT,
|
|
1266
|
-
"--user",
|
|
1267
|
-
this.config.config.USER,
|
|
1268
|
-
"--password",
|
|
1269
|
-
this.config.config.PASSWORD,
|
|
1303
|
+
String(this.config.config.PORT),
|
|
1270
1304
|
"--motor",
|
|
1271
1305
|
this.config.type
|
|
1272
1306
|
];
|
|
1307
|
+
if (this.config.config.USER != null && this.config.config.USER !== "") {
|
|
1308
|
+
args.push("--user", this.config.config.USER);
|
|
1309
|
+
}
|
|
1310
|
+
if (this.config.config.PASSWORD != null && this.config.config.PASSWORD !== "") {
|
|
1311
|
+
args.push("--password", this.config.config.PASSWORD);
|
|
1312
|
+
}
|
|
1273
1313
|
}
|
|
1314
|
+
const pool = this.config.pool ?? {};
|
|
1315
|
+
if (pool.maxConnections != null) args.push("--max-connections", String(pool.maxConnections));
|
|
1316
|
+
if (pool.minConnections != null) args.push("--min-connections", String(pool.minConnections));
|
|
1317
|
+
if (pool.acquireTimeoutMs != null) args.push("--acquire-timeout-ms", String(pool.acquireTimeoutMs));
|
|
1318
|
+
if (pool.idleTimeoutMs != null) args.push("--idle-timeout-ms", String(pool.idleTimeoutMs));
|
|
1274
1319
|
return args;
|
|
1275
1320
|
}
|
|
1321
|
+
/** El daemon puede desactivarse por config (daemon.enabled=false) o por env (DBCUBE_DAEMON=0). */
|
|
1322
|
+
daemonEnabled() {
|
|
1323
|
+
const flag = process.env.DBCUBE_DAEMON;
|
|
1324
|
+
if (flag === "0" || flag === "false") return false;
|
|
1325
|
+
return this.config?.daemon?.enabled !== false;
|
|
1326
|
+
}
|
|
1276
1327
|
setConfig(name) {
|
|
1277
1328
|
const configInstance = new Config();
|
|
1278
1329
|
try {
|
|
@@ -1308,18 +1359,71 @@ var QueryEngine = class {
|
|
|
1308
1359
|
const isExecuteAction = actionIndex !== -1 && args[actionIndex + 1] === "execute";
|
|
1309
1360
|
const isQueryEngine = binary === "query_engine";
|
|
1310
1361
|
if (isQueryEngine && isExecuteAction) {
|
|
1311
|
-
return this.executeWithTcpServer(args);
|
|
1362
|
+
return this.executeWithTcpServer(this.argsToCommand(args));
|
|
1312
1363
|
} else {
|
|
1313
1364
|
return this.createProcess(binary, args);
|
|
1314
1365
|
}
|
|
1315
1366
|
}
|
|
1316
|
-
|
|
1367
|
+
argsToCommand(args) {
|
|
1368
|
+
const command = {};
|
|
1369
|
+
for (let i = 0; i < args.length; i += 2) {
|
|
1370
|
+
if (args[i].startsWith("--")) {
|
|
1371
|
+
command[args[i].substring(2)] = args[i + 1];
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
return command;
|
|
1375
|
+
}
|
|
1376
|
+
/**
|
|
1377
|
+
* Executes a DML plan over the persistent TCP server.
|
|
1378
|
+
* Pass txId to run it inside an active transaction.
|
|
1379
|
+
*/
|
|
1380
|
+
async executeDml(dml, txId) {
|
|
1381
|
+
const command = { action: "execute", dml: JSON.stringify(dml) };
|
|
1382
|
+
if (txId) command.tx_id = txId;
|
|
1383
|
+
return this.executeWithTcpServer(command);
|
|
1384
|
+
}
|
|
1385
|
+
/**
|
|
1386
|
+
* Executes raw SQL (or a MongoDB command document) with bound parameters
|
|
1387
|
+
* over the persistent TCP server.
|
|
1388
|
+
*/
|
|
1389
|
+
async rawQuery(query, params = [], txId) {
|
|
1390
|
+
const command = { action: "raw", query, params };
|
|
1391
|
+
if (txId) command.tx_id = txId;
|
|
1392
|
+
return this.executeWithTcpServer(command);
|
|
1393
|
+
}
|
|
1394
|
+
/** Starts a server-side transaction and returns its id. */
|
|
1395
|
+
async beginTransaction() {
|
|
1396
|
+
const res = await this.executeWithTcpServer({ action: "begin" });
|
|
1397
|
+
if (res.status !== 200 || !res.data?.tx_id) {
|
|
1398
|
+
throw new Error(String(res.message || "Failed to begin transaction (update the query-engine binary: npx dbcube update)"));
|
|
1399
|
+
}
|
|
1400
|
+
return res.data.tx_id;
|
|
1401
|
+
}
|
|
1402
|
+
async commitTransaction(txId) {
|
|
1403
|
+
const res = await this.executeWithTcpServer({ action: "commit", tx_id: txId });
|
|
1404
|
+
if (res.status !== 200) throw new Error(String(res.message || "Failed to commit transaction"));
|
|
1405
|
+
}
|
|
1406
|
+
async rollbackTransaction(txId) {
|
|
1407
|
+
const res = await this.executeWithTcpServer({ action: "rollback", tx_id: txId });
|
|
1408
|
+
if (res.status !== 200) throw new Error(String(res.message || "Failed to rollback transaction"));
|
|
1409
|
+
}
|
|
1410
|
+
async executeWithTcpServer(command) {
|
|
1411
|
+
if (!this.daemonEnabled()) {
|
|
1412
|
+
if (command.tx_id || ["begin", "commit", "rollback"].includes(command.action)) {
|
|
1413
|
+
throw new Error("Transactions require daemon mode. Remove daemon.enabled=false from dbcube.config.js (or unset DBCUBE_DAEMON=0).");
|
|
1414
|
+
}
|
|
1415
|
+
const args = [];
|
|
1416
|
+
for (const [key, value] of Object.entries(command)) {
|
|
1417
|
+
args.push(`--${key.replace(/_/g, "-")}`, typeof value === "string" ? value : JSON.stringify(value));
|
|
1418
|
+
}
|
|
1419
|
+
return this.createProcess("query_engine", args);
|
|
1420
|
+
}
|
|
1317
1421
|
const serverInfo = globalTcpServers.get(this.connectionId);
|
|
1318
1422
|
if (!serverInfo || !serverInfo.process || serverInfo.process.killed) {
|
|
1319
1423
|
await this.startTcpServer();
|
|
1320
1424
|
await this.waitForServerReady();
|
|
1321
1425
|
}
|
|
1322
|
-
return this.sendTcpRequestFast(
|
|
1426
|
+
return this.sendTcpRequestFast(command);
|
|
1323
1427
|
}
|
|
1324
1428
|
async waitForServerReady() {
|
|
1325
1429
|
const maxRetries = 10;
|
|
@@ -1362,10 +1466,11 @@ var QueryEngine = class {
|
|
|
1362
1466
|
return queryCache.get(dmlJson);
|
|
1363
1467
|
}
|
|
1364
1468
|
const parsed = JSON.parse(dmlJson);
|
|
1365
|
-
if (
|
|
1366
|
-
queryCache.
|
|
1367
|
-
|
|
1469
|
+
if (queryCache.size >= MAX_CACHE_SIZE) {
|
|
1470
|
+
const oldest = queryCache.keys().next().value;
|
|
1471
|
+
if (oldest !== void 0) queryCache.delete(oldest);
|
|
1368
1472
|
}
|
|
1473
|
+
queryCache.set(dmlJson, parsed);
|
|
1369
1474
|
return parsed;
|
|
1370
1475
|
}
|
|
1371
1476
|
async startTcpServer() {
|
|
@@ -1412,14 +1517,14 @@ var QueryEngine = class {
|
|
|
1412
1517
|
});
|
|
1413
1518
|
});
|
|
1414
1519
|
}
|
|
1415
|
-
async sendTcpRequestFast(
|
|
1520
|
+
async sendTcpRequestFast(command) {
|
|
1416
1521
|
return new Promise((resolve5, reject) => {
|
|
1417
1522
|
let queue = connectionQueues.get(this.connectionId);
|
|
1418
1523
|
if (!queue) {
|
|
1419
1524
|
queue = [];
|
|
1420
1525
|
connectionQueues.set(this.connectionId, queue);
|
|
1421
1526
|
}
|
|
1422
|
-
queue.push({
|
|
1527
|
+
queue.push({ command, resolve: resolve5, reject });
|
|
1423
1528
|
this.processQueue();
|
|
1424
1529
|
});
|
|
1425
1530
|
}
|
|
@@ -1446,9 +1551,16 @@ var QueryEngine = class {
|
|
|
1446
1551
|
connection = await this.createNewConnection(serverInfo.port);
|
|
1447
1552
|
globalTcpConnections.set(this.connectionId, connection);
|
|
1448
1553
|
}
|
|
1449
|
-
const result = await this.executeOnConnection(connection, request.
|
|
1554
|
+
const result = await this.executeOnConnection(connection, request.command);
|
|
1450
1555
|
request.resolve(result);
|
|
1451
1556
|
} catch (error) {
|
|
1557
|
+
const staleConnection = globalTcpConnections.get(this.connectionId);
|
|
1558
|
+
if (staleConnection) {
|
|
1559
|
+
try {
|
|
1560
|
+
staleConnection.destroy();
|
|
1561
|
+
} catch {
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1452
1564
|
globalTcpConnections.delete(this.connectionId);
|
|
1453
1565
|
request.reject(error);
|
|
1454
1566
|
}
|
|
@@ -1476,16 +1588,8 @@ var QueryEngine = class {
|
|
|
1476
1588
|
});
|
|
1477
1589
|
});
|
|
1478
1590
|
}
|
|
1479
|
-
async executeOnConnection(connection,
|
|
1591
|
+
async executeOnConnection(connection, command) {
|
|
1480
1592
|
return new Promise((resolve5, reject) => {
|
|
1481
|
-
const command = {};
|
|
1482
|
-
for (let i = 0; i < args.length; i += 2) {
|
|
1483
|
-
if (args[i].startsWith("--")) {
|
|
1484
|
-
const key = args[i].substring(2);
|
|
1485
|
-
const value = args[i + 1];
|
|
1486
|
-
command[key] = value;
|
|
1487
|
-
}
|
|
1488
|
-
}
|
|
1489
1593
|
let responseBuffer = "";
|
|
1490
1594
|
let isResolved = false;
|
|
1491
1595
|
const timeout = setTimeout(() => {
|
|
@@ -1498,14 +1602,18 @@ var QueryEngine = class {
|
|
|
1498
1602
|
}, this.timeout);
|
|
1499
1603
|
const onData = (data) => {
|
|
1500
1604
|
responseBuffer += data.toString();
|
|
1501
|
-
|
|
1502
|
-
|
|
1605
|
+
let idx;
|
|
1606
|
+
while ((idx = responseBuffer.indexOf("\n")) !== -1 && !isResolved) {
|
|
1607
|
+
const line = responseBuffer.slice(0, idx);
|
|
1608
|
+
responseBuffer = responseBuffer.slice(idx + 1);
|
|
1609
|
+
const marker = line.indexOf("PROCESS_RESPONSE:");
|
|
1610
|
+
if (marker === -1) continue;
|
|
1503
1611
|
isResolved = true;
|
|
1504
1612
|
clearTimeout(timeout);
|
|
1505
1613
|
connection.removeListener("data", onData);
|
|
1506
1614
|
connection.removeListener("error", onError);
|
|
1507
1615
|
try {
|
|
1508
|
-
const response = JSON.parse(
|
|
1616
|
+
const response = JSON.parse(line.slice(marker + "PROCESS_RESPONSE:".length));
|
|
1509
1617
|
resolve5({
|
|
1510
1618
|
status: response.status,
|
|
1511
1619
|
message: response.message,
|
|
@@ -1527,7 +1635,7 @@ var QueryEngine = class {
|
|
|
1527
1635
|
};
|
|
1528
1636
|
connection.on("data", onData);
|
|
1529
1637
|
connection.on("error", onError);
|
|
1530
|
-
connection.write(JSON.stringify(command));
|
|
1638
|
+
connection.write(JSON.stringify(command) + "\n");
|
|
1531
1639
|
});
|
|
1532
1640
|
}
|
|
1533
1641
|
async createProcess(binary, args) {
|
|
@@ -1554,12 +1662,15 @@ var QueryEngine = class {
|
|
|
1554
1662
|
resolve5(response);
|
|
1555
1663
|
}
|
|
1556
1664
|
};
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1665
|
+
const tryParseLines = (buffer) => {
|
|
1666
|
+
let idx;
|
|
1667
|
+
while ((idx = buffer.indexOf("\n")) !== -1) {
|
|
1668
|
+
const line = buffer.slice(0, idx);
|
|
1669
|
+
buffer = buffer.slice(idx + 1);
|
|
1670
|
+
const marker = line.indexOf("PROCESS_RESPONSE:");
|
|
1671
|
+
if (marker === -1) continue;
|
|
1561
1672
|
try {
|
|
1562
|
-
const response = JSON.parse(
|
|
1673
|
+
const response = JSON.parse(line.slice(marker + "PROCESS_RESPONSE:".length));
|
|
1563
1674
|
resolveOnce({
|
|
1564
1675
|
status: response.status,
|
|
1565
1676
|
message: response.message,
|
|
@@ -1573,26 +1684,13 @@ var QueryEngine = class {
|
|
|
1573
1684
|
});
|
|
1574
1685
|
}
|
|
1575
1686
|
}
|
|
1687
|
+
return buffer;
|
|
1688
|
+
};
|
|
1689
|
+
child.stdout.on("data", (data) => {
|
|
1690
|
+
stdoutBuffer = tryParseLines(stdoutBuffer + data.toString());
|
|
1576
1691
|
});
|
|
1577
1692
|
child.stderr.on("data", (data) => {
|
|
1578
|
-
stderrBuffer
|
|
1579
|
-
const match = stderrBuffer.match(/PROCESS_RESPONSE:(\{.*\})/);
|
|
1580
|
-
if (match) {
|
|
1581
|
-
try {
|
|
1582
|
-
const response = JSON.parse(match[1]);
|
|
1583
|
-
resolveOnce({
|
|
1584
|
-
status: response.status,
|
|
1585
|
-
message: response.message,
|
|
1586
|
-
data: response.data
|
|
1587
|
-
});
|
|
1588
|
-
} catch (error) {
|
|
1589
|
-
resolveOnce({
|
|
1590
|
-
status: 500,
|
|
1591
|
-
message: "Failed to parse response JSON",
|
|
1592
|
-
data: null
|
|
1593
|
-
});
|
|
1594
|
-
}
|
|
1595
|
-
}
|
|
1693
|
+
stderrBuffer = tryParseLines(stderrBuffer + data.toString());
|
|
1596
1694
|
});
|
|
1597
1695
|
child.on("close", (code) => {
|
|
1598
1696
|
clearTimeout(timeoutId);
|
|
@@ -2452,7 +2550,7 @@ var ComputedFieldProcessor = class {
|
|
|
2452
2550
|
const tableExistsQuery = `SELECT name FROM sqlite_master WHERE type='table' AND name='dbcube_computes_config'`;
|
|
2453
2551
|
const tableExistsResult = await DbConfig_default.query(tableExistsQuery);
|
|
2454
2552
|
if (tableExistsResult.status === "success" && tableExistsResult.data && tableExistsResult.data.length > 0) {
|
|
2455
|
-
const queryComputes = await DbConfig_default.
|
|
2553
|
+
const queryComputes = await DbConfig_default.queryWithParameters(`SELECT * FROM dbcube_computes_config WHERE database_ref=?`, [name]);
|
|
2456
2554
|
computedFields = queryComputes.data;
|
|
2457
2555
|
} else {
|
|
2458
2556
|
computedFields = [];
|
|
@@ -2483,21 +2581,10 @@ var ComputedFieldProcessor = class {
|
|
|
2483
2581
|
}
|
|
2484
2582
|
functionBody = functionBody.replace(/@column\(([^)]+)\)/g, (_match, columnName) => {
|
|
2485
2583
|
const cleanColumnName = columnName.trim().replace(/['"]/g, "");
|
|
2486
|
-
|
|
2487
|
-
if (value === null || value === void 0) {
|
|
2488
|
-
return "null";
|
|
2489
|
-
} else if (typeof value === "string") {
|
|
2490
|
-
return `"${value.replace(/"/g, '\\"')}"`;
|
|
2491
|
-
} else if (typeof value === "number" || typeof value === "boolean") {
|
|
2492
|
-
return value.toString();
|
|
2493
|
-
} else if (value instanceof Date) {
|
|
2494
|
-
return `new Date("${value.toISOString()}")`;
|
|
2495
|
-
} else {
|
|
2496
|
-
return JSON.stringify(value);
|
|
2497
|
-
}
|
|
2584
|
+
return `__row[${JSON.stringify(cleanColumnName)}]`;
|
|
2498
2585
|
});
|
|
2499
|
-
const computeFunction = new Function(functionBody);
|
|
2500
|
-
return computeFunction();
|
|
2586
|
+
const computeFunction = new Function("__row", functionBody);
|
|
2587
|
+
return computeFunction(rowData);
|
|
2501
2588
|
} catch (error) {
|
|
2502
2589
|
console.error("Error processing computed field:", error);
|
|
2503
2590
|
return null;
|
|
@@ -2540,14 +2627,7 @@ var ComputedFieldProcessor = class {
|
|
|
2540
2627
|
/@column\(([^)]+)\)/g,
|
|
2541
2628
|
(match, columnName) => {
|
|
2542
2629
|
const cleanColumnName = columnName.replace(/['"]/g, "");
|
|
2543
|
-
|
|
2544
|
-
if (typeof value === "string") {
|
|
2545
|
-
return `"${value}"`;
|
|
2546
|
-
} else if (value === null || value === void 0) {
|
|
2547
|
-
return "null";
|
|
2548
|
-
} else {
|
|
2549
|
-
return String(value);
|
|
2550
|
-
}
|
|
2630
|
+
return `__row[${JSON.stringify(cleanColumnName)}]`;
|
|
2551
2631
|
}
|
|
2552
2632
|
);
|
|
2553
2633
|
const computeMatch = processedExpression.match(/@compute\s*\(\s*\(\s*\)\s*=>\s*\{(.*)\}\s*\)/s);
|
|
@@ -2555,8 +2635,8 @@ var ComputedFieldProcessor = class {
|
|
|
2555
2635
|
throw new Error(`Formato de @compute inv\xE1lido para campo ${fieldName}`);
|
|
2556
2636
|
}
|
|
2557
2637
|
const functionBody = computeMatch[1];
|
|
2558
|
-
const computeFunction = new Function(functionBody);
|
|
2559
|
-
let result = computeFunction();
|
|
2638
|
+
const computeFunction = new Function("__row", functionBody);
|
|
2639
|
+
let result = computeFunction(processedItem);
|
|
2560
2640
|
result = convertToType(result, type2);
|
|
2561
2641
|
processedItem[fieldName] = result;
|
|
2562
2642
|
} catch (error) {
|
|
@@ -2748,14 +2828,14 @@ var TableProcessor = class {
|
|
|
2748
2828
|
if (await DbConfig_default.ifExist()) {
|
|
2749
2829
|
await DbConfig_default.connect();
|
|
2750
2830
|
try {
|
|
2751
|
-
const tableExistsQuery = `SELECT name FROM sqlite_master WHERE type='table' AND name='
|
|
2831
|
+
const tableExistsQuery = `SELECT name FROM sqlite_master WHERE type='table' AND name='dbcube_schemas_config'`;
|
|
2752
2832
|
const tableExistsResult = await DbConfig_default.query(tableExistsQuery);
|
|
2753
2833
|
if (tableExistsResult.status === "success" && tableExistsResult.data && tableExistsResult.data.length > 0) {
|
|
2754
|
-
const queryComputes = await DbConfig_default.
|
|
2834
|
+
const queryComputes = await DbConfig_default.queryWithParameters(`SELECT * FROM dbcube_schemas_config WHERE table_ref=? AND database_ref=?`, [tableName, database_ref]);
|
|
2755
2835
|
const oldQuery = queryComputes.data[0];
|
|
2756
2836
|
if (!oldQuery || !oldQuery.struct) {
|
|
2757
|
-
|
|
2758
|
-
return [];
|
|
2837
|
+
await DbConfig_default.disconnect();
|
|
2838
|
+
return [nowQuery];
|
|
2759
2839
|
}
|
|
2760
2840
|
const nowSchema = parseCreateTableQuery(nowQuery, dbType);
|
|
2761
2841
|
const oldSchema = parseCreateTableQuery(oldQuery.struct, dbType);
|
|
@@ -2790,7 +2870,7 @@ var TableProcessor = class {
|
|
|
2790
2870
|
if (await DbConfig_default.ifExist()) {
|
|
2791
2871
|
await DbConfig_default.connect();
|
|
2792
2872
|
try {
|
|
2793
|
-
await DbConfig_default.
|
|
2873
|
+
await DbConfig_default.queryWithParameters(`DELETE FROM dbcube_schemas_config WHERE table_ref=? AND database_ref=?`, [table_ref, database_ref]);
|
|
2794
2874
|
const tableExistsQuery = `INSERT INTO dbcube_schemas_config (table_ref, database_ref, struct) VALUES (?, ?, ?)`;
|
|
2795
2875
|
await DbConfig_default.queryWithParameters(tableExistsQuery, [table_ref, database_ref, struct]);
|
|
2796
2876
|
} catch (error) {
|
|
@@ -2809,7 +2889,7 @@ var TriggerProcessor = class {
|
|
|
2809
2889
|
const tableExistsQuery = `SELECT name FROM sqlite_master WHERE type='table' AND name='dbcube_triggers_config'`;
|
|
2810
2890
|
const tableExistsResult = await DbConfig_default.query(tableExistsQuery);
|
|
2811
2891
|
if (tableExistsResult.status === "success" && tableExistsResult.data && tableExistsResult.data.length > 0) {
|
|
2812
|
-
const queryComputes = await DbConfig_default.
|
|
2892
|
+
const queryComputes = await DbConfig_default.queryWithParameters(`SELECT * FROM dbcube_triggers_config WHERE database_ref=?`, [name]);
|
|
2813
2893
|
triggers = queryComputes.data;
|
|
2814
2894
|
} else {
|
|
2815
2895
|
triggers = [];
|