From 2dba2ebfae916705076fb2887ea6490cf3b820a4 Mon Sep 17 00:00:00 2001 From: Alvar San Martin Date: Tue, 28 Apr 2026 15:23:27 +0200 Subject: [PATCH] Query de sims por networkStatus y tiempo de suspension --- docs/sim-api/France Suspended Lines.bru | 26 +++++++++ .../aplication/Sim.controller.test.ts | 5 +- .../aplication/Sim.controller.ts | 33 ++++++++++++ .../aplication/Sim.usecases.ts | 39 +++++++++++--- .../aplication/httpValidators.ts | 18 +++++++ .../config/intranetPostgresConfig.ts | 20 +++++++ packages/sim-consumidor-objenious/index.ts | 31 +++++++++-- .../sim-consumidor-objenious/package.json | 4 +- .../aplication/Order.controller.ts | 2 +- .../aplication/Order.usecases.ts | 2 +- packages/sim-entrada-eventos/domain/common.ts | 6 --- .../infrastructure/franceRoutes.http.ts | 12 +---- packages/sim-objenious-cron/index.ts | 8 +-- .../tasks/volcado_lineas.ts | 2 +- packages/sim-shared/domain/PaginationArgs.ts | 14 +++++ .../ObjeniousLinesRepository.test.ts | 6 +-- .../ObjeniousLinesRepository.ts | 54 ++++++++++++++++++- 17 files changed, 243 insertions(+), 39 deletions(-) create mode 100644 docs/sim-api/France Suspended Lines.bru create mode 100644 packages/sim-consumidor-objenious/aplication/httpValidators.ts create mode 100644 packages/sim-consumidor-objenious/config/intranetPostgresConfig.ts delete mode 100644 packages/sim-entrada-eventos/domain/common.ts create mode 100644 packages/sim-shared/domain/PaginationArgs.ts rename packages/{sim-objenious-cron/infranstructure => sim-shared/infrastructure}/ObjeniousLinesRepository.test.ts (87%) rename packages/{sim-objenious-cron/infranstructure => sim-shared/infrastructure}/ObjeniousLinesRepository.ts (72%) diff --git a/docs/sim-api/France Suspended Lines.bru b/docs/sim-api/France Suspended Lines.bru new file mode 100644 index 0000000..fe38d87 --- /dev/null +++ b/docs/sim-api/France Suspended Lines.bru @@ -0,0 +1,26 @@ +meta { + name: France Suspended Lines + type: http + seq: 17 +} + +get { + url: {{baseurl}}/france/lines?status=SUSPENDED&limit=100 + body: none + auth: inherit +} + +params:query { + status: SUSPENDED + limit: 100 +} + +vars:pre-request { + iccid: 8933201125065160331 + ~baseurl: http://localhost:3002 +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/packages/sim-consumidor-objenious/aplication/Sim.controller.test.ts b/packages/sim-consumidor-objenious/aplication/Sim.controller.test.ts index b408723..0eb784e 100644 --- a/packages/sim-consumidor-objenious/aplication/Sim.controller.test.ts +++ b/packages/sim-consumidor-objenious/aplication/Sim.controller.test.ts @@ -10,6 +10,7 @@ import { OrderRepository } from "sim-shared/infrastructure/OrderRepository.js"; import { PauseCancelTaskRepository } from "#adapters/PauseCancelTaskRepository.js"; import { ObjeniousOperationsRepository } from "sim-shared/infrastructure/ObjeniousOperationRepository.js"; import { ActionData } from "#domain/DTOs/objeniousapi.js"; +import { ObjeniousLinesRepository } from "sim-shared/infrastructure/ObjeniousLinesRepository.js"; describe("SimController Integration Tests (Real UseCases)", () => { let eventBusMock: any; @@ -32,11 +33,13 @@ describe("SimController Integration Tests (Real UseCases)", () => { ); const orderRepository = new OrderRepository(postgrClient); const pauseRepository = new PauseCancelTaskRepository(postgrClient); + const linesRepository = new ObjeniousLinesRepository(postgrClient) // tiene que apuntar a "intranet" useCases = new SimUseCases({ httpClient: httpInstance, operationRepository: operationRepository, orderRepository: orderRepository, - pauseRepository: pauseRepository + pauseRepository: pauseRepository, + objeniousLinesRepository: linesRepository }); // @ts-expect-error useCases.findActivationDate = async (data: ActionData) => new Date() diff --git a/packages/sim-consumidor-objenious/aplication/Sim.controller.ts b/packages/sim-consumidor-objenious/aplication/Sim.controller.ts index a5eb029..2905385 100644 --- a/packages/sim-consumidor-objenious/aplication/Sim.controller.ts +++ b/packages/sim-consumidor-objenious/aplication/Sim.controller.ts @@ -4,6 +4,9 @@ import { SimUseCases } from "./Sim.usecases.js"; import { SimEvents } from "sim-shared/domain/SimEvents.js"; import { Result } from "sim-shared/domain/Result.js"; import { ActionData } from "#domain/DTOs/objeniousapi.js"; +import { Request, Response } from "express" +import { PaginationArgs, QueryPaginationArgs } from "sim-shared/domain/PaginationArgs.js"; +import { paginationValidator } from "./httpValidators.js"; /** * La clase usa generadores de funciones para mantener el contexto @@ -219,6 +222,36 @@ export class SimController { } } + public queryLines() { + const DEFAULT_LIMIT = 1000 + const DEFAULT_OFFSET = 0 + + return async (req: Request, res: Response) => { + const queryParams = req.query + + const paginationArgs: QueryPaginationArgs = { + limit: queryParams.limit as string | undefined, + offset: queryParams.offset as string | undefined + } + + const validationRes = paginationValidator.validate(paginationArgs) + if (validationRes.error != undefined) { + res.status(402).json(validationRes) + return; + } + + const paginationValues = { + limit: (queryParams.limit != undefined) ? Number(queryParams.limit) : DEFAULT_LIMIT, + offset: (queryParams.offset != undefined) ? Number(queryParams.offset) : DEFAULT_OFFSET + } + + const status = req.query.status + + const queryRes = await this.useCases.getLinesByQuery({ status: status as string | undefined }, paginationValues) + res.json(queryRes) + } + } + /** * TODO: * - Loguear motivos de la no validacion diff --git a/packages/sim-consumidor-objenious/aplication/Sim.usecases.ts b/packages/sim-consumidor-objenious/aplication/Sim.usecases.ts index 36e744b..e6a73e8 100644 --- a/packages/sim-consumidor-objenious/aplication/Sim.usecases.ts +++ b/packages/sim-consumidor-objenious/aplication/Sim.usecases.ts @@ -7,6 +7,9 @@ import assert from "node:assert" import { OrderRepository } from "sim-shared/infrastructure/OrderRepository.js" import { CreatePauseCancelTaskDTO, PauseCancelTaskRepository } from "#adapters/PauseCancelTaskRepository.js" import { ObjeniousOperationsRepository } from "sim-shared/infrastructure/ObjeniousOperationRepository.js" +import { ObjeniousLinesRepository } from "sim-shared/infrastructure/ObjeniousLinesRepository.js" +import { error } from "node:console" +import { ObjeniousLine, ObjeniousLineDb } from "sim-shared/domain/objeniousLine.js" // TODO: // - Pasar a un archivo de DTOs @@ -17,17 +20,19 @@ export class SimUseCases { private readonly objeniousRepository: ObjeniousOperationsRepository private readonly orderRepository: OrderRepository private readonly pauseRepository: PauseCancelTaskRepository - + private readonly objeniousLinesRepository: ObjeniousLinesRepository constructor(args: { httpClient: HttpClient, operationRepository: ObjeniousOperationsRepository, orderRepository: OrderRepository, - pauseRepository: PauseCancelTaskRepository + pauseRepository: PauseCancelTaskRepository, + objeniousLinesRepository: ObjeniousLinesRepository }) { this.httpClient = args.httpClient this.objeniousRepository = args.operationRepository this.orderRepository = args.orderRepository this.pauseRepository = args.pauseRepository + this.objeniousLinesRepository = args.objeniousLinesRepository } private async logOperation(data: ObjeniousOperation) { @@ -119,7 +124,6 @@ export class SimUseCases { const iccid = activationData.identifier.identifiers // Comporbación excepcional para saber si la linea está suspendida const statusLinea = await this.objeniousRepository.getLinesAPI("ICCID", [String(iccid)]) - console.log("statusLinea, ", iccid, statusLinea) if (statusLinea.data != undefined && statusLinea.data[0].status.networkStatus == "SUSPENDED") { const res = await this.reActivate(activationData)() return res; @@ -278,7 +282,7 @@ export class SimUseCases { // Si no se pueden sacar datos de la linea guardo momentaneamente el error // pero no se cancela la operacion, el error puede ser de objenious y no nos // puede afectar - console.log("LineData", lineData.data) + //console.log("LineData", lineData.data) if (lineData.error != undefined) { console.error(lineData.error) } else { @@ -435,7 +439,7 @@ export class SimUseCases { identifier: terminationData.identifier }, url: OPERATION_URL, - iccid: terminationData.identifier.identifiers[0], // + iccid: terminationData.identifier.identifiers[0], operation: "terminate" }) } @@ -443,7 +447,8 @@ export class SimUseCases { /** * Calcula el tiempo que una linea ha estado en suspensión */ - public async getSuspendedTime(iccid: string): Promise> { + public async getSuspendedTime(iccid: string): + Promise> { try { const result = await this.objeniousRepository.getSuspendedTime(iccid); if (result.error !== undefined) { @@ -461,4 +466,26 @@ export class SimUseCases { } } + /** + * Busqueda de líneas **en nuestro volcado** según una query y con paginacion + */ + public async getLinesByQuery(query: { status?: string | undefined }, pagination: { limit: number, offset: number }) + : Promise> { + try { + + const linesQuery = await this.objeniousLinesRepository.getLinesByStatus(query, pagination) + return { + data: linesQuery, + } + } catch (e) { + return { + error: String(e) + } + } + } + } diff --git a/packages/sim-consumidor-objenious/aplication/httpValidators.ts b/packages/sim-consumidor-objenious/aplication/httpValidators.ts new file mode 100644 index 0000000..a9c6313 --- /dev/null +++ b/packages/sim-consumidor-objenious/aplication/httpValidators.ts @@ -0,0 +1,18 @@ +import { BodyValidator, Validator } from "sim-shared/aplication/BodyValidator.js"; +import { QueryPaginationArgs } from "sim-shared/domain/PaginationArgs.js"; + +const limitPositiveOrUndefined = >{ + field: "limit", + validationFunc: (args) => (args.limit == undefined || !isNaN(+args.limit) && parseInt(args.limit) >= 0), + errorMsg: "El campo limit debe ser un numero o undefined (default 0)" +} +const offsetPositiveOrUndefined = >{ + field: "offset", + validationFunc: (args) => (args.offset == undefined || isNaN(+args.offset) && parseInt(args.offset) >= 1), + errorMsg: "El campo offset debe ser un numero o undefined (default 0)" +} + +export const paginationValidator = new BodyValidator([ + limitPositiveOrUndefined, + offsetPositiveOrUndefined +]) diff --git a/packages/sim-consumidor-objenious/config/intranetPostgresConfig.ts b/packages/sim-consumidor-objenious/config/intranetPostgresConfig.ts new file mode 100644 index 0000000..7797136 --- /dev/null +++ b/packages/sim-consumidor-objenious/config/intranetPostgresConfig.ts @@ -0,0 +1,20 @@ +/** + * Cliente de postgres para la intranet. Se usa solo porque hace falta para el + * volcado de datos, si se usa en mas partes algo estás haciendo mal. + */ + +import { Pool } from 'pg'; +import { PgClient } from 'sim-shared/infrastructure/PgClient.js' +import { env } from './env/index.js'; + +export const pgPoolIntranet = new Pool({ + user: env.POSTGRES_USER, + host: env.POSTGRES_HOST, + database: "intranet", + password: env.POSTGRES_PASSWORD, + port: Number(env.POSTGRES_PORT) || 5432, +}); + +export const postgresClientIntranet = new PgClient({ + pool: pgPoolIntranet +}) diff --git a/packages/sim-consumidor-objenious/index.ts b/packages/sim-consumidor-objenious/index.ts index 5e218d7..38b6dda 100644 --- a/packages/sim-consumidor-objenious/index.ts +++ b/packages/sim-consumidor-objenious/index.ts @@ -14,6 +14,8 @@ import express from "express" import cors from "cors" import assert from "node:assert"; import { env } from "#config/env/index.js" +import { ObjeniousLinesRepository } from "sim-shared/infrastructure/ObjeniousLinesRepository.js" +import { postgresClientIntranet } from "#config/intranetPostgresConfig.js" async function startWorker() { const rmqClient = await startRMQClient() @@ -31,26 +33,29 @@ async function startWorker() { const orderRepository = new OrderRepository(pgClient) const pauseRepository = new PauseCancelTaskRepository(pgClient) + const linesRepository = new ObjeniousLinesRepository( + postgresClientIntranet + ) const simUseCases = new SimUseCases({ httpClient: httpClient, operationRepository: operationRepository, orderRepository: orderRepository, - pauseRepository: pauseRepository + pauseRepository: pauseRepository, + objeniousLinesRepository: linesRepository }) - const simActivationController = new SimController( + const simController = new SimController( rmqClient, simUseCases ) - const simRouter = new SimRouter(simActivationController, rmqClient) + const simRouter = new SimRouter(simController, rmqClient) // de momento solo una cola por simplificar rmqClient.consume("sim.objenious", simRouter.route) // Servidor express const port = env.PORT - console.log("PUERTO OBJ ", port) const app = express() app.use(cors()) app.use(express.json()) @@ -76,6 +81,24 @@ async function startWorker() { res.json(result) // {data:{...}} || {error:{...}} }) + /** + * Opciones query: + * - state + * + * Respuestas: + * - OK: data: { + * lines: ObjeniousLineDb[], + * offset: number, + * rowCount: number + * } + * + * - ERR: error: { + * message: string + * } + */ + app.get("/lines", simController.queryLines()) + + assert.ok(port, "Puerto del servicio no definido") app.listen(port, () => { console.log(`[o] HTTP server listening on port ${port}`) diff --git a/packages/sim-consumidor-objenious/package.json b/packages/sim-consumidor-objenious/package.json index 5fc7f6e..8b01b66 100644 --- a/packages/sim-consumidor-objenious/package.json +++ b/packages/sim-consumidor-objenious/package.json @@ -13,10 +13,10 @@ "types": "./config/*.ts", "default": "./config/*.js" }, - "#shared/*.js": { + "sim-shared/*.js": { "default": "../sim-shared/*.js" }, - "#shared/*": { + "sim-shared/*": { "default": "../sim-shared/*.js" }, "#adapters/*.js": { diff --git a/packages/sim-entrada-eventos/aplication/Order.controller.ts b/packages/sim-entrada-eventos/aplication/Order.controller.ts index e52bf96..39c7909 100644 --- a/packages/sim-entrada-eventos/aplication/Order.controller.ts +++ b/packages/sim-entrada-eventos/aplication/Order.controller.ts @@ -1,8 +1,8 @@ import { BodyValidator } from "sim-shared/aplication/BodyValidator.js" import { OrderUsecases } from "./Order.usecases.js" import { Request, Response } from "express" -import { PaginationArgs } from "#domain/common.js" import { idValidator, uuidValidator } from "./httpValidators.js" +import { PaginationArgs } from "sim-shared/domain/PaginationArgs.js" export class OrderController { private orderUseCases: OrderUsecases diff --git a/packages/sim-entrada-eventos/aplication/Order.usecases.ts b/packages/sim-entrada-eventos/aplication/Order.usecases.ts index 83b389b..ec1a1a1 100644 --- a/packages/sim-entrada-eventos/aplication/Order.usecases.ts +++ b/packages/sim-entrada-eventos/aplication/Order.usecases.ts @@ -1,4 +1,4 @@ -import { PaginationArgs } from "#domain/common.js"; +import { PaginationArgs } from "sim-shared/domain/PaginationArgs.js"; import { OrderRepository } from "sim-shared/infrastructure/OrderRepository.js"; diff --git a/packages/sim-entrada-eventos/domain/common.ts b/packages/sim-entrada-eventos/domain/common.ts deleted file mode 100644 index 94b32f6..0000000 --- a/packages/sim-entrada-eventos/domain/common.ts +++ /dev/null @@ -1,6 +0,0 @@ - -export type PaginationArgs = { - limit?: number, - offset?: number, - start?: number -} diff --git a/packages/sim-entrada-eventos/infrastructure/franceRoutes.http.ts b/packages/sim-entrada-eventos/infrastructure/franceRoutes.http.ts index 47a722f..3446ece 100644 --- a/packages/sim-entrada-eventos/infrastructure/franceRoutes.http.ts +++ b/packages/sim-entrada-eventos/infrastructure/franceRoutes.http.ts @@ -18,24 +18,16 @@ franceRoutes.use("", createProxyMiddleware({ on: { proxyReq: (proxyReq: ClientRequest, req: Request) => { + /* Debug de las peticiones */ const protocol = req.protocol; const host = req.get('host'); const originalFullUrl = `${protocol}://${host}${req.originalUrl}`; const destinationFullUrl = `${FRANCE_URL}${proxyReq.path}`; - - console.log('──────────────────────────────────────────────────'); - console.log(`[PROXY_DEBUG]`); - console.log(` ENTRADA: ${originalFullUrl}`); - console.log(` MÉTODO : ${req.method}`); - console.log(` DESTINO: ${destinationFullUrl}`); - console.log('──────────────────────────────────────────────────'); - - console.log(`[Proxy Req]: ${req.method} ${req.url} -> ${proxyReq.path}`); + //console.log(`[Proxy Req]: ${req.method} ${req.url} -> ${proxyReq.path}`); } } } )) - //orderRoutes.get("/:iccid/suspended-time",) export { franceRoutes } diff --git a/packages/sim-objenious-cron/index.ts b/packages/sim-objenious-cron/index.ts index 5ae82f8..7642d56 100644 --- a/packages/sim-objenious-cron/index.ts +++ b/packages/sim-objenious-cron/index.ts @@ -6,7 +6,7 @@ import { CheckObjeniousRequests } from "./tasks/check_objenious_request.js" import { ObjeniousOperationsRepository } from "sim-shared/infrastructure/ObjeniousOperationRepository.js" import { OrderRepository } from "sim-shared/infrastructure/OrderRepository.js" import { TaskVolcadoLineas } from "./tasks/volcado_lineas.js" -import { ObjeniousLinesRepository } from "./infranstructure/ObjeniousLinesRepository.js" +import { ObjeniousLinesRepository } from "sim-shared/infrastructure/ObjeniousLinesRepository.js" import { postgresClientIntranet } from "./config/intranetPostgresConfig.js" import { PauseCancelTaskRepository } from "sim-consumidor-objenious/infrastructure/PauseCancelTaskRepository.js" import { PauseTerminateTask } from "./tasks/check_pause_terminate.js" @@ -52,7 +52,8 @@ async function startCron() { httpClient: httpClient, operationRepository: operationRepository, orderRepository: orderRepository, - pauseRepository: pauseRepo + pauseRepository: pauseRepo, + objeniousLinesRepository: objeniousLineRepository }) const pauseTask = new PauseTerminateTask( @@ -73,6 +74,7 @@ async function startCron() { }, PERIODO_PETICIONES) const PERIODO_VOLCADO = 60 * 60 * 1000 + //await volcadoLineasTask.loadLines() const volcadoInterval = setInterval(async () => { try { await volcadoLineasTask.loadLines() @@ -81,7 +83,7 @@ async function startCron() { } }, PERIODO_VOLCADO) - await pauseTask.run() + // await pauseTask.run() const PERIODO_CANCELACIONES = 60 * 60 * 1000; const clacelacionesInterval = setInterval(async () => { await pauseTask.run() diff --git a/packages/sim-objenious-cron/tasks/volcado_lineas.ts b/packages/sim-objenious-cron/tasks/volcado_lineas.ts index d06eb87..5083d1a 100644 --- a/packages/sim-objenious-cron/tasks/volcado_lineas.ts +++ b/packages/sim-objenious-cron/tasks/volcado_lineas.ts @@ -1,5 +1,5 @@ import { lineToCreateLineDto, ObjeniousLine } from "sim-shared/domain/objeniousLine.js"; -import { ObjeniousLinesRepository } from "../infranstructure/ObjeniousLinesRepository.js"; +import { ObjeniousLinesRepository } from "sim-shared/infrastructure/ObjeniousLinesRepository.js"; import { ObjeniousOperationsRepository } from "sim-shared/infrastructure/ObjeniousOperationRepository.js"; export class TaskVolcadoLineas { diff --git a/packages/sim-shared/domain/PaginationArgs.ts b/packages/sim-shared/domain/PaginationArgs.ts new file mode 100644 index 0000000..9adc18e --- /dev/null +++ b/packages/sim-shared/domain/PaginationArgs.ts @@ -0,0 +1,14 @@ +/** + * Los parametros según entran por la query pueden ser de tipo string + */ +export type QueryPaginationArgs = { + limit?: string, + offset?: string, + start?: string// start = offset; Por compatibilidad, normalmente solo limit y offset +} + +export type PaginationArgs = { + limit?: number, + offset?: number, + start?: number // start = offset; Por compatibilidad, normalmente solo limit y offset +} diff --git a/packages/sim-objenious-cron/infranstructure/ObjeniousLinesRepository.test.ts b/packages/sim-shared/infrastructure/ObjeniousLinesRepository.test.ts similarity index 87% rename from packages/sim-objenious-cron/infranstructure/ObjeniousLinesRepository.test.ts rename to packages/sim-shared/infrastructure/ObjeniousLinesRepository.test.ts index 7fa5623..00a8565 100644 --- a/packages/sim-objenious-cron/infranstructure/ObjeniousLinesRepository.test.ts +++ b/packages/sim-shared/infrastructure/ObjeniousLinesRepository.test.ts @@ -1,12 +1,12 @@ import test, { after, before, describe } from "node:test"; import { CreateObjeniousLineDTO } from "sim-shared/domain/objeniousLine.js"; -import { ObjeniousLinesRepository } from "./ObjeniousLinesRepository.js"; -import { postgrClient } from "../config/postgreConfig.js"; +import { ObjeniousLinesRepository } from "sim-shared/infrastructure/ObjeniousLinesRepository.js"; import assert from "node:assert"; +import { postgresClient } from "../config/config.test.js"; describe("Line insertion test", async () => { //const pgClient = postgreClientIntranet - const pgClient = postgrClient // En prod hay que usar el de Intrantet para usar la otra base de datos + const pgClient = postgresClient// En prod hay que usar el de Intrantet para usar la otra base de datos const lineRepository = new ObjeniousLinesRepository(pgClient) const lineaTest: CreateObjeniousLineDTO = { simId: 1234, diff --git a/packages/sim-objenious-cron/infranstructure/ObjeniousLinesRepository.ts b/packages/sim-shared/infrastructure/ObjeniousLinesRepository.ts similarity index 72% rename from packages/sim-objenious-cron/infranstructure/ObjeniousLinesRepository.ts rename to packages/sim-shared/infrastructure/ObjeniousLinesRepository.ts index 4bba217..5bf5dd6 100644 --- a/packages/sim-objenious-cron/infranstructure/ObjeniousLinesRepository.ts +++ b/packages/sim-shared/infrastructure/ObjeniousLinesRepository.ts @@ -4,7 +4,7 @@ */ import { createHash } from "node:crypto"; import { PoolClient } from "pg"; -import { CreateObjeniousLineDTO } from "sim-shared/domain/objeniousLine.js"; +import { CreateObjeniousLineDTO, ObjeniousLineDb } from "sim-shared/domain/objeniousLine.js"; import { PgClient } from "sim-shared/infrastructure/PgClient.js"; export class ObjeniousLinesRepository { @@ -24,6 +24,58 @@ export class ObjeniousLinesRepository { } } + /** + * Hay que hacer la query un poco mas general + */ + public async getLinesByStatus(query: { status?: string | undefined }, pagination: { limit: number, offset: number }) { + // $1 y $2 se reservan para paginación + + const values: (string | number)[] = [ + pagination.limit, + pagination.offset, + ] + const paginationStr = ` + LIMIT $1 + OFFSET $2 + ` + + const conditionsStr = ` + WHERE + raw -> 'status' ->> 'networkStatus' = $3 + ` + + let queryStr = ` + SELECT * FROM objenious_lines + ` + if (query.status != undefined) { + queryStr = queryStr + conditionsStr + values.push(query.status) + + } + + queryStr = queryStr + ` + ${paginationStr}; + ` + + let client: PoolClient | undefined = undefined; + try { + client = await this.pgClient.connect(); + const res = await client.query(queryStr, values); + return { + data: res.rows, + offset: pagination.offset, + rowCount: res.rowCount ?? 0, + } + } catch (err) { + console.error('Error en la query:', err); + throw err; + } finally { + if (client != undefined) { + client.release() + } + } + } + public async insertOrUpdate(data: CreateObjeniousLineDTO) { const query = ` INSERT INTO objenious_lines (