feat: enhance query execution with response handling and add QueryResponse type

This commit is contained in:
Boris D
2025-10-06 10:23:46 +03:00
parent efbb9f5c21
commit 1e84297e84
4 changed files with 92 additions and 9 deletions

View File

@ -1,6 +1,15 @@
import { Body, Controller, Headers, Inject, Param, Post } from "@nestjs/common"; import {
Body,
Controller,
Headers,
Inject,
Param,
Post,
Res,
} from "@nestjs/common";
import { QueryHandlerService } from "../handler/query.handler.service"; import { QueryHandlerService } from "../handler/query.handler.service";
import { QueryExecuterService } from "../executer/query.executer.service"; import { QueryExecuterService } from "../executer/query.executer.service";
import { Response } from "express";
@Controller("command") @Controller("command")
export class CommandController { export class CommandController {
@ -30,8 +39,26 @@ export class CommandController {
async runQuery( async runQuery(
@Param("token") token: string, @Param("token") token: string,
@Body() query: Record<string, any>, @Body() query: Record<string, any>,
@Headers() headers: Record<string, any> @Headers() headers: Record<string, any>,
@Res() res: Response
) { ) {
return this.queryExecuterService.runQuery(token, query, headers); const queryResult = await this.queryExecuterService.runQuery(
token,
query,
headers
);
res.status(queryResult.statusCode);
if (queryResult.statusCode === 302 && queryResult.headers["Location"]) {
res.redirect(queryResult.headers["Location"]);
return;
}
for (const [key, value] of Object.entries(queryResult.headers)) {
res.setHeader(key, value);
}
res.send(queryResult.response);
} }
} }

View File

@ -1,4 +1,13 @@
import { Body, Controller, Headers, Inject, Param, Post } from "@nestjs/common"; import {
Body,
Controller,
Headers,
Inject,
Param,
Post,
Res,
} from "@nestjs/common";
import { Response } from "express";
import { QueryExecuterService } from "./query.executer.service"; import { QueryExecuterService } from "./query.executer.service";
@Controller("query") @Controller("query")
@ -12,8 +21,26 @@ export class QueryExecuterController {
async runQuery( async runQuery(
@Param("token") token: string, @Param("token") token: string,
@Body() query: Record<string, any>, @Body() query: Record<string, any>,
@Headers() headers: Record<string, any> @Headers() headers: Record<string, any>,
@Res() res: Response
) { ) {
return this.queryExecuterService.runQuery(token, query, headers); const queryResult = await this.queryExecuterService.runQuery(
token,
query,
headers
);
res.status(queryResult.statusCode);
if (queryResult.statusCode === 302 && queryResult.headers["Location"]) {
res.redirect(queryResult.headers["Location"]);
return;
}
for (const [key, value] of Object.entries(queryResult.headers)) {
res.setHeader(key, value);
}
res.send(queryResult.response);
} }
} }

View File

@ -4,7 +4,11 @@ import { Query } from "../entities/query.entity";
import { Repository } from "typeorm"; import { Repository } from "typeorm";
import { Vm } from "../../vm/vm.class"; import { Vm } from "../../vm/vm.class";
import { VModule } from "src/vm/module.class"; import { VModule } from "src/vm/module.class";
import { registeredModules, registeredPlugins } from "src/vm/vm.constants"; import {
QueryResponse,
registeredModules,
registeredPlugins,
} from "src/vm/vm.constants";
import { DatabaseManagerService } from "src/databaseManager/database/database.manager.service"; import { DatabaseManagerService } from "src/databaseManager/database/database.manager.service";
@Injectable() @Injectable()
@ -38,7 +42,7 @@ export class QueryExecuterService {
token: string, token: string,
queryData: any, queryData: any,
headers: Record<string, any> = {} headers: Record<string, any> = {}
) { ): Promise<QueryResponse> {
const query = await this.queryRepository.findOne({ const query = await this.queryRepository.findOne({
where: { id: token }, where: { id: token },
relations: ["project"], relations: ["project"],
@ -55,7 +59,11 @@ export class QueryExecuterService {
headers headers
); );
return { message: "Query executed", result, query: queryData }; if (this.checkResponse(result)) {
throw new Error(`Error initializing VM: ${JSON.stringify(result)}`);
}
return result;
} }
private async createVm(query: Query) { private async createVm(query: Query) {
@ -97,4 +105,19 @@ export class QueryExecuterService {
return await vm.init(); return await vm.init();
} }
private checkResponse(obj: any): obj is QueryResponse {
return (
obj !== null &&
typeof obj === "object" &&
typeof obj.statusCode === "number" &&
typeof obj.response === "object" &&
obj.response !== null &&
typeof obj.headers === "object" &&
obj.headers !== null &&
Object.keys(obj.headers).every(
(key) => typeof obj.headers[key] === "string"
)
);
}
} }

View File

@ -29,3 +29,9 @@ export const registeredModules = {
squel: "dist/vm/modules/squel.js", squel: "dist/vm/modules/squel.js",
asyncCall: "dist/vm/modules/async.js", asyncCall: "dist/vm/modules/async.js",
}; };
export type QueryResponse = {
statusCode: number;
response: Record<string, any>;
headers: Record<string, string>;
};