querymongo 1.0.1 → 1.1.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.
Files changed (58) hide show
  1. package/README.md +17 -44
  2. package/dist/application/MongoConverter.js +20 -0
  3. package/dist/application/MongoConverter.js.map +1 -0
  4. package/dist/application/MongoConverter.spec.js +59 -0
  5. package/dist/application/MongoConverter.spec.js.map +1 -0
  6. package/dist/cli/main.js.map +1 -0
  7. package/dist/domain/interfaces/Converter.js +2 -0
  8. package/dist/domain/interfaces/Converter.js.map +1 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/infrastructure/converters/ConverterFactory.js +14 -0
  11. package/dist/infrastructure/converters/ConverterFactory.js.map +1 -0
  12. package/dist/infrastructure/converters/CreateConverter.js +27 -0
  13. package/dist/infrastructure/converters/CreateConverter.js.map +1 -0
  14. package/dist/infrastructure/converters/DeleteConverter.js +21 -0
  15. package/dist/infrastructure/converters/DeleteConverter.js.map +1 -0
  16. package/dist/infrastructure/converters/SelectConverter.js +24 -0
  17. package/dist/infrastructure/converters/SelectConverter.js.map +1 -0
  18. package/dist/infrastructure/converters/UpdateConverter.js +23 -0
  19. package/dist/infrastructure/converters/UpdateConverter.js.map +1 -0
  20. package/dist/infrastructure/parser/sqlParser.js +13 -0
  21. package/dist/infrastructure/parser/sqlParser.js.map +1 -0
  22. package/dist/infrastructure/utils/queryUtils.js +71 -0
  23. package/dist/infrastructure/utils/queryUtils.js.map +1 -0
  24. package/dist/types/application/MongoConverter.d.ts +5 -0
  25. package/dist/types/application/MongoConverter.d.ts.map +1 -0
  26. package/dist/types/application/MongoConverter.spec.d.ts +2 -0
  27. package/dist/types/application/MongoConverter.spec.d.ts.map +1 -0
  28. package/dist/types/cli/main.d.ts +3 -0
  29. package/dist/types/cli/main.d.ts.map +1 -0
  30. package/{src/domain/interfaces/Converter.ts → dist/types/domain/interfaces/Converter.d.ts} +3 -2
  31. package/dist/types/domain/interfaces/Converter.d.ts.map +1 -0
  32. package/{src/index.ts → dist/types/index.d.ts} +2 -4
  33. package/dist/types/index.d.ts.map +1 -0
  34. package/dist/types/infrastructure/converters/ConverterFactory.d.ts +8 -0
  35. package/dist/types/infrastructure/converters/ConverterFactory.d.ts.map +1 -0
  36. package/dist/types/infrastructure/converters/CreateConverter.d.ts +7 -0
  37. package/dist/types/infrastructure/converters/CreateConverter.d.ts.map +1 -0
  38. package/dist/types/infrastructure/converters/DeleteConverter.d.ts +7 -0
  39. package/dist/types/infrastructure/converters/DeleteConverter.d.ts.map +1 -0
  40. package/dist/types/infrastructure/converters/SelectConverter.d.ts +7 -0
  41. package/dist/types/infrastructure/converters/SelectConverter.d.ts.map +1 -0
  42. package/dist/types/infrastructure/converters/UpdateConverter.d.ts +7 -0
  43. package/dist/types/infrastructure/converters/UpdateConverter.d.ts.map +1 -0
  44. package/dist/types/infrastructure/parser/sqlParser.d.ts +11 -0
  45. package/dist/types/infrastructure/parser/sqlParser.d.ts.map +1 -0
  46. package/dist/types/infrastructure/utils/queryUtils.d.ts +9 -0
  47. package/dist/types/infrastructure/utils/queryUtils.d.ts.map +1 -0
  48. package/package.json +4 -9
  49. package/src/application/MongoConverter.spec.ts +0 -73
  50. package/src/application/MongoConverter.ts +0 -29
  51. package/src/cli/main.ts +0 -64
  52. package/src/infrastructure/converters/ConverterFactory.ts +0 -21
  53. package/src/infrastructure/converters/CreateConverter.ts +0 -37
  54. package/src/infrastructure/converters/DeleteConverter.ts +0 -32
  55. package/src/infrastructure/converters/SelectConverter.ts +0 -37
  56. package/src/infrastructure/converters/UpdateConverter.ts +0 -36
  57. package/src/infrastructure/parser/sqlParser.ts +0 -17
  58. package/src/infrastructure/utils/queryUtils.ts +0 -93
package/README.md CHANGED
@@ -45,32 +45,35 @@ src/
45
45
  - **Dependency Inversion**: Se depende de la interface `IConverter`, no de implementaciones
46
46
  - **Single Responsibility**: Cada conversor tiene un propósito único
47
47
 
48
- ## 🚀 Instalación
48
+ ## 💻 Uso
49
+
50
+ ### 🚀 Instalación Global - CLI
51
+
52
+ Para instalar QueryMongo globalmente en tu máquina:
49
53
 
50
54
  ```bash
51
- npm install
52
- npm run build
55
+ npm i querymongo -g
53
56
  ```
54
57
 
55
- ## 💻 Uso
56
-
57
- ### Modo CLI - Interactivo
58
+ Luego ejecuta desde cualquier directorio:
58
59
 
59
60
  ```bash
60
- npm run dev -- interactive
61
+ querymongo
61
62
  ```
62
63
 
63
- Ingresa queries SQL y recibe instantáneamente el equivalente en MongoDB.
64
+ ### 🛠️ Desarrollo Local
64
65
 
65
- ### Usar como librería
66
+ Para trabajar en el desarrollo del proyecto:
66
67
 
