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