114 lines
3.4 KiB
TypeScript
114 lines
3.4 KiB
TypeScript
import { BadRequestException } from '@nestjs/common';
|
|
|
|
import { GraphQLResolveInfo } from 'graphql';
|
|
|
|
import { DataSourceService } from 'src/metadata/data-source/data-source.service';
|
|
import { FieldMetadata } from 'src/metadata/field-metadata/field-metadata.entity';
|
|
import { parseResult } from 'src/tenant/entity-resolver/utils/parse-result.util';
|
|
|
|
import { PGGraphQLQueryBuilder } from './pg-graphql-query-builder.util';
|
|
|
|
interface QueryRunnerOptions {
|
|
tableName: string;
|
|
workspaceId: string;
|
|
info: GraphQLResolveInfo;
|
|
fields: FieldMetadata[];
|
|
}
|
|
|
|
export class PGGraphQLQueryRunner {
|
|
private queryBuilder: PGGraphQLQueryBuilder;
|
|
private options: QueryRunnerOptions;
|
|
|
|
constructor(
|
|
private dataSourceService: DataSourceService,
|
|
options: QueryRunnerOptions,
|
|
) {
|
|
this.queryBuilder = new PGGraphQLQueryBuilder({
|
|
tableName: options.tableName,
|
|
info: options.info,
|
|
fields: options.fields,
|
|
});
|
|
this.options = options;
|
|
}
|
|
|
|
private async execute(query: string, workspaceId: string): Promise<any> {
|
|
const workspaceDataSource =
|
|
await this.dataSourceService.connectToWorkspaceDataSource(workspaceId);
|
|
|
|
await workspaceDataSource?.query(`
|
|
SET search_path TO ${this.dataSourceService.getSchemaName(workspaceId)};
|
|
`);
|
|
|
|
return workspaceDataSource?.query(`
|
|
SELECT graphql.resolve($$
|
|
${query}
|
|
$$);
|
|
`);
|
|
}
|
|
|
|
private parseResult(graphqlResult: any, command: string): any {
|
|
const tableName = this.options.tableName;
|
|
const entityKey = `${command}${tableName}Collection`;
|
|
const result = graphqlResult?.[0]?.resolve?.data?.[entityKey];
|
|
|
|
if (!result) {
|
|
throw new BadRequestException('Malformed result from GraphQL query');
|
|
}
|
|
|
|
return parseResult(result);
|
|
}
|
|
|
|
async findMany(args: {
|
|
first?: number;
|
|
last?: number;
|
|
before?: string;
|
|
after?: string;
|
|
filter?: any;
|
|
orderBy?: any;
|
|
}): Promise<any[]> {
|
|
const query = this.queryBuilder.findMany(args);
|
|
const result = await this.execute(query, this.options.workspaceId);
|
|
|
|
return this.parseResult(result, '');
|
|
}
|
|
|
|
async findOne(args: { filter?: any }): Promise<any> {
|
|
if (!args.filter || Object.keys(args.filter).length === 0) {
|
|
throw new BadRequestException('Missing filter argument');
|
|
}
|
|
|
|
const query = this.queryBuilder.findOne(args);
|
|
const result = await this.execute(query, this.options.workspaceId);
|
|
const parsedResult = this.parseResult(result, '');
|
|
|
|
return parsedResult?.edges?.[0]?.node;
|
|
}
|
|
|
|
async createMany(args: { data: any[] }): Promise<any[]> {
|
|
const query = this.queryBuilder.createMany(args);
|
|
const result = await this.execute(query, this.options.workspaceId);
|
|
|
|
return this.parseResult(result, 'insertInto')?.records;
|
|
}
|
|
|
|
async createOne(args: { data: any }): Promise<any> {
|
|
const records = await this.createMany({ data: [args.data] });
|
|
|
|
return records?.[0];
|
|
}
|
|
|
|
async updateOne(args: { id: string; data: any }): Promise<any> {
|
|
const query = this.queryBuilder.updateOne(args);
|
|
const result = await this.execute(query, this.options.workspaceId);
|
|
|
|
return this.parseResult(result, 'update')?.records?.[0];
|
|
}
|
|
|
|
async deleteOne(args: { id: string }): Promise<any> {
|
|
const query = this.queryBuilder.deleteOne(args);
|
|
const result = await this.execute(query, this.options.workspaceId);
|
|
|
|
return this.parseResult(result, 'deleteFrom')?.records?.[0];
|
|
}
|
|
}
|