67
- ```typescript
68
- import { mongoConverter } from "./src/application/MongoConverter.ts";
69
-
70
- const result = mongoConverter.convert("SELECT name FROM users WHERE age > 18");
71
- console.log(result);
68
+ ```bash
69
+ git clone https://github.com/rubsuadav/querymongo
70
+ cd querymongo
71
+ npm install
72
+ npm run dev interactive
72
73
  ```
73
74
 
75
+ Esto abrirá la CLI interactiva donde puedes ingresar queries SQL y recibir instantáneamente el equivalente en MongoDB.
76
+
74
77
  ## 📚 Ejemplos de Conversión
75
78
 
76
79
  ### SELECT con proyección
@@ -141,36 +144,6 @@ npm test
141
144
 
142
145
  Cobertura: **100%** en líneas y funciones.
143
146
 
144
- ## 📖 API Reference
145
-
146
- ### `MongoConverter`
147
-
148
- Clase principal para conversiones.
149
-
150
- ```typescript
151
- class MongoConverter {
152
- convert(sql: string): Record<string, any>;
153
- }
154
- ```
155
-
156
- **Parámetros:**
157
-
158
- - `sql` (string): Query SQL a convertir
159
-
160
- **Retorna:** Objeto con estructura MongoDB
161
-
162
- **Lanza:** Error si el query SQL no es soportado
163
-
164
- ### Exports Públicos
165
-
166
- ```typescript
167
- export {
168
- MongoConverter,
169
- mongoConverter,
170
- } from "./src/application/MongoConverter.ts";
171
- export type { IConverter } from "./src/domain/interfaces/Converter.ts";
172
- ```
173
-
174
147
  ## 🔧 Operadores Soportados
175
148
 
176
149
  | SQL | MongoDB |
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Servicio principal de conversión
3
+ * Orquesta el parsing y la conversión a MongoDB
4
+ */
5
+ import { parseSqlQuery, normalizeQuery, } from "../infrastructure/parser/sqlParser.js";
6
+ import { getConverter } from "../infrastructure/converters/ConverterFactory.js";
7
+ export class MongoConverter {
8
+ convert(sql) {
9
+ const normalized = normalizeQuery(sql);
10
+ const parsed = parseSqlQuery(normalized);
11
+ const statement = Array.isArray(parsed) ? parsed[0] : parsed;
12
+ const converter = getConverter(normalized);
13
+ if (!converter) {
14
+ throw new Error(`Unsupported SQL statement: ${normalized.substring(0, 50)}...`);
15
+ }
16
+ return converter.convert(statement);
17
+ }
18
+ }
19
+ export const mongoConverter = new MongoConverter();
20
+ //# sourceMappingURL=MongoConverter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MongoConverter.js","sourceRoot":"","sources":["../../src/application/MongoConverter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,aAAa,EACb,cAAc,GACf,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,kDAAkD,CAAC;AAEhF,MAAM,OAAO,cAAc;IACzB,OAAO,CAAC,GAAW;QACjB,MAAM,UAAU,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QACvC,MAAM,MAAM,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;QAEzC,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAC7D,MAAM,SAAS,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;QAE3C,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACb,8BAA8B,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAC/D,CAAC;QACJ,CAAC;QAED,OAAO,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC;CACF;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,cAAc,EAAE,CAAC"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Tests para verificar las conversiones SQL a MongoDB
3
+ */
4
+ import { test, describe } from "node:test";
5
+ import { equal, ok, throws } from "node:assert";
6
+ import { mongoConverter } from "../application/MongoConverter.js";
7
+ describe("MongoConverter", () => {
8
+ describe("SELECT queries", () => {
9
+ test("should convert simple SELECT query", () => {
10
+ const sql = "SELECT name, email FROM users";
11
+ const result = mongoConverter.convert(sql);
12
+ equal(result.collection, "users");
13
+ ok(result.pipeline.some((stage) => stage.$project));
14
+ });
15
+ test("should convert SELECT with WHERE clause", () => {
16
+ const sql = "SELECT * FROM users WHERE id = 1";
17
+ const result = mongoConverter.convert(sql);
18
+ equal(result.collection, "users");
19
+ ok(result.pipeline.some((stage) => stage.$match));
20
+ });
21
+ test("should convert SELECT with LIMIT", () => {
22
+ const sql = "SELECT name FROM products LIMIT 10";
23
+ const result = mongoConverter.convert(sql);
24
+ ok(result.pipeline.some((stage) => stage.$limit === 10));
25
+ });
26
+ });
27
+ describe("INSERT queries", () => {
28
+ test("should convert INSERT query", () => {
29
+ const sql = "INSERT INTO users (name, email) VALUES ('John', 'john@example.com')";
30
+ const result = mongoConverter.convert(sql);
31
+ equal(result.collection, "users");
32
+ equal(result.operation, "insertOne");
33
+ });
34
+ });
35
+ describe("UPDATE queries", () => {
36
+ test("should convert UPDATE query", () => {
37
+ const sql = 'UPDATE users SET name = "Jane" WHERE id = 1';
38
+ const result = mongoConverter.convert(sql);
39
+ equal(result.collection, "users");
40
+ equal(result.operation, "updateOne");
41
+ ok(result.update.$set);
42
+ });
43
+ });
44
+ describe("DELETE queries", () => {
45
+ test("should convert DELETE query", () => {
46
+ const sql = "DELETE FROM users WHERE id = 1";
47
+ const result = mongoConverter.convert(sql);
48
+ equal(result.collection, "users");
49
+ equal(result.operation, "deleteOne");
50
+ });
51
+ });
52
+ describe("Error handling", () => {
53
+ test("should throw on unsupported query type", () => {
54
+ const sql = "GRANT SELECT ON users TO john";
55
+ throws(() => mongoConverter.convert(sql), /Unsupported SQL statement/);
56
+ });
57
+ });
58
+ });
59
+ //# sourceMappingURL=MongoConverter.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MongoConverter.spec.js","sourceRoot":"","sources":["../../src/application/MongoConverter.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":";;;;;;;;;;AAEA;;;GAGG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAElE,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,YAAY,CAAC;KAClB,WAAW,CAAC,uCAAuC,CAAC;KACpD,OAAO,CAAC,OAAO,CAAC;KAChB,KAAK,CAAC,WAAW,CAAC,CAAC;AAEtB,OAAO;KACJ,OAAO,CAAC,aAAa,CAAC;KACtB,WAAW,CAAC,wBAAwB,CAAC;KACrC,MAAM,CAAC,GAAS,EAAE;IACjB,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;IAC1C,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC;QAClC,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,CAAC,MAAc,EAAmB,EAAE;QACnD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAChE,CAAC,CAAC;IAEF,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,IAAI,CAAC,0DAA0D,CAAC,CACvE,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC;IAEjD,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;QAEzD,IAAI,GAAG,CAAC,WAAW,EAAE,KAAK,MAAM,EAAE,CAAC;YACjC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC;YACzC,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,MAAM;QACR,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE;YAAE,SAAS;QAE1B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAC3C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC,CAAC;YACjD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAClE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CACX,KAAK,CAAC,GAAG,CACP,YAAY,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,IAAI,CACzE,CACF,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC,CAAA,CAAC;KACD,KAAK,CAAC,GAAG,CAAC,CAAC;AAEd,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=Converter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Converter.js","sourceRoot":"","sources":["../../../src/domain/interfaces/Converter.ts"],"names":[],"mappings":""}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,cAAc,EACd,cAAc,GACf,MAAM,iCAAiC,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { SelectConverter } from "./SelectConverter.js";
2
+ import { CreateConverter } from "./CreateConverter.js";
3
+ import { UpdateConverter } from "./UpdateConverter.js";
4
+ import { DeleteConverter } from "./DeleteConverter.js";
5
+ const CONVERTERS = [
6
+ SelectConverter,
7
+ CreateConverter,
8
+ UpdateConverter,
9
+ DeleteConverter,
10
+ ];
11
+ export const getConverter = (statement) => {
12
+ return CONVERTERS.find((converter) => converter.can(statement)) || null;
13
+ };
14
+ //# sourceMappingURL=ConverterFactory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConverterFactory.js","sourceRoot":"","sources":["../../../src/infrastructure/converters/ConverterFactory.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,MAAM,UAAU,GAAiB;IAC/B,eAAe;IACf,eAAe;IACf,eAAe;IACf,eAAe;CAChB,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,SAAiB,EAAqB,EAAE;IACnE,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,IAAI,CAAC;AAC1E,CAAC,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { removeUndefinedFields } from "../utils/queryUtils.js";
2
+ export const CreateConverter = {
3
+ can: (statement) => {
4
+ const lower = statement.toLowerCase();
5
+ return lower.startsWith("insert") || lower.startsWith("create");
6
+ },
7
+ convert: (query) => {
8
+ var _a;
9
+ const { ast } = query;
10
+ const { table, columns, values } = ast;
11
+ const collectionName = ((_a = table === null || table === void 0 ? void 0 : table[0]) === null || _a === void 0 ? void 0 : _a.table) || "collection";
12
+ const valuesList = values.values || [];
13
+ const docs = valuesList.map((v) => {
14
+ const row = v.value || v;
15
+ return Object.fromEntries(columns.map((col, idx) => { var _a; return [
16
+ col,
17
+ ((_a = row[idx]) === null || _a === void 0 ? void 0 : _a.value) || row[idx],
18
+ ]; }));
19
+ });
20
+ return removeUndefinedFields({
21
+ collection: collectionName,
22
+ operation: docs.length > 1 ? "insertMany" : "insertOne",
23
+ documents: docs.length === 1 ? docs[0] : docs,
24
+ });
25
+ },
26
+ };
27
+ //# sourceMappingURL=CreateConverter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CreateConverter.js","sourceRoot":"","sources":["../../../src/infrastructure/converters/CreateConverter.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,MAAM,CAAC,MAAM,eAAe,GAAe;IACzC,GAAG,EAAE,CAAC,SAAiB,EAAW,EAAE;QAClC,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC;QACtC,OAAO,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAClE,CAAC;IAED,OAAO,EAAE,CAAC,KAAU,EAAuB,EAAE;;QAC3C,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;QACtB,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;QAEvC,MAAM,cAAc,GAAG,CAAA,MAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAG,CAAC,CAAC,0CAAE,KAAK,KAAI,YAAY,CAAC;QACzD,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC;QAEvC,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE;YACrC,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;YACzB,OAAO,MAAM,CAAC,WAAW,CACvB,OAAO,CAAC,GAAG,CAAC,CAAC,GAAW,EAAE,GAAW,EAAE,EAAE,kBAAC;gBACxC,GAAG;gBACH,CAAA,MAAA,GAAG,CAAC,GAAG,CAAC,0CAAE,KAAK,KAAI,GAAG,CAAC,GAAG,CAAC;aAC5B,GAAA,CAAC,CACH,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,OAAO,qBAAqB,CAAC;YAC3B,UAAU,EAAE,cAAc;YAC1B,SAAS,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WAAW;YACvD,SAAS,EAAE,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI;SAC9C,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { buildFilter, determineOperation, removeUndefinedFields, } from "../utils/queryUtils.js";
2
+ export const DeleteConverter = {
3
+ can: (statement) => {
4
+ return statement.toLowerCase().startsWith("delete");
5
+ },
6
+ convert: (query) => {
7
+ var _a;
8
+ const { ast } = query;
9
+ const { from, where } = ast;
10
+ const collectionName = ((_a = from === null || from === void 0 ? void 0 : from[0]) === null || _a === void 0 ? void 0 : _a.table) || "collection";
11
+ return removeUndefinedFields({
12
+ collection: collectionName,
13
+ operation: determineOperation(where, {
14
+ one: "deleteOne",
15
+ many: "deleteMany",
16
+ }),
17
+ filter: where ? buildFilter(where) : {},
18
+ });
19
+ },
20
+ };
21
+ //# sourceMappingURL=DeleteConverter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeleteConverter.js","sourceRoot":"","sources":["../../../src/infrastructure/converters/DeleteConverter.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,CAAC,MAAM,eAAe,GAAe;IACzC,GAAG,EAAE,CAAC,SAAiB,EAAW,EAAE;QAClC,OAAO,SAAS,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IACtD,CAAC;IAED,OAAO,EAAE,CAAC,KAAU,EAAuB,EAAE;;QAC3C,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;QACtB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC;QAE5B,MAAM,cAAc,GAAG,CAAA,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAG,CAAC,CAAC,0CAAE,KAAK,KAAI,YAAY,CAAC;QAExD,OAAO,qBAAqB,CAAC;YAC3B,UAAU,EAAE,cAAc;YAC1B,SAAS,EAAE,kBAAkB,CAAC,KAAK,EAAE;gBACnC,GAAG,EAAE,WAAW;gBAChB,IAAI,EAAE,YAAY;aACnB,CAAC;YACF,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;SACxC,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { buildProjection, buildFilter, removeUndefinedFields, } from "../utils/queryUtils.js";
2
+ export const SelectConverter = {
3
+ can: (statement) => {
4
+ return statement.toLowerCase().startsWith("select");
5
+ },
6
+ convert: (query) => {
7
+ var _a, _b, _c, _d, _e;
8
+ const { ast } = query;
9
+ const { columns, from, where, limit } = ast;
10
+ const fields = columns && ((_b = (_a = columns[0]) === null || _a === void 0 ? void 0 : _a.expr) === null || _b === void 0 ? void 0 : _b.column) !== "*"
11
+ ? columns.map((col) => col.expr.column)
12
+ : "*";
13
+ const limitValue = ((_d = (_c = limit === null || limit === void 0 ? void 0 : limit.value) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.value) || (limit === null || limit === void 0 ? void 0 : limit.value) || limit;
14
+ return removeUndefinedFields({
15
+ collection: ((_e = from === null || from === void 0 ? void 0 : from[0]) === null || _e === void 0 ? void 0 : _e.table) || "collection",
16
+ pipeline: [
17
+ where && { $match: buildFilter(where) },
18
+ fields !== "*" && { $project: buildProjection(fields) },
19
+ limitValue && { $limit: limitValue },
20
+ ].filter(Boolean),
21
+ });
22
+ },
23
+ };
24
+ //# sourceMappingURL=SelectConverter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SelectConverter.js","sourceRoot":"","sources":["../../../src/infrastructure/converters/SelectConverter.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,eAAe,EACf,WAAW,EACX,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,CAAC,MAAM,eAAe,GAAe;IACzC,GAAG,EAAE,CAAC,SAAiB,EAAW,EAAE;QAClC,OAAO,SAAS,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IACtD,CAAC;IAED,OAAO,EAAE,CAAC,KAAU,EAAuB,EAAE;;QAC3C,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;QACtB,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC;QAE5C,MAAM,MAAM,GACV,OAAO,IAAI,CAAA,MAAA,MAAA,OAAO,CAAC,CAAC,CAAC,0CAAE,IAAI,0CAAE,MAAM,MAAK,GAAG;YACzC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAQ,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;YAC5C,CAAC,CAAC,GAAG,CAAC;QAEV,MAAM,UAAU,GAAG,CAAA,MAAA,MAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,KAAK,0CAAG,CAAC,CAAC,0CAAE,KAAK,MAAI,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,KAAK,CAAA,IAAI,KAAK,CAAC;QAErE,OAAO,qBAAqB,CAAC;YAC3B,UAAU,EAAE,CAAA,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAG,CAAC,CAAC,0CAAE,KAAK,KAAI,YAAY;YAC5C,QAAQ,EAAE;gBACR,KAAK,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE;gBACvC,MAAM,KAAK,GAAG,IAAI,EAAE,QAAQ,EAAE,eAAe,CAAC,MAAM,CAAC,EAAE;gBACvD,UAAU,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE;aACrC,CAAC,MAAM,CAAC,OAAO,CAAC;SAClB,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { buildFilter, determineOperation, removeUndefinedFields, } from "../utils/queryUtils.js";
2
+ export const UpdateConverter = {
3
+ can: (statement) => {
4
+ return statement.toLowerCase().startsWith("update");
5
+ },
6
+ convert: (query) => {
7
+ var _a;
8
+ const { ast } = query;
9
+ const { table, set, where } = ast;
10
+ const collectionName = ((_a = table === null || table === void 0 ? void 0 : table[0]) === null || _a === void 0 ? void 0 : _a.table) || "collection";
11
+ const updateData = Object.fromEntries(set.map((item) => { var _a; return [item.column, ((_a = item.value) === null || _a === void 0 ? void 0 : _a.value) || item.value]; }));
12
+ return removeUndefinedFields({
13
+ collection: collectionName,
14
+ operation: determineOperation(where, {
15
+ one: "updateOne",
16
+ many: "updateMany",
17
+ }),
18
+ filter: where ? buildFilter(where) : {},
19
+ update: { $set: updateData },
20
+ });
21
+ },
22
+ };
23
+ //# sourceMappingURL=UpdateConverter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UpdateConverter.js","sourceRoot":"","sources":["../../../src/infrastructure/converters/UpdateConverter.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,CAAC,MAAM,eAAe,GAAe;IACzC,GAAG,EAAE,CAAC,SAAiB,EAAW,EAAE;QAClC,OAAO,SAAS,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IACtD,CAAC;IAED,OAAO,EAAE,CAAC,KAAU,EAAuB,EAAE;;QAC3C,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;QACtB,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC;QAElC,MAAM,cAAc,GAAG,CAAA,MAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAG,CAAC,CAAC,0CAAE,KAAK,KAAI,YAAY,CAAC;QACzD,MAAM,UAAU,GAAG,MAAM,CAAC,WAAW,CACnC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAS,EAAE,EAAE,kBAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAA,MAAA,IAAI,CAAC,KAAK,0CAAE,KAAK,KAAI,IAAI,CAAC,KAAK,CAAC,GAAA,CAAC,CACvE,CAAC;QAEF,OAAO,qBAAqB,CAAC;YAC3B,UAAU,EAAE,cAAc;YAC1B,SAAS,EAAE,kBAAkB,CAAC,KAAK,EAAE;gBACnC,GAAG,EAAE,WAAW;gBAChB,IAAI,EAAE,YAAY;aACnB,CAAC;YACF,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;YACvC,MAAM,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE;SAC7B,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Parser SQL que encapsula node-sql-parser
3
+ * Abstrae la dependencia externa y proporciona una interfaz limpia
4
+ */
5
+ import sqlParser from "node-sql-parser";
6
+ const parser = new sqlParser.Parser();
7
+ export const parseSqlQuery = (sql) => {
8
+ return parser.parse(sql);
9
+ };
10
+ export const normalizeQuery = (query) => {
11
+ return query.trim().replace(/;$/, "").replace(/\s+/g, " ");
12
+ };
13
+ //# sourceMappingURL=sqlParser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlParser.js","sourceRoot":"","sources":["../../../src/infrastructure/parser/sqlParser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,SAAS,MAAM,iBAAiB,CAAC;AAExC,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,MAAM,EAAE,CAAC;AAItC,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,GAAW,EAA+B,EAAE;IACxE,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AAC3B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,KAAa,EAAU,EAAE;IACtD,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAC7D,CAAC,CAAC"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Utilidades para conversión de queries SQL a MongoDB
3
+ * Centraliza lógica reutilizable siguiendo principio DRY
4
+ */
5
+ import _ from "lodash";
6
+ export const removeUndefinedFields = (obj) => {
7
+ return _.omitBy(obj, _.isUndefined);
8
+ };
9
+ export const normalizeFieldName = (field) => {
10
+ return field.trim().replace(/`|"/g, "");
11
+ };
12
+ const normalizeFieldNames = (fields) => {
13
+ return fields.map(normalizeFieldName);
14
+ };
15
+ export const buildProjection = (fields) => {
16
+ if (fields === "*")
17
+ return {};
18
+ return Object.fromEntries(normalizeFieldNames(fields).map((f) => [f, 1]));
19
+ };
20
+ export const buildFilter = (condition) => {
21
+ if (!condition)
22
+ return {};
23
+ const { operator, left, right } = condition;
24
+ if (!operator)
25
+ return {};
26
+ if (operator.toUpperCase() === "AND") {
27
+ return {
28
+ $and: [buildFilter(left), buildFilter(right)],
29
+ };
30
+ }
31
+ if (operator.toUpperCase() === "OR") {
32
+ return {
33
+ $or: [buildFilter(left), buildFilter(right)],
34
+ };
35
+ }
36
+ const field = normalizeFieldName((left === null || left === void 0 ? void 0 : left.column) || (left === null || left === void 0 ? void 0 : left.value) || left || "");
37
+ const value = (right === null || right === void 0 ? void 0 : right.value) !== undefined ? right.value : right;
38
+ const operatorMap = {
39
+ "=": "$eq",
40
+ "!=": "$ne",
41
+ "<>": "$ne",
42
+ "<": "$lt",
43
+ ">": "$gt",
44
+ "<=": "$lte",
45
+ ">=": "$gte",
46
+ like: "$regex",
47
+ in: "$in",
48
+ "not in": "$nin",
49
+ };
50
+ const mongoOp = operatorMap[operator.toLowerCase()];
51
+ return mongoOp ? { [field]: { [mongoOp]: value } } : {};
52
+ };
53
+ export function determineOperation(where, operations) {
54
+ var _a;
55
+ const uniqueFields = ["id", "_id", "email", "username"];
56
+ const { operator, left } = where;
57
+ if (!where)
58
+ return operations.many;
59
+ if (["and", "or"].includes(operator === null || operator === void 0 ? void 0 : operator.toLowerCase())) {
60
+ return operations.many;
61
+ }
62
+ const field = (left === null || left === void 0 ? void 0 : left.column) || (left === null || left === void 0 ? void 0 : left.value) || left || "";
63
+ const isUniqueField = uniqueFields.includes((_a = field === null || field === void 0 ? void 0 : field.toLowerCase) === null || _a === void 0 ? void 0 : _a.call(field));
64
+ if (isUniqueField && operator === "=") {
65
+ return operations.one;
66
+ }
67
+ return [">", "<", ">=", "<=", "!=", "<>", "like", "in"].includes(operator === null || operator === void 0 ? void 0 : operator.toLowerCase())
68
+ ? operations.many
69
+ : operations.one;
70
+ }
71
+ //# sourceMappingURL=queryUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queryUtils.js","sourceRoot":"","sources":["../../../src/infrastructure/utils/queryUtils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare class MongoConverter {
2
+ convert(sql: string): Record<string, any>;
3
+ }
4
+ export declare const mongoConverter: MongoConverter;
5
+ //# sourceMappingURL=MongoConverter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MongoConverter.d.ts","sourceRoot":"","sources":["../../../src/application/MongoConverter.ts"],"names":[],"mappings":"AAUA,qBAAa,cAAc;IACzB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAcxC;CACF;AAED,eAAO,MAAM,cAAc,gBAAuB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=MongoConverter.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MongoConverter.spec.d.ts","sourceRoot":"","sources":["../../../src/application/MongoConverter.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../src/cli/main.ts"],"names":[],"mappings":""}
@@ -3,6 +3,7 @@
3
3
  * Implementa Strategy Pattern para permitir diferentes estrategias de conversión
