diff --git a/deployment/database/migrations/1.0.0_orders.sql b/deployment/database/migrations/1.0.0_orders.sql index 912710a..3278e9f 100644 --- a/deployment/database/migrations/1.0.0_orders.sql +++ b/deployment/database/migrations/1.0.0_orders.sql @@ -24,7 +24,6 @@ CREATE TABLE IF NOT EXISTS order_tracking ( payload JSONB, -- Duda si es optimo guardar la copia, es útil en caso de fallo -- Campos de reintentos? - status order_status NOT NULL DEFAULT 'pending', retry_count INT DEFAULT 0, error_message TEXT, -- Razón del fallo diff --git a/docs/sim-alai/Login.yml b/docs/sim-alai/Login.yml new file mode 100644 index 0000000..0256ae9 --- /dev/null +++ b/docs/sim-alai/Login.yml @@ -0,0 +1,51 @@ +info: + name: Login + type: http + seq: 2 + +http: + method: POST + url: "{{baseurl}}/v1/auth/login" + body: + type: json + data: |- + { + "username": "{{username}}", + "password": "{{password}}", + "brandID": "{{brandId}}" + } + auth: inherit + +runtime: + scripts: + - type: after-response + code: |- + const data = res.getBody(); + + if (data.staus != 200) { + console.error("Error de login: ", data) + return 1; + } + + if (data && data.accessToken) { + + bru.setEnvVar("alai_token", data.accessToken); + + if (data.tokenType) { + bru.setEnvVar("alai_token_type", data.tokenType); + } + + console.log("Token guardado correctamente"); + } else { + console.error("No se pudo encontrar el accessToken en la respuesta"); + } + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 + +docs: |- + Necesita un certificado p12 (PFX) y la contraseña asociada para efectuar la operacion. + Collection Settings => ClientCertificates => Add Certificate diff --git a/docs/sim-alai/New Order.yml b/docs/sim-alai/New Order.yml new file mode 100644 index 0000000..e342c26 --- /dev/null +++ b/docs/sim-alai/New Order.yml @@ -0,0 +1,15 @@ +info: + name: New Order + type: http + seq: 3 + +http: + method: POST + url: "{{baseurl}}/v1/order" + auth: inherit + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 diff --git a/docs/sim-alai/certificates/alai_cert.p12 b/docs/sim-alai/certificates/alai_cert.p12 new file mode 100644 index 0000000..86217c6 Binary files /dev/null and b/docs/sim-alai/certificates/alai_cert.p12 differ diff --git a/docs/sim-alai/environments/local.yml b/docs/sim-alai/environments/local.yml index 678d231..db39cbc 100644 --- a/docs/sim-alai/environments/local.yml +++ b/docs/sim-alai/environments/local.yml @@ -2,6 +2,6 @@ name: local color: "#2E8A54" variables: - name: baseurl - value: http://localhost:3001 + value: http://localhost:3002 - secret: true name: token diff --git a/docs/sim-alai/environments/prod.yml b/docs/sim-alai/environments/prod.yml index 080fcff..58204fa 100644 --- a/docs/sim-alai/environments/prod.yml +++ b/docs/sim-alai/environments/prod.yml @@ -2,6 +2,12 @@ name: prod color: "#CE4F3B" variables: - name: baseurl - value: https://nosconnectcenter-api.iot-x.com + value: https://wsaccess.alaisecure.com/bssrest + - name: username + value: palomaibanez + - name: password + value: palomaibanez123 - secret: true - name: token + name: certPasswd + - name: brandId + value: savefamily diff --git a/docs/sim-alai/opencollection.yml b/docs/sim-alai/opencollection.yml index 297aed6..6d6bccb 100644 --- a/docs/sim-alai/opencollection.yml +++ b/docs/sim-alai/opencollection.yml @@ -2,6 +2,22 @@ opencollection: 1.0.0 info: name: sim-alai +config: + proxy: + inherit: true + config: + protocol: http + hostname: "" + port: "" + auth: + username: "" + password: "" + bypassProxy: "" + clientCertificates: + - domain: wsaccess.alaisecure.com + type: pkcs12 + pkcs12FilePath: certificates\alai_cert.p12 + passphrase: iHaaek+zyzWz6cH6rg== bundled: false extensions: bruno: diff --git a/docs/sim-api/Activate.bru b/docs/sim-api/Activate.bru index bbc6a60..46a58b0 100644 --- a/docs/sim-api/Activate.bru +++ b/docs/sim-api/Activate.bru @@ -6,16 +6,80 @@ meta { post { url: {{baseurl}}/sim/activate - body: formUrlEncoded + body: json auth: inherit } +body:json { + { + "iccid": "1234" + } +} + body:form-urlencoded { - iccid: 8933201125065156057 - offer: SAVEFAMILY1 + iccid: 123 + offer: mensual } settings { encodeUrl: true timeout: 0 } + +docs { + Campos de entrada: + ```ts + // Header requerido + // > content-type:application/x-www-form-urlencoded + // > content-type:application/json + // Cualquiera de los 2 es valido + + // Esquema body + { + iccid: string, + offer: "mensual" | "anual" | "SAVEFAMILY1" | "SAVEFAMILY2" + webhook?: string, + } + ``` + + En el campo `offer` "mensual" equivale a "SAVEFAMILY2" y "anual" a "SAVEFAMILY1" porque se mantien los códigos de Oferta de Objenious por compatibilidad pero se espera usar "mensual" y "anual" y hacer la conversión en el servicio de cada proveedor. + + Para las llamadas al webhook se va a usar siempre el metodo `POST`, ahora mismo no se firman los mensajes. Se introduce la URL completa tal que `https://dominion.com/v1/endpoint`. + + Respuestas: + - **200**: OK + ``` ts + // Esquema + { + iccid: string, + operation: string, + message_id: string, //uuidv7 + } + ``` + ``` json + // Ejemplo + { + "iccid": "89332011250651xxxxx", + "operation": "activation", + "message_id": "019dbeaf-8abb-7783-8b51-94fbd9f0b0df" + } + ``` + + *iccid*: Confirmación del iccid enviado. + *operation*: Confirmación de la operacion que se ha aplicado. + *message_id*: Id de la operación, para consultar en orders. + + > A futuro se va a incluir un campo `"ref":[]` para añadir los enlaces a las consultas de la operación. El body va a permitir tambien json. + + - **402**: Algún campo es incorrecto + Se indica que campo es incorrecto, si hubiese mas de uno solo aparecería el primero en comprobarse. + ```json + "errors": { + "msg": "La longitud del iccid es incorrecta debera ser de 19 caracteres", + "field": "iccid" + } + ``` + + - **500**: Error general + Ha ocurrido un error imprevisto durante la +} diff --git a/docs/sim-api/Activation Email.bru b/docs/sim-api/Activation Email.bru index 8f72b9e..2d7dec1 100644 --- a/docs/sim-api/Activation Email.bru +++ b/docs/sim-api/Activation Email.bru @@ -1,7 +1,7 @@ meta { name: Activation Email type: http - seq: 6 + seq: 7 } post { diff --git a/docs/sim-api/Cancel.bru b/docs/sim-api/Cancel.bru index 3e31352..a4f77ec 100644 --- a/docs/sim-api/Cancel.bru +++ b/docs/sim-api/Cancel.bru @@ -1,7 +1,7 @@ meta { name: Cancel type: http - seq: 1 + seq: 3 } post { diff --git a/docs/sim-api/Docs.bru b/docs/sim-api/Docs.bru index 613bf7b..d2e6145 100644 --- a/docs/sim-api/Docs.bru +++ b/docs/sim-api/Docs.bru @@ -1,7 +1,7 @@ meta { name: Docs type: http - seq: 12 + seq: 10 } get { diff --git a/docs/sim-api/Health.bru b/docs/sim-api/Health.bru index 5c7748b..ab5d247 100644 --- a/docs/sim-api/Health.bru +++ b/docs/sim-api/Health.bru @@ -1,7 +1,7 @@ meta { name: Health type: http - seq: 5 + seq: 6 } get { diff --git a/docs/sim-api/Get pending orders.bru b/docs/sim-api/Orders/Get pending orders.bru similarity index 94% rename from docs/sim-api/Get pending orders.bru rename to docs/sim-api/Orders/Get pending orders.bru index 70b9eed..3888958 100644 --- a/docs/sim-api/Get pending orders.bru +++ b/docs/sim-api/Orders/Get pending orders.bru @@ -1,7 +1,7 @@ meta { name: Get pending orders type: http - seq: 11 + seq: 10 } get { diff --git a/docs/sim-api/Order by id.bru b/docs/sim-api/Orders/Order by id.bru similarity index 68% rename from docs/sim-api/Order by id.bru rename to docs/sim-api/Orders/Order by id.bru index 80104c0..6d3d66a 100644 --- a/docs/sim-api/Order by id.bru +++ b/docs/sim-api/Orders/Order by id.bru @@ -5,7 +5,7 @@ meta { } get { - url: {{baseurl}}/orders/ + url: {{baseurl}}/orders/019dbeaf-8abb-7783-8b51-94fbd9f0b0df body: none auth: inherit } diff --git a/docs/sim-api/Orders by message_id.bru b/docs/sim-api/Orders/Orders by message_id.bru similarity index 50% rename from docs/sim-api/Orders by message_id.bru rename to docs/sim-api/Orders/Orders by message_id.bru index a37a6a6..787fd86 100644 --- a/docs/sim-api/Orders by message_id.bru +++ b/docs/sim-api/Orders/Orders by message_id.bru @@ -5,15 +5,11 @@ meta { } get { - url: {{baseurl}}/orders/message_id/019c93d3-014a-711d-b958-03dd629be78d + url: {{baseurl}}/orders/message_id/019dbeaf-8abb-7783-8b51-94fbd9f0b0df body: none auth: inherit } -params:query { - ~message_id: 019c93d3-014a-711d-b958-03dd629be78d -} - settings { encodeUrl: true timeout: 0 diff --git a/docs/sim-api/Orders/folder.bru b/docs/sim-api/Orders/folder.bru new file mode 100644 index 0000000..6623108 --- /dev/null +++ b/docs/sim-api/Orders/folder.bru @@ -0,0 +1,44 @@ +meta { + name: Orders +} + +auth { + mode: inherit +} + +docs { + # Orders + + Los *order* representan ordenes que se hacen al servidor y representan en que estado se encuentran las peticiones. Los *order* se generan cuando se solicita una operacion y devuelven su identificador en el campo `message_id` de todas las respuestas a peticiones que requieran cambios. Los identificadores de `order` son UUIDv7, aunque tambien tienen asociado un id tradicional BIGINT en la BDD. + + ## Ciclo de vida + + Cuando se crea un *order* comienza en estado `pending`, inicando que ha entrado en la cola y está pendiente de iniciarse; una vez se ha consumido por un servicio pasa a estado `running` indicando que la operacion asociada al *order* ha comenzado, el order continuara en este estado durante un tiempo indefinido (pueden pasar semanas para algunos casos), hasta que la tara finalize correctamente o con errores. En el caso que la tarea finalize con éxito el *order* pasará a estado `finished`, en caso de que haya habido un error el estado será `failed` y se almacenará el error en los campos `error_message` y opcionalemente en `error_stacktrace` según gravedad del error. + + - Caso normal + `pending` -> `running` -> `finished` + + - Error durante el consumo + `pending` -> `failed` + + - Error durante la operacion + `pending` -> `running` -> `failed` + + ## Endpoints + Estan sujetos a cambios en cuanto a mostrar información + + - [WIP]**GET** /orders?{query} + Devuelve todos los orders con un campo que tenga el valor especificado en la query + + - **GET** /orders/{id} + Devuelve el order objetivo según su UUID de mensaje (No según el uuid de mensaje) + + - **GET** /orders/base_id/{id} + Devuelve el id según su id de la bdd, no es el metodo normal de usar la api + + - **GET** /orders/pending + Devuelve todas las order que no hayan finalizado + + + +} diff --git a/docs/sim-api/Pause.bru b/docs/sim-api/Pause.bru index cfb5e5e..255b8ec 100644 --- a/docs/sim-api/Pause.bru +++ b/docs/sim-api/Pause.bru @@ -1,7 +1,7 @@ meta { name: Pause type: http - seq: 1 + seq: 4 } post { diff --git a/docs/sim-api/Preactivate.bru b/docs/sim-api/Preactivate.bru index c9053de..ed73ab1 100644 --- a/docs/sim-api/Preactivate.bru +++ b/docs/sim-api/Preactivate.bru @@ -1,7 +1,7 @@ meta { name: Preactivate type: http - seq: 1 + seq: 5 } post { diff --git a/docs/sim-api/ReActivate.bru b/docs/sim-api/ReActivate.bru index 6477b85..8fd13df 100644 --- a/docs/sim-api/ReActivate.bru +++ b/docs/sim-api/ReActivate.bru @@ -1,7 +1,7 @@ meta { name: ReActivate type: http - seq: 13 + seq: 11 } post { diff --git a/docs/sim-api/collection.bru b/docs/sim-api/collection.bru index 5fe677a..1ec9cfd 100644 --- a/docs/sim-api/collection.bru +++ b/docs/sim-api/collection.bru @@ -1,5 +1,6 @@ docs { - Los endpoint tienen unos campos comunes de entrada: + Todos los endpoint tienen unos campos comunes de entrada: + ```ts { iccid: string, diff --git a/docs/sim-api/test proxy.bru b/docs/sim-api/test proxy.bru index d4e17b0..cb85bc8 100644 --- a/docs/sim-api/test proxy.bru +++ b/docs/sim-api/test proxy.bru @@ -1,7 +1,7 @@ meta { name: test proxy type: http - seq: 14 + seq: 12 } get { diff --git a/packages/sim-consumidor-alai/aplication/SimAlai.controller.ts b/packages/sim-consumidor-alai/aplication/SimAlai.controller.ts index 1c4aac4..7e401da 100644 --- a/packages/sim-consumidor-alai/aplication/SimAlai.controller.ts +++ b/packages/sim-consumidor-alai/aplication/SimAlai.controller.ts @@ -1,6 +1,6 @@ import { ConsumeMessage } from "amqplib"; import { Request, Response } from "express" -import { SimNosUsecases } from "./SimNOS.usecases.js"; +import { SimAlaiUsecases } from "./SimAlai.usecases.js"; import { EventBus } from "sim-shared/domain/EventBus.port.js"; import { Result } from "sim-shared/domain/Result.js"; import { SimEvents } from "sim-shared/domain/SimEvents.js"; @@ -9,7 +9,7 @@ import { iccidValidator } from "./httpValidators.js"; export class SimAlaiController { constructor( - private uscases: SimNosUsecases, + private uscases: SimAlaiUsecases, private eventBus: EventBus, ) { } @@ -51,12 +51,12 @@ export class SimAlaiController { await this.eventBus.ack(msg) return result } else { - console.error("Error procesando el caso de uso (NOS)", result.error) + console.error("Error procesando el caso de uso (Alai)", result.error) this.eventBus.nack(msg) return result } } catch (e) { - console.error("Error general procesando el caso de uso (NOS)") + console.error("Error general procesando el caso de uso (Alai)") this.eventBus.nack(msg) return { error: String(e) diff --git a/packages/sim-consumidor-alai/certificates/wsaccess_alaisecure_com_cert_client_new.p12 b/packages/sim-consumidor-alai/certificates/wsaccess_alaisecure_com_cert_client_new.p12 new file mode 100644 index 0000000..86217c6 Binary files /dev/null and b/packages/sim-consumidor-alai/certificates/wsaccess_alaisecure_com_cert_client_new.p12 differ diff --git a/packages/sim-entrada-eventos/README.md b/packages/sim-entrada-eventos/README.md new file mode 100644 index 0000000..e69de29 diff --git a/packages/sim-entrada-eventos/aplication/Order.controller.ts b/packages/sim-entrada-eventos/aplication/Order.controller.ts index e52bf96..f924e96 100644 --- a/packages/sim-entrada-eventos/aplication/Order.controller.ts +++ b/packages/sim-entrada-eventos/aplication/Order.controller.ts @@ -32,14 +32,23 @@ export class OrderController { } public getByQueueId() { - return this.controllerGenerator<{ correlation_id: string }, { correlation_id: string }>({ + return this.controllerGenerator<{ uuid: string }, { correlation_id: string }>({ validator: uuidValidator, + mapBody: (e) => ({ correlation_id: e.uuid }), useCase: this.orderUseCases.getByQueueId(), onError: (data, error) => { console.error(error) }, onSuccess: (data) => console.log(data) }) } + public getByQuery() { + return this.controllerGenerator({ + validator: undefined, + useCase: this.orderUseCases.getByQuery(), + onError: (data, error) => { console.error(error) }, + onSuccess: (data) => console.log(data) + }) + } /** * TODO: @@ -77,7 +86,7 @@ export class OrderController { }) } - // 2. Transformacion del body + // 2. Transformacion del body O => P let data: P = body; try { if (args.mapBody != undefined) diff --git a/packages/sim-entrada-eventos/aplication/Order.usecases.ts b/packages/sim-entrada-eventos/aplication/Order.usecases.ts index 83b389b..01cc8a6 100644 --- a/packages/sim-entrada-eventos/aplication/Order.usecases.ts +++ b/packages/sim-entrada-eventos/aplication/Order.usecases.ts @@ -1,4 +1,5 @@ import { PaginationArgs } from "#domain/common.js"; +import { OrderQuery } from "sim-shared/domain/Order.js"; import { OrderRepository } from "sim-shared/infrastructure/OrderRepository.js"; @@ -36,4 +37,10 @@ export class OrderUsecases { } } + // WIP + public getByQuery() { + return async (args: OrderQuery) => { + return await this.orderRepository.getOrdersByQuery(args) + } + } } diff --git a/packages/sim-entrada-eventos/aplication/httpValidators.ts b/packages/sim-entrada-eventos/aplication/httpValidators.ts index ad566f8..b055b40 100644 --- a/packages/sim-entrada-eventos/aplication/httpValidators.ts +++ b/packages/sim-entrada-eventos/aplication/httpValidators.ts @@ -32,10 +32,10 @@ const offerExists = >{ validationFunc: (a: { offer: string }) => offers.has(a.offer), } -const isUuidv7 = >{ - field: "correlation_id", +const isUuidv7 = >{ + field: "uuid", errorMsg: "El uuid no es un uuidv7 valido", - validationFunc: (a) => a.correlation_id != undefined && a.correlation_id.length < 36 + validationFunc: (a) => a.uuid != undefined && a.uuid.length < 36 } const definedId = >{ @@ -73,7 +73,7 @@ export const iccidValidator = new BodyValidator<{ iccid: string }>( ] ) -export const uuidValidator = new BodyValidator<{ correlation_id?: string }>([ +export const uuidValidator = new BodyValidator<{ uuid?: string }>([ isUuidv7 ]) diff --git a/packages/sim-entrada-eventos/infrastructure/orderRoutes.http.ts b/packages/sim-entrada-eventos/infrastructure/orderRoutes.http.ts index 2c1fbfb..9d4d574 100644 --- a/packages/sim-entrada-eventos/infrastructure/orderRoutes.http.ts +++ b/packages/sim-entrada-eventos/infrastructure/orderRoutes.http.ts @@ -28,13 +28,17 @@ const orderController = new OrderController({ * */ orderRoutes.get("/", (req, res) => { res.send("ok") }) -orderRoutes.get("/message_id/:correlation_id", orderController.getByQueueId()) +/* + * Ahora es el id de bdd + * */ +orderRoutes.get("/message_id/:id", orderController.getById()) /** Operaciones pendientes */ orderRoutes.get("/pending", orderController.getPending()) /** Order por id (uuid del mensaje) */ -orderRoutes.get("/:id", orderController.getById()) +// TODO: falla +orderRoutes.get("/:id", orderController.getByQueueId()) export { orderRoutes } diff --git a/packages/sim-entrada-eventos/infrastructure/simconnectionsRoutes.ts b/packages/sim-entrada-eventos/infrastructure/simconnectionsRoutes.ts index 3f04022..b66e154 100644 --- a/packages/sim-entrada-eventos/infrastructure/simconnectionsRoutes.ts +++ b/packages/sim-entrada-eventos/infrastructure/simconnectionsRoutes.ts @@ -9,8 +9,7 @@ export const connectionsRoutes = Router() const CONNECTIONS_URL = env.CONNECTIONS_URL// TODO: Meter al ENV //const CONNECTIONS_URL = "http://sf-nfc-server.savefamilygps.net" -console.log("CONNURL: ", CONNECTIONS_URL) - +//console.log("CONNURL: ", CONNECTIONS_URL) connectionsRoutes.use("", createProxyMiddleware({ target: CONNECTIONS_URL, changeOrigin: true, diff --git a/packages/sim-shared/domain/Order.ts b/packages/sim-shared/domain/Order.ts index df1c2f3..027228e 100644 --- a/packages/sim-shared/domain/Order.ts +++ b/packages/sim-shared/domain/Order.ts @@ -94,4 +94,19 @@ export type ErrorOrderDTO = stackTrace?: string } - +/* + * Se considera cada entrada de conditions como un filtro sobre un campo + * cada fila se podrá expresar como campo:filtro + * ```json + * { + * "value": "-gte 200" // Un valor >= 200 + * "text": "-eq 'busqueda' " // El campo tiene que ser exactamente 'busqueada' + * } + * ``` + * TODO: sacar opciones de paginación + * */ +export type OrderQuery = { + conditions: Record, + limit?: number | undefined, + offset?: number | undefined, +} diff --git a/packages/sim-shared/infrastructure/OrderRepository.test.ts b/packages/sim-shared/infrastructure/OrderRepository.test.ts index 4636fe3..e5f1ce2 100644 --- a/packages/sim-shared/infrastructure/OrderRepository.test.ts +++ b/packages/sim-shared/infrastructure/OrderRepository.test.ts @@ -1,8 +1,9 @@ import { before, describe, it } from "node:test"; import { OrderRepository } from "./OrderRepository.js"; -import { CreateOrderDTO } from "../domain/Order.js"; +import { CreateOrderDTO, OrderQuery } from "../domain/Order.js"; import { postgresClient } from "../config/config.test.js"; import assert from "node:assert"; +import { Query } from "pg"; const order1 = { correlation_id: "fakeRMQid-1234", @@ -169,4 +170,16 @@ describe("Test OrderRepository", {}, (ctx) => { assert(result.data.status === "dlx") assert(result.data.finish_date != null) }) + + it("Query generates with parameters", async () => { + const params: OrderQuery = { + conditions: { + status: "-eq 'pending'" + } + } + //@ts-expect-error + const res = orderRepo.generateTableQuery("test", params) + console.log("Query:", res) + assert.ok(res != undefined) + }) }) diff --git a/packages/sim-shared/infrastructure/OrderRepository.ts b/packages/sim-shared/infrastructure/OrderRepository.ts index 26d05f0..1faa675 100644 --- a/packages/sim-shared/infrastructure/OrderRepository.ts +++ b/packages/sim-shared/infrastructure/OrderRepository.ts @@ -2,7 +2,7 @@ * TODO: Usar */ import { PoolClient, QueryResult, QueryResultRow } from "pg"; -import { CreateOrderDTO, ErrorOrderDTO, FinishOrderDTO, OrderTracking, UpdateOrderDTO } from "../domain/Order.js"; +import { CreateOrderDTO, ErrorOrderDTO, FinishOrderDTO, OrderQuery, OrderTracking, UpdateOrderDTO } from "../domain/Order.js"; import { Result, tryCatch } from "../domain/Result.js"; import { PgClient } from "./PgClient.js"; import assert from "node:assert"; @@ -55,7 +55,77 @@ export class OrderRepository { } } + /** + * Mapeo de prefijos a operadores SQL + */ + private OPERATOR_MAP: Record = { + "-eq": "=", + "-neq": "!=", + "-gt": ">", + "-gte": ">=", + "-lt": "<", + "-lte": "<=", + "-like": "LIKE", + }; + /** + * Tabla general para sacar datos de la tabla en base a unas condiciones + * TODO: + * - Dar la opción de generar los campos a devolver en vez de * + * - Garantizar el numero de parametros de respuesta + */ + private generateTableQuery(table: string, query: OrderQuery) { + const { conditions, limit, offset } = query; + const whereClauses: string[] = []; + const queryValues: any[] = []; + + let paramIndex = 1; // Para los parametros de PostgreSQL ($1, $2) (que empiezan por 1) + + for (const [column, filter] of Object.entries(conditions)) { + const match = filter.match(/^(-\w+)\s+(.+)$/); + + if (match) { + const [_, prefix, value] = match; + const operator = this.OPERATOR_MAP[prefix]; + + if (operator) { + // Eliminación de comillas + const cleanValue = value.replace(/^'|'$/g, ""); + + whereClauses.push(`${column} ${operator} $${paramIndex}`); + queryValues.push(operator === "LIKE" ? `%${cleanValue}%` : cleanValue); + paramIndex++; + } + } + } + + // 2. Query completa + // TODO: Cambair el * por parametros + let sql = `SELECT * FROM ${table}`; + + if (whereClauses.length > 0) { + sql += ` WHERE ${whereClauses.join(" AND ")}`; + } + + // 3. Paginacion + if (limit !== undefined) { + sql += ` LIMIT ${Number(limit)}`; + } + if (offset !== undefined) { + sql += ` OFFSET ${Number(offset)}`; + } + + return { + sql, + values: queryValues, + }; + } + + public async getOrdersByQuery(args: OrderQuery) { + const query = this.generateTableQuery('order_tracking', args) + const queryPromise = this.pgClient.query>>(query.sql, query.values) + const result = await this.getAll(queryPromise) + } /** * El tipo representa el contenido del mensaje de los order