@dbcube/core 3.0.3 → 3.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -37,6 +37,7 @@ __export(index_exports, {
37
37
  DbConfig: () => DbConfig,
38
38
  Engine: () => Engine,
39
39
  FileLogger: () => FileLogger,
40
+ QueryEngine: () => QueryEngine,
40
41
  TableProcessor: () => TableProcessor,
41
42
  TriggerProcessor: () => TriggerProcessor
42
43
  });
@@ -600,17 +601,11 @@ var Engine = class {
600
601
  arguments;
601
602
  binary = null;
602
603
  timeout;
603
- connectionId;
604
- isConnected = false;
605
604
  constructor(name, timeout = 3e4) {
606
605
  this.name = name;
607
606
  this.config = this.setConfig(name);
608
607
  this.arguments = this.setArguments();
609
608
  this.timeout = timeout;
610
- this.connectionId = this.generateConnectionId();
611
- }
612
- generateConnectionId() {
613
- return `${this.name}_${this.config.type}_${this.config.config.DATABASE}_${this.config.config.HOST || "localhost"}`;
614
609
  }
615
610
  async initializeBinary() {
616
611
  if (!this.binary) {
@@ -677,33 +672,297 @@ var Engine = class {
677
672
  getConfig() {
678
673
  return this.config;
679
674
  }
680
- async ensurePersistentConnection() {
681
- if (!this.isConnected) {
682
- console.log("\u{1F50C} Creating persistent connection...");
683
- const response = await this.createProcess("query_engine", [
684
- "--action",
685
- "connect"
686
- ]);
687
- if (response.status === 200) {
688
- this.isConnected = true;
689
- console.log("\u2705 Persistent connection established");
675
+ async run(binary, args) {
676
+ await this.initializeBinary();
677
+ if (!this.binary) {
678
+ throw new Error("Binary not initialized");
679
+ }
680
+ return new Promise((resolve5, reject) => {
681
+ const child = (0, import_child_process.spawn)(this.binary[binary], [...this.arguments, ...args]);
682
+ let stdoutBuffer = "";
683
+ let stderrBuffer = "";
684
+ let isResolved = false;
685
+ const timeoutId = setTimeout(() => {
686
+ if (!isResolved) {
687
+ isResolved = true;
688
+ child.kill();
689
+ reject(new Error("Process timeout"));
690
+ }
691
+ }, this.timeout);
692
+ const resolveOnce = (response) => {
693
+ if (!isResolved) {
694
+ isResolved = true;
695
+ clearTimeout(timeoutId);
696
+ resolve5(response);
697
+ }
698
+ };
699
+ child.stdout.on("data", (data) => {
700
+ stdoutBuffer += data.toString();
701
+ const match = stdoutBuffer.match(/PROCESS_RESPONSE:(\{.*\})/);
702
+ if (match) {
703
+ try {
704
+ const response = JSON.parse(match[1]);
705
+ resolveOnce({
706
+ status: response.status,
707
+ message: response.message,
708
+ data: response.data
709
+ });
710
+ } catch (error) {
711
+ resolveOnce({
712
+ status: 500,
713
+ message: "Failed to parse response JSON",
714
+ data: null
715
+ });
716
+ }
717
+ }
718
+ });
719
+ child.stderr.on("data", (data) => {
720
+ stderrBuffer += data.toString();
721
+ const match = stderrBuffer.match(/PROCESS_RESPONSE:(\{.*\})/);
722
+ if (match) {
723
+ try {
724
+ const response = JSON.parse(match[1]);
725
+ resolveOnce({
726
+ status: response.status,
727
+ message: response.message,
728
+ data: response.data
729
+ });
730
+ } catch (error) {
731
+ resolveOnce({
732
+ status: 500,
733
+ message: "Failed to parse response JSON",
734
+ data: null
735
+ });
736
+ }
737
+ }
738
+ });
739
+ child.on("close", (code) => {
740
+ clearTimeout(timeoutId);
741
+ if (!isResolved) {
742
+ resolveOnce({
743
+ status: code === 0 ? 200 : 500,
744
+ message: code === 0 ? "Process completed" : `Process exited with code ${code}`,
745
+ data: null
746
+ });
747
+ }
748
+ });
749
+ child.on("error", (error) => {
750
+ clearTimeout(timeoutId);
751
+ if (!isResolved) {
752
+ resolveOnce({
753
+ status: 500,
754
+ message: `Process error: ${error.message}`,
755
+ data: null
756
+ });
757
+ }
758
+ });
759
+ child.unref();
760
+ });
761
+ }
762
+ };
763
+
764
+ // src/lib/QueryEngine.ts
765
+ var import_path2 = __toESM(require("path"));
766
+ var import_module2 = require("module");
767
+ var net = __toESM(require("net"));
768
+ var import_child_process2 = require("child_process");
769
+ var globalTcpServers = /* @__PURE__ */ new Map();
770
+ var QueryEngine = class {
771
+ name;
772
+ config;
773
+ arguments;
774
+ binary = null;
775
+ timeout;
776
+ connectionId;
777
+ tcpPort;
778
+ constructor(name, timeout = 3e4) {
779
+ this.name = name;
780
+ this.config = this.setConfig(name);
781
+ this.arguments = this.setArguments();
782
+ this.timeout = timeout;
783
+ this.connectionId = `${name}_${this.config.type}_${this.config.config.DATABASE}_${this.config.config.HOST || "localhost"}`;
784
+ this.tcpPort = this.generatePort();
785
+ }
786
+ generatePort() {
787
+ let hash = 0;
788
+ for (let i = 0; i < this.connectionId.length; i++) {
789
+ const char = this.connectionId.charCodeAt(i);
790
+ hash = (hash << 5) - hash + char;
791
+ hash = hash & hash;
792
+ }
793
+ return 8100 + Math.abs(hash % 900);
794
+ }
795
+ async initializeBinary() {
796
+ if (!this.binary) {
797
+ this.binary = await Binary.get();
798
+ }
799
+ }
800
+ setArguments() {
801
+ let args = [];
802
+ if (this.config.type == "sqlite") {
803
+ args = [
804
+ "--id",
805
+ "dbcube-" + this.name,
806
+ "--database-ref",
807
+ this.name,
808
+ "--database",
809
+ this.config.config.DATABASE + ".db",
810
+ "--motor",
811
+ this.config.type
812
+ ];
813
+ } else {
814
+ args = [
815
+ "--id",
816
+ "dbcube-" + this.name,
817
+ "--database-ref",
818
+ this.name,
819
+ "--database",
820
+ this.config.config.DATABASE,
821
+ "--host",
822
+ this.config.config.HOST,
823
+ "--port",
824
+ this.config.config.PORT,
825
+ "--user",
826
+ this.config.config.USER,
827
+ "--password",
828
+ this.config.config.PASSWORD,
829
+ "--motor",
830
+ this.config.type
831
+ ];
832
+ }
833
+ return args;
834
+ }
835
+ setConfig(name) {
836
+ const configInstance = new Config();
837
+ try {
838
+ const configFilePath = import_path2.default.resolve(process.cwd(), "dbcube.config.js");
839
+ const requireUrl = typeof __filename !== "undefined" ? __filename : process.cwd();
840
+ const require2 = (0, import_module2.createRequire)(requireUrl);
841
+ delete require2.cache[require2.resolve(configFilePath)];
842
+ const configModule = require2(configFilePath);
843
+ const configFn = configModule.default || configModule;
844
+ if (typeof configFn === "function") {
845
+ configFn(configInstance);
690
846
  } else {
691
- throw new Error(`Failed to create persistent connection: ${response.message}`);
847
+ console.error("\u274C El archivo dbcube.config.js no exporta una funci\xF3n.");
848
+ }
849
+ } catch (error) {
850
+ console.error("\u274C Error loading config file:", error.message);
851
+ if (error.code === "MODULE_NOT_FOUND") {
852
+ console.error("\u274C Config file not found, please create a dbcube.config.js file");
692
853
  }
693
854
  }
855
+ return configInstance.getDatabase(name);
856
+ }
857
+ getConfig() {
858
+ return this.config;
694
859
  }
695
860
  async run(binary, args) {
696
- const actionIndex = args.indexOf("--action");
861
+ const actionIndex = args.findIndex((arg) => arg === "--action");
697
862
  const isExecuteAction = actionIndex !== -1 && args[actionIndex + 1] === "execute";
698
863
  if (isExecuteAction) {
699
- await this.ensurePersistentConnection();
700
- return this.executeWithPersistentConnection(args);
864
+ return this.executeWithTcpServer(args);
701
865
  } else {
702
866
  return this.createProcess(binary, args);
703
867
  }
704
868
  }
705
- async executeWithPersistentConnection(args) {
706
- return this.createProcess("query_engine", args);
869
+ async executeWithTcpServer(args) {
870
+ const serverInfo = globalTcpServers.get(this.connectionId);
871
+ if (!serverInfo || !serverInfo.process || serverInfo.process.killed) {
872
+ console.log("\u{1F680} Starting TCP server for ultra-fast queries...");
873
+ await this.startTcpServer();
874
+ }
875
+ console.log("\u26A1 Using TCP server (ultra-fast)");
876
+ return this.sendTcpRequest(args);
877
+ }
878
+ async startTcpServer() {
879
+ await this.initializeBinary();
880
+ if (!this.binary) {
881
+ throw new Error("Binary not initialized");
882
+ }
883
+ return new Promise((resolve5, reject) => {
884
+ const serverArgs = [...this.arguments, "--action", "server", "--port", this.tcpPort.toString()];
885
+ const serverProcess = (0, import_child_process2.spawn)(this.binary["query_engine"], serverArgs);
886
+ let started = false;
887
+ const timeout = setTimeout(() => {
888
+ if (!started) {
889
+ serverProcess.kill();
890
+ reject(new Error("TCP server startup timeout"));
891
+ }
892
+ }, 1e4);
893
+ serverProcess.stdout.on("data", (data) => {
894
+ const output = data.toString();
895
+ console.log(`[TCP Server] ${output.trim()}`);
896
+ if (output.includes("TCP Server listening on")) {
897
+ if (!started) {
898
+ started = true;
899
+ clearTimeout(timeout);
900
+ globalTcpServers.set(this.connectionId, {
901
+ port: this.tcpPort,
902
+ process: serverProcess
903
+ });
904
+ resolve5();
905
+ }
906
+ }
907
+ });
908
+ serverProcess.stderr.on("data", (data) => {
909
+ console.error(`[TCP Server Error] ${data.toString().trim()}`);
910
+ });
911
+ serverProcess.on("close", (code) => {
912
+ console.log(`[TCP Server] Process exited with code ${code}`);
913
+ globalTcpServers.delete(this.connectionId);
914
+ });
915
+ serverProcess.on("error", (error) => {
916
+ if (!started) {
917
+ clearTimeout(timeout);
918
+ reject(error);
919
+ }
920
+ });
921
+ });
922
+ }
923
+ async sendTcpRequest(args) {
924
+ return new Promise((resolve5, reject) => {
925
+ const client = new net.Socket();
926
+ let responseBuffer = "";
927
+ const timeout = setTimeout(() => {
928
+ client.destroy();
929
+ reject(new Error("TCP request timeout"));
930
+ }, this.timeout);
931
+ client.connect(this.tcpPort, "127.0.0.1", () => {
932
+ const command = {
933
+ action: "execute",
934
+ args
935
+ };
936
+ client.write(JSON.stringify(command) + "\n");
937
+ });
938
+ client.on("data", (data) => {
939
+ responseBuffer += data.toString();
940
+ if (responseBuffer.includes("\n")) {
941
+ clearTimeout(timeout);
942
+ client.destroy();
943
+ try {
944
+ const response = JSON.parse(responseBuffer.trim());
945
+ resolve5({
946
+ status: response.status || 200,
947
+ message: response.message || "Success",
948
+ data: response.data
949
+ });
950
+ } catch (error) {
951
+ reject(new Error("Failed to parse TCP response"));
952
+ }
953
+ }
954
+ });
955
+ client.on("error", (error) => {
956
+ clearTimeout(timeout);
957
+ reject(error);
958
+ });
959
+ client.on("close", () => {
960
+ clearTimeout(timeout);
961
+ if (responseBuffer && !responseBuffer.includes("\n")) {
962
+ reject(new Error("Incomplete TCP response"));
963
+ }
964
+ });
965
+ });
707
966
  }
708
967
  async createProcess(binary, args) {
709
968
  await this.initializeBinary();
@@ -711,7 +970,7 @@ var Engine = class {
711
970
  throw new Error("Binary not initialized");
712
971
  }
713
972
  return new Promise((resolve5, reject) => {
714
- const child = (0, import_child_process.spawn)(this.binary[binary], [...this.arguments, ...args]);
973
+ const child = (0, import_child_process2.spawn)(this.binary[binary], [...this.arguments, ...args]);
715
974
  let stdoutBuffer = "";
716
975
  let stderrBuffer = "";
717
976
  let isResolved = false;
@@ -793,33 +1052,32 @@ var Engine = class {
793
1052
  });
794
1053
  }
795
1054
  async disconnect() {
796
- if (this.isConnected) {
797
- console.log("\u{1F50C} Disconnecting persistent connection...");
798
- const response = await this.createProcess("query_engine", [
799
- "--action",
800
- "disconnect"
801
- ]);
802
- if (response.status === 200) {
803
- this.isConnected = false;
804
- console.log("\u2705 Persistent connection closed");
805
- }
806
- return response;
1055
+ const serverInfo = globalTcpServers.get(this.connectionId);
1056
+ if (serverInfo && serverInfo.process && !serverInfo.process.killed) {
1057
+ console.log("\u{1F50C} Stopping TCP server...");
1058
+ serverInfo.process.kill();
1059
+ globalTcpServers.delete(this.connectionId);
1060
+ return {
1061
+ status: 200,
1062
+ message: "TCP server stopped",
1063
+ data: null
1064
+ };
807
1065
  }
808
1066
  return {
809
1067
  status: 200,
810
- message: "No persistent connection to disconnect",
1068
+ message: "No TCP server to stop",
811
1069
  data: null
812
1070
  };
813
1071
  }
814
1072
  };
815
1073
 
816
1074
  // src/lib/SqliteExecutor.ts
817
- var import_child_process2 = require("child_process");
818
- var path4 = __toESM(require("path"));
1075
+ var import_child_process3 = require("child_process");
1076
+ var path5 = __toESM(require("path"));
819
1077
  var fs3 = __toESM(require("fs"));
820
1078
  var import_util = require("util");
821
- var import_module2 = require("module");
822
- var execAsync = (0, import_util.promisify)(import_child_process2.exec);
1079
+ var import_module3 = require("module");
1080
+ var execAsync = (0, import_util.promisify)(import_child_process3.exec);
823
1081
  var SqliteExecutor = class {
824
1082
  binaryPath;
825
1083
  dbPath;
@@ -829,27 +1087,27 @@ var SqliteExecutor = class {
829
1087
  }
830
1088
  getBinaryPath() {
831
1089
  const possibleDirs = [
832
- path4.resolve(process.cwd(), ".dbcube", "bin"),
833
- path4.resolve(process.cwd(), "node_modules", ".dbcube", "bin"),
834
- path4.resolve(__dirname, "..", "bin")
1090
+ path5.resolve(process.cwd(), ".dbcube", "bin"),
1091
+ path5.resolve(process.cwd(), "node_modules", ".dbcube", "bin"),
1092
+ path5.resolve(__dirname, "..", "bin")
835
1093
  ];
836
1094
  const platform2 = process.platform;
837
1095
  const extension = platform2 === "win32" ? ".exe" : "";
838
1096
  const binaryName = `sqlite-engine-${platform2 === "win32" ? "windows" : platform2 === "darwin" ? "macos" : "linux"}-x64${extension}`;
839
1097
  for (const dir of possibleDirs) {
840
- const fullPath = path4.join(dir, binaryName);
1098
+ const fullPath = path5.join(dir, binaryName);
841
1099
  if (fs3.existsSync(fullPath)) {
842
1100
  return fullPath;
843
1101
  }
844
1102
  }
845
1103
  const fallbackName = `sqlite-engine${extension}`;
846
1104
  for (const dir of possibleDirs) {
847
- const fullPath = path4.join(dir, fallbackName);
1105
+ const fullPath = path5.join(dir, fallbackName);
848
1106
  if (fs3.existsSync(fullPath)) {
849
1107
  return fullPath;
850
1108
  }
851
1109
  }
852
- return path4.join(possibleDirs[0], binaryName);
1110
+ return path5.join(possibleDirs[0], binaryName);
853
1111
  }
854
1112
  async executeBinary(args) {
855
1113
  const escapedArgs = args.map((arg) => {
@@ -951,7 +1209,7 @@ var SqliteExecutor = class {
951
1209
  // Para compatibilidad con better-sqlite3 API sincrona usando deasync si es necesario
952
1210
  prepareSync(sql) {
953
1211
  const requireUrl = typeof __filename !== "undefined" ? __filename : process.cwd();
954
- const require2 = (0, import_module2.createRequire)(requireUrl);
1212
+ const require2 = (0, import_module3.createRequire)(requireUrl);
955
1213
  const deasync = require2("deasync");
956
1214
  return {
957
1215
  all: (...params) => {
@@ -999,9 +1257,9 @@ var SqliteExecutor = class {
999
1257
  };
1000
1258
 
1001
1259
  // src/lib/DbConfig.ts
1002
- var path5 = __toESM(require("path"));
1260
+ var path6 = __toESM(require("path"));
1003
1261
  var import_fs = __toESM(require("fs"));
1004
- var rootPath = path5.resolve(process.cwd(), ".dbcube");
1262
+ var rootPath = path6.resolve(process.cwd(), ".dbcube");
1005
1263
  var SQLite = class {
1006
1264
  executor = null;
1007
1265
  database;
@@ -1011,7 +1269,7 @@ var SQLite = class {
1011
1269
  async ifExist() {
1012
1270
  if (this.database) {
1013
1271
  const dbPath = this.database || ":memory:";
1014
- const configPath = path5.join(rootPath, dbPath + ".db");
1272
+ const configPath = path6.join(rootPath, dbPath + ".db");
1015
1273
  if (!import_fs.default.existsSync(rootPath)) {
1016
1274
  import_fs.default.mkdirSync(rootPath, { recursive: true });
1017
1275
  }
@@ -1030,7 +1288,7 @@ var SQLite = class {
1030
1288
  try {
1031
1289
  if (!this.executor) {
1032
1290
  const dbPath = this.database || ":memory:";
1033
- const configPath = path5.join(rootPath, dbPath + ".db");
1291
+ const configPath = path6.join(rootPath, dbPath + ".db");
1034
1292
  if (!import_fs.default.existsSync(rootPath)) {
1035
1293
  import_fs.default.mkdirSync(rootPath, { recursive: true });
1036
1294
  }
@@ -1215,7 +1473,7 @@ var DbConfig_default = DbConfig;
1215
1473
 
1216
1474
  // src/lib/FileLogger.ts
1217
1475
  var fs5 = __toESM(require("fs"));
1218
- var path6 = __toESM(require("path"));
1476
+ var path7 = __toESM(require("path"));
1219
1477
  var import_events = require("events");
1220
1478
  var FileLogger = class _FileLogger extends import_events.EventEmitter {
1221
1479
  static watchers = /* @__PURE__ */ new Map();
@@ -1230,7 +1488,7 @@ var FileLogger = class _FileLogger extends import_events.EventEmitter {
1230
1488
  */
1231
1489
  static async write(filePath, message, level = "INFO", append = true) {
1232
1490
  try {
1233
- const dir = path6.dirname(filePath);
1491
+ const dir = path7.dirname(filePath);
1234
1492
  if (!fs5.existsSync(dir)) {
1235
1493
  fs5.mkdirSync(dir, { recursive: true });
1236
1494
  }
@@ -1269,7 +1527,7 @@ var FileLogger = class _FileLogger extends import_events.EventEmitter {
1269
1527
  const buffer = _FileLogger.buffers.get(filePath);
1270
1528
  if (buffer && buffer.length > 0) {
1271
1529
  try {
1272
- const dir = path6.dirname(filePath);
1530
+ const dir = path7.dirname(filePath);
1273
1531
  if (!fs5.existsSync(dir)) {
1274
1532
  fs5.mkdirSync(dir, { recursive: true });
1275
1533
  }
@@ -1993,6 +2251,7 @@ function convertToType(value, type2) {
1993
2251
  DbConfig,
1994
2252
  Engine,
1995
2253
  FileLogger,
2254
+ QueryEngine,
1996
2255
  TableProcessor,
1997
2256
  TriggerProcessor
1998
2257
  });