@dbcube/core 5.2.2 → 5.2.3
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/bin.cjs +29 -17
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +31 -19
- package/dist/bin.js.map +1 -1
- package/dist/index.cjs +485 -172
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +17 -6
- package/dist/index.d.ts +17 -6
- package/dist/index.js +506 -186
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.cjs
CHANGED
|
@@ -194,7 +194,7 @@ var Downloader = class {
|
|
|
194
194
|
*/
|
|
195
195
|
static async fetchLatestVersion(prefix) {
|
|
196
196
|
const url = this.VERSION_URLS[prefix];
|
|
197
|
-
return new Promise((
|
|
197
|
+
return new Promise((resolve6, reject) => {
|
|
198
198
|
https.get(url, (response) => {
|
|
199
199
|
let data = "";
|
|
200
200
|
response.on("data", (chunk) => {
|
|
@@ -204,7 +204,7 @@ var Downloader = class {
|
|
|
204
204
|
try {
|
|
205
205
|
const versions = JSON.parse(data);
|
|
206
206
|
if (versions && versions.length > 0) {
|
|
207
|
-
|
|
207
|
+
resolve6(versions[0].version);
|
|
208
208
|
} else {
|
|
209
209
|
reject(new Error("No versions found"));
|
|
210
210
|
}
|
|
@@ -413,7 +413,7 @@ var Downloader = class {
|
|
|
413
413
|
if (attempt < maxRetries && (errorMessage.includes("ECONNRESET") || errorMessage.includes("timeout") || errorMessage.includes("ETIMEDOUT") || errorMessage.includes("ENOTFOUND"))) {
|
|
414
414
|
attempt++;
|
|
415
415
|
console.log(`\u{1F504} Retrying ${binary.prefix}-engine (${attempt}/${maxRetries})...`);
|
|
416
|
-
await new Promise((
|
|
416
|
+
await new Promise((resolve6) => setTimeout(resolve6, 1e3 + Math.random() * 1e3));
|
|
417
417
|
} else {
|
|
418
418
|
throw new Error(`Error downloading ${binary.prefix}: ${errorMessage}`);
|
|
419
419
|
}
|
|
@@ -461,12 +461,12 @@ var Downloader = class {
|
|
|
461
461
|
return `[${filledBar}${emptyBar}] ${percentage}`;
|
|
462
462
|
}
|
|
463
463
|
static downloadFileWithProgress(url, outputPath, prefix) {
|
|
464
|
-
return new Promise((
|
|
464
|
+
return new Promise((resolve6, reject) => {
|
|
465
465
|
const request = https.get(url, { timeout: 0 }, (response) => {
|
|
466
466
|
if (response.statusCode === 302 || response.statusCode === 301) {
|
|
467
467
|
const redirectUrl = response.headers.location;
|
|
468
468
|
if (redirectUrl) {
|
|
469
|
-
return this.downloadFileWithProgress(redirectUrl, outputPath, prefix).then(
|
|
469
|
+
return this.downloadFileWithProgress(redirectUrl, outputPath, prefix).then(resolve6).catch(reject);
|
|
470
470
|
}
|
|
471
471
|
}
|
|
472
472
|
if (response.statusCode !== 200) {
|
|
@@ -489,7 +489,7 @@ var Downloader = class {
|
|
|
489
489
|
}
|
|
490
490
|
});
|
|
491
491
|
response.on("end", () => {
|
|
492
|
-
file.end(() =>
|
|
492
|
+
file.end(() => resolve6());
|
|
493
493
|
});
|
|
494
494
|
response.on("error", (err) => {
|
|
495
495
|
file.close();
|
|
@@ -521,35 +521,47 @@ var Downloader = class {
|
|
|
521
521
|
this.mainSpinner.text = `\u{1F4E5} ${import_chalk.default.bold(binary)} - ${progressText}`;
|
|
522
522
|
}
|
|
523
523
|
static extractBinary(zipPath, outputPath, prefix) {
|
|
524
|
-
return new Promise((
|
|
525
|
-
|
|
524
|
+
return new Promise((resolve6, reject) => {
|
|
525
|
+
const outDir = path.dirname(outputPath);
|
|
526
|
+
let extracted = 0;
|
|
527
|
+
const pending = [];
|
|
526
528
|
fs.createReadStream(zipPath).pipe(unzipper.Parse()).on("entry", (entry) => {
|
|
527
|
-
if (entry.type
|
|
528
|
-
|
|
529
|
-
|
|
529
|
+
if (entry.type !== "File") {
|
|
530
|
+
entry.autodrain();
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
const isMain = extracted === 0;
|
|
534
|
+
extracted++;
|
|
535
|
+
const target = isMain ? outputPath : path.join(outDir, path.basename(entry.path));
|
|
536
|
+
pending.push(new Promise((res, rej) => {
|
|
537
|
+
const writeStream = fs.createWriteStream(target);
|
|
530
538
|
entry.pipe(writeStream);
|
|
531
539
|
writeStream.on("finish", () => {
|
|
532
540
|
if (process.platform !== "win32") {
|
|
533
|
-
|
|
541
|
+
try {
|
|
542
|
+
fs.chmodSync(target, 493);
|
|
543
|
+
} catch {
|
|
544
|
+
}
|
|
534
545
|
}
|
|
535
|
-
|
|
536
|
-
resolve5();
|
|
537
|
-
});
|
|
538
|
-
writeStream.on("error", (err) => {
|
|
539
|
-
this.cleanupFile(zipPath);
|
|
540
|
-
reject(err);
|
|
546
|
+
res();
|
|
541
547
|
});
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
}
|
|
548
|
+
writeStream.on("error", rej);
|
|
549
|
+
}));
|
|
545
550
|
}).on("error", (err) => {
|
|
546
551
|
this.cleanupFile(zipPath);
|
|
547
552
|
reject(err);
|
|
548
553
|
}).on("close", () => {
|
|
549
|
-
|
|
554
|
+
Promise.all(pending).then(() => {
|
|
550
555
|
this.cleanupFile(zipPath);
|
|
551
|
-
|
|
552
|
-
|
|
556
|
+
if (extracted === 0) {
|
|
557
|
+
reject(new Error(`No se encontr\xF3 archivo v\xE1lido en el ZIP para ${prefix}`));
|
|
558
|
+
} else {
|
|
559
|
+
resolve6();
|
|
560
|
+
}
|
|
561
|
+
}).catch((err) => {
|
|
562
|
+
this.cleanupFile(zipPath);
|
|
563
|
+
reject(err);
|
|
564
|
+
});
|
|
553
565
|
});
|
|
554
566
|
});
|
|
555
567
|
}
|
|
@@ -864,22 +876,22 @@ var DaemonClient = class _DaemonClient {
|
|
|
864
876
|
child.unref();
|
|
865
877
|
}
|
|
866
878
|
tryConnect(port) {
|
|
867
|
-
return new Promise((
|
|
879
|
+
return new Promise((resolve6) => {
|
|
868
880
|
const socket = import_net.default.createConnection({ host: "127.0.0.1", port }, async () => {
|
|
869
881
|
socket.setNoDelay(true);
|
|
870
882
|
this.attach(socket);
|
|
871
883
|
try {
|
|
872
884
|
const pong = await this.send({ action: "ping" }, 2e3);
|
|
873
|
-
|
|
885
|
+
resolve6(pong.status === 200);
|
|
874
886
|
} catch {
|
|
875
887
|
this.detach();
|
|
876
|
-
|
|
888
|
+
resolve6(false);
|
|
877
889
|
}
|
|
878
890
|
});
|
|
879
|
-
socket.once("error", () =>
|
|
891
|
+
socket.once("error", () => resolve6(false));
|
|
880
892
|
socket.setTimeout(3e3, () => {
|
|
881
893
|
socket.destroy();
|
|
882
|
-
|
|
894
|
+
resolve6(false);
|
|
883
895
|
});
|
|
884
896
|
});
|
|
885
897
|
}
|
|
@@ -927,7 +939,7 @@ var DaemonClient = class _DaemonClient {
|
|
|
927
939
|
* single socket, so pending requests resolve in send order.
|
|
928
940
|
*/
|
|
929
941
|
send(payload, timeoutMs) {
|
|
930
|
-
return new Promise((
|
|
942
|
+
return new Promise((resolve6, reject) => {
|
|
931
943
|
if (!this.socket || this.socket.destroyed) {
|
|
932
944
|
reject(new Error("Daemon not connected"));
|
|
933
945
|
return;
|
|
@@ -938,12 +950,12 @@ var DaemonClient = class _DaemonClient {
|
|
|
938
950
|
reject(new Error("Daemon request timeout"));
|
|
939
951
|
this.detach();
|
|
940
952
|
}, timeoutMs ?? this.requestTimeout);
|
|
941
|
-
this.pending.push({ resolve:
|
|
953
|
+
this.pending.push({ resolve: resolve6, reject, timer });
|
|
942
954
|
this.socket.write(JSON.stringify(payload) + "\n");
|
|
943
955
|
});
|
|
944
956
|
}
|
|
945
957
|
async execute(dml, txId) {
|
|
946
|
-
const payload = { action: "execute", dml
|
|
958
|
+
const payload = { action: "execute", dml };
|
|
947
959
|
if (txId) payload.tx_id = txId;
|
|
948
960
|
return this.send(payload);
|
|
949
961
|
}
|
|
@@ -1010,8 +1022,8 @@ var Engine = class {
|
|
|
1010
1022
|
const binaryPath = this.binary["query_engine"];
|
|
1011
1023
|
if (!binaryPath) return null;
|
|
1012
1024
|
const client = DaemonClient.get(this.name, binaryPath, this.arguments);
|
|
1013
|
-
const
|
|
1014
|
-
if (!
|
|
1025
|
+
const ok2 = await client.ensure();
|
|
1026
|
+
if (!ok2) {
|
|
1015
1027
|
this.daemonFailed = true;
|
|
1016
1028
|
return null;
|
|
1017
1029
|
}
|
|
@@ -1142,7 +1154,7 @@ var Engine = class {
|
|
|
1142
1154
|
if (!this.binary) {
|
|
1143
1155
|
throw new Error("Binary not initialized");
|
|
1144
1156
|
}
|
|
1145
|
-
return new Promise((
|
|
1157
|
+
return new Promise((resolve6, reject) => {
|
|
1146
1158
|
const child = (0, import_child_process2.spawn)(this.binary[binary], [...this.arguments, ...args]);
|
|
1147
1159
|
let stdoutBuffer = "";
|
|
1148
1160
|
let stderrBuffer = "";
|
|
@@ -1158,7 +1170,7 @@ var Engine = class {
|
|
|
1158
1170
|
if (!isResolved) {
|
|
1159
1171
|
isResolved = true;
|
|
1160
1172
|
clearTimeout(timeoutId);
|
|
1161
|
-
|
|
1173
|
+
resolve6(response);
|
|
1162
1174
|
}
|
|
1163
1175
|
};
|
|
1164
1176
|
const tryParseLines = (buffer) => {
|
|
@@ -1224,13 +1236,264 @@ var Engine = class {
|
|
|
1224
1236
|
|
|
1225
1237
|
// src/lib/QueryEngine.ts
|
|
1226
1238
|
var import_path5 = __toESM(require("path"));
|
|
1239
|
+
|
|
1240
|
+
// src/lib/EmbeddedEngine.ts
|
|
1241
|
+
var fs4 = __toESM(require("fs"));
|
|
1242
|
+
var path5 = __toESM(require("path"));
|
|
1243
|
+
if (!process.env.UV_THREADPOOL_SIZE) {
|
|
1244
|
+
process.env.UV_THREADPOOL_SIZE = "16";
|
|
1245
|
+
}
|
|
1246
|
+
var backend = null;
|
|
1247
|
+
var loadFailed = false;
|
|
1248
|
+
var handles = /* @__PURE__ */ new Map();
|
|
1249
|
+
var connecting = /* @__PURE__ */ new Map();
|
|
1250
|
+
function platTag() {
|
|
1251
|
+
const arch2 = process.arch === "arm64" ? "arm64" : "x64";
|
|
1252
|
+
if (process.platform === "win32") return { plat: "windows", ext: "dll", arch: arch2 };
|
|
1253
|
+
if (process.platform === "darwin") return { plat: "macos", ext: "dylib", arch: arch2 };
|
|
1254
|
+
return { plat: "linux", ext: "so", arch: arch2 };
|
|
1255
|
+
}
|
|
1256
|
+
function findFile(name) {
|
|
1257
|
+
const candidates = [
|
|
1258
|
+
path5.resolve(process.cwd(), ".dbcube", "bin", name),
|
|
1259
|
+
path5.resolve(process.cwd(), "node_modules", ".dbcube", "bin", name)
|
|
1260
|
+
];
|
|
1261
|
+
for (const c of candidates) {
|
|
1262
|
+
if (fs4.existsSync(c)) return c;
|
|
1263
|
+
}
|
|
1264
|
+
return null;
|
|
1265
|
+
}
|
|
1266
|
+
function ok(data) {
|
|
1267
|
+
return { status: 200, message: "OK", data };
|
|
1268
|
+
}
|
|
1269
|
+
function errResp(e) {
|
|
1270
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1271
|
+
return { status: 500, message: msg, data: null };
|
|
1272
|
+
}
|
|
1273
|
+
function loadNapiBackend() {
|
|
1274
|
+
const { plat, arch: arch2 } = platTag();
|
|
1275
|
+
const addonPath = findFile(`query-engine-node-${plat}-${arch2}.node`);
|
|
1276
|
+
if (!addonPath) return null;
|
|
1277
|
+
try {
|
|
1278
|
+
const addon = require(addonPath);
|
|
1279
|
+
if (typeof addon.connect !== "function") return null;
|
|
1280
|
+
return {
|
|
1281
|
+
async connect(cfgJson) {
|
|
1282
|
+
return Number(await addon.connect(cfgJson));
|
|
1283
|
+
},
|
|
1284
|
+
async execute(handle, dml, txId) {
|
|
1285
|
+
try {
|
|
1286
|
+
const rows = await addon.execute(handle, dml, txId ?? void 0);
|
|
1287
|
+
return ok(rows);
|
|
1288
|
+
} catch (e) {
|
|
1289
|
+
return errResp(e);
|
|
1290
|
+
}
|
|
1291
|
+
},
|
|
1292
|
+
async executeBatch(handle, ops) {
|
|
1293
|
+
try {
|
|
1294
|
+
const results = await addon.executeBatch(handle, ops);
|
|
1295
|
+
return ok(results);
|
|
1296
|
+
} catch (e) {
|
|
1297
|
+
return errResp(e);
|
|
1298
|
+
}
|
|
1299
|
+
},
|
|
1300
|
+
async raw(handle, query, params, txId) {
|
|
1301
|
+
try {
|
|
1302
|
+
const rows = await addon.raw(handle, query, params, txId ?? void 0);
|
|
1303
|
+
return ok(rows);
|
|
1304
|
+
} catch (e) {
|
|
1305
|
+
return errResp(e);
|
|
1306
|
+
}
|
|
1307
|
+
},
|
|
1308
|
+
async begin(handle) {
|
|
1309
|
+
try {
|
|
1310
|
+
const txId = await addon.begin(handle);
|
|
1311
|
+
return ok({ tx_id: txId });
|
|
1312
|
+
} catch (e) {
|
|
1313
|
+
return errResp(e);
|
|
1314
|
+
}
|
|
1315
|
+
},
|
|
1316
|
+
async commit(_handle, txId) {
|
|
1317
|
+
try {
|
|
1318
|
+
await addon.commit(txId);
|
|
1319
|
+
return ok(null);
|
|
1320
|
+
} catch (e) {
|
|
1321
|
+
return errResp(e);
|
|
1322
|
+
}
|
|
1323
|
+
},
|
|
1324
|
+
async rollback(_handle, txId) {
|
|
1325
|
+
try {
|
|
1326
|
+
await addon.rollback(txId);
|
|
1327
|
+
return ok(null);
|
|
1328
|
+
} catch (e) {
|
|
1329
|
+
return errResp(e);
|
|
1330
|
+
}
|
|
1331
|
+
},
|
|
1332
|
+
async disconnect(handle) {
|
|
1333
|
+
try {
|
|
1334
|
+
addon.disconnect(handle);
|
|
1335
|
+
} catch {
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
};
|
|
1339
|
+
} catch {
|
|
1340
|
+
return null;
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
function loadKoffiBackend() {
|
|
1344
|
+
const { plat, ext, arch: arch2 } = platTag();
|
|
1345
|
+
const libPath = findFile(`query-engine-embedded-${plat}-${arch2}.${ext}`);
|
|
1346
|
+
if (!libPath) return null;
|
|
1347
|
+
try {
|
|
1348
|
+
const koffi = require("koffi");
|
|
1349
|
+
const lib = koffi.load(libPath);
|
|
1350
|
+
const cConnect = lib.func("dbc_connect", "void *", ["str"]);
|
|
1351
|
+
const cExecute = lib.func("dbc_execute", "void *", ["uint64", "str", "str"]);
|
|
1352
|
+
const cExecuteBatch = lib.func("dbc_execute_batch", "void *", ["uint64", "str"]);
|
|
1353
|
+
const cRaw = lib.func("dbc_raw", "void *", ["uint64", "str", "str", "str"]);
|
|
1354
|
+
const cBegin = lib.func("dbc_begin", "void *", ["uint64"]);
|
|
1355
|
+
const cCommit = lib.func("dbc_commit", "void *", ["uint64", "str"]);
|
|
1356
|
+
const cRollback = lib.func("dbc_rollback", "void *", ["uint64", "str"]);
|
|
1357
|
+
const cDisconnect = lib.func("dbc_disconnect", "void *", ["uint64"]);
|
|
1358
|
+
const cFree = lib.func("dbc_free", "void", ["void *"]);
|
|
1359
|
+
const take = (ptr) => {
|
|
1360
|
+
if (!ptr) return { status: 500, message: "embedded engine returned null", data: null };
|
|
1361
|
+
const s = koffi.decode(ptr, "char", -1);
|
|
1362
|
+
cFree(ptr);
|
|
1363
|
+
try {
|
|
1364
|
+
const r = JSON.parse(s);
|
|
1365
|
+
return { status: r.status ?? 500, message: r.message ?? "", data: r.data ?? null };
|
|
1366
|
+
} catch (e) {
|
|
1367
|
+
return { status: 500, message: `Invalid embedded response: ${e.message}`, data: null };
|
|
1368
|
+
}
|
|
1369
|
+
};
|
|
1370
|
+
const call = (fn, ...args) => new Promise((resolve6, reject) => {
|
|
1371
|
+
fn.async(...args, (err, ptr) => {
|
|
1372
|
+
if (err) return reject(err);
|
|
1373
|
+
resolve6(take(ptr));
|
|
1374
|
+
});
|
|
1375
|
+
});
|
|
1376
|
+
return {
|
|
1377
|
+
async connect(cfgJson) {
|
|
1378
|
+
const res = await call(cConnect, cfgJson);
|
|
1379
|
+
if (res.status !== 200 || !res.data?.handle) {
|
|
1380
|
+
throw new Error(String(res.message || "embedded connect failed"));
|
|
1381
|
+
}
|
|
1382
|
+
return Number(res.data.handle);
|
|
1383
|
+
},
|
|
1384
|
+
execute: (handle, dml, txId) => call(cExecute, handle, JSON.stringify(dml), txId),
|
|
1385
|
+
executeBatch: (handle, ops) => call(cExecuteBatch, handle, JSON.stringify(ops)),
|
|
1386
|
+
raw: (handle, query, params, txId) => call(cRaw, handle, query, JSON.stringify(params ?? []), txId),
|
|
1387
|
+
begin: (handle) => call(cBegin, handle),
|
|
1388
|
+
commit: (handle, txId) => call(cCommit, handle, txId),
|
|
1389
|
+
rollback: (handle, txId) => call(cRollback, handle, txId),
|
|
1390
|
+
async disconnect(handle) {
|
|
1391
|
+
try {
|
|
1392
|
+
await call(cDisconnect, handle);
|
|
1393
|
+
} catch {
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
};
|
|
1397
|
+
} catch {
|
|
1398
|
+
return null;
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
function loadBackend() {
|
|
1402
|
+
if (backend) return backend;
|
|
1403
|
+
if (loadFailed) return null;
|
|
1404
|
+
if (process.env.DBCUBE_EMBEDDED === "0" || process.env.DBCUBE_EMBEDDED === "false") {
|
|
1405
|
+
loadFailed = true;
|
|
1406
|
+
return null;
|
|
1407
|
+
}
|
|
1408
|
+
backend = loadNapiBackend() ?? loadKoffiBackend();
|
|
1409
|
+
if (!backend) loadFailed = true;
|
|
1410
|
+
return backend;
|
|
1411
|
+
}
|
|
1412
|
+
var EmbeddedEngine = class {
|
|
1413
|
+
/** true si algún backend nativo está disponible en esta instalación. */
|
|
1414
|
+
static available() {
|
|
1415
|
+
return loadBackend() !== null;
|
|
1416
|
+
}
|
|
1417
|
+
static async handleFor(connectionId, config) {
|
|
1418
|
+
const existing = handles.get(connectionId);
|
|
1419
|
+
if (existing) return existing;
|
|
1420
|
+
const inFlight = connecting.get(connectionId);
|
|
1421
|
+
if (inFlight) return inFlight;
|
|
1422
|
+
const promise = (async () => {
|
|
1423
|
+
const be = loadBackend();
|
|
1424
|
+
if (!be) throw new Error("embedded engine not available");
|
|
1425
|
+
const motor = config.type === "postgres" ? "postgresql" : config.type;
|
|
1426
|
+
const cfg = {
|
|
1427
|
+
databaseRef: connectionId,
|
|
1428
|
+
motor,
|
|
1429
|
+
database: config.type === "sqlite" ? `${config.config.DATABASE}.db` : config.config.DATABASE,
|
|
1430
|
+
host: config.config.HOST,
|
|
1431
|
+
port: config.config.PORT != null ? Number(config.config.PORT) : void 0,
|
|
1432
|
+
user: config.config.USER,
|
|
1433
|
+
password: config.config.PASSWORD,
|
|
1434
|
+
maxConnections: config.pool?.maxConnections,
|
|
1435
|
+
minConnections: config.pool?.minConnections,
|
|
1436
|
+
acquireTimeoutMs: config.pool?.acquireTimeoutMs,
|
|
1437
|
+
idleTimeoutMs: config.pool?.idleTimeoutMs
|
|
1438
|
+
};
|
|
1439
|
+
const handle = await be.connect(JSON.stringify(cfg));
|
|
1440
|
+
handles.set(connectionId, handle);
|
|
1441
|
+
return handle;
|
|
1442
|
+
})();
|
|
1443
|
+
connecting.set(connectionId, promise);
|
|
1444
|
+
try {
|
|
1445
|
+
return await promise;
|
|
1446
|
+
} finally {
|
|
1447
|
+
connecting.delete(connectionId);
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
static async executeDml(connectionId, config, dml, txId) {
|
|
1451
|
+
const be = loadBackend();
|
|
1452
|
+
const handle = await this.handleFor(connectionId, config);
|
|
1453
|
+
return be.execute(handle, dml, txId ?? null);
|
|
1454
|
+
}
|
|
1455
|
+
static async executeBatch(connectionId, config, ops) {
|
|
1456
|
+
const be = loadBackend();
|
|
1457
|
+
const handle = await this.handleFor(connectionId, config);
|
|
1458
|
+
return be.executeBatch(handle, ops);
|
|
1459
|
+
}
|
|
1460
|
+
static async rawQuery(connectionId, config, query, params, txId) {
|
|
1461
|
+
const be = loadBackend();
|
|
1462
|
+
const handle = await this.handleFor(connectionId, config);
|
|
1463
|
+
return be.raw(handle, query, params ?? [], txId ?? null);
|
|
1464
|
+
}
|
|
1465
|
+
static async begin(connectionId, config) {
|
|
1466
|
+
const be = loadBackend();
|
|
1467
|
+
const handle = await this.handleFor(connectionId, config);
|
|
1468
|
+
return be.begin(handle);
|
|
1469
|
+
}
|
|
1470
|
+
static async commit(connectionId, config, txId) {
|
|
1471
|
+
const be = loadBackend();
|
|
1472
|
+
const handle = await this.handleFor(connectionId, config);
|
|
1473
|
+
return be.commit(handle, txId);
|
|
1474
|
+
}
|
|
1475
|
+
static async rollback(connectionId, config, txId) {
|
|
1476
|
+
const be = loadBackend();
|
|
1477
|
+
const handle = await this.handleFor(connectionId, config);
|
|
1478
|
+
return be.rollback(handle, txId);
|
|
1479
|
+
}
|
|
1480
|
+
static async disconnect(connectionId) {
|
|
1481
|
+
const be = loadBackend();
|
|
1482
|
+
const handle = handles.get(connectionId);
|
|
1483
|
+
if (be && handle) {
|
|
1484
|
+
handles.delete(connectionId);
|
|
1485
|
+
await be.disconnect(handle);
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
};
|
|
1489
|
+
|
|
1490
|
+
// src/lib/QueryEngine.ts
|
|
1227
1491
|
var import_module2 = require("module");
|
|
1228
1492
|
var net2 = __toESM(require("net"));
|
|
1229
1493
|
var import_child_process3 = require("child_process");
|
|
1230
1494
|
var globalTcpServers = /* @__PURE__ */ new Map();
|
|
1231
|
-
var
|
|
1232
|
-
var
|
|
1233
|
-
var connectionProcessing = /* @__PURE__ */ new Map();
|
|
1495
|
+
var socketPools = /* @__PURE__ */ new Map();
|
|
1496
|
+
var CLIENT_POOL_SIZE = 10;
|
|
1234
1497
|
var queryCache = /* @__PURE__ */ new Map();
|
|
1235
1498
|
var MAX_CACHE_SIZE = 500;
|
|
1236
1499
|
var QueryEngine = class {
|
|
@@ -1261,12 +1524,12 @@ var QueryEngine = class {
|
|
|
1261
1524
|
throw new Error("No available ports found in range 9900-9944");
|
|
1262
1525
|
}
|
|
1263
1526
|
isPortAvailable(port) {
|
|
1264
|
-
return new Promise((
|
|
1527
|
+
return new Promise((resolve6) => {
|
|
1265
1528
|
const tester = net2.createServer();
|
|
1266
|
-
tester.once("error", () =>
|
|
1529
|
+
tester.once("error", () => resolve6(false));
|
|
1267
1530
|
tester.once("listening", () => {
|
|
1268
1531
|
tester.close();
|
|
1269
|
-
|
|
1532
|
+
resolve6(true);
|
|
1270
1533
|
});
|
|
1271
1534
|
tester.listen(port, "127.0.0.1");
|
|
1272
1535
|
});
|
|
@@ -1373,38 +1636,79 @@ var QueryEngine = class {
|
|
|
1373
1636
|
}
|
|
1374
1637
|
return command;
|
|
1375
1638
|
}
|
|
1639
|
+
/** El motor embebido (FFI) es el camino por defecto cuando la librería
|
|
1640
|
+
* nativa está disponible; el daemon TCP queda como fallback y como modo
|
|
1641
|
+
* multi-proceso explícito. */
|
|
1642
|
+
useEmbedded() {
|
|
1643
|
+
return EmbeddedEngine.available();
|
|
1644
|
+
}
|
|
1376
1645
|
/**
|
|
1377
|
-
* Executes a DML plan
|
|
1646
|
+
* Executes a DML plan. Embedded engine when available (in-process FFI,
|
|
1647
|
+
* no network hop); persistent TCP daemon otherwise.
|
|
1378
1648
|
* Pass txId to run it inside an active transaction.
|
|
1379
1649
|
*/
|
|
1380
1650
|
async executeDml(dml, txId) {
|
|
1381
|
-
|
|
1651
|
+
if (this.useEmbedded()) {
|
|
1652
|
+
return EmbeddedEngine.executeDml(this.connectionId, this.config, dml, txId);
|
|
1653
|
+
}
|
|
1654
|
+
const command = { action: "execute", dml };
|
|
1382
1655
|
if (txId) command.tx_id = txId;
|
|
1383
1656
|
return this.executeWithTcpServer(command);
|
|
1384
1657
|
}
|
|
1385
1658
|
/**
|
|
1386
|
-
*
|
|
1387
|
-
* over the
|
|
1659
|
+
* Atomic batch: N write plans inside one transaction with a single
|
|
1660
|
+
* engine round-trip. Falls back to begin/ops/commit over the daemon
|
|
1661
|
+
* when the embedded engine is not available.
|
|
1662
|
+
*/
|
|
1663
|
+
async executeBatch(ops) {
|
|
1664
|
+
if (this.useEmbedded()) {
|
|
1665
|
+
return EmbeddedEngine.executeBatch(this.connectionId, this.config, ops);
|
|
1666
|
+
}
|
|
1667
|
+
const txId = await this.beginTransaction();
|
|
1668
|
+
try {
|
|
1669
|
+
const results = [];
|
|
1670
|
+
for (const op of ops) {
|
|
1671
|
+
const res = await this.executeDml(op, txId);
|
|
1672
|
+
if (res.status !== 200) {
|
|
1673
|
+
throw new Error(String(res.message));
|
|
1674
|
+
}
|
|
1675
|
+
results.push(res.data);
|
|
1676
|
+
}
|
|
1677
|
+
await this.commitTransaction(txId);
|
|
1678
|
+
return { status: 200, message: "Batch committed", data: results };
|
|
1679
|
+
} catch (error) {
|
|
1680
|
+
try {
|
|
1681
|
+
await this.rollbackTransaction(txId);
|
|
1682
|
+
} catch {
|
|
1683
|
+
}
|
|
1684
|
+
return { status: 500, message: error?.message ?? String(error), data: null };
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
/**
|
|
1688
|
+
* Executes raw SQL (or a MongoDB command document) with bound parameters.
|
|
1388
1689
|
*/
|
|
1389
1690
|
async rawQuery(query, params = [], txId) {
|
|
1691
|
+
if (this.useEmbedded()) {
|
|
1692
|
+
return EmbeddedEngine.rawQuery(this.connectionId, this.config, query, params, txId);
|
|
1693
|
+
}
|
|
1390
1694
|
const command = { action: "raw", query, params };
|
|
1391
1695
|
if (txId) command.tx_id = txId;
|
|
1392
1696
|
return this.executeWithTcpServer(command);
|
|
1393
1697
|
}
|
|
1394
|
-
/** Starts a
|
|
1698
|
+
/** Starts a transaction and returns its id. */
|
|
1395
1699
|
async beginTransaction() {
|
|
1396
|
-
const res = await this.executeWithTcpServer({ action: "begin" });
|
|
1700
|
+
const res = this.useEmbedded() ? await EmbeddedEngine.begin(this.connectionId, this.config) : await this.executeWithTcpServer({ action: "begin" });
|
|
1397
1701
|
if (res.status !== 200 || !res.data?.tx_id) {
|
|
1398
1702
|
throw new Error(String(res.message || "Failed to begin transaction (update the query-engine binary: npx dbcube update)"));
|
|
1399
1703
|
}
|
|
1400
1704
|
return res.data.tx_id;
|
|
1401
1705
|
}
|
|
1402
1706
|
async commitTransaction(txId) {
|
|
1403
|
-
const res = await this.executeWithTcpServer({ action: "commit", tx_id: txId });
|
|
1707
|
+
const res = this.useEmbedded() ? await EmbeddedEngine.commit(this.connectionId, this.config, txId) : await this.executeWithTcpServer({ action: "commit", tx_id: txId });
|
|
1404
1708
|
if (res.status !== 200) throw new Error(String(res.message || "Failed to commit transaction"));
|
|
1405
1709
|
}
|
|
1406
1710
|
async rollbackTransaction(txId) {
|
|
1407
|
-
const res = await this.executeWithTcpServer({ action: "rollback", tx_id: txId });
|
|
1711
|
+
const res = this.useEmbedded() ? await EmbeddedEngine.rollback(this.connectionId, this.config, txId) : await this.executeWithTcpServer({ action: "rollback", tx_id: txId });
|
|
1408
1712
|
if (res.status !== 200) throw new Error(String(res.message || "Failed to rollback transaction"));
|
|
1409
1713
|
}
|
|
1410
1714
|
async executeWithTcpServer(command) {
|
|
@@ -1423,7 +1727,63 @@ var QueryEngine = class {
|
|
|
1423
1727
|
await this.startTcpServer();
|
|
1424
1728
|
await this.waitForServerReady();
|
|
1425
1729
|
}
|
|
1426
|
-
|
|
1730
|
+
const port = globalTcpServers.get(this.connectionId).port;
|
|
1731
|
+
const socket = await this.acquireSocket(port);
|
|
1732
|
+
try {
|
|
1733
|
+
const result = await this.executeOnConnection(socket, command);
|
|
1734
|
+
this.releaseSocket(socket, false);
|
|
1735
|
+
return result;
|
|
1736
|
+
} catch (error) {
|
|
1737
|
+
this.releaseSocket(socket, true);
|
|
1738
|
+
throw error;
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
poolFor() {
|
|
1742
|
+
let pool = socketPools.get(this.connectionId);
|
|
1743
|
+
if (!pool) {
|
|
1744
|
+
pool = { free: [], total: 0, waiters: [] };
|
|
1745
|
+
socketPools.set(this.connectionId, pool);
|
|
1746
|
+
}
|
|
1747
|
+
return pool;
|
|
1748
|
+
}
|
|
1749
|
+
async acquireSocket(port) {
|
|
1750
|
+
const pool = this.poolFor();
|
|
1751
|
+
while (pool.free.length > 0) {
|
|
1752
|
+
const s = pool.free.pop();
|
|
1753
|
+
if (!s.destroyed) return s;
|
|
1754
|
+
pool.total--;
|
|
1755
|
+
}
|
|
1756
|
+
if (pool.total < CLIENT_POOL_SIZE) {
|
|
1757
|
+
pool.total++;
|
|
1758
|
+
try {
|
|
1759
|
+
return await this.createNewConnection(port);
|
|
1760
|
+
} catch (e) {
|
|
1761
|
+
pool.total--;
|
|
1762
|
+
throw e;
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
return new Promise((resolve6) => pool.waiters.push(resolve6));
|
|
1766
|
+
}
|
|
1767
|
+
releaseSocket(socket, broken) {
|
|
1768
|
+
const pool = socketPools.get(this.connectionId);
|
|
1769
|
+
if (!pool) {
|
|
1770
|
+
socket.destroy();
|
|
1771
|
+
return;
|
|
1772
|
+
}
|
|
1773
|
+
if (broken || socket.destroyed) {
|
|
1774
|
+
pool.total--;
|
|
1775
|
+
try {
|
|
1776
|
+
socket.destroy();
|
|
1777
|
+
} catch {
|
|
1778
|
+
}
|
|
1779
|
+
return;
|
|
1780
|
+
}
|
|
1781
|
+
const waiter = pool.waiters.shift();
|
|
1782
|
+
if (waiter) {
|
|
1783
|
+
waiter(socket);
|
|
1784
|
+
} else {
|
|
1785
|
+
pool.free.push(socket);
|
|
1786
|
+
}
|
|
1427
1787
|
}
|
|
1428
1788
|
async waitForServerReady() {
|
|
1429
1789
|
const maxRetries = 10;
|
|
@@ -1441,25 +1801,25 @@ var QueryEngine = class {
|
|
|
1441
1801
|
throw new Error("TCP server failed to become ready within timeout");
|
|
1442
1802
|
}
|
|
1443
1803
|
async isServerResponding(port) {
|
|
1444
|
-
return new Promise((
|
|
1804
|
+
return new Promise((resolve6) => {
|
|
1445
1805
|
const client = new net2.Socket();
|
|
1446
1806
|
const timeout = setTimeout(() => {
|
|
1447
1807
|
client.destroy();
|
|
1448
|
-
|
|
1808
|
+
resolve6(false);
|
|
1449
1809
|
}, 1e3);
|
|
1450
1810
|
client.connect(port, "127.0.0.1", () => {
|
|
1451
1811
|
clearTimeout(timeout);
|
|
1452
1812
|
client.destroy();
|
|
1453
|
-
|
|
1813
|
+
resolve6(true);
|
|
1454
1814
|
});
|
|
1455
1815
|
client.on("error", () => {
|
|
1456
1816
|
clearTimeout(timeout);
|
|
1457
|
-
|
|
1817
|
+
resolve6(false);
|
|
1458
1818
|
});
|
|
1459
1819
|
});
|
|
1460
1820
|
}
|
|
1461
1821
|
sleep(ms) {
|
|
1462
|
-
return new Promise((
|
|
1822
|
+
return new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
1463
1823
|
}
|
|
1464
1824
|
getCachedDML(dmlJson) {
|
|
1465
1825
|
if (queryCache.has(dmlJson)) {
|
|
@@ -1479,7 +1839,7 @@ var QueryEngine = class {
|
|
|
1479
1839
|
throw new Error("Binary not initialized");
|
|
1480
1840
|
}
|
|
1481
1841
|
this.tcpPort = await this.findAvailablePort(this.tcpPort);
|
|
1482
|
-
return new Promise((
|
|
1842
|
+
return new Promise((resolve6, reject) => {
|
|
1483
1843
|
const serverArgs = [...this.arguments, "--action", "server", "--tcp-port", this.tcpPort.toString()];
|
|
1484
1844
|
const serverProcess = (0, import_child_process3.spawn)(this.binary["query_engine"], serverArgs);
|
|
1485
1845
|
let started = false;
|
|
@@ -1499,7 +1859,7 @@ var QueryEngine = class {
|
|
|
1499
1859
|
port: this.tcpPort,
|
|
1500
1860
|
process: serverProcess
|
|
1501
1861
|
});
|
|
1502
|
-
|
|
1862
|
+
resolve6();
|
|
1503
1863
|
}
|
|
1504
1864
|
}
|
|
1505
1865
|
});
|
|
@@ -1517,60 +1877,8 @@ var QueryEngine = class {
|
|
|
1517
1877
|
});
|
|
1518
1878
|
});
|
|
1519
1879
|
}
|
|
1520
|
-
async sendTcpRequestFast(command) {
|
|
1521
|
-
return new Promise((resolve5, reject) => {
|
|
1522
|
-
let queue = connectionQueues.get(this.connectionId);
|
|
1523
|
-
if (!queue) {
|
|
1524
|
-
queue = [];
|
|
1525
|
-
connectionQueues.set(this.connectionId, queue);
|
|
1526
|
-
}
|
|
1527
|
-
queue.push({ command, resolve: resolve5, reject });
|
|
1528
|
-
this.processQueue();
|
|
1529
|
-
});
|
|
1530
|
-
}
|
|
1531
|
-
async processQueue() {
|
|
1532
|
-
if (connectionProcessing.get(this.connectionId)) {
|
|
1533
|
-
return;
|
|
1534
|
-
}
|
|
1535
|
-
const queue = connectionQueues.get(this.connectionId);
|
|
1536
|
-
if (!queue || queue.length === 0) {
|
|
1537
|
-
return;
|
|
1538
|
-
}
|
|
1539
|
-
connectionProcessing.set(this.connectionId, true);
|
|
1540
|
-
try {
|
|
1541
|
-
const serverInfo = globalTcpServers.get(this.connectionId);
|
|
1542
|
-
if (!serverInfo) {
|
|
1543
|
-
throw new Error("Server not initialized");
|
|
1544
|
-
}
|
|
1545
|
-
while (queue.length > 0) {
|
|
1546
|
-
const request = queue.shift();
|
|
1547
|
-
if (!request) break;
|
|
1548
|
-
try {
|
|
1549
|
-
let connection = globalTcpConnections.get(this.connectionId);
|
|
1550
|
-
if (!connection || connection.destroyed || connection.readyState !== "open") {
|
|
1551
|
-
connection = await this.createNewConnection(serverInfo.port);
|
|
1552
|
-
globalTcpConnections.set(this.connectionId, connection);
|
|
1553
|
-
}
|
|
1554
|
-
const result = await this.executeOnConnection(connection, request.command);
|
|
1555
|
-
request.resolve(result);
|
|
1556
|
-
} catch (error) {
|
|
1557
|
-
const staleConnection = globalTcpConnections.get(this.connectionId);
|
|
1558
|
-
if (staleConnection) {
|
|
1559
|
-
try {
|
|
1560
|
-
staleConnection.destroy();
|
|
1561
|
-
} catch {
|
|
1562
|
-
}
|
|
1563
|
-
}
|
|
1564
|
-
globalTcpConnections.delete(this.connectionId);
|
|
1565
|
-
request.reject(error);
|
|
1566
|
-
}
|
|
1567
|
-
}
|
|
1568
|
-
} finally {
|
|
1569
|
-
connectionProcessing.set(this.connectionId, false);
|
|
1570
|
-
}
|
|
1571
|
-
}
|
|
1572
1880
|
async createNewConnection(port) {
|
|
1573
|
-
return new Promise((
|
|
1881
|
+
return new Promise((resolve6, reject) => {
|
|
1574
1882
|
const client = new net2.Socket();
|
|
1575
1883
|
client.setNoDelay(true);
|
|
1576
1884
|
client.setKeepAlive(true, 6e4);
|
|
@@ -1580,7 +1888,7 @@ var QueryEngine = class {
|
|
|
1580
1888
|
}, 5e3);
|
|
1581
1889
|
client.connect(port, "127.0.0.1", () => {
|
|
1582
1890
|
clearTimeout(timeout);
|
|
1583
|
-
|
|
1891
|
+
resolve6(client);
|
|
1584
1892
|
});
|
|
1585
1893
|
client.on("error", (error) => {
|
|
1586
1894
|
clearTimeout(timeout);
|
|
@@ -1589,7 +1897,7 @@ var QueryEngine = class {
|
|
|
1589
1897
|
});
|
|
1590
1898
|
}
|
|
1591
1899
|
async executeOnConnection(connection, command) {
|
|
1592
|
-
return new Promise((
|
|
1900
|
+
return new Promise((resolve6, reject) => {
|
|
1593
1901
|
let responseBuffer = "";
|
|
1594
1902
|
let isResolved = false;
|
|
1595
1903
|
const timeout = setTimeout(() => {
|
|
@@ -1614,7 +1922,7 @@ var QueryEngine = class {
|
|
|
1614
1922
|
connection.removeListener("error", onError);
|
|
1615
1923
|
try {
|
|
1616
1924
|
const response = JSON.parse(line.slice(marker + "PROCESS_RESPONSE:".length));
|
|
1617
|
-
|
|
1925
|
+
resolve6({
|
|
1618
1926
|
status: response.status,
|
|
1619
1927
|
message: response.message,
|
|
1620
1928
|
data: response.data
|
|
@@ -1643,7 +1951,7 @@ var QueryEngine = class {
|
|
|
1643
1951
|
if (!this.binary) {
|
|
1644
1952
|
throw new Error("Binary not initialized");
|
|
1645
1953
|
}
|
|
1646
|
-
return new Promise((
|
|
1954
|
+
return new Promise((resolve6, reject) => {
|
|
1647
1955
|
const child = (0, import_child_process3.spawn)(this.binary[binary], [...this.arguments, ...args]);
|
|
1648
1956
|
let stdoutBuffer = "";
|
|
1649
1957
|
let stderrBuffer = "";
|
|
@@ -1659,7 +1967,7 @@ var QueryEngine = class {
|
|
|
1659
1967
|
if (!isResolved) {
|
|
1660
1968
|
isResolved = true;
|
|
1661
1969
|
clearTimeout(timeoutId);
|
|
1662
|
-
|
|
1970
|
+
resolve6(response);
|
|
1663
1971
|
}
|
|
1664
1972
|
};
|
|
1665
1973
|
const tryParseLines = (buffer) => {
|
|
@@ -1716,11 +2024,16 @@ var QueryEngine = class {
|
|
|
1716
2024
|
});
|
|
1717
2025
|
}
|
|
1718
2026
|
async disconnect() {
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
2027
|
+
await EmbeddedEngine.disconnect(this.connectionId);
|
|
2028
|
+
const pool = socketPools.get(this.connectionId);
|
|
2029
|
+
if (pool) {
|
|
2030
|
+
for (const s of pool.free) {
|
|
2031
|
+
try {
|
|
2032
|
+
s.destroy();
|
|
2033
|
+
} catch {
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
socketPools.delete(this.connectionId);
|
|
1724
2037
|
}
|
|
1725
2038
|
const serverInfo = globalTcpServers.get(this.connectionId);
|
|
1726
2039
|
if (serverInfo && serverInfo.process && !serverInfo.process.killed) {
|
|
@@ -1742,8 +2055,8 @@ var QueryEngine = class {
|
|
|
1742
2055
|
|
|
1743
2056
|
// src/lib/SqliteExecutor.ts
|
|
1744
2057
|
var import_child_process4 = require("child_process");
|
|
1745
|
-
var
|
|
1746
|
-
var
|
|
2058
|
+
var path7 = __toESM(require("path"));
|
|
2059
|
+
var fs5 = __toESM(require("fs"));
|
|
1747
2060
|
var import_util = require("util");
|
|
1748
2061
|
var import_module3 = require("module");
|
|
1749
2062
|
var import_url3 = require("url");
|
|
@@ -1759,13 +2072,13 @@ var SqliteExecutor = class {
|
|
|
1759
2072
|
}
|
|
1760
2073
|
findVersionedBinary(binDir, platform2) {
|
|
1761
2074
|
try {
|
|
1762
|
-
const files =
|
|
2075
|
+
const files = fs5.readdirSync(binDir);
|
|
1763
2076
|
const extension = platform2 === "win32" ? ".exe" : "";
|
|
1764
2077
|
const platformName = platform2 === "win32" ? "windows" : platform2 === "darwin" ? "macos" : "linux";
|
|
1765
2078
|
const pattern = new RegExp(`^sqlite-engine-v\\d+\\.\\d+\\.\\d+-${platformName}-x64${extension.replace(".", "\\.")}$`);
|
|
1766
2079
|
const matchingFile = files.find((f) => pattern.test(f));
|
|
1767
2080
|
if (matchingFile) {
|
|
1768
|
-
return
|
|
2081
|
+
return path7.join(binDir, matchingFile);
|
|
1769
2082
|
}
|
|
1770
2083
|
} catch (error) {
|
|
1771
2084
|
}
|
|
@@ -1775,34 +2088,34 @@ var SqliteExecutor = class {
|
|
|
1775
2088
|
const __filename2 = typeof import_meta3 !== "undefined" && import_meta3.url ? (0, import_url3.fileURLToPath)(import_meta3.url) : "";
|
|
1776
2089
|
const __dirname = __filename2 ? (0, import_path6.dirname)(__filename2) : process.cwd();
|
|
1777
2090
|
const possibleDirs = [
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
2091
|
+
path7.resolve(process.cwd(), ".dbcube", "bin"),
|
|
2092
|
+
path7.resolve(process.cwd(), "node_modules", ".dbcube", "bin"),
|
|
2093
|
+
path7.resolve(__dirname, "..", "bin")
|
|
1781
2094
|
];
|
|
1782
2095
|
const platform2 = process.platform;
|
|
1783
2096
|
const extension = platform2 === "win32" ? ".exe" : "";
|
|
1784
2097
|
const platformName = platform2 === "win32" ? "windows" : platform2 === "darwin" ? "macos" : "linux";
|
|
1785
2098
|
for (const dir of possibleDirs) {
|
|
1786
2099
|
const versionedPath = this.findVersionedBinary(dir, platform2);
|
|
1787
|
-
if (versionedPath &&
|
|
2100
|
+
if (versionedPath && fs5.existsSync(versionedPath)) {
|
|
1788
2101
|
return versionedPath;
|
|
1789
2102
|
}
|
|
1790
2103
|
}
|
|
1791
2104
|
const binaryName = `sqlite-engine-${platformName}-x64${extension}`;
|
|
1792
2105
|
for (const dir of possibleDirs) {
|
|
1793
|
-
const fullPath =
|
|
1794
|
-
if (
|
|
2106
|
+
const fullPath = path7.join(dir, binaryName);
|
|
2107
|
+
if (fs5.existsSync(fullPath)) {
|
|
1795
2108
|
return fullPath;
|
|
1796
2109
|
}
|
|
1797
2110
|
}
|
|
1798
2111
|
const fallbackName = `sqlite-engine${extension}`;
|
|
1799
2112
|
for (const dir of possibleDirs) {
|
|
1800
|
-
const fullPath =
|
|
1801
|
-
if (
|
|
2113
|
+
const fullPath = path7.join(dir, fallbackName);
|
|
2114
|
+
if (fs5.existsSync(fullPath)) {
|
|
1802
2115
|
return fullPath;
|
|
1803
2116
|
}
|
|
1804
2117
|
}
|
|
1805
|
-
return
|
|
2118
|
+
return path7.join(possibleDirs[0], binaryName);
|
|
1806
2119
|
}
|
|
1807
2120
|
async executeBinary(args) {
|
|
1808
2121
|
const escapedArgs = args.map((arg) => {
|
|
@@ -1953,9 +2266,9 @@ var SqliteExecutor = class {
|
|
|
1953
2266
|
};
|
|
1954
2267
|
|
|
1955
2268
|
// src/lib/DbConfig.ts
|
|
1956
|
-
var
|
|
2269
|
+
var path8 = __toESM(require("path"));
|
|
1957
2270
|
var import_fs2 = __toESM(require("fs"));
|
|
1958
|
-
var rootPath =
|
|
2271
|
+
var rootPath = path8.resolve(process.cwd(), ".dbcube");
|
|
1959
2272
|
var SQLite = class {
|
|
1960
2273
|
executor = null;
|
|
1961
2274
|
database;
|
|
@@ -1965,7 +2278,7 @@ var SQLite = class {
|
|
|
1965
2278
|
async ifExist() {
|
|
1966
2279
|
if (this.database) {
|
|
1967
2280
|
const dbPath = this.database || ":memory:";
|
|
1968
|
-
const configPath =
|
|
2281
|
+
const configPath = path8.join(rootPath, dbPath + ".db");
|
|
1969
2282
|
if (!import_fs2.default.existsSync(rootPath)) {
|
|
1970
2283
|
import_fs2.default.mkdirSync(rootPath, { recursive: true });
|
|
1971
2284
|
}
|
|
@@ -1980,11 +2293,11 @@ var SQLite = class {
|
|
|
1980
2293
|
return false;
|
|
1981
2294
|
}
|
|
1982
2295
|
async connect() {
|
|
1983
|
-
return new Promise(async (
|
|
2296
|
+
return new Promise(async (resolve6, reject) => {
|
|
1984
2297
|
try {
|
|
1985
2298
|
if (!this.executor) {
|
|
1986
2299
|
const dbPath = this.database || ":memory:";
|
|
1987
|
-
const configPath =
|
|
2300
|
+
const configPath = path8.join(rootPath, dbPath + ".db");
|
|
1988
2301
|
if (!import_fs2.default.existsSync(rootPath)) {
|
|
1989
2302
|
import_fs2.default.mkdirSync(rootPath, { recursive: true });
|
|
1990
2303
|
}
|
|
@@ -1994,22 +2307,22 @@ var SQLite = class {
|
|
|
1994
2307
|
throw new Error("Failed to connect to SQLite database");
|
|
1995
2308
|
}
|
|
1996
2309
|
}
|
|
1997
|
-
|
|
2310
|
+
resolve6(this.executor);
|
|
1998
2311
|
} catch (error) {
|
|
1999
2312
|
reject(error);
|
|
2000
2313
|
}
|
|
2001
2314
|
});
|
|
2002
2315
|
}
|
|
2003
2316
|
async disconnect() {
|
|
2004
|
-
return new Promise((
|
|
2317
|
+
return new Promise((resolve6) => {
|
|
2005
2318
|
if (this.executor) {
|
|
2006
2319
|
this.executor = null;
|
|
2007
2320
|
}
|
|
2008
|
-
|
|
2321
|
+
resolve6();
|
|
2009
2322
|
});
|
|
2010
2323
|
}
|
|
2011
2324
|
async query(sqlQuery) {
|
|
2012
|
-
return new Promise(async (
|
|
2325
|
+
return new Promise(async (resolve6) => {
|
|
2013
2326
|
try {
|
|
2014
2327
|
if (typeof sqlQuery !== "string") {
|
|
2015
2328
|
throw new Error("The SQL query must be a string.");
|
|
@@ -2022,20 +2335,20 @@ var SQLite = class {
|
|
|
2022
2335
|
}
|
|
2023
2336
|
const result = await this.executor.queryMultiple(sqlQuery);
|
|
2024
2337
|
if (result.status === "error") {
|
|
2025
|
-
|
|
2338
|
+
resolve6({
|
|
2026
2339
|
status: "error",
|
|
2027
2340
|
message: result.message,
|
|
2028
2341
|
data: null
|
|
2029
2342
|
});
|
|
2030
2343
|
} else {
|
|
2031
|
-
|
|
2344
|
+
resolve6({
|
|
2032
2345
|
status: "success",
|
|
2033
2346
|
message: "Query executed successfully",
|
|
2034
2347
|
data: result.data
|
|
2035
2348
|
});
|
|
2036
2349
|
}
|
|
2037
2350
|
} catch (error) {
|
|
2038
|
-
|
|
2351
|
+
resolve6({
|
|
2039
2352
|
status: "error",
|
|
2040
2353
|
message: error.message || "An error occurred while executing the query.",
|
|
2041
2354
|
data: null
|
|
@@ -2044,7 +2357,7 @@ var SQLite = class {
|
|
|
2044
2357
|
});
|
|
2045
2358
|
}
|
|
2046
2359
|
async queryWithParameters(sqlQuery, params = []) {
|
|
2047
|
-
return new Promise(async (
|
|
2360
|
+
return new Promise(async (resolve6) => {
|
|
2048
2361
|
try {
|
|
2049
2362
|
if (typeof sqlQuery !== "string") {
|
|
2050
2363
|
throw new Error("The SQL query must be a string.");
|
|
@@ -2060,13 +2373,13 @@ var SQLite = class {
|
|
|
2060
2373
|
}
|
|
2061
2374
|
const result = await this.executor.query(sqlQuery, params);
|
|
2062
2375
|
if (result.status === "error") {
|
|
2063
|
-
|
|
2376
|
+
resolve6({
|
|
2064
2377
|
status: "error",
|
|
2065
2378
|
message: result.message,
|
|
2066
2379
|
data: null
|
|
2067
2380
|
});
|
|
2068
2381
|
} else {
|
|
2069
|
-
|
|
2382
|
+
resolve6({
|
|
2070
2383
|
status: "success",
|
|
2071
2384
|
message: "Query executed successfully",
|
|
2072
2385
|
data: result.data
|
|
@@ -2074,7 +2387,7 @@ var SQLite = class {
|
|
|
2074
2387
|
}
|
|
2075
2388
|
} catch (error) {
|
|
2076
2389
|
console.log(error);
|
|
2077
|
-
|
|
2390
|
+
resolve6({
|
|
2078
2391
|
status: "error",
|
|
2079
2392
|
message: error.message || "An error occurred while executing the query.",
|
|
2080
2393
|
data: null
|
|
@@ -2168,8 +2481,8 @@ var DbConfig = new SQLite({ DATABASE: "config" });
|
|
|
2168
2481
|
var DbConfig_default = DbConfig;
|
|
2169
2482
|
|
|
2170
2483
|
// src/lib/FileLogger.ts
|
|
2171
|
-
var
|
|
2172
|
-
var
|
|
2484
|
+
var fs7 = __toESM(require("fs"));
|
|
2485
|
+
var path9 = __toESM(require("path"));
|
|
2173
2486
|
var import_events = require("events");
|
|
2174
2487
|
var FileLogger = class _FileLogger extends import_events.EventEmitter {
|
|
2175
2488
|
static watchers = /* @__PURE__ */ new Map();
|
|
@@ -2184,9 +2497,9 @@ var FileLogger = class _FileLogger extends import_events.EventEmitter {
|
|
|
2184
2497
|
*/
|
|
2185
2498
|
static async write(filePath, message, level = "INFO", append = true) {
|
|
2186
2499
|
try {
|
|
2187
|
-
const dir =
|
|
2188
|
-
if (!
|
|
2189
|
-
|
|
2500
|
+
const dir = path9.dirname(filePath);
|
|
2501
|
+
if (!fs7.existsSync(dir)) {
|
|
2502
|
+
fs7.mkdirSync(dir, { recursive: true });
|
|
2190
2503
|
}
|
|
2191
2504
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
2192
2505
|
const formattedMessage = `[${timestamp}] [${level}] ${message}
|
|
@@ -2196,9 +2509,9 @@ var FileLogger = class _FileLogger extends import_events.EventEmitter {
|
|
|
2196
2509
|
return true;
|
|
2197
2510
|
}
|
|
2198
2511
|
if (append) {
|
|
2199
|
-
await
|
|
2512
|
+
await fs7.promises.appendFile(filePath, formattedMessage, "utf8");
|
|
2200
2513
|
} else {
|
|
2201
|
-
await
|
|
2514
|
+
await fs7.promises.writeFile(filePath, formattedMessage, "utf8");
|
|
2202
2515
|
}
|
|
2203
2516
|
return true;
|
|
2204
2517
|
} catch (error) {
|
|
@@ -2223,12 +2536,12 @@ var FileLogger = class _FileLogger extends import_events.EventEmitter {
|
|
|
2223
2536
|
const buffer = _FileLogger.buffers.get(filePath);
|
|
2224
2537
|
if (buffer && buffer.length > 0) {
|
|
2225
2538
|
try {
|
|
2226
|
-
const dir =
|
|
2227
|
-
if (!
|
|
2228
|
-
|
|
2539
|
+
const dir = path9.dirname(filePath);
|
|
2540
|
+
if (!fs7.existsSync(dir)) {
|
|
2541
|
+
fs7.mkdirSync(dir, { recursive: true });
|
|
2229
2542
|
}
|
|
2230
2543
|
const content = buffer.join("");
|
|
2231
|
-
await
|
|
2544
|
+
await fs7.promises.appendFile(filePath, content, "utf8");
|
|
2232
2545
|
_FileLogger.buffers.delete(filePath);
|
|
2233
2546
|
return true;
|
|
2234
2547
|
} catch (error) {
|
|
@@ -2364,10 +2677,10 @@ var FileLogger = class _FileLogger extends import_events.EventEmitter {
|
|
|
2364
2677
|
// Si debe retornar como array de líneas
|
|
2365
2678
|
} = options;
|
|
2366
2679
|
try {
|
|
2367
|
-
if (!
|
|
2680
|
+
if (!fs7.existsSync(filePath)) {
|
|
2368
2681
|
return asArray ? [] : "";
|
|
2369
2682
|
}
|
|
2370
|
-
let content = await
|
|
2683
|
+
let content = await fs7.promises.readFile(filePath, "utf8");
|
|
2371
2684
|
if (asArray) {
|
|
2372
2685
|
let linesArray = content.split("\n").filter((line) => line.trim() !== "");
|
|
2373
2686
|
if (lines !== null) {
|
|
@@ -2410,15 +2723,15 @@ var FileLogger = class _FileLogger extends import_events.EventEmitter {
|
|
|
2410
2723
|
} = options;
|
|
2411
2724
|
let lastSize = 0;
|
|
2412
2725
|
let lastPosition = 0;
|
|
2413
|
-
if (
|
|
2414
|
-
const stats =
|
|
2726
|
+
if (fs7.existsSync(filePath)) {
|
|
2727
|
+
const stats = fs7.statSync(filePath);
|
|
2415
2728
|
lastSize = stats.size;
|
|
2416
2729
|
lastPosition = fromEnd ? stats.size : 0;
|
|
2417
2730
|
}
|
|
2418
2731
|
const listener = async (curr, prev) => {
|
|
2419
2732
|
try {
|
|
2420
2733
|
if (curr.size > lastSize) {
|
|
2421
|
-
const stream =
|
|
2734
|
+
const stream = fs7.createReadStream(filePath, {
|
|
2422
2735
|
start: lastPosition,
|
|
2423
2736
|
end: curr.size - 1,
|
|
2424
2737
|
encoding: "utf8"
|
|
@@ -2446,7 +2759,7 @@ var FileLogger = class _FileLogger extends import_events.EventEmitter {
|
|
|
2446
2759
|
console.error("Error en watcher:", error);
|
|
2447
2760
|
}
|
|
2448
2761
|
};
|
|
2449
|
-
|
|
2762
|
+
fs7.watchFile(filePath, { persistent, interval }, listener);
|
|
2450
2763
|
const watcherId = `${filePath}_${Date.now()}`;
|
|
2451
2764
|
_FileLogger.watchers.set(watcherId, listener);
|
|
2452
2765
|
return {
|
|
@@ -2454,7 +2767,7 @@ var FileLogger = class _FileLogger extends import_events.EventEmitter {
|
|
|
2454
2767
|
stop: () => {
|
|
2455
2768
|
const storedListener = _FileLogger.watchers.get(watcherId);
|
|
2456
2769
|
if (storedListener) {
|
|
2457
|
-
|
|
2770
|
+
fs7.unwatchFile(filePath, storedListener);
|
|
2458
2771
|
_FileLogger.watchers.delete(watcherId);
|
|
2459
2772
|
}
|
|
2460
2773
|
},
|
|
@@ -2467,7 +2780,7 @@ var FileLogger = class _FileLogger extends import_events.EventEmitter {
|
|
|
2467
2780
|
static stopAllWatchers() {
|
|
2468
2781
|
for (const [watcherId] of _FileLogger.watchers) {
|
|
2469
2782
|
const filePath = watcherId.split("_")[0];
|
|
2470
|
-
|
|
2783
|
+
fs7.unwatchFile(filePath);
|
|
2471
2784
|
}
|
|
2472
2785
|
_FileLogger.watchers.clear();
|
|
2473
2786
|
}
|
|
@@ -2497,7 +2810,7 @@ var FileLogger = class _FileLogger extends import_events.EventEmitter {
|
|
|
2497
2810
|
if (lines.length > maxLines) {
|
|
2498
2811
|
const keepLines = lines.slice(-maxLines);
|
|
2499
2812
|
const content = keepLines.join("\n") + "\n";
|
|
2500
|
-
await
|
|
2813
|
+
await fs7.promises.writeFile(filePath, content, "utf8");
|
|
2501
2814
|
return lines.length - maxLines;
|
|
2502
2815
|
}
|
|
2503
2816
|
return 0;
|
|
@@ -2512,8 +2825,8 @@ var FileLogger = class _FileLogger extends import_events.EventEmitter {
|
|
|
2512
2825
|
*/
|
|
2513
2826
|
static async deleteLogFile(filePath) {
|
|
2514
2827
|
try {
|
|
2515
|
-
if (
|
|
2516
|
-
await
|
|
2828
|
+
if (fs7.existsSync(filePath)) {
|
|
2829
|
+
await fs7.promises.unlink(filePath);
|
|
2517
2830
|
return true;
|
|
2518
2831
|
}
|
|
2519
2832
|
return false;
|