Refactor VM and Plugin Management

- Removed the `plugins.constants.ts` file as it was no longer needed.
- Updated the `vm.class.ts` to improve result handling and logging.
- Introduced `vm.constants.ts` to manage registered plugins and modules.
- Simplified the test payload in `case1-payload.js` by removing unnecessary insert logic.
- Enhanced `case1.ts` to include database and migration setup, improving test clarity.
- Deleted unused functions for adding modules and plugins, streamlining the codebase.
This commit is contained in:
lborv
2025-09-29 20:58:51 +03:00
parent 1b552e651f
commit 593acf2a9a
21 changed files with 5391 additions and 469 deletions

View File

@ -3,20 +3,41 @@ import { InjectRepository } from "@nestjs/typeorm";
import { Query } from "../entities/query.entity";
import { Repository } from "typeorm";
import { Vm } from "../../vm/vm.class";
import { VModule } from "../../vm/module.class";
import { DatabasePlugin } from "src/vm/plugins/database.plugin";
import { VModule } from "src/vm/module.class";
import { registeredModules, registeredPlugins } from "src/vm/vm.constants";
import { DatabaseManagerService } from "src/databaseManager/database/database.manager.service";
@Injectable()
export class QueryExecuterService {
constructor(
@InjectRepository(Query)
private readonly queryRepository: Repository<Query>
readonly queryRepository: Repository<Query>,
readonly databaseManagerService: DatabaseManagerService
) {}
parseImports(source: string): string[] {
const importRegex =
/import\s+(?:[\w*\s{},]*\s+from\s+)?["']([^"']+)["'];?/g;
const imports: string[] = [];
let match: RegExpExecArray | null;
while ((match = importRegex.exec(source)) !== null) {
imports.push(match[1]);
}
return imports;
}
clearImports(source: string): string {
return source
.replace(/import\s+(?:[\w*\s{},]*\s+from\s+)?["']([^"']+)["'];?/g, "")
.trim();
}
async runQuery(token: string, queryData: any) {
const query = await this.queryRepository.findOne({
where: { id: token },
relations: ["modules", "plugins"],
relations: ["project"],
});
if (!query) {
@ -24,37 +45,51 @@ export class QueryExecuterService {
}
const vm = await this.createVm(query);
const result = await vm.runScript(query.source, queryData);
const result = await vm.runScript(
this.clearImports(query.source),
queryData
);
return { message: "Query executed", result, query: queryData };
}
private async createVm(query: Query) {
if (query.modules === undefined) {
query.modules = [];
}
const imports = this.parseImports(query.source);
const importsParsed = imports.map((imp) => {
const item = imp.split("/");
if (query.plugins === undefined) {
query.plugins = [];
return {
type: item[0],
name: item[1],
};
});
const moduleNames = importsParsed.filter((imp) => imp.type === "module");
const pluginNames = importsParsed.filter((imp) => imp.type === "plugin");
const modules = moduleNames.map((mod) => {
if (registeredModules[mod.name]) {
return new VModule(mod.name, registeredModules[mod.name]);
}
throw new Error(`Module ${mod.name} not found`);
});
const plugins = [];
for (const plugin of pluginNames) {
if (!registeredPlugins[plugin.name]) {
throw new Error(`Plugin ${plugin.name} not found`);
}
plugins.push(
await registeredPlugins[plugin.name].initMethod(this, query)
);
}
const vm = new Vm({
memoryLimit: 128,
modules: query.modules.map((module) => {
return new VModule(module.name, module.sourcePath);
}),
plugins: await Promise.all(
query.plugins.map((plugin) => {
switch (plugin.class) {
case "DATABASE": {
const config = JSON.parse(plugin.config);
return DatabasePlugin.init(plugin.name, config);
}
default:
throw new Error(`Unknown plugin class: ${plugin.class}`);
}
})
),
modules: modules,
plugins: plugins,
});
return await vm.init();