4
4
  */
5
5
  export interface IConverter {
6
- can(statement: string): boolean;
7
- convert(query: any): Record<string, any>;
6
+ can(statement: string): boolean;
7
+ convert(query: any): Record<string, any>;
8
8
  }
9
+ //# sourceMappingURL=Converter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Converter.d.ts","sourceRoot":"","sources":["../../../../src/domain/interfaces/Converter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,OAAO,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC1C"}
@@ -2,8 +2,6 @@
2
2
  * API pública del módulo
3
3
  * Exporta las funcionalidades principales para uso como librería
4
4
  */
5
- export {
6
- MongoConverter,
7
- mongoConverter,
8
- } from "./application/MongoConverter.ts";
5
+ export { MongoConverter, mongoConverter, } from "./application/MongoConverter.ts";
9
6
  export type { IConverter } from "./domain/interfaces/Converter.ts";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,cAAc,EACd,cAAc,GACf,MAAM,iCAAiC,CAAC;AACzC,YAAY,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Factory que orquesta los conversores
3
+ * Implementa Strategy Pattern + Factory Pattern
4
+ * Centraliza la lógica de selección de conversor
5
+ */
6
+ import type { IConverter } from "../../domain/interfaces/Converter.ts";
7
+ export declare const getConverter: (statement: string) => IConverter | null;
8
+ //# sourceMappingURL=ConverterFactory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConverterFactory.d.ts","sourceRoot":"","sources":["../../../../src/infrastructure/converters/ConverterFactory.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sCAAsC,CAAC;AAavE,eAAO,MAAM,YAAY,cAAe,MAAM,KAAG,UAAU,GAAG,IAE7D,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Conversor para queries CREATE/INSERT
3
+ * Convierte CREATE/INSERT SQL a insertOne/insertMany de MongoDB
4
+ */
5
+ import type { IConverter } from "../../domain/interfaces/Converter.ts";
6
+ export declare const CreateConverter: IConverter;
7
+ //# sourceMappingURL=CreateConverter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CreateConverter.d.ts","sourceRoot":"","sources":["../../../../src/infrastructure/converters/CreateConverter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sCAAsC,CAAC;AAGvE,eAAO,MAAM,eAAe,EAAE,UA6B7B,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Conversor para queries DELETE
3
+ * Convierte DELETE SQL a deleteOne/deleteMany de MongoDB
4
+ */
5
+ import type { IConverter } from "../../domain/interfaces/Converter.ts";
6
+ export declare const DeleteConverter: IConverter;
7
+ //# sourceMappingURL=DeleteConverter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeleteConverter.d.ts","sourceRoot":"","sources":["../../../../src/infrastructure/converters/DeleteConverter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sCAAsC,CAAC;AAOvE,eAAO,MAAM,eAAe,EAAE,UAoB7B,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Conversor para queries SELECT
3
+ * Convierte SELECT SQL a aggregation pipeline o find query de MongoDB
4
+ */
5
+ import type { IConverter } from "../../domain/interfaces/Converter.ts";
6
+ export declare const SelectConverter: IConverter;
7
+ //# sourceMappingURL=SelectConverter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SelectConverter.d.ts","sourceRoot":"","sources":["../../../../src/infrastructure/converters/SelectConverter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sCAAsC,CAAC;AAOvE,eAAO,MAAM,eAAe,EAAE,UAyB7B,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Conversor para queries UPDATE
3
+ * Convierte UPDATE SQL a updateOne/updateMany de MongoDB
4
+ */
5
+ import type { IConverter } from "../../domain/interfaces/Converter.ts";
6
+ export declare const UpdateConverter: IConverter;
7
+ //# sourceMappingURL=UpdateConverter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UpdateConverter.d.ts","sourceRoot":"","sources":["../../../../src/infrastructure/converters/UpdateConverter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sCAAsC,CAAC;AAOvE,eAAO,MAAM,eAAe,EAAE,UAwB7B,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Parser SQL que encapsula node-sql-parser
3
+ * Abstrae la dependencia externa y proporciona una interfaz limpia
4
+ */
5
+ import sqlParser from "node-sql-parser";
6
+ declare const parser: sqlParser.Parser;
7
+ export type ParsedQuery = ReturnType<typeof parser.parse>;
8
+ export declare const parseSqlQuery: (sql: string) => ParsedQuery | ParsedQuery[];
9
+ export declare const normalizeQuery: (query: string) => string;
10
+ export {};
11
+ //# sourceMappingURL=sqlParser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlParser.d.ts","sourceRoot":"","sources":["../../../../src/infrastructure/parser/sqlParser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,SAAS,MAAM,iBAAiB,CAAC;AAExC,QAAA,MAAM,MAAM,kBAAyB,CAAC;AAEtC,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AAE1D,eAAO,MAAM,aAAa,QAAS,MAAM,KAAG,WAAW,GAAG,WAAW,EAEpE,CAAC;AAEF,eAAO,MAAM,cAAc,UAAW,MAAM,KAAG,MAE9C,CAAC"}
@@ -0,0 +1,9 @@
1
+ export declare const removeUndefinedFields: (obj: Record<string, any>) => Record<string, any>;
2
+ export declare const normalizeFieldName: (field: string) => string;
3
+ export declare const buildProjection: (fields: string[] | "*") => Record<string, 1 | 0>;
4
+ export declare const buildFilter: (condition: any) => Record<string, any>;
5
+ export declare function determineOperation(where: any, operations: {
6
+ one: string;
7
+ many: string;
8
+ }): string;
9
+ //# sourceMappingURL=queryUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queryUtils.d.ts","sourceRoot":"","sources":["../../../../src/infrastructure/utils/queryUtils.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,qBAAqB,QAC3B,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KACvB,MAAM,CAAC,MAAM,EAAE,GAAG,CAEpB,CAAC;AAEF,eAAO,MAAM,kBAAkB,UAAW,MAAM,KAAG,MAElD,CAAC;AAMF,eAAO,MAAM,eAAe,WAClB,MAAM,EAAE,GAAG,GAAG,KACrB,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAGtB,CAAC;AAEF,eAAO,MAAM,WAAW,cAAe,GAAG,KAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAsC9D,CAAC;AAEF,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,GAAG,EACV,UAAU,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACxC,MAAM,CAsBR"}
package/package.json CHANGED
@@ -1,13 +1,12 @@
1
1
  {
2
2
  "name": "querymongo",
3
3
  "type": "module",
4
- "version": "1.0.1",
4
+ "version": "1.1.1",
5
5
  "description": "SQL to MongoDB Query Converter CLI",
6
- "main": "dist/index.js",
7
- "bin": {
8
- "querymongo": "dist/cli/main.js"
9
- },
6
+ "main": "dist/cli/main.js",
7
+ "bin": "dist/cli/main.js",
10
8
  "scripts": {
9
+ "prepare": "npm run build",
11
10
  "clean": "node -e \"require('fs').rmSync('dist', { recursive: true, force: true })\"",
12
11
  "build": "npm run clean && tsc",
13
12
  "start": "npm run build && node dist/cli/main.js",
@@ -21,10 +20,6 @@
21
20
  "converter",
22
21
  "query"
23
22
  ],
24
- "files": [
25
- "src",
26
- "package.json"
27
- ],
28
23
  "repository": {
29
24
  "url": "https://github.com/rubsuadav/querymongo",
30
25
  "type": "git"
@@ -1,73 +0,0 @@
1
- /**
2
- * Tests para verificar las conversiones SQL a MongoDB
3
- */
4
- import { test, describe } from "node:test";
5
- import { equal, ok, throws } from "node:assert";
6
- import { mongoConverter } from "../application/MongoConverter.ts";
7
-
8
- describe("MongoConverter", () => {
9
- describe("SELECT queries", () => {
10
- test("should convert simple SELECT query", () => {
11
- const sql = "SELECT name, email FROM users";
12
- const result = mongoConverter.convert(sql);
13
-
14
- equal(result.collection, "users");
15
- ok(result.pipeline.some((stage: any) => stage.$project));
16
- });
17
-
18
- test("should convert SELECT with WHERE clause", () => {
19
- const sql = "SELECT * FROM users WHERE id = 1";
20
- const result = mongoConverter.convert(sql);
21
-
22
- equal(result.collection, "users");
23
- ok(result.pipeline.some((stage: any) => stage.$match));
24
- });
25
-
26
- test("should convert SELECT with LIMIT", () => {
27
- const sql = "SELECT name FROM products LIMIT 10";
28
- const result = mongoConverter.convert(sql);
29
-
30
- ok(result.pipeline.some((stage: any) => stage.$limit === 10));
31
- });
32
- });
33
-
34
- describe("INSERT queries", () => {
35
- test("should convert INSERT query", () => {
36
- const sql =
37
- "INSERT INTO users (name, email) VALUES ('John', 'john@example.com')";
38
- const result = mongoConverter.convert(sql);
39
-
40
- equal(result.collection, "users");
41
- equal(result.operation, "insertOne");
42
- });
43
- });
44
-
45
- describe("UPDATE queries", () => {
46
- test("should convert UPDATE query", () => {
47
- const sql = 'UPDATE users SET name = "Jane" WHERE id = 1';
48
- const result = mongoConverter.convert(sql);
49
-
50
- equal(result.collection, "users");
51
- equal(result.operation, "updateOne");
52
- ok(result.update.$set);
53
- });
54
- });
55
-
56
- describe("DELETE queries", () => {
57
- test("should convert DELETE query", () => {
58
- const sql = "DELETE FROM users WHERE id = 1";
59
- const result = mongoConverter.convert(sql);
60
-
61
- equal(result.collection, "users");
62
- equal(result.operation, "deleteOne");
63
- });
64
- });
65
-
66
- describe("Error handling", () => {
67
- test("should throw on unsupported query type", () => {
68
- const sql = "GRANT SELECT ON users TO john";
69
-
70
- throws(() => mongoConverter.convert(sql), /Unsupported SQL statement/);
71
- });
72
- });
73
- });
@@ -1,29 +0,0 @@
1
- /**
2
- * Servicio principal de conversión
3
- * Orquesta el parsing y la conversión a MongoDB
4
- */
5
- import {
6
- parseSqlQuery,
7
- normalizeQuery,
8
- } from "../infrastructure/parser/sqlParser.ts";
9
- import { getConverter } from "../infrastructure/converters/ConverterFactory.ts";
10
-
11
- export class MongoConverter {
12
- convert(sql: string): Record<string, any> {
13
- const normalized = normalizeQuery(sql);
14
- const parsed = parseSqlQuery(normalized);
15
-
16
- const statement = Array.isArray(parsed) ? parsed[0] : parsed;
17
- const converter = getConverter(normalized);
18
-
19
- if (!converter) {
20
- throw new Error(
21
- `Unsupported SQL statement: ${normalized.substring(0, 50)}...`,
22
- );
23
- }
24
-
25
- return converter.convert(statement);
26
- }
27
- }
28
-
29
- export const mongoConverter = new MongoConverter();
package/src/cli/main.ts DELETED
@@ -1,64 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * CLI para convertir queries SQL a MongoDB
5
- * Interfaz de línea de comandos usando Commander
6
- */
7
- import { Command } from "commander";
8
- import chalk from "chalk";
9
- import { mongoConverter } from "../application/MongoConverter.ts";
10
-
11
- const program = new Command();
12
-
13
- program
14
- .name("querymongo")
15
- .description("Convert SQL queries to MongoDB format")
16
- .version("1.0.0")
17
- .usage("[command]");
18
-
19
- program
20
- .command("interactive")
21
- .description("Start interactive mode")
22
- .action(async () => {
23
- const readline = await import("readline");
24
- const rl = readline.createInterface({
25
- input: process.stdin,
26
- output: process.stdout,
27
- });
28
-
29
- const question = (prompt: string): Promise<string> => {
30
- return new Promise((resolve) => rl.question(prompt, resolve));
31
- };
32
-
33
- console.log(
34
- chalk.blue("\n📊 SQL to MongoDB Query Converter - Interactive Mode\n"),
35
- );
36
- console.log(chalk.gray('Type "exit" to quit\n'));
37
-
38
- while (true) {
39
- const sql = await question(chalk.yellow("SQL Query > "));
40
-
41
- if (sql.toLowerCase() === "exit") {
42
- console.log(chalk.blue("Goodbye! 👋\n"));
43
- rl.close();
44
- break;
45
- }
46
-
47
- if (!sql.trim()) continue;
48
-
49
- try {
50
- const result = mongoConverter.convert(sql);
51
- console.log(chalk.green("\n✓ MongoDB Query:\n"));
52
- console.log(chalk.cyan(JSON.stringify(result, null, 2)) + "\n");
53
- } catch (error) {
54
- console.error(
55
- chalk.red(
56
- `✗ Error: ${error instanceof Error ? error.message : "Unknown error"}\n`,
57
- ),
58
- );
59
- }
60
- }
61
- })
62
- .usage(" ");
63
-
64
- program.parse(process.argv);
@@ -1,21 +0,0 @@
1
- /**
2
- * Factory que orquesta los conversores
3
- * Implementa Strategy Pattern + Factory Pattern
4
- * Centraliza la lógica de selección de conversor
5
- */
6
- import type { IConverter } from "../../domain/interfaces/Converter.ts";
7
- import { SelectConverter } from "./SelectConverter.ts";
8
- import { CreateConverter } from "./CreateConverter.ts";
9
- import { UpdateConverter } from "./UpdateConverter.ts";
10
- import { DeleteConverter } from "./DeleteConverter.ts";
11
-
12
- const CONVERTERS: IConverter[] = [
13
- SelectConverter,
14
- CreateConverter,
15
- UpdateConverter,
16
- DeleteConverter,
17
- ];
18
-
19
- export const getConverter = (statement: string): IConverter | null => {
20
- return CONVERTERS.find((converter) => converter.can(statement)) || null;
21
- };
@@ -1,37 +0,0 @@
1
- /**
2
- * Conversor para queries CREATE/INSERT
3
- * Convierte CREATE/INSERT SQL a insertOne/insertMany de MongoDB
4
- */
5
- import type { IConverter } from "../../domain/interfaces/Converter.ts";
6
- import { removeUndefinedFields } from "../utils/queryUtils.ts";
7
-
8
- export const CreateConverter: IConverter = {
9
- can: (statement: string): boolean => {
10
- const lower = statement.toLowerCase();
11
- return lower.startsWith("insert") || lower.startsWith("create");
12
- },
13
-
14
- convert: (query: any): Record<string, any> => {
15
- const { ast } = query;
16
- const { table, columns, values } = ast;
17
-
18
- const collectionName = table?.[0]?.table || "collection";
19
- const valuesList = values.values || [];
20
-
21
- const docs = valuesList.map((v: any) => {
22
- const row = v.value || v;
23
- return Object.fromEntries(
24
- columns.map((col: string, idx: number) => [
25
- col,
26
- row[idx]?.value || row[idx],
27
- ]),
28
- );
29
- });
30
-
31
- return removeUndefinedFields({
32
- collection: collectionName,
33
- operation: docs.length > 1 ? "insertMany" : "insertOne",
34
- documents: docs.length === 1 ? docs[0] : docs,
35
- });
36
- },
37
- };
@@ -1,32 +0,0 @@
1
- /**
2
- * Conversor para queries DELETE
3
- * Convierte DELETE SQL a deleteOne/deleteMany de MongoDB
4
- */
5
- import type { IConverter } from "../../domain/interfaces/Converter.ts";
6
- import {
7
- buildFilter,
8
- determineOperation,
9
- removeUndefinedFields,
10
- } from "../utils/queryUtils.ts";
11
-
12
- export const DeleteConverter: IConverter = {
13
- can: (statement: string): boolean => {
14
- return statement.toLowerCase().startsWith("delete");
15
- },
16
-
17
- convert: (query: any): Record<string, any> => {
18
- const { ast } = query;
19
- const { from, where } = ast;
20
-
21
- const collectionName = from?.[0]?.table || "collection";
22
-
23
- return removeUndefinedFields({
24
- collection: collectionName,
25
- operation: determineOperation(where, {
26
- one: "deleteOne",
27
- many: "deleteMany",
28
- }),
29
- filter: where ? buildFilter(where) : {},
30
- });
31
- },
32
- };
@@ -1,37 +0,0 @@
1
- /**
2
- * Conversor para queries SELECT
3
- * Convierte SELECT SQL a aggregation pipeline o find query de MongoDB
4
- */
5
- import type { IConverter } from "../../domain/interfaces/Converter.ts";
6
- import {
7
- buildProjection,
8
- buildFilter,
9
- removeUndefinedFields,
10
- } from "../utils/queryUtils.ts";
11
-
12
- export const SelectConverter: IConverter = {
13
- can: (statement: string): boolean => {
14
- return statement.toLowerCase().startsWith("select");
15
- },
16
-
17
- convert: (query: any): Record<string, any> => {
18
- const { ast } = query;
19
- const { columns, from, where, limit } = ast;
20
-
21
- const fields =
22
- columns && columns[0]?.expr?.column !== "*"
23
- ? columns.map((col: any) => col.expr.column)
24
- : "*";
25
-
26
- const limitValue = limit?.value?.[0]?.value || limit?.value || limit;
27
-
28
- return removeUndefinedFields({
29
- collection: from?.[0]?.table || "collection",
30
- pipeline: [
31
- where && { $match: buildFilter(where) },
32
- fields !== "*" && { $project: buildProjection(fields) },
33
- limitValue && { $limit: limitValue },
34
- ].filter(Boolean),
35
- });
36
- },
37
- };
@@ -1,36 +0,0 @@
1
- /**
2
- * Conversor para queries UPDATE
3
- * Convierte UPDATE SQL a updateOne/updateMany de MongoDB
4
- */
5
- import type { IConverter } from "../../domain/interfaces/Converter.ts";
6
- import {
7
- buildFilter,
8
- determineOperation,
9
- removeUndefinedFields,
10
- } from "../utils/queryUtils.ts";
11
-
12
- export const UpdateConverter: IConverter = {
13
- can: (statement: string): boolean => {
14
- return statement.toLowerCase().startsWith("update");
15
- },
16
-
17
- convert: (query: any): Record<string, any> => {
18
- const { ast } = query;
19
- const { table, set, where } = ast;
20
-
21
- const collectionName = table?.[0]?.table || "collection";
22
- const updateData = Object.fromEntries(
23
- set.map((item: any) => [item.column, item.value?.value || item.value]),
24
- );
25
-
26
- return removeUndefinedFields({
27
- collection: collectionName,
28
- operation: determineOperation(where, {
29
- one: "updateOne",
30
- many: "updateMany",
31
- }),
32
- filter: where ? buildFilter(where) : {},
33
- update: { $set: updateData },
34
- });
35
- },
36
- };
@@ -1,17 +0,0 @@
1
- /**
2
- * Parser SQL que encapsula node-sql-parser
3
- * Abstrae la dependencia externa y proporciona una interfaz limpia
4
- */
5
- import sqlParser from "node-sql-parser";
6
-
7
- const parser = new sqlParser.Parser();
8
-
9
- export type ParsedQuery = ReturnType<typeof parser.parse>;
10
-
11
- export const parseSqlQuery = (sql: string): ParsedQuery | ParsedQuery[] => {
12
- return parser.parse(sql);
13
- };
14
-
15
- export const normalizeQuery = (query: string): string => {
16
- return query.trim().replace(/;$/, "").replace(/\s+/g, " ");
17
- };
@@ -1,93 +0,0 @@
1
- /**
2
- * Utilidades para conversión de queries SQL a MongoDB
3
- * Centraliza lógica reutilizable siguiendo principio DRY
4
- */
5
- import _ from "lodash";
6
-
7
- export const removeUndefinedFields = (
8
- obj: Record<string, any>,
9
- ): Record<string, any> => {
10
- return _.omitBy(obj, _.isUndefined);
11
- };
12
-
13
- export const normalizeFieldName = (field: string): string => {
14
- return field.trim().replace(/`|"/g, "");
15
- };
16
-
17
- const normalizeFieldNames = (fields: string[]): string[] => {
18
- return fields.map(normalizeFieldName);
19
- };
20
-
21
- export const buildProjection = (
22
- fields: string[] | "*",
23
- ): Record<string, 1 | 0> => {
24
- if (fields === "*") return {};
25
- return Object.fromEntries(normalizeFieldNames(fields).map((f) => [f, 1]));
26
- };
27
-
28
- export const buildFilter = (condition: any): Record<string, any> => {
29
- if (!condition) return {};
30
-
31
- const { operator, left, right } = condition;
32
-
33
- if (!operator) return {};
34
-
35
- if (operator.toUpperCase() === "AND") {
36
- return {
37
- $and: [buildFilter(left), buildFilter(right)],
38
- };
39
- }
40
-
41
- if (operator.toUpperCase() === "OR") {
42
- return {
43
- $or: [buildFilter(left), buildFilter(right)],
44
- };
45
- }
46
-
47
- const field = normalizeFieldName(left?.column || left?.value || left || "");
48
- const value = right?.value !== undefined ? right.value : right;
49
-
50
- const operatorMap: Record<string, string> = {
51
- "=": "$eq",
52
- "!=": "$ne",
53
- "<>": "$ne",
54
- "<": "$lt",
55
- ">": "$gt",
56
- "<=": "$lte",
57
- ">=": "$gte",
58
- like: "$regex",
59
- in: "$in",
60
- "not in": "$nin",
61
- };
62
-
63
- const mongoOp = operatorMap[operator.toLowerCase()];
64
-
65
- return mongoOp ? { [field]: { [mongoOp]: value } } : {};
66
- };
67
-
68
- export function determineOperation(
69
- where: any,
70
- operations: { one: string; many: string },
71
- ): string {
72
- const uniqueFields = ["id", "_id", "email", "username"];
73
- const { operator, left } = where;
74
-
75
- if (!where) return operations.many;
76
-
77
- if (["and", "or"].includes(operator?.toLowerCase())) {
78
- return operations.many;
79
- }
80
-
81
- const field = left?.column || left?.value || left || "";
82
- const isUniqueField = uniqueFields.includes(field?.toLowerCase?.());
83
-
84
- if (isUniqueField && operator === "=") {
85
- return operations.one;
86
- }
87
-
88
- return [">", "<", ">=", "<=", "!=", "<>", "like", "in"].includes(
89
- operator?.toLowerCase(),
90
- )
91
- ? operations.many
92
- : operations.one;
93
- }