import { Body, Delete, Headers, Inject, Param, Post, Res, UseGuards, } from "@nestjs/common"; import { Response } from "express"; import { QueryHandlerService } from "../handler/query.handler.service"; import { ApiTokenGuard } from "src/api/guards/api-token.guard"; import { QueryExecuterService } from "../executer/query.executer.service"; import { QueryGuard } from "src/query/guards/query.guard"; import { LoggerService } from "../logger/logger.service"; import { TLogType } from "../logger/logger.types"; import { QueryResponse } from "src/vm/vm.constants"; @UseGuards(ApiTokenGuard) export abstract class BaseQueryController { constructor( @Inject(QueryHandlerService) protected readonly queryHandlerService: QueryHandlerService, @Inject(QueryExecuterService) protected readonly queryExecuterService: QueryExecuterService, @Inject(LoggerService) protected readonly loggerService: LoggerService ) {} protected abstract getIsCommand(): boolean; @Post("create") async createQuery( @Body() queryData: { projectToken: string; source: string } ) { return this.queryHandlerService.createQuery(queryData, this.getIsCommand()); } @Post("update/:id") @UseGuards(QueryGuard) async updateQuery( @Body() updateData: Partial<{ source: string }>, @Param("id") id: string ) { return this.queryHandlerService.updateQuery(id, updateData); } @Post("/run/:id") @UseGuards(QueryGuard) async runQuery( @Param("id") id: string, @Body() query: Record, @Headers() headers: Record, @Res() res: Response ) { let queryResult: QueryResponse; const loggerTraceId = headers["x-trace-id"] || LoggerService.generateTraceId(); const log = LoggerService.log( { traceId: loggerTraceId, startTime: new Date().getTime(), payload: query, headers: headers, cookies: headers.cookie, url: `/run/${id}`, response: null, content: [], }, { content: "", type: TLogType.info, timeStamp: new Date().getTime() } ); try { queryResult = await this.queryExecuterService.runQueryQueued( id, query, log, headers, headers.cookie.split("; ").reduce((acc, cookie) => { const [key, value] = cookie.split("="); acc[key] = value; return acc; }, {}) ); } catch (error) { log.content.push({ content: `Query execution failed: ${error.message}`, type: TLogType.error, timeStamp: new Date().getTime(), }); log.endTime = new Date().getTime(); await this.loggerService.create(log.traceId, log); res.status(500).send({ error: "Internal Server Error" }); return; } if (queryResult?.log) { queryResult.log.endTime = new Date().getTime(); const res = JSON.parse(JSON.stringify(queryResult)); delete res.log; queryResult.log.response = res; await this.loggerService.create(queryResult.log.traceId, queryResult.log); } res.status(queryResult?.statusCode || 200); if (queryResult?.cookies) { for (const [key, value] of Object.entries(queryResult?.cookies || {})) { res.cookie(key, value); } } if ( queryResult?.redirect || (queryResult?.statusCode === 302 && queryResult?.headers && queryResult?.headers["Location"]) ) { res.redirect(queryResult?.redirect || queryResult?.headers["Location"]); return; } for (const [key, value] of Object.entries(queryResult?.headers || {})) { res.setHeader(key, value); } res.send(queryResult?.response || null); } @Delete("/delete/:id") @UseGuards(QueryGuard) async deleteQuery(@Param("id") id: string) { return this.queryHandlerService.deleteQuery(id); } }