Skip to content

Commit

Permalink
feat: add execution context with switching functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
kostyazgara committed Oct 28, 2022
1 parent 1158aa1 commit f2f0490
Show file tree
Hide file tree
Showing 21 changed files with 433 additions and 235 deletions.
1 change: 1 addition & 0 deletions packages/core/lib/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './knexion-execution-context-host';
95 changes: 95 additions & 0 deletions packages/core/lib/helpers/knexion-execution-context-host.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { Type } from '@nestjs/common/interfaces';
import {
KnexArgumentsHost,
KnexionContextType,
KnexionExecutionContext,
KnexionMethodType,
} from '../interfaces';
import { DefaultRepositoryOptions } from '../repository';

export class KnexionExecutionContextHost<
TRecord,
TResult,
IdType = DefaultRepositoryOptions['idType'],
> implements KnexionExecutionContext<TRecord, TResult, IdType>
{
private contextType = 'knex';
private methodType = null;

constructor(
private readonly args: any[],
private readonly constructorRef: Type = null,
private readonly handler: Function = null,
) {}

setType<TContext extends string = KnexionContextType>(type: TContext): void {
type && (this.contextType = type);
}

getType<TContext extends string = KnexionContextType>(): TContext {
return this.contextType as TContext;
}

setMethod<TMethod extends string = KnexionMethodType>(type: TMethod): void {
type && (this.methodType = type);
}

getMethod<TMethod extends string = KnexionMethodType>(): TMethod {
return this.methodType as TMethod;
}

getClass<T = any>(): Type<T> {
return this.constructorRef;
}

getHandler(): Function {
return this.handler;
}

getArgs<T extends Array<any> = any[]>(): T {
return this.args as T;
}

getArgByIndex<T = any>(index: number): T {
return this.args[index] as T;
}

switchToKnex(): KnexArgumentsHost<TRecord, TResult, IdType> {
return Object.assign(this, {
getQueryBuilder: () => this.getArgByIndex(0),
getRawBuilder: () => this.getArgByIndex(1),
createQueryBuilder: () => this.getArgByIndex(2)(),
getOptions: () => this.getArgByIndex(3),
switchToList: () =>
Object.assign(this, {
getQueryBuilder: () => this.getArgByIndex(0),
getOptions: () => this.getArgByIndex(3),
}),
switchToCreate: () =>
Object.assign(this, {
getQueryBuilder: () => this.getArgByIndex(0),
getOptions: () => this.getArgByIndex(3),
getPayload: () => this.getArgByIndex(4),
}),
switchToRetrieve: () =>
Object.assign(this, {
getQueryBuilder: () => this.getArgByIndex(0),
getOptions: () => this.getArgByIndex(3),
getId: () => this.getArgByIndex(4),
}),
switchToUpdate: () =>
Object.assign(this, {
getQueryBuilder: () => this.getArgByIndex(0),
getOptions: () => this.getArgByIndex(3),
getId: () => this.getArgByIndex(4),
getPayload: () => this.getArgByIndex(5),
}),
switchToDelete: () =>
Object.assign(this, {
getQueryBuilder: () => this.getArgByIndex(0),
getOptions: () => this.getArgByIndex(3),
getId: () => this.getArgByIndex(4),
}),
});
}
}
2 changes: 1 addition & 1 deletion packages/core/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
export * from './decorators';
export * from './helpers';
export * from './indicators';
export * from './interfaces';
export * from './services';
export * from './utils';
export * from './interceptors-consumer';
export * from './knexion.module';
export * from './knexion-context';
export * from './repository';
10 changes: 5 additions & 5 deletions packages/core/lib/interceptors-consumer.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { defer, from, isObservable, lastValueFrom, Observable } from 'rxjs';
import { mergeAll, switchMap } from 'rxjs/operators';
import { KnexionCallHandler } from './interfaces';
import { KnexionContext } from './knexion-context';
import { KnexionCallHandler, KnexionInterceptors } from './interfaces';
import { KnexionExecutionContextHost } from './helpers';

