@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.js
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
1
8
|
// src/lib/Engine.ts
|
|
2
9
|
import path4 from "path";
|
|
3
10
|
|
|
@@ -132,7 +139,7 @@ import * as unzipper from "unzipper";
|
|
|
132
139
|
import ora from "ora";
|
|
133
140
|
import chalk from "chalk";
|
|
134
141
|
import { fileURLToPath } from "url";
|
|
135
|
-
import { dirname } from "path";
|
|
142
|
+
import { dirname as dirname2 } from "path";
|
|
136
143
|
var { https } = followRedirects;
|
|
137
144
|
var Downloader = class {
|
|
138
145
|
static mainSpinner = null;
|
|
@@ -147,7 +154,7 @@ var Downloader = class {
|
|
|
147
154
|
*/
|
|
148
155
|
static async fetchLatestVersion(prefix) {
|
|
149
156
|
const url = this.VERSION_URLS[prefix];
|
|
150
|
-
return new Promise((
|
|
157
|
+
return new Promise((resolve6, reject) => {
|
|
151
158
|
https.get(url, (response) => {
|
|
152
159
|
let data = "";
|
|
153
160
|
response.on("data", (chunk) => {
|
|
@@ -157,7 +164,7 @@ var Downloader = class {
|
|
|
157
164
|
try {
|
|
158
165
|
const versions = JSON.parse(data);
|
|
159
166
|
if (versions && versions.length > 0) {
|
|
160
|
-
|
|
167
|
+
resolve6(versions[0].version);
|
|
161
168
|
} else {
|
|
162
169
|
reject(new Error("No versions found"));
|
|
163
170
|
}
|
|
@@ -366,7 +373,7 @@ var Downloader = class {
|
|
|
366
373
|
if (attempt < maxRetries && (errorMessage.includes("ECONNRESET") || errorMessage.includes("timeout") || errorMessage.includes("ETIMEDOUT") || errorMessage.includes("ENOTFOUND"))) {
|
|
367
374
|
attempt++;
|
|
368
375
|
console.log(`\u{1F504} Retrying ${binary.prefix}-engine (${attempt}/${maxRetries})...`);
|
|
369
|
-
await new Promise((
|
|
376
|
+
await new Promise((resolve6) => setTimeout(resolve6, 1e3 + Math.random() * 1e3));
|
|
370
377
|
} else {
|
|
371
378
|
throw new Error(`Error downloading ${binary.prefix}: ${errorMessage}`);
|
|
372
379
|
}
|
|
@@ -414,12 +421,12 @@ var Downloader = class {
|
|
|
414
421
|
return `[${filledBar}${emptyBar}] ${percentage}`;
|
|
415
422
|
}
|
|
416
423
|
static downloadFileWithProgress(url, outputPath, prefix) {
|
|
417
|
-
return new Promise((
|
|
424
|
+
return new Promise((resolve6, reject) => {
|
|
418
425
|
const request = https.get(url, { timeout: 0 }, (response) => {
|
|
419
426
|
if (response.statusCode === 302 || response.statusCode === 301) {
|
|
420
427
|
const redirectUrl = response.headers.location;
|
|
421
428
|
if (redirectUrl) {
|
|
422
|
-
return this.downloadFileWithProgress(redirectUrl, outputPath, prefix).then(
|
|
429
|
+
return this.downloadFileWithProgress(redirectUrl, outputPath, prefix).then(resolve6).catch(reject);
|
|
423
430
|
}
|
|
424
431
|
}
|
|
425
432
|
if (response.statusCode !== 200) {
|
|
@@ -442,7 +449,7 @@ var Downloader = class {
|
|
|
442
449
|
}
|
|
443
450
|
});
|
|
444
451
|
response.on("end", () => {
|
|
445
|
-
file.end(() =>
|
|
452
|
+
file.end(() => resolve6());
|
|
446
453
|
});
|
|
447
454
|
response.on("error", (err) => {
|
|
448
455
|
file.close();
|
|
@@ -474,35 +481,47 @@ var Downloader = class {
|
|
|
474
481
|
this.mainSpinner.text = `\u{1F4E5} ${chalk.bold(binary)} - ${progressText}`;
|
|
475
482
|
}
|
|
476
483
|
static extractBinary(zipPath, outputPath, prefix) {
|
|
477
|
-
return new Promise((
|
|
478
|
-
|
|
484
|
+
return new Promise((resolve6, reject) => {
|
|
485
|
+
const outDir = path.dirname(outputPath);
|
|
486
|
+
let extracted = 0;
|
|
487
|
+
const pending = [];
|
|
479
488
|
fs.createReadStream(zipPath).pipe(unzipper.Parse()).on("entry", (entry) => {
|
|
480
|
-
if (entry.type
|
|
481
|
-
|
|
482
|
-
|
|
489
|
+
if (entry.type !== "File") {
|
|
490
|
+
entry.autodrain();
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
const isMain = extracted === 0;
|
|
494
|
+
extracted++;
|
|
495
|
+
const target = isMain ? outputPath : path.join(outDir, path.basename(entry.path));
|
|
496
|
+
pending.push(new Promise((res, rej) => {
|
|
497
|
+
const writeStream = fs.createWriteStream(target);
|
|
483
498
|
entry.pipe(writeStream);
|
|
484
499
|
writeStream.on("finish", () => {
|
|
485
500
|
if (process.platform !== "win32") {
|
|
486
|
-
|
|
501
|
+
try {
|
|
502
|
+
fs.chmodSync(target, 493);
|
|
503
|
+
} catch {
|
|
504
|
+
}
|
|
487
505
|
}
|
|
488
|
-
|
|
489
|
-
resolve5();
|
|
506
|
+
res();
|
|
490
507
|
});
|
|
491
|
-
writeStream.on("error",
|
|
492
|
-
|
|
493
|
-
reject(err);
|
|
494
|
-
});
|
|
495
|
-
} else {
|
|
496
|
-
entry.autodrain();
|
|
497
|
-
}
|
|
508
|
+
writeStream.on("error", rej);
|
|
509
|
+
}));
|
|
498
510
|
}).on("error", (err) => {
|
|
499
511
|
this.cleanupFile(zipPath);
|
|
500
512
|
reject(err);
|
|
501
513
|
}).on("close", () => {
|
|
502
|
-
|
|
514
|
+
Promise.all(pending).then(() => {
|
|
503
515
|
this.cleanupFile(zipPath);
|
|
504
|
-
|
|
505
|
-
|
|
516
|
+
if (extracted === 0) {
|
|
517
|
+
reject(new Error(`No se encontr\xF3 archivo v\xE1lido en el ZIP para ${prefix}`));
|
|
518
|
+
} else {
|
|
519
|
+
resolve6();
|
|
520
|
+
}
|
|
521
|
+
}).catch((err) => {
|
|
522
|
+
this.cleanupFile(zipPath);
|
|
523
|
+
reject(err);
|
|
524
|
+
});
|
|
506
525
|
});
|
|
507
526
|
});
|
|
508
527
|
}
|
|
@@ -516,7 +535,7 @@ var Downloader = class {
|
|
|
516
535
|
}
|
|
517
536
|
static getDefaultBinDir() {
|
|
518
537
|
const __filename2 = typeof import.meta !== "undefined" && import.meta.url ? fileURLToPath(import.meta.url) : "";
|
|
519
|
-
const __dirname = __filename2 ?
|
|
538
|
+
const __dirname = __filename2 ? dirname2(__filename2) : process.cwd();
|
|
520
539
|
const possibleDirs = [
|
|
521
540
|
path.resolve(process.cwd(), ".dbcube", "bin"),
|
|
522
541
|
path.resolve(process.cwd(), "node_modules", ".dbcube", "bin"),
|
|
@@ -546,7 +565,7 @@ import * as fs2 from "fs";
|
|
|
546
565
|
import * as path2 from "path";
|
|
547
566
|
import * as os3 from "os";
|
|
548
567
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
549
|
-
import { dirname as
|
|
568
|
+
import { dirname as dirname3 } from "path";
|
|
550
569
|
var Binary = class {
|
|
551
570
|
static isDownloading = false;
|
|
552
571
|
static downloadPromise = null;
|
|
@@ -579,7 +598,7 @@ var Binary = class {
|
|
|
579
598
|
}
|
|
580
599
|
static getBinDir() {
|
|
581
600
|
const __filename2 = typeof import.meta !== "undefined" && import.meta.url ? fileURLToPath2(import.meta.url) : "";
|
|
582
|
-
const __dirname = __filename2 ?
|
|
601
|
+
const __dirname = __filename2 ? dirname3(__filename2) : process.cwd();
|
|
583
602
|
const possibleDirs = [
|
|
584
603
|
path2.resolve(process.cwd(), ".dbcube", "bin"),
|
|
585
604
|
path2.resolve(process.cwd(), "node_modules", ".dbcube", "bin"),
|
|
@@ -816,22 +835,22 @@ var DaemonClient = class _DaemonClient {
|
|
|
816
835
|
child.unref();
|
|
817
836
|
}
|
|
818
837
|
tryConnect(port) {
|
|
819
|
-
return new Promise((
|
|
838
|
+
return new Promise((resolve6) => {
|
|
820
839
|
const socket = net.createConnection({ host: "127.0.0.1", port }, async () => {
|
|
821
840
|
socket.setNoDelay(true);
|
|
822
841
|
this.attach(socket);
|
|
823
842
|
try {
|
|
824
843
|
const pong = await this.send({ action: "ping" }, 2e3);
|
|
825
|
-
|
|
844
|
+
resolve6(pong.status === 200);
|
|
826
845
|
} catch {
|
|
827
846
|
this.detach();
|
|
828
|
-
|
|
847
|
+
resolve6(false);
|
|
829
848
|
}
|
|
830
849
|
});
|
|
831
|
-
socket.once("error", () =>
|
|
850
|
+
socket.once("error", () => resolve6(false));
|
|
832
851
|
socket.setTimeout(3e3, () => {
|
|
833
852
|
socket.destroy();
|
|
834
|
-
|
|
853
|
+
resolve6(false);
|
|
835
854
|
});
|
|
836
855
|
});
|
|
837
856
|
}
|
|
@@ -879,7 +898,7 @@ var DaemonClient = class _DaemonClient {
|
|
|
879
898
|
* single socket, so pending requests resolve in send order.
|
|
880
899
|
*/
|
|
881
900
|
send(payload, timeoutMs) {
|
|
882
|
-
return new Promise((
|
|
901
|
+
return new Promise((resolve6, reject) => {
|
|
883
902
|
if (!this.socket || this.socket.destroyed) {
|
|
884
903
|
reject(new Error("Daemon not connected"));
|
|
885
904
|
return;
|
|
@@ -890,12 +909,12 @@ var DaemonClient = class _DaemonClient {
|
|
|
890
909
|
reject(new Error("Daemon request timeout"));
|
|
891
910
|
this.detach();
|
|
892
911
|
}, timeoutMs ?? this.requestTimeout);
|
|
893
|
-
this.pending.push({ resolve:
|
|
912
|
+
this.pending.push({ resolve: resolve6, reject, timer });
|
|
894
913
|
this.socket.write(JSON.stringify(payload) + "\n");
|
|
895
914
|
});
|
|
896
915
|
}
|
|
897
916
|
async execute(dml, txId) {
|
|
898
|
-
const payload = { action: "execute", dml
|
|
917
|
+
const payload = { action: "execute", dml };
|
|
899
918
|
if (txId) payload.tx_id = txId;
|
|
900
919
|
return this.send(payload);
|
|
901
920
|
}
|
|
@@ -962,8 +981,8 @@ var Engine = class {
|
|
|
962
981
|
const binaryPath = this.binary["query_engine"];
|
|
963
982
|
if (!binaryPath) return null;
|
|
964
983
|
const client = DaemonClient.get(this.name, binaryPath, this.arguments);
|
|
965
|
-
const
|
|
966
|
-
if (!
|
|
984
|
+
const ok2 = await client.ensure();
|
|
985
|
+
if (!ok2) {
|
|
967
986
|
this.daemonFailed = true;
|
|
968
987
|
return null;
|
|
969
988
|
}
|
|
@@ -1094,7 +1113,7 @@ var Engine = class {
|
|
|
1094
1113
|
if (!this.binary) {
|
|
1095
1114
|
throw new Error("Binary not initialized");
|
|
1096
1115
|
}
|
|
1097
|
-
return new Promise((
|
|
1116
|
+
return new Promise((resolve6, reject) => {
|
|
1098
1117
|
const child = spawn2(this.binary[binary], [...this.arguments, ...args]);
|
|
1099
1118
|
let stdoutBuffer = "";
|
|
1100
1119
|
let stderrBuffer = "";
|
|
@@ -1110,7 +1129,7 @@ var Engine = class {
|
|
|
1110
1129
|
if (!isResolved) {
|
|
1111
1130
|
isResolved = true;
|
|
1112
1131
|
clearTimeout(timeoutId);
|
|
1113
|
-
|
|
1132
|
+
resolve6(response);
|
|
1114
1133
|
}
|
|
1115
1134
|
};
|
|
1116
1135
|
const tryParseLines = (buffer) => {
|
|
@@ -1175,14 +1194,265 @@ var Engine = class {
|
|
|
1175
1194
|
};
|
|
1176
1195
|
|
|
1177
1196
|
// src/lib/QueryEngine.ts
|
|
1178
|
-
import
|
|
1197
|
+
import path6 from "path";
|
|
1198
|
+
|
|
1199
|
+
// src/lib/EmbeddedEngine.ts
|
|
1200
|
+
import * as fs4 from "fs";
|
|
1201
|
+
import * as path5 from "path";
|
|
1202
|
+
if (!process.env.UV_THREADPOOL_SIZE) {
|
|
1203
|
+
process.env.UV_THREADPOOL_SIZE = "16";
|
|
1204
|
+
}
|
|
1205
|
+
var backend = null;
|
|
1206
|
+
var loadFailed = false;
|
|
1207
|
+
var handles = /* @__PURE__ */ new Map();
|
|
1208
|
+
var connecting = /* @__PURE__ */ new Map();
|
|
1209
|
+
function platTag() {
|
|
1210
|
+
const arch2 = process.arch === "arm64" ? "arm64" : "x64";
|
|
1211
|
+
if (process.platform === "win32") return { plat: "windows", ext: "dll", arch: arch2 };
|
|
1212
|
+
if (process.platform === "darwin") return { plat: "macos", ext: "dylib", arch: arch2 };
|
|
1213
|
+
return { plat: "linux", ext: "so", arch: arch2 };
|
|
1214
|
+
}
|
|
1215
|
+
function findFile(name) {
|
|
1216
|
+
const candidates = [
|
|
1217
|
+
path5.resolve(process.cwd(), ".dbcube", "bin", name),
|
|
1218
|
+
path5.resolve(process.cwd(), "node_modules", ".dbcube", "bin", name)
|
|
1219
|
+
];
|
|
1220
|
+
for (const c of candidates) {
|
|
1221
|
+
if (fs4.existsSync(c)) return c;
|
|
1222
|
+
}
|
|
1223
|
+
return null;
|
|
1224
|
+
}
|
|
1225
|
+
function ok(data) {
|
|
1226
|
+
return { status: 200, message: "OK", data };
|
|
1227
|
+
}
|
|
1228
|
+
function errResp(e) {
|
|
1229
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1230
|
+
return { status: 500, message: msg, data: null };
|
|
1231
|
+
}
|
|
1232
|
+
function loadNapiBackend() {
|
|
1233
|
+
const { plat, arch: arch2 } = platTag();
|
|
1234
|
+
const addonPath = findFile(`query-engine-node-${plat}-${arch2}.node`);
|
|
1235
|
+
if (!addonPath) return null;
|
|
1236
|
+
try {
|
|
1237
|
+
const addon = __require(addonPath);
|
|
1238
|
+
if (typeof addon.connect !== "function") return null;
|
|
1239
|
+
return {
|
|
1240
|
+
async connect(cfgJson) {
|
|
1241
|
+
return Number(await addon.connect(cfgJson));
|
|
1242
|
+
},
|
|
1243
|
+
async execute(handle, dml, txId) {
|
|
1244
|
+
try {
|
|
1245
|
+
const rows = await addon.execute(handle, dml, txId ?? void 0);
|
|
1246
|
+
return ok(rows);
|
|
1247
|
+
} catch (e) {
|
|
1248
|
+
return errResp(e);
|
|
1249
|
+
}
|
|
1250
|
+
},
|
|
1251
|
+
async executeBatch(handle, ops) {
|
|
1252
|
+
try {
|
|
1253
|
+
const results = await addon.executeBatch(handle, ops);
|
|
1254
|
+
return ok(results);
|
|
1255
|
+
} catch (e) {
|
|
1256
|
+
return errResp(e);
|
|
1257
|
+
}
|
|
1258
|
+
},
|
|
1259
|
+
async raw(handle, query, params, txId) {
|
|
1260
|
+
try {
|
|
1261
|
+
const rows = await addon.raw(handle, query, params, txId ?? void 0);
|
|
1262
|
+
return ok(rows);
|
|
1263
|
+
} catch (e) {
|
|
1264
|
+
return errResp(e);
|
|
1265
|
+
}
|
|
1266
|
+
},
|
|
1267
|
+
async begin(handle) {
|
|
1268
|
+
try {
|
|
1269
|
+
const txId = await addon.begin(handle);
|
|
1270
|
+
return ok({ tx_id: txId });
|
|
1271
|
+
} catch (e) {
|
|
1272
|
+
return errResp(e);
|
|
1273
|
+
}
|
|
1274
|
+
},
|
|
1275
|
+
async commit(_handle, txId) {
|
|
1276
|
+
try {
|
|
1277
|
+
await addon.commit(txId);
|
|
1278
|
+
return ok(null);
|
|
1279
|
+
} catch (e) {
|
|
1280
|
+
return errResp(e);
|
|
1281
|
+
}
|
|
1282
|
+
},
|
|
1283
|
+
async rollback(_handle, txId) {
|
|
1284
|
+
try {
|
|
1285
|
+
await addon.rollback(txId);
|
|
1286
|
+
return ok(null);
|
|
1287
|
+
} catch (e) {
|
|
1288
|
+
return errResp(e);
|
|
1289
|
+
}
|
|
1290
|
+
},
|
|
1291
|
+
async disconnect(handle) {
|
|
1292
|
+
try {
|
|
1293
|
+
addon.disconnect(handle);
|
|
1294
|
+
} catch {
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
};
|
|
1298
|
+
} catch {
|
|
1299
|
+
return null;
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
function loadKoffiBackend() {
|
|
1303
|
+
const { plat, ext, arch: arch2 } = platTag();
|
|
1304
|
+
const libPath = findFile(`query-engine-embedded-${plat}-${arch2}.${ext}`);
|
|
1305
|
+
if (!libPath) return null;
|
|
1306
|
+
try {
|
|
1307
|
+
const koffi = __require("koffi");
|
|
1308
|
+
const lib = koffi.load(libPath);
|
|
1309
|
+
const cConnect = lib.func("dbc_connect", "void *", ["str"]);
|
|
1310
|
+
const cExecute = lib.func("dbc_execute", "void *", ["uint64", "str", "str"]);
|
|
1311
|
+
const cExecuteBatch = lib.func("dbc_execute_batch", "void *", ["uint64", "str"]);
|
|
1312
|
+
const cRaw = lib.func("dbc_raw", "void *", ["uint64", "str", "str", "str"]);
|
|
1313
|
+
const cBegin = lib.func("dbc_begin", "void *", ["uint64"]);
|
|
1314
|
+
const cCommit = lib.func("dbc_commit", "void *", ["uint64", "str"]);
|
|
1315
|
+
const cRollback = lib.func("dbc_rollback", "void *", ["uint64", "str"]);
|
|
1316
|
+
const cDisconnect = lib.func("dbc_disconnect", "void *", ["uint64"]);
|
|
1317
|
+
const cFree = lib.func("dbc_free", "void", ["void *"]);
|
|
1318
|
+
const take = (ptr) => {
|
|
1319
|
+
if (!ptr) return { status: 500, message: "embedded engine returned null", data: null };
|
|
1320
|
+
const s = koffi.decode(ptr, "char", -1);
|
|
1321
|
+
cFree(ptr);
|
|
1322
|
+
try {
|
|
1323
|
+
const r = JSON.parse(s);
|
|
1324
|
+
return { status: r.status ?? 500, message: r.message ?? "", data: r.data ?? null };
|
|
1325
|
+
} catch (e) {
|
|
1326
|
+
return { status: 500, message: `Invalid embedded response: ${e.message}`, data: null };
|
|
1327
|
+
}
|
|
1328
|
+
};
|
|
1329
|
+
const call = (fn, ...args) => new Promise((resolve6, reject) => {
|
|
1330
|
+
fn.async(...args, (err, ptr) => {
|
|
1331
|
+
if (err) return reject(err);
|
|
1332
|
+
resolve6(take(ptr));
|
|
1333
|
+
});
|
|
1334
|
+
});
|
|
1335
|
+
return {
|
|
1336
|
+
async connect(cfgJson) {
|
|
1337
|
+
const res = await call(cConnect, cfgJson);
|
|
1338
|
+
if (res.status !== 200 || !res.data?.handle) {
|
|
1339
|
+
throw new Error(String(res.message || "embedded connect failed"));
|
|
1340
|
+
}
|
|
1341
|
+
return Number(res.data.handle);
|
|
1342
|
+
},
|
|
1343
|
+
execute: (handle, dml, txId) => call(cExecute, handle, JSON.stringify(dml), txId),
|
|
1344
|
+
executeBatch: (handle, ops) => call(cExecuteBatch, handle, JSON.stringify(ops)),
|
|
1345
|
+
raw: (handle, query, params, txId) => call(cRaw, handle, query, JSON.stringify(params ?? []), txId),
|
|
1346
|
+
begin: (handle) => call(cBegin, handle),
|
|
1347
|
+
commit: (handle, txId) => call(cCommit, handle, txId),
|
|
1348
|
+
rollback: (handle, txId) => call(cRollback, handle, txId),
|
|
1349
|
+
async disconnect(handle) {
|
|
1350
|
+
try {
|
|
1351
|
+
await call(cDisconnect, handle);
|
|
1352
|
+
} catch {
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
};
|
|
1356
|
+
} catch {
|
|
1357
|
+
return null;
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
function loadBackend() {
|
|
1361
|
+
if (backend) return backend;
|
|
1362
|
+
if (loadFailed) return null;
|
|
1363
|
+
if (process.env.DBCUBE_EMBEDDED === "0" || process.env.DBCUBE_EMBEDDED === "false") {
|
|
1364
|
+
loadFailed = true;
|
|
1365
|
+
return null;
|
|
1366
|
+
}
|
|
1367
|
+
backend = loadNapiBackend() ?? loadKoffiBackend();
|
|
1368
|
+
if (!backend) loadFailed = true;
|
|
1369
|
+
return backend;
|
|
1370
|
+
}
|
|
1371
|
+
var EmbeddedEngine = class {
|
|
1372
|
+
/** true si algún backend nativo está disponible en esta instalación. */
|
|
1373
|
+
static available() {
|
|
1374
|
+
return loadBackend() !== null;
|
|
1375
|
+
}
|
|
1376
|
+
static async handleFor(connectionId, config) {
|
|
1377
|
+
const existing = handles.get(connectionId);
|
|
1378
|
+
if (existing) return existing;
|
|
1379
|
+
const inFlight = connecting.get(connectionId);
|
|
1380
|
+
if (inFlight) return inFlight;
|
|
1381
|
+
const promise = (async () => {
|
|
1382
|
+
const be = loadBackend();
|
|
1383
|
+
if (!be) throw new Error("embedded engine not available");
|
|
1384
|
+
const motor = config.type === "postgres" ? "postgresql" : config.type;
|
|
1385
|
+
const cfg = {
|
|
1386
|
+
databaseRef: connectionId,
|
|
1387
|
+
motor,
|
|
1388
|
+
database: config.type === "sqlite" ? `${config.config.DATABASE}.db` : config.config.DATABASE,
|
|
1389
|
+
host: config.config.HOST,
|
|
1390
|
+
port: config.config.PORT != null ? Number(config.config.PORT) : void 0,
|
|
1391
|
+
user: config.config.USER,
|
|
1392
|
+
password: config.config.PASSWORD,
|
|
1393
|
+
maxConnections: config.pool?.maxConnections,
|
|
1394
|
+
minConnections: config.pool?.minConnections,
|
|
1395
|
+
acquireTimeoutMs: config.pool?.acquireTimeoutMs,
|
|
1396
|
+
idleTimeoutMs: config.pool?.idleTimeoutMs
|
|
1397
|
+
};
|
|
1398
|
+
const handle = await be.connect(JSON.stringify(cfg));
|
|
1399
|
+
handles.set(connectionId, handle);
|
|
1400
|
+
return handle;
|
|
1401
|
+
})();
|
|
1402
|
+
connecting.set(connectionId, promise);
|
|
1403
|
+
try {
|
|
1404
|
+
return await promise;
|
|
1405
|
+
} finally {
|
|
1406
|
+
connecting.delete(connectionId);
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
static async executeDml(connectionId, config, dml, txId) {
|
|
1410
|
+
const be = loadBackend();
|
|
1411
|
+
const handle = await this.handleFor(connectionId, config);
|
|
1412
|
+
return be.execute(handle, dml, txId ?? null);
|
|
1413
|
+
}
|
|
1414
|
+
static async executeBatch(connectionId, config, ops) {
|
|
1415
|
+
const be = loadBackend();
|
|
1416
|
+
const handle = await this.handleFor(connectionId, config);
|
|
1417
|
+
return be.executeBatch(handle, ops);
|
|
1418
|
+
}
|
|
1419
|
+
static async rawQuery(connectionId, config, query, params, txId) {
|
|
1420
|
+
const be = loadBackend();
|
|
1421
|
+
const handle = await this.handleFor(connectionId, config);
|
|
1422
|
+
return be.raw(handle, query, params ?? [], txId ?? null);
|
|
1423
|
+
}
|
|
1424
|
+
static async begin(connectionId, config) {
|
|
1425
|
+
const be = loadBackend();
|
|
1426
|
+
const handle = await this.handleFor(connectionId, config);
|
|
1427
|
+
return be.begin(handle);
|
|
1428
|
+
}
|
|
1429
|
+
static async commit(connectionId, config, txId) {
|
|
1430
|
+
const be = loadBackend();
|
|
1431
|
+
const handle = await this.handleFor(connectionId, config);
|
|
1432
|
+
return be.commit(handle, txId);
|
|
1433
|
+
}
|
|
1434
|
+
static async rollback(connectionId, config, txId) {
|
|
1435
|
+
const be = loadBackend();
|
|
1436
|
+
const handle = await this.handleFor(connectionId, config);
|
|
1437
|
+
return be.rollback(handle, txId);
|
|
1438
|
+
}
|
|
1439
|
+
static async disconnect(connectionId) {
|
|
1440
|
+
const be = loadBackend();
|
|
1441
|
+
const handle = handles.get(connectionId);
|
|
1442
|
+
if (be && handle) {
|
|
1443
|
+
handles.delete(connectionId);
|
|
1444
|
+
await be.disconnect(handle);
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
};
|
|
1448
|
+
|
|
1449
|
+
// src/lib/QueryEngine.ts
|
|
1179
1450
|
import { createRequire as createRequire2 } from "module";
|
|
1180
1451
|
import * as net2 from "net";
|
|
1181
1452
|
import { spawn as spawn3 } from "child_process";
|
|
1182
1453
|
var globalTcpServers = /* @__PURE__ */ new Map();
|
|
1183
|
-
var
|
|
1184
|
-
var
|
|
1185
|
-
var connectionProcessing = /* @__PURE__ */ new Map();
|
|
1454
|
+
var socketPools = /* @__PURE__ */ new Map();
|
|
1455
|
+
var CLIENT_POOL_SIZE = 10;
|
|
1186
1456
|
var queryCache = /* @__PURE__ */ new Map();
|
|
1187
1457
|
var MAX_CACHE_SIZE = 500;
|
|
1188
1458
|
var QueryEngine = class {
|
|
@@ -1213,12 +1483,12 @@ var QueryEngine = class {
|
|
|
1213
1483
|
throw new Error("No available ports found in range 9900-9944");
|
|
1214
1484
|
}
|
|
1215
1485
|
isPortAvailable(port) {
|
|
1216
|
-
return new Promise((
|
|
1486
|
+
return new Promise((resolve6) => {
|
|
1217
1487
|
const tester = net2.createServer();
|
|
1218
|
-
tester.once("error", () =>
|
|
1488
|
+
tester.once("error", () => resolve6(false));
|
|
1219
1489
|
tester.once("listening", () => {
|
|
1220
1490
|
tester.close();
|
|
1221
|
-
|
|
1491
|
+
resolve6(true);
|
|
1222
1492
|
});
|
|
1223
1493
|
tester.listen(port, "127.0.0.1");
|
|
1224
1494
|
});
|
|
@@ -1279,7 +1549,7 @@ var QueryEngine = class {
|
|
|
1279
1549
|
setConfig(name) {
|
|
1280
1550
|
const configInstance = new Config();
|
|
1281
1551
|
try {
|
|
1282
|
-
const configFilePath =
|
|
1552
|
+
const configFilePath = path6.resolve(process.cwd(), "dbcube.config.js");
|
|
1283
1553
|
const requireUrl = typeof __filename !== "undefined" ? __filename : process.cwd();
|
|
1284
1554
|
const require2 = createRequire2(requireUrl);
|
|
1285
1555
|
if (require2.cache && require2.resolve) {
|
|
@@ -1325,38 +1595,79 @@ var QueryEngine = class {
|
|
|
1325
1595
|
}
|
|
1326
1596
|
return command;
|
|
1327
1597
|
}
|
|
1598
|
+
/** El motor embebido (FFI) es el camino por defecto cuando la librería
|
|
1599
|
+
* nativa está disponible; el daemon TCP queda como fallback y como modo
|
|
1600
|
+
* multi-proceso explícito. */
|
|
1601
|
+
useEmbedded() {
|
|
1602
|
+
return EmbeddedEngine.available();
|
|
1603
|
+
}
|
|
1328
1604
|
/**
|
|
1329
|
-
* Executes a DML plan
|
|
1605
|
+
* Executes a DML plan. Embedded engine when available (in-process FFI,
|
|
1606
|
+
* no network hop); persistent TCP daemon otherwise.
|
|
1330
1607
|
* Pass txId to run it inside an active transaction.
|
|
1331
1608
|
*/
|
|
1332
1609
|
async executeDml(dml, txId) {
|
|
1333
|
-
|
|
1610
|
+
if (this.useEmbedded()) {
|
|
1611
|
+
return EmbeddedEngine.executeDml(this.connectionId, this.config, dml, txId);
|
|
1612
|
+
}
|
|
1613
|
+
const command = { action: "execute", dml };
|
|
1334
1614
|
if (txId) command.tx_id = txId;
|
|
1335
1615
|
return this.executeWithTcpServer(command);
|
|
1336
1616
|
}
|
|
1337
1617
|
/**
|
|
1338
|
-
*
|
|
1339
|
-
* over the
|
|
1618
|
+
* Atomic batch: N write plans inside one transaction with a single
|
|
1619
|
+
* engine round-trip. Falls back to begin/ops/commit over the daemon
|
|
1620
|
+
* when the embedded engine is not available.
|
|
1621
|
+
*/
|
|
1622
|
+
async executeBatch(ops) {
|
|
1623
|
+
if (this.useEmbedded()) {
|
|
1624
|
+
return EmbeddedEngine.executeBatch(this.connectionId, this.config, ops);
|
|
1625
|
+
}
|
|
1626
|
+
const txId = await this.beginTransaction();
|
|
1627
|
+
try {
|
|
1628
|
+
const results = [];
|
|
1629
|
+
for (const op of ops) {
|
|
1630
|
+
const res = await this.executeDml(op, txId);
|
|
1631
|
+
if (res.status !== 200) {
|
|
1632
|
+
throw new Error(String(res.message));
|
|
1633
|
+
}
|
|
1634
|
+
results.push(res.data);
|
|
1635
|
+
}
|
|
1636
|
+
await this.commitTransaction(txId);
|
|
1637
|
+
return { status: 200, message: "Batch committed", data: results };
|
|
1638
|
+
} catch (error) {
|
|
1639
|
+
try {
|
|
1640
|
+
await this.rollbackTransaction(txId);
|
|
1641
|
+
} catch {
|
|
1642
|
+
}
|
|
1643
|
+
return { status: 500, message: error?.message ?? String(error), data: null };
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
/**
|
|
1647
|
+
* Executes raw SQL (or a MongoDB command document) with bound parameters.
|
|
1340
1648
|
*/
|
|
1341
1649
|
async rawQuery(query, params = [], txId) {
|
|
1650
|
+
if (this.useEmbedded()) {
|
|
1651
|
+
return EmbeddedEngine.rawQuery(this.connectionId, this.config, query, params, txId);
|
|
1652
|
+
}
|
|
1342
1653
|
const command = { action: "raw", query, params };
|
|
1343
1654
|
if (txId) command.tx_id = txId;
|
|
1344
1655
|
return this.executeWithTcpServer(command);
|
|
1345
1656
|
}
|
|
1346
|
-
/** Starts a
|
|
1657
|
+
/** Starts a transaction and returns its id. */
|
|
1347
1658
|
async beginTransaction() {
|
|
1348
|
-
const res = await this.executeWithTcpServer({ action: "begin" });
|
|
1659
|
+
const res = this.useEmbedded() ? await EmbeddedEngine.begin(this.connectionId, this.config) : await this.executeWithTcpServer({ action: "begin" });
|
|
1349
1660
|
if (res.status !== 200 || !res.data?.tx_id) {
|
|
1350
1661
|
throw new Error(String(res.message || "Failed to begin transaction (update the query-engine binary: npx dbcube update)"));
|
|
1351
1662
|
}
|
|
1352
1663
|
return res.data.tx_id;
|
|
1353
1664
|
}
|
|
1354
1665
|
async commitTransaction(txId) {
|
|
1355
|
-
const res = await this.executeWithTcpServer({ action: "commit", tx_id: txId });
|
|
1666
|
+
const res = this.useEmbedded() ? await EmbeddedEngine.commit(this.connectionId, this.config, txId) : await this.executeWithTcpServer({ action: "commit", tx_id: txId });
|
|
1356
1667
|
if (res.status !== 200) throw new Error(String(res.message || "Failed to commit transaction"));
|
|
1357
1668
|
}
|
|
1358
1669
|
async rollbackTransaction(txId) {
|
|
1359
|
-
const res = await this.executeWithTcpServer({ action: "rollback", tx_id: txId });
|
|
1670
|
+
const res = this.useEmbedded() ? await EmbeddedEngine.rollback(this.connectionId, this.config, txId) : await this.executeWithTcpServer({ action: "rollback", tx_id: txId });
|
|
1360
1671
|
if (res.status !== 200) throw new Error(String(res.message || "Failed to rollback transaction"));
|
|
1361
1672
|
}
|
|
1362
1673
|
async executeWithTcpServer(command) {
|
|
@@ -1375,7 +1686,63 @@ var QueryEngine = class {
|
|
|
1375
1686
|
await this.startTcpServer();
|
|
1376
1687
|
await this.waitForServerReady();
|
|
1377
1688
|
}
|
|
1378
|
-
|
|
1689
|
+
const port = globalTcpServers.get(this.connectionId).port;
|
|
1690
|
+
const socket = await this.acquireSocket(port);
|
|
1691
|
+
try {
|
|
1692
|
+
const result = await this.executeOnConnection(socket, command);
|
|
1693
|
+
this.releaseSocket(socket, false);
|
|
1694
|
+
return result;
|
|
1695
|
+
} catch (error) {
|
|
1696
|
+
this.releaseSocket(socket, true);
|
|
1697
|
+
throw error;
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
poolFor() {
|
|
1701
|
+
let pool = socketPools.get(this.connectionId);
|
|
1702
|
+
if (!pool) {
|
|
1703
|
+
pool = { free: [], total: 0, waiters: [] };
|
|
1704
|
+
socketPools.set(this.connectionId, pool);
|
|
1705
|
+
}
|
|
1706
|
+
return pool;
|
|
1707
|
+
}
|
|
1708
|
+
async acquireSocket(port) {
|
|
1709
|
+
const pool = this.poolFor();
|
|
1710
|
+
while (pool.free.length > 0) {
|
|
1711
|
+
const s = pool.free.pop();
|
|
1712
|
+
if (!s.destroyed) return s;
|
|
1713
|
+
pool.total--;
|
|
1714
|
+
}
|
|
1715
|
+
if (pool.total < CLIENT_POOL_SIZE) {
|
|
1716
|
+
pool.total++;
|
|
1717
|
+
try {
|
|
1718
|
+
return await this.createNewConnection(port);
|
|
1719
|
+
} catch (e) {
|
|
1720
|
+
pool.total--;
|
|
1721
|
+
throw e;
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
return new Promise((resolve6) => pool.waiters.push(resolve6));
|
|
1725
|
+
}
|
|
1726
|
+
releaseSocket(socket, broken) {
|
|
1727
|
+
const pool = socketPools.get(this.connectionId);
|
|
1728
|
+
if (!pool) {
|
|
1729
|
+
socket.destroy();
|
|
1730
|
+
return;
|
|
1731
|
+
}
|
|
1732
|
+
if (broken || socket.destroyed) {
|
|
1733
|
+
pool.total--;
|
|
1734
|
+
try {
|
|
1735
|
+
socket.destroy();
|
|
1736
|
+
} catch {
|
|
1737
|
+
}
|
|
1738
|
+
return;
|
|
1739
|
+
}
|
|
1740
|
+
const waiter = pool.waiters.shift();
|
|
1741
|
+
if (waiter) {
|
|
1742
|
+
waiter(socket);
|
|
1743
|
+
} else {
|
|
1744
|
+
pool.free.push(socket);
|
|
1745
|
+
}
|
|
1379
1746
|
}
|
|
1380
1747
|
async waitForServerReady() {
|
|
1381
1748
|
const maxRetries = 10;
|
|
@@ -1393,25 +1760,25 @@ var QueryEngine = class {
|
|
|
1393
1760
|
throw new Error("TCP server failed to become ready within timeout");
|
|
1394
1761
|
}
|
|
1395
1762
|
async isServerResponding(port) {
|
|
1396
|
-
return new Promise((
|
|
1763
|
+
return new Promise((resolve6) => {
|
|
1397
1764
|
const client = new net2.Socket();
|
|
1398
1765
|
const timeout = setTimeout(() => {
|
|
1399
1766
|
client.destroy();
|
|
1400
|
-
|
|
1767
|
+
resolve6(false);
|
|
1401
1768
|
}, 1e3);
|
|
1402
1769
|
client.connect(port, "127.0.0.1", () => {
|
|
1403
1770
|
clearTimeout(timeout);
|
|
1404
1771
|
client.destroy();
|
|
1405
|
-
|
|
1772
|
+
resolve6(true);
|
|
1406
1773
|
});
|
|
1407
1774
|
client.on("error", () => {
|
|
1408
1775
|
clearTimeout(timeout);
|
|
1409
|
-
|
|
1776
|
+
resolve6(false);
|
|
1410
1777
|
});
|
|
1411
1778
|
});
|
|
1412
1779
|
}
|
|
1413
1780
|
sleep(ms) {
|
|
1414
|
-
return new Promise((
|
|
1781
|
+
return new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
1415
1782
|
}
|
|
1416
1783
|
getCachedDML(dmlJson) {
|
|
1417
1784
|
if (queryCache.has(dmlJson)) {
|
|
@@ -1431,7 +1798,7 @@ var QueryEngine = class {
|
|
|
1431
1798
|
throw new Error("Binary not initialized");
|
|
1432
1799
|
}
|
|
1433
1800
|
this.tcpPort = await this.findAvailablePort(this.tcpPort);
|
|
1434
|
-
return new Promise((
|
|
1801
|
+
return new Promise((resolve6, reject) => {
|
|
1435
1802
|
const serverArgs = [...this.arguments, "--action", "server", "--tcp-port", this.tcpPort.toString()];
|
|
1436
1803
|
const serverProcess = spawn3(this.binary["query_engine"], serverArgs);
|
|
1437
1804
|
let started = false;
|
|
@@ -1451,7 +1818,7 @@ var QueryEngine = class {
|
|
|
1451
1818
|
port: this.tcpPort,
|
|
1452
1819
|
process: serverProcess
|
|
1453
1820
|
});
|
|
1454
|
-
|
|
1821
|
+
resolve6();
|
|
1455
1822
|
}
|
|
1456
1823
|
}
|
|
1457
1824
|
});
|
|
@@ -1469,60 +1836,8 @@ var QueryEngine = class {
|
|
|
1469
1836
|
});
|
|
1470
1837
|
});
|
|
1471
1838
|
}
|
|
1472
|
-
async sendTcpRequestFast(command) {
|
|
1473
|
-
return new Promise((resolve5, reject) => {
|
|
1474
|
-
let queue = connectionQueues.get(this.connectionId);
|
|
1475
|
-
if (!queue) {
|
|
1476
|
-
queue = [];
|
|
1477
|
-
connectionQueues.set(this.connectionId, queue);
|
|
1478
|
-
}
|
|
1479
|
-
queue.push({ command, resolve: resolve5, reject });
|
|
1480
|
-
this.processQueue();
|
|
1481
|
-
});
|
|
1482
|
-
}
|
|
1483
|
-
async processQueue() {
|
|
1484
|
-
if (connectionProcessing.get(this.connectionId)) {
|
|
1485
|
-
return;
|
|
1486
|
-
}
|
|
1487
|
-
const queue = connectionQueues.get(this.connectionId);
|
|
1488
|
-
if (!queue || queue.length === 0) {
|
|
1489
|
-
return;
|
|
1490
|
-
}
|
|
1491
|
-
connectionProcessing.set(this.connectionId, true);
|
|
1492
|
-
try {
|
|
1493
|
-
const serverInfo = globalTcpServers.get(this.connectionId);
|
|
1494
|
-
if (!serverInfo) {
|
|
1495
|
-
throw new Error("Server not initialized");
|
|
1496
|
-
}
|
|
1497
|
-
while (queue.length > 0) {
|
|
1498
|
-
const request = queue.shift();
|
|
1499
|
-
if (!request) break;
|
|
1500
|
-
try {
|
|
1501
|
-
let connection = globalTcpConnections.get(this.connectionId);
|
|
1502
|
-
if (!connection || connection.destroyed || connection.readyState !== "open") {
|
|
1503
|
-
connection = await this.createNewConnection(serverInfo.port);
|
|
1504
|
-
globalTcpConnections.set(this.connectionId, connection);
|
|
1505
|
-
}
|
|
1506
|
-
const result = await this.executeOnConnection(connection, request.command);
|
|
1507
|
-
request.resolve(result);
|
|
1508
|
-
} catch (error) {
|
|
1509
|
-
const staleConnection = globalTcpConnections.get(this.connectionId);
|
|
1510
|
-
if (staleConnection) {
|
|
1511
|
-
try {
|
|
1512
|
-
staleConnection.destroy();
|
|
1513
|
-
} catch {
|
|
1514
|
-
}
|
|
1515
|
-
}
|
|
1516
|
-
globalTcpConnections.delete(this.connectionId);
|
|
1517
|
-
request.reject(error);
|
|
1518
|
-
}
|
|
1519
|
-
}
|
|
1520
|
-
} finally {
|
|
1521
|
-
connectionProcessing.set(this.connectionId, false);
|
|
1522
|
-
}
|
|
1523
|
-
}
|
|
1524
1839
|
async createNewConnection(port) {
|
|
1525
|
-
return new Promise((
|
|
1840
|
+
return new Promise((resolve6, reject) => {
|
|
1526
1841
|
const client = new net2.Socket();
|
|
1527
1842
|
client.setNoDelay(true);
|
|
1528
1843
|
client.setKeepAlive(true, 6e4);
|
|
@@ -1532,7 +1847,7 @@ var QueryEngine = class {
|
|
|
1532
1847
|
}, 5e3);
|
|
1533
1848
|
client.connect(port, "127.0.0.1", () => {
|
|
1534
1849
|
clearTimeout(timeout);
|
|
1535
|
-
|
|
1850
|
+
resolve6(client);
|
|
1536
1851
|
});
|
|
1537
1852
|
client.on("error", (error) => {
|
|
1538
1853
|
clearTimeout(timeout);
|
|
@@ -1541,7 +1856,7 @@ var QueryEngine = class {
|
|
|
1541
1856
|
});
|
|
1542
1857
|
}
|
|
1543
1858
|
async executeOnConnection(connection, command) {
|
|
1544
|
-
return new Promise((
|
|
1859
|
+
return new Promise((resolve6, reject) => {
|
|
1545
1860
|
let responseBuffer = "";
|
|
1546
1861
|
let isResolved = false;
|
|
1547
1862
|
const timeout = setTimeout(() => {
|
|
@@ -1566,7 +1881,7 @@ var QueryEngine = class {
|
|
|
1566
1881
|
connection.removeListener("error", onError);
|
|
1567
1882
|
try {
|
|
1568
1883
|
const response = JSON.parse(line.slice(marker + "PROCESS_RESPONSE:".length));
|
|
1569
|
-
|
|
1884
|
+
resolve6({
|
|
1570
1885
|
status: response.status,
|
|
1571
1886
|
message: response.message,
|
|
1572
1887
|
data: response.data
|
|
@@ -1595,7 +1910,7 @@ var QueryEngine = class {
|
|
|
1595
1910
|
if (!this.binary) {
|
|
1596
1911
|
throw new Error("Binary not initialized");
|
|
1597
1912
|
}
|
|
1598
|
-
return new Promise((
|
|
1913
|
+
return new Promise((resolve6, reject) => {
|
|
1599
1914
|
const child = spawn3(this.binary[binary], [...this.arguments, ...args]);
|
|
1600
1915
|
let stdoutBuffer = "";
|
|
1601
1916
|
let stderrBuffer = "";
|
|
@@ -1611,7 +1926,7 @@ var QueryEngine = class {
|
|
|
1611
1926
|
if (!isResolved) {
|
|
1612
1927
|
isResolved = true;
|
|
1613
1928
|
clearTimeout(timeoutId);
|
|
1614
|
-
|
|
1929
|
+
resolve6(response);
|
|
1615
1930
|
}
|
|
1616
1931
|
};
|
|
1617
1932
|
const tryParseLines = (buffer) => {
|
|
@@ -1668,11 +1983,16 @@ var QueryEngine = class {
|
|
|
1668
1983
|
});
|
|
1669
1984
|
}
|
|
1670
1985
|
async disconnect() {
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1986
|
+
await EmbeddedEngine.disconnect(this.connectionId);
|
|
1987
|
+
const pool = socketPools.get(this.connectionId);
|
|
1988
|
+
if (pool) {
|
|
1989
|
+
for (const s of pool.free) {
|
|
1990
|
+
try {
|
|
1991
|
+
s.destroy();
|
|
1992
|
+
} catch {
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
socketPools.delete(this.connectionId);
|
|
1676
1996
|
}
|
|
1677
1997
|
const serverInfo = globalTcpServers.get(this.connectionId);
|
|
1678
1998
|
if (serverInfo && serverInfo.process && !serverInfo.process.killed) {
|
|
@@ -1694,12 +2014,12 @@ var QueryEngine = class {
|
|
|
1694
2014
|
|
|
1695
2015
|
// src/lib/SqliteExecutor.ts
|
|
1696
2016
|
import { exec } from "child_process";
|
|
1697
|
-
import * as
|
|
1698
|
-
import * as
|
|
2017
|
+
import * as path7 from "path";
|
|
2018
|
+
import * as fs5 from "fs";
|
|
1699
2019
|
import { promisify } from "util";
|
|
1700
2020
|
import { createRequire as createRequire3 } from "module";
|
|
1701
2021
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
1702
|
-
import { dirname as
|
|
2022
|
+
import { dirname as dirname4 } from "path";
|
|
1703
2023
|
var execAsync = promisify(exec);
|
|
1704
2024
|
var SqliteExecutor = class {
|
|
1705
2025
|
binaryPath;
|
|
@@ -1710,13 +2030,13 @@ var SqliteExecutor = class {
|
|
|
1710
2030
|
}
|
|
1711
2031
|
findVersionedBinary(binDir, platform2) {
|
|
1712
2032
|
try {
|
|
1713
|
-
const files =
|
|
2033
|
+
const files = fs5.readdirSync(binDir);
|
|
1714
2034
|
const extension = platform2 === "win32" ? ".exe" : "";
|
|
1715
2035
|
const platformName = platform2 === "win32" ? "windows" : platform2 === "darwin" ? "macos" : "linux";
|
|
1716
2036
|
const pattern = new RegExp(`^sqlite-engine-v\\d+\\.\\d+\\.\\d+-${platformName}-x64${extension.replace(".", "\\.")}$`);
|
|
1717
2037
|
const matchingFile = files.find((f) => pattern.test(f));
|
|
1718
2038
|
if (matchingFile) {
|
|
1719
|
-
return
|
|
2039
|
+
return path7.join(binDir, matchingFile);
|
|
1720
2040
|
}
|
|
1721
2041
|
} catch (error) {
|
|
1722
2042
|
}
|
|
@@ -1724,36 +2044,36 @@ var SqliteExecutor = class {
|
|
|
1724
2044
|
}
|
|
1725
2045
|
getBinaryPath() {
|
|
1726
2046
|
const __filename2 = typeof import.meta !== "undefined" && import.meta.url ? fileURLToPath3(import.meta.url) : "";
|
|
1727
|
-
const __dirname = __filename2 ?
|
|
2047
|
+
const __dirname = __filename2 ? dirname4(__filename2) : process.cwd();
|
|
1728
2048
|
const possibleDirs = [
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
2049
|
+
path7.resolve(process.cwd(), ".dbcube", "bin"),
|
|
2050
|
+
path7.resolve(process.cwd(), "node_modules", ".dbcube", "bin"),
|
|
2051
|
+
path7.resolve(__dirname, "..", "bin")
|
|
1732
2052
|
];
|
|
1733
2053
|
const platform2 = process.platform;
|
|
1734
2054
|
const extension = platform2 === "win32" ? ".exe" : "";
|
|
1735
2055
|
const platformName = platform2 === "win32" ? "windows" : platform2 === "darwin" ? "macos" : "linux";
|
|
1736
2056
|
for (const dir of possibleDirs) {
|
|
1737
2057
|
const versionedPath = this.findVersionedBinary(dir, platform2);
|
|
1738
|
-
if (versionedPath &&
|
|
2058
|
+
if (versionedPath && fs5.existsSync(versionedPath)) {
|
|
1739
2059
|
return versionedPath;
|
|
1740
2060
|
}
|
|
1741
2061
|
}
|
|
1742
2062
|
const binaryName = `sqlite-engine-${platformName}-x64${extension}`;
|
|
1743
2063
|
for (const dir of possibleDirs) {
|
|
1744
|
-
const fullPath =
|
|
1745
|
-
if (
|
|
2064
|
+
const fullPath = path7.join(dir, binaryName);
|
|
2065
|
+
if (fs5.existsSync(fullPath)) {
|
|
1746
2066
|
return fullPath;
|
|
1747
2067
|
}
|
|
1748
2068
|
}
|
|
1749
2069
|
const fallbackName = `sqlite-engine${extension}`;
|
|
1750
2070
|
for (const dir of possibleDirs) {
|
|
1751
|
-
const fullPath =
|
|
1752
|
-
if (
|
|
2071
|
+
const fullPath = path7.join(dir, fallbackName);
|
|
2072
|
+
if (fs5.existsSync(fullPath)) {
|
|
1753
2073
|
return fullPath;
|
|
1754
2074
|
}
|
|
1755
2075
|
}
|
|
1756
|
-
return
|
|
2076
|
+
return path7.join(possibleDirs[0], binaryName);
|
|
1757
2077
|
}
|
|
1758
2078
|
async executeBinary(args) {
|
|
1759
2079
|
const escapedArgs = args.map((arg) => {
|
|
@@ -1904,9 +2224,9 @@ var SqliteExecutor = class {
|
|
|
1904
2224
|
};
|
|
1905
2225
|
|
|
1906
2226
|
// src/lib/DbConfig.ts
|
|
1907
|
-
import * as
|
|
1908
|
-
import
|
|
1909
|
-
var rootPath =
|
|
2227
|
+
import * as path8 from "path";
|
|
2228
|
+
import fs6 from "fs";
|
|
2229
|
+
var rootPath = path8.resolve(process.cwd(), ".dbcube");
|
|
1910
2230
|
var SQLite = class {
|
|
1911
2231
|
executor = null;
|
|
1912
2232
|
database;
|
|
@@ -1916,11 +2236,11 @@ var SQLite = class {
|
|
|
1916
2236
|
async ifExist() {
|
|
1917
2237
|
if (this.database) {
|
|
1918
2238
|
const dbPath = this.database || ":memory:";
|
|
1919
|
-
const configPath =
|
|
1920
|
-
if (!
|
|
1921
|
-
|
|
2239
|
+
const configPath = path8.join(rootPath, dbPath + ".db");
|
|
2240
|
+
if (!fs6.existsSync(rootPath)) {
|
|
2241
|
+
fs6.mkdirSync(rootPath, { recursive: true });
|
|
1922
2242
|
}
|
|
1923
|
-
if (
|
|
2243
|
+
if (fs6.existsSync(configPath)) {
|
|
1924
2244
|
return true;
|
|
1925
2245
|
}
|
|
1926
2246
|
if (!this.executor) {
|
|
@@ -1931,13 +2251,13 @@ var SQLite = class {
|
|
|
1931
2251
|
return false;
|
|
1932
2252
|
}
|
|
1933
2253
|
async connect() {
|
|
1934
|
-
return new Promise(async (
|
|
2254
|
+
return new Promise(async (resolve6, reject) => {
|
|
1935
2255
|
try {
|
|
1936
2256
|
if (!this.executor) {
|
|
1937
2257
|
const dbPath = this.database || ":memory:";
|
|
1938
|
-
const configPath =
|
|
1939
|
-
if (!
|
|
1940
|
-
|
|
2258
|
+
const configPath = path8.join(rootPath, dbPath + ".db");
|
|
2259
|
+
if (!fs6.existsSync(rootPath)) {
|
|
2260
|
+
fs6.mkdirSync(rootPath, { recursive: true });
|
|
1941
2261
|
}
|
|
1942
2262
|
this.executor = new SqliteExecutor(configPath);
|
|
1943
2263
|
const connected = await this.executor.connect();
|
|
@@ -1945,22 +2265,22 @@ var SQLite = class {
|
|
|
1945
2265
|
throw new Error("Failed to connect to SQLite database");
|
|
1946
2266
|
}
|
|
1947
2267
|
}
|
|
1948
|
-
|
|
2268
|
+
resolve6(this.executor);
|
|
1949
2269
|
} catch (error) {
|
|
1950
2270
|
reject(error);
|
|
1951
2271
|
}
|
|
1952
2272
|
});
|
|
1953
2273
|
}
|
|
1954
2274
|
async disconnect() {
|
|
1955
|
-
return new Promise((
|
|
2275
|
+
return new Promise((resolve6) => {
|
|
1956
2276
|
if (this.executor) {
|
|
1957
2277
|
this.executor = null;
|
|
1958
2278
|
}
|
|
1959
|
-
|
|
2279
|
+
resolve6();
|
|
1960
2280
|
});
|
|
1961
2281
|
}
|
|
1962
2282
|
async query(sqlQuery) {
|
|
1963
|
-
return new Promise(async (
|
|
2283
|
+
return new Promise(async (resolve6) => {
|
|
1964
2284
|
try {
|
|
1965
2285
|
if (typeof sqlQuery !== "string") {
|
|
1966
2286
|
throw new Error("The SQL query must be a string.");
|
|
@@ -1973,20 +2293,20 @@ var SQLite = class {
|
|
|
1973
2293
|
}
|
|
1974
2294
|
const result = await this.executor.queryMultiple(sqlQuery);
|
|
1975
2295
|
if (result.status === "error") {
|
|
1976
|
-
|
|
2296
|
+
resolve6({
|
|
1977
2297
|
status: "error",
|
|
1978
2298
|
message: result.message,
|
|
1979
2299
|
data: null
|
|
1980
2300
|
});
|
|
1981
2301
|
} else {
|
|
1982
|
-
|
|
2302
|
+
resolve6({
|
|
1983
2303
|
status: "success",
|
|
1984
2304
|
message: "Query executed successfully",
|
|
1985
2305
|
data: result.data
|
|
1986
2306
|
});
|
|
1987
2307
|
}
|
|
1988
2308
|
} catch (error) {
|
|
1989
|
-
|
|
2309
|
+
resolve6({
|
|
1990
2310
|
status: "error",
|
|
1991
2311
|
message: error.message || "An error occurred while executing the query.",
|
|
1992
2312
|
data: null
|
|
@@ -1995,7 +2315,7 @@ var SQLite = class {
|
|
|
1995
2315
|
});
|
|
1996
2316
|
}
|
|
1997
2317
|
async queryWithParameters(sqlQuery, params = []) {
|
|
1998
|
-
return new Promise(async (
|
|
2318
|
+
return new Promise(async (resolve6) => {
|
|
1999
2319
|
try {
|
|
2000
2320
|
if (typeof sqlQuery !== "string") {
|
|
2001
2321
|
throw new Error("The SQL query must be a string.");
|
|
@@ -2011,13 +2331,13 @@ var SQLite = class {
|
|
|
2011
2331
|
}
|
|
2012
2332
|
const result = await this.executor.query(sqlQuery, params);
|
|
2013
2333
|
if (result.status === "error") {
|
|
2014
|
-
|
|
2334
|
+
resolve6({
|
|
2015
2335
|
status: "error",
|
|
2016
2336
|
message: result.message,
|
|
2017
2337
|
data: null
|
|
2018
2338
|
});
|
|
2019
2339
|
} else {
|
|
2020
|
-
|
|
2340
|
+
resolve6({
|
|
2021
2341
|
status: "success",
|
|
2022
2342
|
message: "Query executed successfully",
|
|
2023
2343
|
data: result.data
|
|
@@ -2025,7 +2345,7 @@ var SQLite = class {
|
|
|
2025
2345
|
}
|
|
2026
2346
|
} catch (error) {
|
|
2027
2347
|
console.log(error);
|
|
2028
|
-
|
|
2348
|
+
resolve6({
|
|
2029
2349
|
status: "error",
|
|
2030
2350
|
message: error.message || "An error occurred while executing the query.",
|
|
2031
2351
|
data: null
|
|
@@ -2119,8 +2439,8 @@ var DbConfig = new SQLite({ DATABASE: "config" });
|
|
|
2119
2439
|
var DbConfig_default = DbConfig;
|
|
2120
2440
|
|
|
2121
2441
|
// src/lib/FileLogger.ts
|
|
2122
|
-
import * as
|
|
2123
|
-
import * as
|
|
2442
|
+
import * as fs7 from "fs";
|
|
2443
|
+
import * as path9 from "path";
|
|
2124
2444
|
import { EventEmitter } from "events";
|
|
2125
2445
|
var FileLogger = class _FileLogger extends EventEmitter {
|
|
2126
2446
|
static watchers = /* @__PURE__ */ new Map();
|
|
@@ -2135,9 +2455,9 @@ var FileLogger = class _FileLogger extends EventEmitter {
|
|
|
2135
2455
|
*/
|
|
2136
2456
|
static async write(filePath, message, level = "INFO", append = true) {
|
|
2137
2457
|
try {
|
|
2138
|
-
const dir =
|
|
2139
|
-
if (!
|
|
2140
|
-
|
|
2458
|
+
const dir = path9.dirname(filePath);
|
|
2459
|
+
if (!fs7.existsSync(dir)) {
|
|
2460
|
+
fs7.mkdirSync(dir, { recursive: true });
|
|
2141
2461
|
}
|
|
2142
2462
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
2143
2463
|
const formattedMessage = `[${timestamp}] [${level}] ${message}
|
|
@@ -2147,9 +2467,9 @@ var FileLogger = class _FileLogger extends EventEmitter {
|
|
|
2147
2467
|
return true;
|
|
2148
2468
|
}
|
|
2149
2469
|
if (append) {
|
|
2150
|
-
await
|
|
2470
|
+
await fs7.promises.appendFile(filePath, formattedMessage, "utf8");
|
|
2151
2471
|
} else {
|
|
2152
|
-
await
|
|
2472
|
+
await fs7.promises.writeFile(filePath, formattedMessage, "utf8");
|
|
2153
2473
|
}
|
|
2154
2474
|
return true;
|
|
2155
2475
|
} catch (error) {
|
|
@@ -2174,12 +2494,12 @@ var FileLogger = class _FileLogger extends EventEmitter {
|
|
|
2174
2494
|
const buffer = _FileLogger.buffers.get(filePath);
|
|
2175
2495
|
if (buffer && buffer.length > 0) {
|
|
2176
2496
|
try {
|
|
2177
|
-
const dir =
|
|
2178
|
-
if (!
|
|
2179
|
-
|
|
2497
|
+
const dir = path9.dirname(filePath);
|
|
2498
|
+
if (!fs7.existsSync(dir)) {
|
|
2499
|
+
fs7.mkdirSync(dir, { recursive: true });
|
|
2180
2500
|
}
|
|
2181
2501
|
const content = buffer.join("");
|
|
2182
|
-
await
|
|
2502
|
+
await fs7.promises.appendFile(filePath, content, "utf8");
|
|
2183
2503
|
_FileLogger.buffers.delete(filePath);
|
|
2184
2504
|
return true;
|
|
2185
2505
|
} catch (error) {
|
|
@@ -2315,10 +2635,10 @@ var FileLogger = class _FileLogger extends EventEmitter {
|
|
|
2315
2635
|
// Si debe retornar como array de líneas
|
|
2316
2636
|
} = options;
|
|
2317
2637
|
try {
|
|
2318
|
-
if (!
|
|
2638
|
+
if (!fs7.existsSync(filePath)) {
|
|
2319
2639
|
return asArray ? [] : "";
|
|
2320
2640
|
}
|
|
2321
|
-
let content = await
|
|
2641
|
+
let content = await fs7.promises.readFile(filePath, "utf8");
|
|
2322
2642
|
if (asArray) {
|
|
2323
2643
|
let linesArray = content.split("\n").filter((line) => line.trim() !== "");
|
|
2324
2644
|
if (lines !== null) {
|
|
@@ -2361,15 +2681,15 @@ var FileLogger = class _FileLogger extends EventEmitter {
|
|
|
2361
2681
|
} = options;
|
|
2362
2682
|
let lastSize = 0;
|
|
2363
2683
|
let lastPosition = 0;
|
|
2364
|
-
if (
|
|
2365
|
-
const stats =
|
|
2684
|
+
if (fs7.existsSync(filePath)) {
|
|
2685
|
+
const stats = fs7.statSync(filePath);
|
|
2366
2686
|
lastSize = stats.size;
|
|
2367
2687
|
lastPosition = fromEnd ? stats.size : 0;
|
|
2368
2688
|
}
|
|
2369
2689
|
const listener = async (curr, prev) => {
|
|
2370
2690
|
try {
|
|
2371
2691
|
if (curr.size > lastSize) {
|
|
2372
|
-
const stream =
|
|
2692
|
+
const stream = fs7.createReadStream(filePath, {
|
|
2373
2693
|
start: lastPosition,
|
|
2374
2694
|
end: curr.size - 1,
|
|
2375
2695
|
encoding: "utf8"
|
|
@@ -2397,7 +2717,7 @@ var FileLogger = class _FileLogger extends EventEmitter {
|
|
|
2397
2717
|
console.error("Error en watcher:", error);
|
|
2398
2718
|
}
|
|
2399
2719
|
};
|
|
2400
|
-
|
|
2720
|
+
fs7.watchFile(filePath, { persistent, interval }, listener);
|
|
2401
2721
|
const watcherId = `${filePath}_${Date.now()}`;
|
|
2402
2722
|
_FileLogger.watchers.set(watcherId, listener);
|
|
2403
2723
|
return {
|
|
@@ -2405,7 +2725,7 @@ var FileLogger = class _FileLogger extends EventEmitter {
|
|
|
2405
2725
|
stop: () => {
|
|
2406
2726
|
const storedListener = _FileLogger.watchers.get(watcherId);
|
|
2407
2727
|
if (storedListener) {
|
|
2408
|
-
|
|
2728
|
+
fs7.unwatchFile(filePath, storedListener);
|
|
2409
2729
|
_FileLogger.watchers.delete(watcherId);
|
|
2410
2730
|
}
|
|
2411
2731
|
},
|
|
@@ -2418,7 +2738,7 @@ var FileLogger = class _FileLogger extends EventEmitter {
|
|
|
2418
2738
|
static stopAllWatchers() {
|
|
2419
2739
|
for (const [watcherId] of _FileLogger.watchers) {
|
|
2420
2740
|
const filePath = watcherId.split("_")[0];
|
|
2421
|
-
|
|
2741
|
+
fs7.unwatchFile(filePath);
|
|
2422
2742
|
}
|
|
2423
2743
|
_FileLogger.watchers.clear();
|
|
2424
2744
|
}
|
|
@@ -2448,7 +2768,7 @@ var FileLogger = class _FileLogger extends EventEmitter {
|
|
|
2448
2768
|
if (lines.length > maxLines) {
|
|
2449
2769
|
const keepLines = lines.slice(-maxLines);
|
|
2450
2770
|
const content = keepLines.join("\n") + "\n";
|
|
2451
|
-
await
|
|
2771
|
+
await fs7.promises.writeFile(filePath, content, "utf8");
|
|
2452
2772
|
return lines.length - maxLines;
|
|
2453
2773
|
}
|
|
2454
2774
|
return 0;
|
|
@@ -2463,8 +2783,8 @@ var FileLogger = class _FileLogger extends EventEmitter {
|
|
|
2463
2783
|
*/
|
|
2464
2784
|
static async deleteLogFile(filePath) {
|
|
2465
2785
|
try {
|
|
2466
|
-
if (
|
|
2467
|
-
await
|
|
2786
|
+
if (fs7.existsSync(filePath)) {
|
|
2787
|
+
await fs7.promises.unlink(filePath);
|
|
2468
2788
|
return true;
|
|
2469
2789
|
}
|
|
2470
2790
|
return false;
|