feat: implement command functionality with new CommandController, update Query entity, and enhance query execution with headers support
This commit is contained in:
15
src/migrations/1759387204103-commands.ts
Normal file
15
src/migrations/1759387204103-commands.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
|
export class Commands1759387204103 implements MigrationInterface {
|
||||||
|
name = "Commands1759387204103";
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE \`query\` ADD \`isCommand\` tinyint NOT NULL DEFAULT '0'`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE \`query\` DROP COLUMN \`isCommand\``);
|
||||||
|
}
|
||||||
|
}
|
||||||
37
src/query/command/command.controller.ts
Normal file
37
src/query/command/command.controller.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { Body, Controller, Headers, Inject, Param, Post } from "@nestjs/common";
|
||||||
|
import { QueryHandlerService } from "../handler/query.handler.service";
|
||||||
|
import { QueryExecuterService } from "../executer/query.executer.service";
|
||||||
|
|
||||||
|
@Controller("command")
|
||||||
|
export class CommandController {
|
||||||
|
constructor(
|
||||||
|
@Inject(QueryHandlerService)
|
||||||
|
private readonly queryHandlerService: QueryHandlerService,
|
||||||
|
@Inject(QueryExecuterService)
|
||||||
|
private readonly queryExecuterService: QueryExecuterService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
@Post("create")
|
||||||
|
async createQuery(
|
||||||
|
@Body() queryData: { projectToken: string; source: string }
|
||||||
|
) {
|
||||||
|
return this.queryHandlerService.createQuery(queryData, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post("update/:id")
|
||||||
|
async updateQuery(
|
||||||
|
@Body() updateData: Partial<{ source: string }>,
|
||||||
|
@Inject("id") id: string
|
||||||
|
) {
|
||||||
|
return this.queryHandlerService.updateQuery(id, updateData);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post("/run/:token")
|
||||||
|
async runQuery(
|
||||||
|
@Param("token") token: string,
|
||||||
|
@Body() query: Record<string, any>,
|
||||||
|
@Headers() headers: Record<string, any>
|
||||||
|
) {
|
||||||
|
return this.queryExecuterService.runQuery(token, query, headers);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -14,4 +14,7 @@ export class Query {
|
|||||||
|
|
||||||
@Column({ type: "tinyint", default: 1 })
|
@Column({ type: "tinyint", default: 1 })
|
||||||
isActive: number;
|
isActive: number;
|
||||||
|
|
||||||
|
@Column({ type: "tinyint", default: 0 })
|
||||||
|
isCommand: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Body, Controller, Inject, Param, Post } from "@nestjs/common";
|
import { Body, Controller, Headers, Inject, Param, Post } from "@nestjs/common";
|
||||||
import { QueryExecuterService } from "./query.executer.service";
|
import { QueryExecuterService } from "./query.executer.service";
|
||||||
|
|
||||||
@Controller("query")
|
@Controller("query")
|
||||||
@ -11,8 +11,9 @@ export class QueryExecuterController {
|
|||||||
@Post("/run/:token")
|
@Post("/run/:token")
|
||||||
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>
|
||||||
) {
|
) {
|
||||||
return this.queryExecuterService.runQuery(token, query);
|
return this.queryExecuterService.runQuery(token, query, headers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,7 +34,11 @@ export class QueryExecuterService {
|
|||||||
.trim();
|
.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
async runQuery(token: string, queryData: any) {
|
async runQuery(
|
||||||
|
token: string,
|
||||||
|
queryData: any,
|
||||||
|
headers: Record<string, any> = {}
|
||||||
|
) {
|
||||||
const query = await this.queryRepository.findOne({
|
const query = await this.queryRepository.findOne({
|
||||||
where: { id: token },
|
where: { id: token },
|
||||||
relations: ["project"],
|
relations: ["project"],
|
||||||
@ -47,7 +51,8 @@ export class QueryExecuterService {
|
|||||||
const vm = await this.createVm(query);
|
const vm = await this.createVm(query);
|
||||||
const result = await vm.runScript(
|
const result = await vm.runScript(
|
||||||
this.clearImports(query.source),
|
this.clearImports(query.source),
|
||||||
queryData
|
queryData,
|
||||||
|
headers
|
||||||
);
|
);
|
||||||
|
|
||||||
return { message: "Query executed", result, query: queryData };
|
return { message: "Query executed", result, query: queryData };
|
||||||
|
|||||||
@ -13,7 +13,10 @@ export class QueryHandlerService {
|
|||||||
private readonly projectService: ProjectService
|
private readonly projectService: ProjectService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async createQuery(queryData: { projectToken: string; source: string }) {
|
async createQuery(
|
||||||
|
queryData: { projectToken: string; source: string },
|
||||||
|
isCommand = false
|
||||||
|
) {
|
||||||
const project = await this.projectService.findById(queryData.projectToken);
|
const project = await this.projectService.findById(queryData.projectToken);
|
||||||
|
|
||||||
if (!project) {
|
if (!project) {
|
||||||
@ -21,6 +24,7 @@ export class QueryHandlerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
queryData["project"] = project;
|
queryData["project"] = project;
|
||||||
|
queryData["isCommand"] = isCommand ? 1 : 0;
|
||||||
delete queryData.projectToken;
|
delete queryData.projectToken;
|
||||||
|
|
||||||
const query = this.queryRepository.create(queryData);
|
const query = this.queryRepository.create(queryData);
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import { QueryExecuterService } from "./executer/query.executer.service";
|
|||||||
import { QueryHandlerService } from "./handler/query.handler.service";
|
import { QueryHandlerService } from "./handler/query.handler.service";
|
||||||
import { ProjectModule } from "src/project/project.module";
|
import { ProjectModule } from "src/project/project.module";
|
||||||
import { DatabaseManagerModule } from "src/databaseManager/database.manager.module";
|
import { DatabaseManagerModule } from "src/databaseManager/database.manager.module";
|
||||||
|
import { CommandController } from "./command/command.controller";
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@ -14,7 +15,11 @@ import { DatabaseManagerModule } from "src/databaseManager/database.manager.modu
|
|||||||
forwardRef(() => DatabaseManagerModule),
|
forwardRef(() => DatabaseManagerModule),
|
||||||
TypeOrmModule.forFeature([Query]),
|
TypeOrmModule.forFeature([Query]),
|
||||||
],
|
],
|
||||||
controllers: [QueryExecuterController, QueryHandlerController],
|
controllers: [
|
||||||
|
QueryExecuterController,
|
||||||
|
QueryHandlerController,
|
||||||
|
CommandController,
|
||||||
|
],
|
||||||
providers: [QueryExecuterService, QueryHandlerService],
|
providers: [QueryExecuterService, QueryHandlerService],
|
||||||
})
|
})
|
||||||
export class QueryModule {}
|
export class QueryModule {}
|
||||||
|
|||||||
25
src/vm/plugins/query.plugin.ts
Normal file
25
src/vm/plugins/query.plugin.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { QueryExecuterService } from "../../query/executer/query.executer.service";
|
||||||
|
import { Query } from "../../query/entities/query.entity";
|
||||||
|
import { Plugin } from "../plugin.class";
|
||||||
|
|
||||||
|
export class QueryPlugin extends Plugin {
|
||||||
|
constructor(
|
||||||
|
name: string,
|
||||||
|
private query: Query,
|
||||||
|
private QueryExecuterService: QueryExecuterService
|
||||||
|
) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async init(query: Query, queryExecuterService: QueryExecuterService) {
|
||||||
|
return new QueryPlugin("query", query, queryExecuterService);
|
||||||
|
}
|
||||||
|
|
||||||
|
async run(data): Promise<any> {
|
||||||
|
return await this.QueryExecuterService.runQuery(this.query.id, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
onFinish() {
|
||||||
|
// No resources to clean up
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -47,7 +47,11 @@ export class Vm {
|
|||||||
this.jail.setSync(name, func);
|
this.jail.setSync(name, func);
|
||||||
}
|
}
|
||||||
|
|
||||||
async runScript(script: string, args: Record<string, any>): Promise<any> {
|
async runScript(
|
||||||
|
script: string,
|
||||||
|
args: Record<string, any>,
|
||||||
|
headers: Record<string, any>
|
||||||
|
): Promise<any> {
|
||||||
let resolvePromise: (value: any) => void;
|
let resolvePromise: (value: any) => void;
|
||||||
let rejectPromise: (reason?: any) => void;
|
let rejectPromise: (reason?: any) => void;
|
||||||
|
|
||||||
@ -76,7 +80,9 @@ export class Vm {
|
|||||||
(async () => {
|
(async () => {
|
||||||
${script}
|
${script}
|
||||||
try {
|
try {
|
||||||
const result = await main(${JSON.stringify(args)});
|
const result = await main(${JSON.stringify(
|
||||||
|
args
|
||||||
|
)}, ${JSON.stringify(headers)});
|
||||||
returnResult(JSON.stringify(result))
|
returnResult(JSON.stringify(result))
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
error(e)
|
error(e)
|
||||||
|
|||||||
@ -1,12 +1,14 @@
|
|||||||
import { QueryExecuterService } from "src/query/executer/query.executer.service";
|
import { QueryExecuterService } from "src/query/executer/query.executer.service";
|
||||||
import { DatabasePlugin } from "./plugins/database.plugin";
|
import { DatabasePlugin } from "./plugins/database.plugin";
|
||||||
import { Query } from "src/query/entities/query.entity";
|
import { Query } from "src/query/entities/query.entity";
|
||||||
|
import { QueryPlugin } from "./plugins/query.plugin";
|
||||||
|
|
||||||
export const registeredPlugins = {
|
export const registeredPlugins = {
|
||||||
db: async (service: QueryExecuterService, query: Query) => {
|
db: async (service: QueryExecuterService, query: Query) => {
|
||||||
const databaseConnection =
|
const databaseConnection =
|
||||||
await service.databaseManagerService.getConnectionOptions(
|
await service.databaseManagerService.getConnectionOptions(
|
||||||
query.project.id
|
query.project.id,
|
||||||
|
query.isCommand == 0
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!databaseConnection) {
|
if (!databaseConnection) {
|
||||||
@ -15,6 +17,12 @@ export const registeredPlugins = {
|
|||||||
|
|
||||||
return DatabasePlugin.init("db", databaseConnection);
|
return DatabasePlugin.init("db", databaseConnection);
|
||||||
},
|
},
|
||||||
|
query: async (service: QueryExecuterService, query: Query) => {
|
||||||
|
return QueryPlugin.init(query, service);
|
||||||
|
},
|
||||||
|
command: async (service: QueryExecuterService, query: Query) => {
|
||||||
|
return QueryPlugin.init(query, service);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const registeredModules = {
|
export const registeredModules = {
|
||||||
|
|||||||
@ -9,9 +9,11 @@ function createSQL(id) {
|
|||||||
return squel.select().from("test").where("id = ?", id).toString();
|
return squel.select().from("test").where("id = ?", id).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function main(input) {
|
async function main(input, headers) {
|
||||||
const sql = createSQL(input.id);
|
const sql = createSQL(input.id);
|
||||||
const res = await asyncCall(db, sql);
|
const res = await asyncCall(db, sql);
|
||||||
|
|
||||||
|
log(headers);
|
||||||
|
|
||||||
return { test: 1, array: [1, 2, [{ id: 1, name: "Test" }]] };
|
return { test: 1, array: [1, 2, [{ id: 1, name: "Test" }]] };
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user