@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.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/lib/Engine.ts
|
|
2
|
-
import
|
|
2
|
+
import path4 from "path";
|
|
3
3
|
|
|
4
4
|
// src/lib/Arquitecture.ts
|
|
5
5
|
import * as os from "os";
|
|
@@ -345,7 +345,7 @@ var Downloader = class {
|
|
|
345
345
|
}
|
|
346
346
|
this.mainSpinner.text = chalk.blue(`Updating ${binariesToDownload.length} binary(ies)...`);
|
|
347
347
|
try {
|
|
348
|
-
await Promise.
|
|
348
|
+
const results = await Promise.allSettled(binariesToDownload.map(async (binary) => {
|
|
349
349
|
const maxRetries = 3;
|
|
350
350
|
let attempt = 0;
|
|
351
351
|
while (attempt <= maxRetries) {
|
|
@@ -373,6 +373,11 @@ var Downloader = class {
|
|
|
373
373
|
}
|
|
374
374
|
}
|
|
375
375
|
}));
|
|
376
|
+
const failures = results.filter((r) => r.status === "rejected");
|
|
377
|
+
if (failures.length > 0) {
|
|
378
|
+
const messages = failures.map((f) => f.reason instanceof Error ? f.reason.message : String(f.reason));
|
|
379
|
+
throw new Error(messages.join(" | "));
|
|
380
|
+
}
|
|
376
381
|
this.mainSpinner.succeed(chalk.green("Binaries updated successfully"));
|
|
377
382
|
} catch (error) {
|
|
378
383
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
@@ -437,8 +442,7 @@ var Downloader = class {
|
|
|
437
442
|
}
|
|
438
443
|
});
|
|
439
444
|
response.on("end", () => {
|
|
440
|
-
file.end();
|
|
441
|
-
resolve5();
|
|
445
|
+
file.end(() => resolve5());
|
|
442
446
|
});
|
|
443
447
|
response.on("error", (err) => {
|
|
444
448
|
file.close();
|
|
@@ -664,7 +668,6 @@ var Config = class {
|
|
|
664
668
|
/**
|
|
665
669
|
* Obtiene un valor de configuración
|
|
666
670
|
* @param key - Clave de configuración
|
|
667
|
-
* @returns Valor de configuración
|
|
668
671
|
*/
|
|
669
672
|
get(key) {
|
|
670
673
|
return this.data[key];
|
|
@@ -672,14 +675,12 @@ var Config = class {
|
|
|
672
675
|
/**
|
|
673
676
|
* Obtiene la configuración de una base de datos específica
|
|
674
677
|
* @param dbName - Nombre de la base de datos
|
|
675
|
-
* @returns Configuración de la base de datos o null
|
|
676
678
|
*/
|
|
677
679
|
getDatabase(dbName) {
|
|
678
680
|
return this.databases[dbName] || null;
|
|
679
681
|
}
|
|
680
682
|
/**
|
|
681
683
|
* Obtiene todas las bases de datos configuradas
|
|
682
|
-
* @returns Todas las configuraciones de bases de datos
|
|
683
684
|
*/
|
|
684
685
|
getAllDatabases() {
|
|
685
686
|
return this.databases;
|
|
@@ -687,14 +688,258 @@ var Config = class {
|
|
|
687
688
|
};
|
|
688
689
|
|
|
689
690
|
// src/lib/Engine.ts
|
|
690
|
-
import { spawn } from "child_process";
|
|
691
|
+
import { spawn as spawn2 } from "child_process";
|
|
691
692
|
import { createRequire } from "module";
|
|
693
|
+
|
|
694
|
+
// src/lib/DaemonClient.ts
|
|
695
|
+
import net from "net";
|
|
696
|
+
import fs3 from "fs";
|
|
697
|
+
import path3 from "path";
|
|
698
|
+
import { spawn } from "child_process";
|
|
699
|
+
var DaemonClient = class _DaemonClient {
|
|
700
|
+
static registry = /* @__PURE__ */ new Map();
|
|
701
|
+
name;
|
|
702
|
+
binaryPath;
|
|
703
|
+
engineArgs;
|
|
704
|
+
socket = null;
|
|
705
|
+
buffer = "";
|
|
706
|
+
pending = [];
|
|
707
|
+
starting = null;
|
|
708
|
+
requestTimeout;
|
|
709
|
+
constructor(name, binaryPath, engineArgs, requestTimeout = 3e4) {
|
|
710
|
+
this.name = name;
|
|
711
|
+
this.binaryPath = binaryPath;
|
|
712
|
+
this.engineArgs = engineArgs;
|
|
713
|
+
this.requestTimeout = requestTimeout;
|
|
714
|
+
}
|
|
715
|
+
static get(name, binaryPath, engineArgs) {
|
|
716
|
+
let client = this.registry.get(name);
|
|
717
|
+
if (!client) {
|
|
718
|
+
client = new _DaemonClient(name, binaryPath, engineArgs);
|
|
719
|
+
this.registry.set(name, client);
|
|
720
|
+
}
|
|
721
|
+
return client;
|
|
722
|
+
}
|
|
723
|
+
static isEnabled() {
|
|
724
|
+
const flag = process.env.DBCUBE_DAEMON;
|
|
725
|
+
if (flag === "0" || flag === "false") return false;
|
|
726
|
+
return true;
|
|
727
|
+
}
|
|
728
|
+
portfilePath() {
|
|
729
|
+
return path3.join(process.cwd(), ".dbcube", "daemon", `${this.name}.json`);
|
|
730
|
+
}
|
|
731
|
+
lockfilePath() {
|
|
732
|
+
return path3.join(process.cwd(), ".dbcube", "daemon", `${this.name}.lock`);
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* Exclusive-create lock so two processes never spawn two daemons for the
|
|
736
|
+
* same database at once. Stale locks (crashed starter) expire after 15s.
|
|
737
|
+
*/
|
|
738
|
+
acquireSpawnLock() {
|
|
739
|
+
const lockPath = this.lockfilePath();
|
|
740
|
+
try {
|
|
741
|
+
fs3.mkdirSync(path3.dirname(lockPath), { recursive: true });
|
|
742
|
+
const fd = fs3.openSync(lockPath, "wx");
|
|
743
|
+
fs3.writeSync(fd, String(process.pid));
|
|
744
|
+
fs3.closeSync(fd);
|
|
745
|
+
return true;
|
|
746
|
+
} catch {
|
|
747
|
+
try {
|
|
748
|
+
const age = Date.now() - fs3.statSync(lockPath).mtimeMs;
|
|
749
|
+
if (age > 15e3) {
|
|
750
|
+
fs3.unlinkSync(lockPath);
|
|
751
|
+
return this.acquireSpawnLock();
|
|
752
|
+
}
|
|
753
|
+
} catch {
|
|
754
|
+
}
|
|
755
|
+
return false;
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
releaseSpawnLock() {
|
|
759
|
+
try {
|
|
760
|
+
fs3.unlinkSync(this.lockfilePath());
|
|
761
|
+
} catch {
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
/**
|
|
765
|
+
* Ensures a usable daemon connection. Returns false when the daemon
|
|
766
|
+
* can't be used (old binary, startup failure) so callers fall back
|
|
767
|
+
* to one-shot spawn mode.
|
|
768
|
+
*/
|
|
769
|
+
async ensure() {
|
|
770
|
+
if (this.socket && !this.socket.destroyed) return true;
|
|
771
|
+
if (this.starting) return this.starting;
|
|
772
|
+
this.starting = this.connectOrStart().catch(() => false);
|
|
773
|
+
const result = await this.starting;
|
|
774
|
+
this.starting = null;
|
|
775
|
+
return result;
|
|
776
|
+
}
|
|
777
|
+
async connectOrStart() {
|
|
778
|
+
const port = this.readPortfile();
|
|
779
|
+
if (port && await this.tryConnect(port)) return true;
|
|
780
|
+
const gotLock = this.acquireSpawnLock();
|
|
781
|
+
try {
|
|
782
|
+
if (gotLock) {
|
|
783
|
+
try {
|
|
784
|
+
fs3.unlinkSync(this.portfilePath());
|
|
785
|
+
} catch {
|
|
786
|
+
}
|
|
787
|
+
this.spawnDaemon();
|
|
788
|
+
}
|
|
789
|
+
const deadline = Date.now() + 1e4;
|
|
790
|
+
while (Date.now() < deadline) {
|
|
791
|
+
await new Promise((r) => setTimeout(r, 150));
|
|
792
|
+
const newPort = this.readPortfile();
|
|
793
|
+
if (newPort && await this.tryConnect(newPort)) return true;
|
|
794
|
+
}
|
|
795
|
+
return false;
|
|
796
|
+
} finally {
|
|
797
|
+
if (gotLock) this.releaseSpawnLock();
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
readPortfile() {
|
|
801
|
+
try {
|
|
802
|
+
const raw = fs3.readFileSync(this.portfilePath(), "utf8");
|
|
803
|
+
const info = JSON.parse(raw);
|
|
804
|
+
const port = info?.port;
|
|
805
|
+
return Number.isInteger(port) && port > 0 && port <= 65535 ? port : null;
|
|
806
|
+
} catch {
|
|
807
|
+
return null;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
spawnDaemon() {
|
|
811
|
+
const child = spawn(this.binaryPath, [...this.engineArgs, "--action", "server", "--tcp-port", "9944"], {
|
|
812
|
+
detached: true,
|
|
813
|
+
stdio: "ignore",
|
|
814
|
+
cwd: process.cwd()
|
|
815
|
+
});
|
|
816
|
+
child.unref();
|
|
817
|
+
}
|
|
818
|
+
tryConnect(port) {
|
|
819
|
+
return new Promise((resolve5) => {
|
|
820
|
+
const socket = net.createConnection({ host: "127.0.0.1", port }, async () => {
|
|
821
|
+
socket.setNoDelay(true);
|
|
822
|
+
this.attach(socket);
|
|
823
|
+
try {
|
|
824
|
+
const pong = await this.send({ action: "ping" }, 2e3);
|
|
825
|
+
resolve5(pong.status === 200);
|
|
826
|
+
} catch {
|
|
827
|
+
this.detach();
|
|
828
|
+
resolve5(false);
|
|
829
|
+
}
|
|
830
|
+
});
|
|
831
|
+
socket.once("error", () => resolve5(false));
|
|
832
|
+
socket.setTimeout(3e3, () => {
|
|
833
|
+
socket.destroy();
|
|
834
|
+
resolve5(false);
|
|
835
|
+
});
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
attach(socket) {
|
|
839
|
+
this.socket = socket;
|
|
840
|
+
this.buffer = "";
|
|
841
|
+
socket.setTimeout(0);
|
|
842
|
+
socket.on("data", (chunk) => this.onData(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
|
|
843
|
+
socket.on("close", () => this.detach());
|
|
844
|
+
socket.on("error", () => this.detach());
|
|
845
|
+
}
|
|
846
|
+
detach() {
|
|
847
|
+
if (this.socket) {
|
|
848
|
+
this.socket.removeAllListeners();
|
|
849
|
+
this.socket.destroy();
|
|
850
|
+
this.socket = null;
|
|
851
|
+
}
|
|
852
|
+
for (const req of this.pending.splice(0)) {
|
|
853
|
+
clearTimeout(req.timer);
|
|
854
|
+
req.reject(new Error("Daemon connection lost"));
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
onData(chunk) {
|
|
858
|
+
this.buffer += chunk.toString("utf8");
|
|
859
|
+
let idx;
|
|
860
|
+
while ((idx = this.buffer.indexOf("\n")) !== -1) {
|
|
861
|
+
const line = this.buffer.slice(0, idx).trim();
|
|
862
|
+
this.buffer = this.buffer.slice(idx + 1);
|
|
863
|
+
if (!line) continue;
|
|
864
|
+
const marker = line.indexOf("PROCESS_RESPONSE:");
|
|
865
|
+
if (marker === -1) continue;
|
|
866
|
+
const jsonPart = line.slice(marker + "PROCESS_RESPONSE:".length);
|
|
867
|
+
const req = this.pending.shift();
|
|
868
|
+
if (!req) continue;
|
|
869
|
+
clearTimeout(req.timer);
|
|
870
|
+
try {
|
|
871
|
+
req.resolve(JSON.parse(jsonPart));
|
|
872
|
+
} catch (e) {
|
|
873
|
+
req.reject(new Error(`Invalid daemon response: ${e.message}`));
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
/**
|
|
878
|
+
* Sends a request to the daemon. Responses arrive in FIFO order on the
|
|
879
|
+
* single socket, so pending requests resolve in send order.
|
|
880
|
+
*/
|
|
881
|
+
send(payload, timeoutMs) {
|
|
882
|
+
return new Promise((resolve5, reject) => {
|
|
883
|
+
if (!this.socket || this.socket.destroyed) {
|
|
884
|
+
reject(new Error("Daemon not connected"));
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
const timer = setTimeout(() => {
|
|
888
|
+
const i = this.pending.findIndex((p) => p.timer === timer);
|
|
889
|
+
if (i !== -1) this.pending.splice(i, 1);
|
|
890
|
+
reject(new Error("Daemon request timeout"));
|
|
891
|
+
this.detach();
|
|
892
|
+
}, timeoutMs ?? this.requestTimeout);
|
|
893
|
+
this.pending.push({ resolve: resolve5, reject, timer });
|
|
894
|
+
this.socket.write(JSON.stringify(payload) + "\n");
|
|
895
|
+
});
|
|
896
|
+
}
|
|
897
|
+
async execute(dml, txId) {
|
|
898
|
+
const payload = { action: "execute", dml: JSON.stringify(dml) };
|
|
899
|
+
if (txId) payload.tx_id = txId;
|
|
900
|
+
return this.send(payload);
|
|
901
|
+
}
|
|
902
|
+
async raw(query, params = [], txId) {
|
|
903
|
+
const payload = { action: "raw", query, params };
|
|
904
|
+
if (txId) payload.tx_id = txId;
|
|
905
|
+
return this.send(payload);
|
|
906
|
+
}
|
|
907
|
+
async begin() {
|
|
908
|
+
const res = await this.send({ action: "begin" });
|
|
909
|
+
if (res.status !== 200 || !res.data?.tx_id) {
|
|
910
|
+
throw new Error(res.message || "Failed to begin transaction");
|
|
911
|
+
}
|
|
912
|
+
return res.data.tx_id;
|
|
913
|
+
}
|
|
914
|
+
async commit(txId) {
|
|
915
|
+
const res = await this.send({ action: "commit", tx_id: txId });
|
|
916
|
+
if (res.status !== 200) throw new Error(res.message || "Failed to commit transaction");
|
|
917
|
+
}
|
|
918
|
+
async rollback(txId) {
|
|
919
|
+
const res = await this.send({ action: "rollback", tx_id: txId });
|
|
920
|
+
if (res.status !== 200) throw new Error(res.message || "Failed to rollback transaction");
|
|
921
|
+
}
|
|
922
|
+
async shutdown() {
|
|
923
|
+
try {
|
|
924
|
+
await this.send({ action: "shutdown" });
|
|
925
|
+
} catch {
|
|
926
|
+
}
|
|
927
|
+
this.detach();
|
|
928
|
+
try {
|
|
929
|
+
fs3.unlinkSync(this.portfilePath());
|
|
930
|
+
} catch {
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
};
|
|
934
|
+
|
|
935
|
+
// src/lib/Engine.ts
|
|
692
936
|
var Engine = class {
|
|
693
937
|
name;
|
|
694
938
|
config;
|
|
695
939
|
arguments;
|
|
696
940
|
binary = null;
|
|
697
941
|
timeout;
|
|
942
|
+
daemonFailed = false;
|
|
698
943
|
constructor(name, timeout = 3e4) {
|
|
699
944
|
this.name = name;
|
|
700
945
|
this.config = this.setConfig(name);
|
|
@@ -706,6 +951,77 @@ var Engine = class {
|
|
|
706
951
|
this.binary = await Binary.get();
|
|
707
952
|
}
|
|
708
953
|
}
|
|
954
|
+
/**
|
|
955
|
+
* Returns a connected DaemonClient for this database, or null when
|
|
956
|
+
* daemon mode is disabled/unavailable (then callers use spawn mode).
|
|
957
|
+
*/
|
|
958
|
+
async getDaemon() {
|
|
959
|
+
if (this.daemonFailed || !DaemonClient.isEnabled()) return null;
|
|
960
|
+
await this.initializeBinary();
|
|
961
|
+
if (!this.binary) return null;
|
|
962
|
+
const binaryPath = this.binary["query_engine"];
|
|
963
|
+
if (!binaryPath) return null;
|
|
964
|
+
const client = DaemonClient.get(this.name, binaryPath, this.arguments);
|
|
965
|
+
const ok = await client.ensure();
|
|
966
|
+
if (!ok) {
|
|
967
|
+
this.daemonFailed = true;
|
|
968
|
+
return null;
|
|
969
|
+
}
|
|
970
|
+
return client;
|
|
971
|
+
}
|
|
972
|
+
/**
|
|
973
|
+
* Executes a DML plan. Uses the persistent daemon (sub-millisecond
|
|
974
|
+
* overhead) when available; falls back to one-shot spawn otherwise.
|
|
975
|
+
*/
|
|
976
|
+
async executeDml(dml, txId) {
|
|
977
|
+
const daemon = await this.getDaemon();
|
|
978
|
+
if (daemon) {
|
|
979
|
+
try {
|
|
980
|
+
return await daemon.execute(dml, txId);
|
|
981
|
+
} catch (error) {
|
|
982
|
+
if (txId) throw error;
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
if (txId) {
|
|
986
|
+
throw new Error("Transactions require daemon mode. Make sure the query-engine binary is up to date (npx dbcube update).");
|
|
987
|
+
}
|
|
988
|
+
return this.run("query_engine", ["--action", "execute", "--dml", JSON.stringify(dml)]);
|
|
989
|
+
}
|
|
990
|
+
/**
|
|
991
|
+
* Executes raw SQL (or a MongoDB command document) with bound parameters.
|
|
992
|
+
*/
|
|
993
|
+
async rawQuery(query, params = [], txId) {
|
|
994
|
+
const daemon = await this.getDaemon();
|
|
995
|
+
if (daemon) {
|
|
996
|
+
try {
|
|
997
|
+
return await daemon.raw(query, params, txId);
|
|
998
|
+
} catch (error) {
|
|
999
|
+
if (txId) throw error;
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
if (txId) {
|
|
1003
|
+
throw new Error("Transactions require daemon mode. Make sure the query-engine binary is up to date (npx dbcube update).");
|
|
1004
|
+
}
|
|
1005
|
+
return this.run("query_engine", ["--action", "raw", "--query", query, "--params", JSON.stringify(params)]);
|
|
1006
|
+
}
|
|
1007
|
+
/** Starts a transaction (daemon mode only). Returns the transaction id. */
|
|
1008
|
+
async beginTransaction() {
|
|
1009
|
+
const daemon = await this.getDaemon();
|
|
1010
|
+
if (!daemon) {
|
|
1011
|
+
throw new Error("Transactions require daemon mode. Make sure the query-engine binary is up to date (npx dbcube update).");
|
|
1012
|
+
}
|
|
1013
|
+
return daemon.begin();
|
|
1014
|
+
}
|
|
1015
|
+
async commitTransaction(txId) {
|
|
1016
|
+
const daemon = await this.getDaemon();
|
|
1017
|
+
if (!daemon) throw new Error("Daemon connection lost during transaction");
|
|
1018
|
+
return daemon.commit(txId);
|
|
1019
|
+
}
|
|
1020
|
+
async rollbackTransaction(txId) {
|
|
1021
|
+
const daemon = await this.getDaemon();
|
|
1022
|
+
if (!daemon) throw new Error("Daemon connection lost during transaction");
|
|
1023
|
+
return daemon.rollback(txId);
|
|
1024
|
+
}
|
|
709
1025
|
setArguments() {
|
|
710
1026
|
let args = [];
|
|
711
1027
|
if (this.config.type == "sqlite") {
|
|
@@ -730,21 +1046,23 @@ var Engine = class {
|
|
|
730
1046
|
"--host",
|
|
731
1047
|
this.config.config.HOST,
|
|
732
1048
|
"--port",
|
|
733
|
-
this.config.config.PORT,
|
|
734
|
-
"--user",
|
|
735
|
-
this.config.config.USER,
|
|
736
|
-
"--password",
|
|
737
|
-
this.config.config.PASSWORD,
|
|
1049
|
+
String(this.config.config.PORT),
|
|
738
1050
|
"--motor",
|
|
739
1051
|
this.config.type
|
|
740
1052
|
];
|
|
1053
|
+
if (this.config.config.USER != null && this.config.config.USER !== "") {
|
|
1054
|
+
args.push("--user", this.config.config.USER);
|
|
1055
|
+
}
|
|
1056
|
+
if (this.config.config.PASSWORD != null && this.config.config.PASSWORD !== "") {
|
|
1057
|
+
args.push("--password", this.config.config.PASSWORD);
|
|
1058
|
+
}
|
|
741
1059
|
}
|
|
742
1060
|
return args;
|
|
743
1061
|
}
|
|
744
1062
|
setConfig(name) {
|
|
745
1063
|
const configInstance = new Config();
|
|
746
1064
|
try {
|
|
747
|
-
const configFilePath =
|
|
1065
|
+
const configFilePath = path4.resolve(process.cwd(), "dbcube.config.js");
|
|
748
1066
|
const requireUrl = typeof __filename !== "undefined" ? __filename : process.cwd();
|
|
749
1067
|
const require2 = createRequire(requireUrl);
|
|
750
1068
|
if (require2.cache && require2.resolve) {
|
|
@@ -777,7 +1095,7 @@ var Engine = class {
|
|
|
777
1095
|
throw new Error("Binary not initialized");
|
|
778
1096
|
}
|
|
779
1097
|
return new Promise((resolve5, reject) => {
|
|
780
|
-
const child =
|
|
1098
|
+
const child = spawn2(this.binary[binary], [...this.arguments, ...args]);
|
|
781
1099
|
let stdoutBuffer = "";
|
|
782
1100
|
let stderrBuffer = "";
|
|
783
1101
|
let isResolved = false;
|
|
@@ -796,8 +1114,10 @@ var Engine = class {
|
|
|
796
1114
|
}
|
|
797
1115
|
};
|
|
798
1116
|
child.stdout.on("data", (data) => {
|
|
799
|
-
|
|
800
|
-
|
|
1117
|
+
const text = data.toString();
|
|
1118
|
+
stdoutBuffer += text;
|
|
1119
|
+
const visible = text.split("\n").filter((l) => l.trim() && !l.includes("PROCESS_RESPONSE:")).join("\n");
|
|
1120
|
+
if (visible) console.log(visible);
|
|
801
1121
|
const match = stdoutBuffer.match(/PROCESS_RESPONSE:(\{.*\})/);
|
|
802
1122
|
if (match) {
|
|
803
1123
|
try {
|
|
@@ -817,8 +1137,10 @@ var Engine = class {
|
|
|
817
1137
|
}
|
|
818
1138
|
});
|
|
819
1139
|
child.stderr.on("data", (data) => {
|
|
820
|
-
|
|
821
|
-
|
|
1140
|
+
const text = data.toString();
|
|
1141
|
+
stderrBuffer += text;
|
|
1142
|
+
const visible = text.split("\n").filter((l) => l.trim() && !l.includes("PROCESS_RESPONSE:")).join("\n");
|
|
1143
|
+
if (visible) console.log(visible);
|
|
822
1144
|
const match = stderrBuffer.match(/PROCESS_RESPONSE:(\{.*\})/);
|
|
823
1145
|
if (match) {
|
|
824
1146
|
try {
|
|
@@ -863,16 +1185,15 @@ var Engine = class {
|
|
|
863
1185
|
};
|
|
864
1186
|
|
|
865
1187
|
// src/lib/QueryEngine.ts
|
|
866
|
-
import
|
|
1188
|
+
import path5 from "path";
|
|
867
1189
|
import { createRequire as createRequire2 } from "module";
|
|
868
|
-
import * as
|
|
869
|
-
import { spawn as
|
|
1190
|
+
import * as net2 from "net";
|
|
1191
|
+
import { spawn as spawn3 } from "child_process";
|
|
870
1192
|
var globalTcpServers = /* @__PURE__ */ new Map();
|
|
871
1193
|
var globalTcpConnections = /* @__PURE__ */ new Map();
|
|
872
1194
|
var connectionQueues = /* @__PURE__ */ new Map();
|
|
873
1195
|
var connectionProcessing = /* @__PURE__ */ new Map();
|
|
874
1196
|
var queryCache = /* @__PURE__ */ new Map();
|
|
875
|
-
var cacheSize = 0;
|
|
876
1197
|
var MAX_CACHE_SIZE = 500;
|
|
877
1198
|
var QueryEngine = class {
|
|
878
1199
|
name;
|
|
@@ -886,7 +1207,7 @@ var QueryEngine = class {
|
|
|
886
1207
|
this.name = name;
|
|
887
1208
|
this.config = this.setConfig(name);
|
|
888
1209
|
this.arguments = this.setArguments();
|
|
889
|
-
this.timeout = timeout;
|
|
1210
|
+
this.timeout = this.config?.daemon?.requestTimeoutMs ?? timeout;
|
|
890
1211
|
this.connectionId = `${name}_query_engine_${this.config.type}_${this.config.config.DATABASE}_${this.config.config.HOST || "localhost"}`;
|
|
891
1212
|
this.tcpPort = this.generatePort();
|
|
892
1213
|
}
|
|
@@ -903,7 +1224,7 @@ var QueryEngine = class {
|
|
|
903
1224
|
}
|
|
904
1225
|
isPortAvailable(port) {
|
|
905
1226
|
return new Promise((resolve5) => {
|
|
906
|
-
const tester =
|
|
1227
|
+
const tester = net2.createServer();
|
|
907
1228
|
tester.once("error", () => resolve5(false));
|
|
908
1229
|
tester.once("listening", () => {
|
|
909
1230
|
tester.close();
|
|
@@ -941,21 +1262,34 @@ var QueryEngine = class {
|
|
|
941
1262
|
"--host",
|
|
942
1263
|
this.config.config.HOST,
|
|
943
1264
|
"--port",
|
|
944
|
-
this.config.config.PORT,
|
|
945
|
-
"--user",
|
|
946
|
-
this.config.config.USER,
|
|
947
|
-
"--password",
|
|
948
|
-
this.config.config.PASSWORD,
|
|
1265
|
+
String(this.config.config.PORT),
|
|
949
1266
|
"--motor",
|
|
950
1267
|
this.config.type
|
|
951
1268
|
];
|
|
1269
|
+
if (this.config.config.USER != null && this.config.config.USER !== "") {
|
|
1270
|
+
args.push("--user", this.config.config.USER);
|
|
1271
|
+
}
|
|
1272
|
+
if (this.config.config.PASSWORD != null && this.config.config.PASSWORD !== "") {
|
|
1273
|
+
args.push("--password", this.config.config.PASSWORD);
|
|
1274
|
+
}
|
|
952
1275
|
}
|
|
1276
|
+
const pool = this.config.pool ?? {};
|
|
1277
|
+
if (pool.maxConnections != null) args.push("--max-connections", String(pool.maxConnections));
|
|
1278
|
+
if (pool.minConnections != null) args.push("--min-connections", String(pool.minConnections));
|
|
1279
|
+
if (pool.acquireTimeoutMs != null) args.push("--acquire-timeout-ms", String(pool.acquireTimeoutMs));
|
|
1280
|
+
if (pool.idleTimeoutMs != null) args.push("--idle-timeout-ms", String(pool.idleTimeoutMs));
|
|
953
1281
|
return args;
|
|
954
1282
|
}
|
|
1283
|
+
/** El daemon puede desactivarse por config (daemon.enabled=false) o por env (DBCUBE_DAEMON=0). */
|
|
1284
|
+
daemonEnabled() {
|
|
1285
|
+
const flag = process.env.DBCUBE_DAEMON;
|
|
1286
|
+
if (flag === "0" || flag === "false") return false;
|
|
1287
|
+
return this.config?.daemon?.enabled !== false;
|
|
1288
|
+
}
|
|
955
1289
|
setConfig(name) {
|
|
956
1290
|
const configInstance = new Config();
|
|
957
1291
|
try {
|
|
958
|
-
const configFilePath =
|
|
1292
|
+
const configFilePath = path5.resolve(process.cwd(), "dbcube.config.js");
|
|
959
1293
|
const requireUrl = typeof __filename !== "undefined" ? __filename : process.cwd();
|
|
960
1294
|
const require2 = createRequire2(requireUrl);
|
|
961
1295
|
if (require2.cache && require2.resolve) {
|
|
@@ -987,18 +1321,71 @@ var QueryEngine = class {
|
|
|
987
1321
|
const isExecuteAction = actionIndex !== -1 && args[actionIndex + 1] === "execute";
|
|
988
1322
|
const isQueryEngine = binary === "query_engine";
|
|
989
1323
|
if (isQueryEngine && isExecuteAction) {
|
|
990
|
-
return this.executeWithTcpServer(args);
|
|
1324
|
+
return this.executeWithTcpServer(this.argsToCommand(args));
|
|
991
1325
|
} else {
|
|
992
1326
|
return this.createProcess(binary, args);
|
|
993
1327
|
}
|
|
994
1328
|
}
|
|
995
|
-
|
|
1329
|
+
argsToCommand(args) {
|
|
1330
|
+
const command = {};
|
|
1331
|
+
for (let i = 0; i < args.length; i += 2) {
|
|
1332
|
+
if (args[i].startsWith("--")) {
|
|
1333
|
+
command[args[i].substring(2)] = args[i + 1];
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
return command;
|
|
1337
|
+
}
|
|
1338
|
+
/**
|
|
1339
|
+
* Executes a DML plan over the persistent TCP server.
|
|
1340
|
+
* Pass txId to run it inside an active transaction.
|
|
1341
|
+
*/
|
|
1342
|
+
async executeDml(dml, txId) {
|
|
1343
|
+
const command = { action: "execute", dml: JSON.stringify(dml) };
|
|
1344
|
+
if (txId) command.tx_id = txId;
|
|
1345
|
+
return this.executeWithTcpServer(command);
|
|
1346
|
+
}
|
|
1347
|
+
/**
|
|
1348
|
+
* Executes raw SQL (or a MongoDB command document) with bound parameters
|
|
1349
|
+
* over the persistent TCP server.
|
|
1350
|
+
*/
|
|
1351
|
+
async rawQuery(query, params = [], txId) {
|
|
1352
|
+
const command = { action: "raw", query, params };
|
|
1353
|
+
if (txId) command.tx_id = txId;
|
|
1354
|
+
return this.executeWithTcpServer(command);
|
|
1355
|
+
}
|
|
1356
|
+
/** Starts a server-side transaction and returns its id. */
|
|
1357
|
+
async beginTransaction() {
|
|
1358
|
+
const res = await this.executeWithTcpServer({ action: "begin" });
|
|
1359
|
+
if (res.status !== 200 || !res.data?.tx_id) {
|
|
1360
|
+
throw new Error(String(res.message || "Failed to begin transaction (update the query-engine binary: npx dbcube update)"));
|
|
1361
|
+
}
|
|
1362
|
+
return res.data.tx_id;
|
|
1363
|
+
}
|
|
1364
|
+
async commitTransaction(txId) {
|
|
1365
|
+
const res = await this.executeWithTcpServer({ action: "commit", tx_id: txId });
|
|
1366
|
+
if (res.status !== 200) throw new Error(String(res.message || "Failed to commit transaction"));
|
|
1367
|
+
}
|
|
1368
|
+
async rollbackTransaction(txId) {
|
|
1369
|
+
const res = await this.executeWithTcpServer({ action: "rollback", tx_id: txId });
|
|
1370
|
+
if (res.status !== 200) throw new Error(String(res.message || "Failed to rollback transaction"));
|
|
1371
|
+
}
|
|
1372
|
+
async executeWithTcpServer(command) {
|
|
1373
|
+
if (!this.daemonEnabled()) {
|
|
1374
|
+
if (command.tx_id || ["begin", "commit", "rollback"].includes(command.action)) {
|
|
1375
|
+
throw new Error("Transactions require daemon mode. Remove daemon.enabled=false from dbcube.config.js (or unset DBCUBE_DAEMON=0).");
|
|
1376
|
+
}
|
|
1377
|
+
const args = [];
|
|
1378
|
+
for (const [key, value] of Object.entries(command)) {
|
|
1379
|
+
args.push(`--${key.replace(/_/g, "-")}`, typeof value === "string" ? value : JSON.stringify(value));
|
|
1380
|
+
}
|
|
1381
|
+
return this.createProcess("query_engine", args);
|
|
1382
|
+
}
|
|
996
1383
|
const serverInfo = globalTcpServers.get(this.connectionId);
|
|
997
1384
|
if (!serverInfo || !serverInfo.process || serverInfo.process.killed) {
|
|
998
1385
|
await this.startTcpServer();
|
|
999
1386
|
await this.waitForServerReady();
|
|
1000
1387
|
}
|
|
1001
|
-
return this.sendTcpRequestFast(
|
|
1388
|
+
return this.sendTcpRequestFast(command);
|
|
1002
1389
|
}
|
|
1003
1390
|
async waitForServerReady() {
|
|
1004
1391
|
const maxRetries = 10;
|
|
@@ -1017,7 +1404,7 @@ var QueryEngine = class {
|
|
|
1017
1404
|
}
|
|
1018
1405
|
async isServerResponding(port) {
|
|
1019
1406
|
return new Promise((resolve5) => {
|
|
1020
|
-
const client = new
|
|
1407
|
+
const client = new net2.Socket();
|
|
1021
1408
|
const timeout = setTimeout(() => {
|
|
1022
1409
|
client.destroy();
|
|
1023
1410
|
resolve5(false);
|
|
@@ -1041,10 +1428,11 @@ var QueryEngine = class {
|
|
|
1041
1428
|
return queryCache.get(dmlJson);
|
|
1042
1429
|
}
|
|
1043
1430
|
const parsed = JSON.parse(dmlJson);
|
|
1044
|
-
if (
|
|
1045
|
-
queryCache.
|
|
1046
|
-
|
|
1431
|
+
if (queryCache.size >= MAX_CACHE_SIZE) {
|
|
1432
|
+
const oldest = queryCache.keys().next().value;
|
|
1433
|
+
if (oldest !== void 0) queryCache.delete(oldest);
|
|
1047
1434
|
}
|
|
1435
|
+
queryCache.set(dmlJson, parsed);
|
|
1048
1436
|
return parsed;
|
|
1049
1437
|
}
|
|
1050
1438
|
async startTcpServer() {
|
|
@@ -1055,7 +1443,7 @@ var QueryEngine = class {
|
|
|
1055
1443
|
this.tcpPort = await this.findAvailablePort(this.tcpPort);
|
|
1056
1444
|
return new Promise((resolve5, reject) => {
|
|
1057
1445
|
const serverArgs = [...this.arguments, "--action", "server", "--tcp-port", this.tcpPort.toString()];
|
|
1058
|
-
const serverProcess =
|
|
1446
|
+
const serverProcess = spawn3(this.binary["query_engine"], serverArgs);
|
|
1059
1447
|
let started = false;
|
|
1060
1448
|
const timeout = setTimeout(() => {
|
|
1061
1449
|
if (!started) {
|
|
@@ -1091,14 +1479,14 @@ var QueryEngine = class {
|
|
|
1091
1479
|
});
|
|
1092
1480
|
});
|
|
1093
1481
|
}
|
|
1094
|
-
async sendTcpRequestFast(
|
|
1482
|
+
async sendTcpRequestFast(command) {
|
|
1095
1483
|
return new Promise((resolve5, reject) => {
|
|
1096
1484
|
let queue = connectionQueues.get(this.connectionId);
|
|
1097
1485
|
if (!queue) {
|
|
1098
1486
|
queue = [];
|
|
1099
1487
|
connectionQueues.set(this.connectionId, queue);
|
|
1100
1488
|
}
|
|
1101
|
-
queue.push({
|
|
1489
|
+
queue.push({ command, resolve: resolve5, reject });
|
|
1102
1490
|
this.processQueue();
|
|
1103
1491
|
});
|
|
1104
1492
|
}
|
|
@@ -1125,9 +1513,16 @@ var QueryEngine = class {
|
|
|
1125
1513
|
connection = await this.createNewConnection(serverInfo.port);
|
|
1126
1514
|
globalTcpConnections.set(this.connectionId, connection);
|
|
1127
1515
|
}
|
|
1128
|
-
const result = await this.executeOnConnection(connection, request.
|
|
1516
|
+
const result = await this.executeOnConnection(connection, request.command);
|
|
1129
1517
|
request.resolve(result);
|
|
1130
1518
|
} catch (error) {
|
|
1519
|
+
const staleConnection = globalTcpConnections.get(this.connectionId);
|
|
1520
|
+
if (staleConnection) {
|
|
1521
|
+
try {
|
|
1522
|
+
staleConnection.destroy();
|
|
1523
|
+
} catch {
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1131
1526
|
globalTcpConnections.delete(this.connectionId);
|
|
1132
1527
|
request.reject(error);
|
|
1133
1528
|
}
|
|
@@ -1138,7 +1533,7 @@ var QueryEngine = class {
|
|
|
1138
1533
|
}
|
|
1139
1534
|
async createNewConnection(port) {
|
|
1140
1535
|
return new Promise((resolve5, reject) => {
|
|
1141
|
-
const client = new
|
|
1536
|
+
const client = new net2.Socket();
|
|
1142
1537
|
client.setNoDelay(true);
|
|
1143
1538
|
client.setKeepAlive(true, 6e4);
|
|
1144
1539
|
const timeout = setTimeout(() => {
|
|
@@ -1155,16 +1550,8 @@ var QueryEngine = class {
|
|
|
1155
1550
|
});
|
|
1156
1551
|
});
|
|
1157
1552
|
}
|
|
1158
|
-
async executeOnConnection(connection,
|
|
1553
|
+
async executeOnConnection(connection, command) {
|
|
1159
1554
|
return new Promise((resolve5, reject) => {
|
|
1160
|
-
const command = {};
|
|
1161
|
-
for (let i = 0; i < args.length; i += 2) {
|
|
1162
|
-
if (args[i].startsWith("--")) {
|
|
1163
|
-
const key = args[i].substring(2);
|
|
1164
|
-
const value = args[i + 1];
|
|
1165
|
-
command[key] = value;
|
|
1166
|
-
}
|
|
1167
|
-
}
|
|
1168
1555
|
let responseBuffer = "";
|
|
1169
1556
|
let isResolved = false;
|
|
1170
1557
|
const timeout = setTimeout(() => {
|
|
@@ -1206,7 +1593,7 @@ var QueryEngine = class {
|
|
|
1206
1593
|
};
|
|
1207
1594
|
connection.on("data", onData);
|
|
1208
1595
|
connection.on("error", onError);
|
|
1209
|
-
connection.write(JSON.stringify(command));
|
|
1596
|
+
connection.write(JSON.stringify(command) + "\n");
|
|
1210
1597
|
});
|
|
1211
1598
|
}
|
|
1212
1599
|
async createProcess(binary, args) {
|
|
@@ -1215,7 +1602,7 @@ var QueryEngine = class {
|
|
|
1215
1602
|
throw new Error("Binary not initialized");
|
|
1216
1603
|
}
|
|
1217
1604
|
return new Promise((resolve5, reject) => {
|
|
1218
|
-
const child =
|
|
1605
|
+
const child = spawn3(this.binary[binary], [...this.arguments, ...args]);
|
|
1219
1606
|
let stdoutBuffer = "";
|
|
1220
1607
|
let stderrBuffer = "";
|
|
1221
1608
|
let isResolved = false;
|
|
@@ -1323,8 +1710,8 @@ var QueryEngine = class {
|
|
|
1323
1710
|
|
|
1324
1711
|
// src/lib/SqliteExecutor.ts
|
|
1325
1712
|
import { exec } from "child_process";
|
|
1326
|
-
import * as
|
|
1327
|
-
import * as
|
|
1713
|
+
import * as path6 from "path";
|
|
1714
|
+
import * as fs4 from "fs";
|
|
1328
1715
|
import { promisify } from "util";
|
|
1329
1716
|
import { createRequire as createRequire3 } from "module";
|
|
1330
1717
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
@@ -1339,13 +1726,13 @@ var SqliteExecutor = class {
|
|
|
1339
1726
|
}
|
|
1340
1727
|
findVersionedBinary(binDir, platform2) {
|
|
1341
1728
|
try {
|
|
1342
|
-
const files =
|
|
1729
|
+
const files = fs4.readdirSync(binDir);
|
|
1343
1730
|
const extension = platform2 === "win32" ? ".exe" : "";
|
|
1344
1731
|
const platformName = platform2 === "win32" ? "windows" : platform2 === "darwin" ? "macos" : "linux";
|
|
1345
1732
|
const pattern = new RegExp(`^sqlite-engine-v\\d+\\.\\d+\\.\\d+-${platformName}-x64${extension.replace(".", "\\.")}$`);
|
|
1346
1733
|
const matchingFile = files.find((f) => pattern.test(f));
|
|
1347
1734
|
if (matchingFile) {
|
|
1348
|
-
return
|
|
1735
|
+
return path6.join(binDir, matchingFile);
|
|
1349
1736
|
}
|
|
1350
1737
|
} catch (error) {
|
|
1351
1738
|
}
|
|
@@ -1355,34 +1742,34 @@ var SqliteExecutor = class {
|
|
|
1355
1742
|
const __filename2 = typeof import.meta !== "undefined" && import.meta.url ? fileURLToPath3(import.meta.url) : "";
|
|
1356
1743
|
const __dirname = __filename2 ? dirname3(__filename2) : process.cwd();
|
|
1357
1744
|
const possibleDirs = [
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1745
|
+
path6.resolve(process.cwd(), ".dbcube", "bin"),
|
|
1746
|
+
path6.resolve(process.cwd(), "node_modules", ".dbcube", "bin"),
|
|
1747
|
+
path6.resolve(__dirname, "..", "bin")
|
|
1361
1748
|
];
|
|
1362
1749
|
const platform2 = process.platform;
|
|
1363
1750
|
const extension = platform2 === "win32" ? ".exe" : "";
|
|
1364
1751
|
const platformName = platform2 === "win32" ? "windows" : platform2 === "darwin" ? "macos" : "linux";
|
|
1365
1752
|
for (const dir of possibleDirs) {
|
|
1366
1753
|
const versionedPath = this.findVersionedBinary(dir, platform2);
|
|
1367
|
-
if (versionedPath &&
|
|
1754
|
+
if (versionedPath && fs4.existsSync(versionedPath)) {
|
|
1368
1755
|
return versionedPath;
|
|
1369
1756
|
}
|
|
1370
1757
|
}
|
|
1371
1758
|
const binaryName = `sqlite-engine-${platformName}-x64${extension}`;
|
|
1372
1759
|
for (const dir of possibleDirs) {
|
|
1373
|
-
const fullPath =
|
|
1374
|
-
if (
|
|
1760
|
+
const fullPath = path6.join(dir, binaryName);
|
|
1761
|
+
if (fs4.existsSync(fullPath)) {
|
|
1375
1762
|
return fullPath;
|
|
1376
1763
|
}
|
|
1377
1764
|
}
|
|
1378
1765
|
const fallbackName = `sqlite-engine${extension}`;
|
|
1379
1766
|
for (const dir of possibleDirs) {
|
|
1380
|
-
const fullPath =
|
|
1381
|
-
if (
|
|
1767
|
+
const fullPath = path6.join(dir, fallbackName);
|
|
1768
|
+
if (fs4.existsSync(fullPath)) {
|
|
1382
1769
|
return fullPath;
|
|
1383
1770
|
}
|
|
1384
1771
|
}
|
|
1385
|
-
return
|
|
1772
|
+
return path6.join(possibleDirs[0], binaryName);
|
|
1386
1773
|
}
|
|
1387
1774
|
async executeBinary(args) {
|
|
1388
1775
|
const escapedArgs = args.map((arg) => {
|
|
@@ -1533,9 +1920,9 @@ var SqliteExecutor = class {
|
|
|
1533
1920
|
};
|
|
1534
1921
|
|
|
1535
1922
|
// src/lib/DbConfig.ts
|
|
1536
|
-
import * as
|
|
1537
|
-
import
|
|
1538
|
-
var rootPath =
|
|
1923
|
+
import * as path7 from "path";
|
|
1924
|
+
import fs5 from "fs";
|
|
1925
|
+
var rootPath = path7.resolve(process.cwd(), ".dbcube");
|
|
1539
1926
|
var SQLite = class {
|
|
1540
1927
|
executor = null;
|
|
1541
1928
|
database;
|
|
@@ -1545,11 +1932,11 @@ var SQLite = class {
|
|
|
1545
1932
|
async ifExist() {
|
|
1546
1933
|
if (this.database) {
|
|
1547
1934
|
const dbPath = this.database || ":memory:";
|
|
1548
|
-
const configPath =
|
|
1549
|
-
if (!
|
|
1550
|
-
|
|
1935
|
+
const configPath = path7.join(rootPath, dbPath + ".db");
|
|
1936
|
+
if (!fs5.existsSync(rootPath)) {
|
|
1937
|
+
fs5.mkdirSync(rootPath, { recursive: true });
|
|
1551
1938
|
}
|
|
1552
|
-
if (
|
|
1939
|
+
if (fs5.existsSync(configPath)) {
|
|
1553
1940
|
return true;
|
|
1554
1941
|
}
|
|
1555
1942
|
if (!this.executor) {
|
|
@@ -1564,9 +1951,9 @@ var SQLite = class {
|
|
|
1564
1951
|
try {
|
|
1565
1952
|
if (!this.executor) {
|
|
1566
1953
|
const dbPath = this.database || ":memory:";
|
|
1567
|
-
const configPath =
|
|
1568
|
-
if (!
|
|
1569
|
-
|
|
1954
|
+
const configPath = path7.join(rootPath, dbPath + ".db");
|
|
1955
|
+
if (!fs5.existsSync(rootPath)) {
|
|
1956
|
+
fs5.mkdirSync(rootPath, { recursive: true });
|
|
1570
1957
|
}
|
|
1571
1958
|
this.executor = new SqliteExecutor(configPath);
|
|
1572
1959
|
const connected = await this.executor.connect();
|
|
@@ -1748,8 +2135,8 @@ var DbConfig = new SQLite({ DATABASE: "config" });
|
|
|
1748
2135
|
var DbConfig_default = DbConfig;
|
|
1749
2136
|
|
|
1750
2137
|
// src/lib/FileLogger.ts
|
|
1751
|
-
import * as
|
|
1752
|
-
import * as
|
|
2138
|
+
import * as fs6 from "fs";
|
|
2139
|
+
import * as path8 from "path";
|
|
1753
2140
|
import { EventEmitter } from "events";
|
|
1754
2141
|
var FileLogger = class _FileLogger extends EventEmitter {
|
|
1755
2142
|
static watchers = /* @__PURE__ */ new Map();
|
|
@@ -1764,9 +2151,9 @@ var FileLogger = class _FileLogger extends EventEmitter {
|
|
|
1764
2151
|
*/
|
|
1765
2152
|
static async write(filePath, message, level = "INFO", append = true) {
|
|
1766
2153
|
try {
|
|
1767
|
-
const dir =
|
|
1768
|
-
if (!
|
|
1769
|
-
|
|
2154
|
+
const dir = path8.dirname(filePath);
|
|
2155
|
+
if (!fs6.existsSync(dir)) {
|
|
2156
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
1770
2157
|
}
|
|
1771
2158
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
1772
2159
|
const formattedMessage = `[${timestamp}] [${level}] ${message}
|
|
@@ -1776,9 +2163,9 @@ var FileLogger = class _FileLogger extends EventEmitter {
|
|
|
1776
2163
|
return true;
|
|
1777
2164
|
}
|
|
1778
2165
|
if (append) {
|
|
1779
|
-
await
|
|
2166
|
+
await fs6.promises.appendFile(filePath, formattedMessage, "utf8");
|
|
1780
2167
|
} else {
|
|
1781
|
-
await
|
|
2168
|
+
await fs6.promises.writeFile(filePath, formattedMessage, "utf8");
|
|
1782
2169
|
}
|
|
1783
2170
|
return true;
|
|
1784
2171
|
} catch (error) {
|
|
@@ -1803,12 +2190,12 @@ var FileLogger = class _FileLogger extends EventEmitter {
|
|
|
1803
2190
|
const buffer = _FileLogger.buffers.get(filePath);
|
|
1804
2191
|
if (buffer && buffer.length > 0) {
|
|
1805
2192
|
try {
|
|
1806
|
-
const dir =
|
|
1807
|
-
if (!
|
|
1808
|
-
|
|
2193
|
+
const dir = path8.dirname(filePath);
|
|
2194
|
+
if (!fs6.existsSync(dir)) {
|
|
2195
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
1809
2196
|
}
|
|
1810
2197
|
const content = buffer.join("");
|
|
1811
|
-
await
|
|
2198
|
+
await fs6.promises.appendFile(filePath, content, "utf8");
|
|
1812
2199
|
_FileLogger.buffers.delete(filePath);
|
|
1813
2200
|
return true;
|
|
1814
2201
|
} catch (error) {
|
|
@@ -1944,10 +2331,10 @@ var FileLogger = class _FileLogger extends EventEmitter {
|
|
|
1944
2331
|
// Si debe retornar como array de líneas
|
|
1945
2332
|
} = options;
|
|
1946
2333
|
try {
|
|
1947
|
-
if (!
|
|
2334
|
+
if (!fs6.existsSync(filePath)) {
|
|
1948
2335
|
return asArray ? [] : "";
|
|
1949
2336
|
}
|
|
1950
|
-
let content = await
|
|
2337
|
+
let content = await fs6.promises.readFile(filePath, "utf8");
|
|
1951
2338
|
if (asArray) {
|
|
1952
2339
|
let linesArray = content.split("\n").filter((line) => line.trim() !== "");
|
|
1953
2340
|
if (lines !== null) {
|
|
@@ -1990,15 +2377,15 @@ var FileLogger = class _FileLogger extends EventEmitter {
|
|
|
1990
2377
|
} = options;
|
|
1991
2378
|
let lastSize = 0;
|
|
1992
2379
|
let lastPosition = 0;
|
|
1993
|
-
if (
|
|
1994
|
-
const stats =
|
|
2380
|
+
if (fs6.existsSync(filePath)) {
|
|
2381
|
+
const stats = fs6.statSync(filePath);
|
|
1995
2382
|
lastSize = stats.size;
|
|
1996
2383
|
lastPosition = fromEnd ? stats.size : 0;
|
|
1997
2384
|
}
|
|
1998
2385
|
const listener = async (curr, prev) => {
|
|
1999
2386
|
try {
|
|
2000
2387
|
if (curr.size > lastSize) {
|
|
2001
|
-
const stream =
|
|
2388
|
+
const stream = fs6.createReadStream(filePath, {
|
|
2002
2389
|
start: lastPosition,
|
|
2003
2390
|
end: curr.size - 1,
|
|
2004
2391
|
encoding: "utf8"
|
|
@@ -2026,7 +2413,7 @@ var FileLogger = class _FileLogger extends EventEmitter {
|
|
|
2026
2413
|
console.error("Error en watcher:", error);
|
|
2027
2414
|
}
|
|
2028
2415
|
};
|
|
2029
|
-
|
|
2416
|
+
fs6.watchFile(filePath, { persistent, interval }, listener);
|
|
2030
2417
|
const watcherId = `${filePath}_${Date.now()}`;
|
|
2031
2418
|
_FileLogger.watchers.set(watcherId, listener);
|
|
2032
2419
|
return {
|
|
@@ -2034,7 +2421,7 @@ var FileLogger = class _FileLogger extends EventEmitter {
|
|
|
2034
2421
|
stop: () => {
|
|
2035
2422
|
const storedListener = _FileLogger.watchers.get(watcherId);
|
|
2036
2423
|
if (storedListener) {
|
|
2037
|
-
|
|
2424
|
+
fs6.unwatchFile(filePath, storedListener);
|
|
2038
2425
|
_FileLogger.watchers.delete(watcherId);
|
|
2039
2426
|
}
|
|
2040
2427
|
},
|
|
@@ -2047,7 +2434,7 @@ var FileLogger = class _FileLogger extends EventEmitter {
|
|
|
2047
2434
|
static stopAllWatchers() {
|
|
2048
2435
|
for (const [watcherId] of _FileLogger.watchers) {
|
|
2049
2436
|
const filePath = watcherId.split("_")[0];
|
|
2050
|
-
|
|
2437
|
+
fs6.unwatchFile(filePath);
|
|
2051
2438
|
}
|
|
2052
2439
|
_FileLogger.watchers.clear();
|
|
2053
2440
|
}
|
|
@@ -2077,7 +2464,7 @@ var FileLogger = class _FileLogger extends EventEmitter {
|
|
|
2077
2464
|
if (lines.length > maxLines) {
|
|
2078
2465
|
const keepLines = lines.slice(-maxLines);
|
|
2079
2466
|
const content = keepLines.join("\n") + "\n";
|
|
2080
|
-
await
|
|
2467
|
+
await fs6.promises.writeFile(filePath, content, "utf8");
|
|
2081
2468
|
return lines.length - maxLines;
|
|
2082
2469
|
}
|
|
2083
2470
|
return 0;
|
|
@@ -2092,8 +2479,8 @@ var FileLogger = class _FileLogger extends EventEmitter {
|
|
|
2092
2479
|
*/
|
|
2093
2480
|
static async deleteLogFile(filePath) {
|
|
2094
2481
|
try {
|
|
2095
|
-
if (
|
|
2096
|
-
await
|
|
2482
|
+
if (fs6.existsSync(filePath)) {
|
|
2483
|
+
await fs6.promises.unlink(filePath);
|
|
2097
2484
|
return true;
|
|
2098
2485
|
}
|
|
2099
2486
|
return false;
|
|
@@ -2130,7 +2517,7 @@ var ComputedFieldProcessor = class {
|
|
|
2130
2517
|
const tableExistsQuery = `SELECT name FROM sqlite_master WHERE type='table' AND name='dbcube_computes_config'`;
|
|
2131
2518
|
const tableExistsResult = await DbConfig_default.query(tableExistsQuery);
|
|
2132
2519
|
if (tableExistsResult.status === "success" && tableExistsResult.data && tableExistsResult.data.length > 0) {
|
|
2133
|
-
const queryComputes = await DbConfig_default.
|
|
2520
|
+
const queryComputes = await DbConfig_default.queryWithParameters(`SELECT * FROM dbcube_computes_config WHERE database_ref=?`, [name]);
|
|
2134
2521
|
computedFields = queryComputes.data;
|
|
2135
2522
|
} else {
|
|
2136
2523
|
computedFields = [];
|
|
@@ -2161,21 +2548,10 @@ var ComputedFieldProcessor = class {
|
|
|
2161
2548
|
}
|
|
2162
2549
|
functionBody = functionBody.replace(/@column\(([^)]+)\)/g, (_match, columnName) => {
|
|
2163
2550
|
const cleanColumnName = columnName.trim().replace(/['"]/g, "");
|
|
2164
|
-
|
|
2165
|
-
if (value === null || value === void 0) {
|
|
2166
|
-
return "null";
|
|
2167
|
-
} else if (typeof value === "string") {
|
|
2168
|
-
return `"${value.replace(/"/g, '\\"')}"`;
|
|
2169
|
-
} else if (typeof value === "number" || typeof value === "boolean") {
|
|
2170
|
-
return value.toString();
|
|
2171
|
-
} else if (value instanceof Date) {
|
|
2172
|
-
return `new Date("${value.toISOString()}")`;
|
|
2173
|
-
} else {
|
|
2174
|
-
return JSON.stringify(value);
|
|
2175
|
-
}
|
|
2551
|
+
return `__row[${JSON.stringify(cleanColumnName)}]`;
|
|
2176
2552
|
});
|
|
2177
|
-
const computeFunction = new Function(functionBody);
|
|
2178
|
-
return computeFunction();
|
|
2553
|
+
const computeFunction = new Function("__row", functionBody);
|
|
2554
|
+
return computeFunction(rowData);
|
|
2179
2555
|
} catch (error) {
|
|
2180
2556
|
console.error("Error processing computed field:", error);
|
|
2181
2557
|
return null;
|
|
@@ -2218,14 +2594,7 @@ var ComputedFieldProcessor = class {
|
|
|
2218
2594
|
/@column\(([^)]+)\)/g,
|
|
2219
2595
|
(match, columnName) => {
|
|
2220
2596
|
const cleanColumnName = columnName.replace(/['"]/g, "");
|
|
2221
|
-
|
|
2222
|
-
if (typeof value === "string") {
|
|
2223
|
-
return `"${value}"`;
|
|
2224
|
-
} else if (value === null || value === void 0) {
|
|
2225
|
-
return "null";
|
|
2226
|
-
} else {
|
|
2227
|
-
return String(value);
|
|
2228
|
-
}
|
|
2597
|
+
return `__row[${JSON.stringify(cleanColumnName)}]`;
|
|
2229
2598
|
}
|
|
2230
2599
|
);
|
|
2231
2600
|
const computeMatch = processedExpression.match(/@compute\s*\(\s*\(\s*\)\s*=>\s*\{(.*)\}\s*\)/s);
|
|
@@ -2233,8 +2602,8 @@ var ComputedFieldProcessor = class {
|
|
|
2233
2602
|
throw new Error(`Formato de @compute inv\xE1lido para campo ${fieldName}`);
|
|
2234
2603
|
}
|
|
2235
2604
|
const functionBody = computeMatch[1];
|
|
2236
|
-
const computeFunction = new Function(functionBody);
|
|
2237
|
-
let result = computeFunction();
|
|
2605
|
+
const computeFunction = new Function("__row", functionBody);
|
|
2606
|
+
let result = computeFunction(processedItem);
|
|
2238
2607
|
result = convertToType(result, type2);
|
|
2239
2608
|
processedItem[fieldName] = result;
|
|
2240
2609
|
} catch (error) {
|
|
@@ -2426,14 +2795,14 @@ var TableProcessor = class {
|
|
|
2426
2795
|
if (await DbConfig_default.ifExist()) {
|
|
2427
2796
|
await DbConfig_default.connect();
|
|
2428
2797
|
try {
|
|
2429
|
-
const tableExistsQuery = `SELECT name FROM sqlite_master WHERE type='table' AND name='
|
|
2798
|
+
const tableExistsQuery = `SELECT name FROM sqlite_master WHERE type='table' AND name='dbcube_schemas_config'`;
|
|
2430
2799
|
const tableExistsResult = await DbConfig_default.query(tableExistsQuery);
|
|
2431
2800
|
if (tableExistsResult.status === "success" && tableExistsResult.data && tableExistsResult.data.length > 0) {
|
|
2432
|
-
const queryComputes = await DbConfig_default.
|
|
2801
|
+
const queryComputes = await DbConfig_default.queryWithParameters(`SELECT * FROM dbcube_schemas_config WHERE table_ref=? AND database_ref=?`, [tableName, database_ref]);
|
|
2433
2802
|
const oldQuery = queryComputes.data[0];
|
|
2434
2803
|
if (!oldQuery || !oldQuery.struct) {
|
|
2435
|
-
|
|
2436
|
-
return [];
|
|
2804
|
+
await DbConfig_default.disconnect();
|
|
2805
|
+
return [nowQuery];
|
|
2437
2806
|
}
|
|
2438
2807
|
const nowSchema = parseCreateTableQuery(nowQuery, dbType);
|
|
2439
2808
|
const oldSchema = parseCreateTableQuery(oldQuery.struct, dbType);
|
|
@@ -2468,7 +2837,7 @@ var TableProcessor = class {
|
|
|
2468
2837
|
if (await DbConfig_default.ifExist()) {
|
|
2469
2838
|
await DbConfig_default.connect();
|
|
2470
2839
|
try {
|
|
2471
|
-
await DbConfig_default.
|
|
2840
|
+
await DbConfig_default.queryWithParameters(`DELETE FROM dbcube_schemas_config WHERE table_ref=? AND database_ref=?`, [table_ref, database_ref]);
|
|
2472
2841
|
const tableExistsQuery = `INSERT INTO dbcube_schemas_config (table_ref, database_ref, struct) VALUES (?, ?, ?)`;
|
|
2473
2842
|
await DbConfig_default.queryWithParameters(tableExistsQuery, [table_ref, database_ref, struct]);
|
|
2474
2843
|
} catch (error) {
|
|
@@ -2487,7 +2856,7 @@ var TriggerProcessor = class {
|
|
|
2487
2856
|
const tableExistsQuery = `SELECT name FROM sqlite_master WHERE type='table' AND name='dbcube_triggers_config'`;
|
|
2488
2857
|
const tableExistsResult = await DbConfig_default.query(tableExistsQuery);
|
|
2489
2858
|
if (tableExistsResult.status === "success" && tableExistsResult.data && tableExistsResult.data.length > 0) {
|
|
2490
|
-
const queryComputes = await DbConfig_default.
|
|
2859
|
+
const queryComputes = await DbConfig_default.queryWithParameters(`SELECT * FROM dbcube_triggers_config WHERE database_ref=?`, [name]);
|
|
2491
2860
|
triggers = queryComputes.data;
|
|
2492
2861
|
} else {
|
|
2493
2862
|
triggers = [];
|
|
@@ -2523,6 +2892,7 @@ export {
|
|
|
2523
2892
|
Binary,
|
|
2524
2893
|
ComputedFieldProcessor,
|
|
2525
2894
|
Config,
|
|
2895
|
+
DaemonClient,
|
|
2526
2896
|
DbConfig,
|
|
2527
2897
|
Engine,
|
|
2528
2898
|
FileLogger,
|