export class InterceptorsConsumer<TRecord> {
public async intercept(
context: KnexionContext<TRecord>,
public async intercept<TResult>(
interceptors: KnexionInterceptors,
context: KnexionExecutionContextHost<TRecord, TResult>,
next: () => Promise<unknown>,
): Promise<unknown> {
const { intercept: interceptors = [] } = context.options;
if (!interceptors.length) {
return next();
}
Expand Down
10 changes: 3 additions & 7 deletions packages/core/lib/interfaces/database-options.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,13 @@ export interface AliasableDatabaseOptions {
alias?: string;
}

export interface DatabaseOptions<TRecord, TResult, Options = unknown> {
export interface DatabaseOptions<TRecord, TResult> {
transaction?: Knex.Transaction;
intercept?: KnexionInterceptors<TRecord, TResult, Options>;
intercept?: KnexionInterceptors<TRecord, TResult>;
}

export interface SelectDatabaseOptions<TRecord, TResult>
extends DatabaseOptions<
TRecord,
TResult,
SelectDatabaseOptions<TRecord, TResult>
>,
extends DatabaseOptions<TRecord, TResult>,
AliasableDatabaseOptions {
[field: string]: unknown;
}
2 changes: 2 additions & 0 deletions packages/core/lib/interfaces/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export * from './database-options.interface';
export * from './knexion-arguments-host.interface';
export * from './knexion-execution-contex.interface';
export * from './knexion-module-options.interface';
export * from './knexion-repository-options.interface';
export * from './knexion-transaction.interface';
Expand Down
118 changes: 118 additions & 0 deletions packages/core/lib/interfaces/knexion-arguments-host.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import {
DatabaseOptions,
SelectDatabaseOptions,
} from './database-options.interface';
import { Knex } from 'knex';

export type KnexionContextType = 'knex';

export type KnexionMethodType =
| 'list'
| 'create'
| 'retrieve'
| 'update'
| 'delete';

export interface KnexMethodArgumentsHost<TRecord, TResult> {
getQueryBuilder(): Knex.QueryBuilder<TRecord, TResult>;
getOptions(): unknown;
}

export interface ListKnexMethodArgumentsHost<TRecord, TResult>
extends KnexMethodArgumentsHost<TRecord, TResult> {
getOptions<
Options extends SelectDatabaseOptions<
TRecord,
TResult
> = SelectDatabaseOptions<TRecord, TResult>,
>(): Options;
}

export interface CreateKnexMethodArgumentsHost<TRecord, TResult>
extends KnexMethodArgumentsHost<TRecord, TResult> {
getPayload<T = any>(): T;
getOptions<
Options extends DatabaseOptions<TRecord, TResult> = DatabaseOptions<
TRecord,
TResult
>,
>(): Options;
}

export interface RetrieveKnexMethodArgumentsHost<TRecord, TResult, IdType>
extends KnexMethodArgumentsHost<TRecord, TResult> {
getId(): IdType;
getOptions<
Options extends SelectDatabaseOptions<
TRecord,
TResult
> = SelectDatabaseOptions<TRecord, TResult>,
>(): Options;
}

export interface UpdateKnexMethodArgumentsHost<TRecord, TResult, IdType>
extends KnexMethodArgumentsHost<TRecord, TResult> {
getId(): IdType;
getPayload<T = any>(): T;
getOptions<
Options extends DatabaseOptions<TRecord, TResult> = DatabaseOptions<
TRecord,
TResult
>,
>(): Options;
}

export interface DeleteKnexMethodArgumentsHost<TRecord, TResult, IdType>
extends KnexMethodArgumentsHost<TRecord, TResult> {
getId(): IdType;
getOptions<
Options extends DatabaseOptions<TRecord, TResult> = DatabaseOptions<
TRecord,
TResult
>,
>(): Options;
}

export interface KnexArgumentsHost<TRecord, TResult, IdType> {
getQueryBuilder(): Knex.QueryBuilder<TRecord, TResult>;
getRawBuilder(): Knex.RawBuilder<TRecord, TResult>;
createQueryBuilder(): Knex.QueryBuilder<TRecord, TResult>;
getOptions<
Options extends DatabaseOptions<TRecord, TResult> = DatabaseOptions<
TRecord,
TResult
>,
>(): Options;
switchToList(): ListKnexMethodArgumentsHost<TRecord, TResult>;
switchToCreate(): CreateKnexMethodArgumentsHost<TRecord, TResult>;
switchToRetrieve(): RetrieveKnexMethodArgumentsHost<TRecord, TResult, IdType>;
switchToUpdate(): UpdateKnexMethodArgumentsHost<TRecord, TResult, IdType>;
switchToDelete(): DeleteKnexMethodArgumentsHost<TRecord, TResult, IdType>;
}

/**
* Provides methods for retrieving the arguments being passed to a handler.
*/
export interface KnexionArgumentsHost<TRecord, TResult, IdType> {
/**
* Returns the array of arguments being passed to the handler.
*/
getArgs<T extends Array<any> = any[]>(): T;
/**
* Returns a particular argument by index.
* @param index index of argument to retrieve
*/
getArgByIndex<T = any>(index: number): T;

/**
* Returns the current execution context type (string)
*/
getType<TContext extends string = KnexionContextType>(): TContext;

/**
* Returns the current execution method type (string)
*/
getMethod<TMethod extends string = KnexionMethodType>(): TMethod;

switchToKnex(): KnexArgumentsHost<TRecord, TResult, IdType>;
}
19 changes: 19 additions & 0 deletions packages/core/lib/interfaces/knexion-execution-contex.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Type } from '@nestjs/common';
import { KnexionArgumentsHost } from './knexion-arguments-host.interface';
import { DefaultRepositoryOptions } from '../repository';

export interface KnexionExecutionContext<
TRecord,
TResult = unknown,
IdType = DefaultRepositoryOptions['idType'],
> extends KnexionArgumentsHost<TRecord, TResult, IdType> {
/**
* Returns the *type* of the controller class which the current handler belongs to.
*/
getClass<T = any>(): Type<T>;
/**
* Returns a reference to the handler (method) that will be invoked next in the
* request pipeline.
*/
getHandler(): Function;
}
15 changes: 3 additions & 12 deletions packages/core/lib/interfaces/repository-interceptor.interface.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Observable } from 'rxjs';
import { KnexionContext } from '../knexion-context';
import { DatabaseOptions } from './database-options.interface';
import { KnexionExecutionContext } from './knexion-execution-contex.interface';

export interface KnexionCallHandler<T = unknown> {
handle(): Observable<T>;
Expand All @@ -9,24 +8,16 @@ export interface KnexionCallHandler<T = unknown> {
export interface KnexionInterceptor<
TRecord = any,
TResult = any,
Options extends DatabaseOptions<TRecord, TResult> = DatabaseOptions<
TRecord,
TResult
>,
TInput = unknown,
TOutput = TInput,
> {
intercept(
context: KnexionContext<TRecord, TResult, Options>,
context: KnexionExecutionContext<TRecord, TResult>,
next: KnexionCallHandler<TInput>,
): Observable<TOutput> | Promise<Observable<TOutput>>;
}

export type KnexionInterceptors<
TRecord = any,
TResult = any,
Options extends DatabaseOptions<TRecord, TResult> = DatabaseOptions<
TRecord,
TResult
>,
> = KnexionInterceptor<TRecord, TResult, Options>[];
> = KnexionInterceptor<TRecord, TResult>[];
42 changes: 0 additions & 42 deletions packages/core/lib/knexion-context.ts

This file was deleted.

Loading

0 comments on commit f2f0490

Please sign in to comment.