UNPKG

@onn-software/ddl-to-gql

Version:

Convert a SQL DDL to a GraphQL implementation with all relations.

219 lines (186 loc) 7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.knexFactrory = exports.main = void 0; exports.main = `import {allGqlQueryResolvers, allGqlTypeResolvers, allGqlMutationResolvers, OnnResolverHooks} from './resolvers'; import {QueryBuilder, QueryOperator, Clause, MutationResult, OnnContext, MemCache} from './model'; import {OnnBaseRepo} from './repos'; export interface GqlParams<GraphQLResolveInfo = any> { parent: any; args: Record<string, any>; context: OnnContext | any; info: GraphQLResolveInfo; } export interface OnnResolverWrapper { before: (resolverName:string, tableName :string, gqlParams: GqlParams) => Promise<any | undefined | null>; after: (resolverName:string, tableName :string, result: any, gqlParams: GqlParams) => Promise<any>; } export type OnnExecute = (knexQb: Knex.QueryBuilder, action: string, options: any, context: OnnContext | any) => Promise<Knex.QueryBuilder | any>; export class OnnDdlToGql<GraphQLResolveInfo = any> { constructor(queryBuilderFactory: <T extends {}>(context: OnnContext | any) => QueryBuilder<T>, options?: { onnWrapperBuilder?: () => OnnResolverWrapper }) { OnnBaseRepo.BUILDER_FACTORY = queryBuilderFactory; if (options?.onnWrapperBuilder) { OnnResolverHooks.buildWrapper = options.onnWrapperBuilder; } } getAllTypeResolvers = () => allGqlTypeResolvers; getAllQueryResolvers = () => allGqlQueryResolvers; getAllGqlMutationResolvers = () => allGqlMutationResolvers; } export const SimpleOnExecute: OnnExecute = async (knexQb, action, options, context = {}) => { return knexQb; } export const contextCachingOnExecute: OnnExecute = async (knexQb, action, options, context = {}) => { if(context?.onn?.extras?.transacting){ knexQb = knexQb.transacting(context.onn.extras.transacting) } if(['QUERY', 'COUNT'].indexOf(action) < 0) return knexQb; if (!context.onn) context.onn = {}; if (context.onn.skipCache) return knexQb; if (!context.onn.cache) { context.onn.cache = new MemCache(); } let res = await context.onn.cache.get(options); if (!res) { res = await knexQb; await context.onn.cache.set(options, res); } return res; }; __FACTORY__ `; exports.knexFactrory = `import { Knex } from 'knex'; export interface KnexQueryBuilderOptions { table: string; where: Clause[]; orderBy?: { field: string; direction: 'asc' | 'desc' }; distinct: string[]; limit?: number; offset?: number; select?: string | string[]; } export const knexQueryBuilderFactory = ( knex: Knex, onExecute: OnnExecute = contextCachingOnExecute ) => <T extends {}>(context: OnnContext | any) => new KnexQueryBuilder<T>(context, knex, onExecute); export class KnexQueryBuilder<TYPE extends {}> implements QueryBuilder<TYPE, Knex> { private options: KnexQueryBuilderOptions = { table: '', where: [], distinct: [], }; constructor(private context: OnnContext | any, private knex: Knex, private onExecute: OnnExecute) {} private build(): Knex.QueryBuilder<TYPE> { let qb = this.knex<TYPE>(this.options.table) as Knex.QueryBuilder<TYPE>; this.options.where.forEach((clause) => { const safeField = this.options.table + "." + clause.field; switch (clause.operator) { case QueryOperator.EQUALS: qb.where(safeField, clause.value); break; case QueryOperator.IN: qb.whereIn(safeField, clause.value); break; case QueryOperator.BETWEEN: qb.whereBetween(safeField, clause.value); break; case QueryOperator.LIKE: qb.whereLike(safeField, clause.value); break; case QueryOperator.NULL: qb.whereNull(safeField); break; case QueryOperator.NOT_EQUALS: qb.whereNot(safeField, clause.value); break; case QueryOperator.NOT_IN: qb.whereNotIn(safeField, clause.value); break; case QueryOperator.NOT_BETWEEN: qb.whereNotBetween(safeField, clause.value); break; case QueryOperator.NOT_NULL: qb.whereNotNull(safeField); break; } }); if(this.options.orderBy?.field) { qb.orderBy(this.options.table + "." + this.options.orderBy.field, this.options.orderBy.direction); } return qb; } async executeQuery(): Promise<TYPE[]> { const qb = this.build(); if (this.options.offset) { qb.offset(this.options.offset); } if (this.options.limit) { qb.limit(this.options.limit); } if(this.options.distinct.length > 0) { qb.distinct(...this.options.distinct).select(...this.options.distinct); } else if (this.options.select) { qb.select(this.options.select); } return this.onExecute(qb, 'QUERY', this.options, this.context); } async executeCount(): Promise<number> { const count = await this.onExecute(this.build().count(), 'COUNT', this.options, this.context); return Object.values(count[0])[0] as number; } async executeInsert(value: any): Promise<MutationResult> { try { const [res] = await this.onExecute(this.build().insert(value), 'INSERT', this.options, this.context); return {rows: res ? 1 : 0, res: \`\${res}\`} } catch (e: any) { return {rows: 0, res: '', error: e.message ?? e.toString()} } } async executeUpdate(value: any): Promise<MutationResult> { try { const rows = await this.onExecute(this.build().update(value), 'UPDATE', this.options, this.context); return {rows, res: '', error: rows > 0 ? undefined : 'Nothing matches clauses'} } catch (e: any) { return {rows: 0, res: '', error: e.message ?? e.toString()} } } async executeDelete(): Promise<MutationResult> { try { const rows = await this.onExecute(this.build().delete(), 'DELETE', this.options, this.context); return {rows, res: '', error: rows > 0 ? undefined : 'Nothing matches clauses'} } catch (e: any) { return {rows: 0, res: '', error: e.message ?? e.toString()} } } limit(limit: number): QueryBuilder<TYPE, Knex> { this.options.limit = limit; return this; } offset(offset: number): QueryBuilder<TYPE, Knex> { this.options.offset = offset; return this; } select(fields: string | string[]): QueryBuilder<TYPE, Knex> { this.options.select = fields; return this; } table(tableName: string): QueryBuilder<TYPE, Knex> { this.options.table = tableName; return this; } orderBy(orderBy?: {field: string, direction: 'asc' | 'desc'}): QueryBuilder<TYPE, Knex> { this.options.orderBy = orderBy; return this; } distinct(distinct: string[] = []): QueryBuilder<TYPE, Knex> { this.options.distinct = distinct; return this; } where(...clauses: Clause[]): QueryBuilder<TYPE, Knex> { this.options.where.push(...clauses); return this; } } `;