Skip to content

Commit

Permalink
refactor(crud-typeorm): extract operator template functions
Browse files Browse the repository at this point in the history
  • Loading branch information
Diluka committed Jul 12, 2019
1 parent 486dfad commit 80fea99
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 99 deletions.
1 change: 1 addition & 0 deletions packages/crud-typeorm/src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './typeorm-crud.service';
export * from './typeorm-operator.service';
123 changes: 25 additions & 98 deletions packages/crud-typeorm/src/typeorm-crud.service.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,31 @@
import { Repository, ObjectLiteral, SelectQueryBuilder, Brackets } from 'typeorm';
import { RelationMetadata } from 'typeorm/metadata/RelationMetadata';
import { plainToClass } from 'class-transformer';
import { ClassType } from 'class-transformer/ClassTransformer';
import {
CreateManyDto,
CrudRequest,
CrudRequestOptions,
CreateManyDto,
QueryOptions,
JoinOptions,
CrudService,
GetManyDefaultResponse,
JoinOptions,
QueryOptions,
} from '@nestjsx/crud';
import { CrudService } from '@nestjsx/crud/lib/services';
import {
QueryJoin,
CondOperator,
ParsedRequestParams,
QueryFilter,
QueryJoin,
QuerySort,
ParsedRequestParams,
} from '@nestjsx/crud-request';
import { isArrayFull, isObject, hasLength, objKeys, isUndefined } from '@nestjsx/util';
import { hasLength, isArrayFull, isObject, isUndefined, objKeys } from '@nestjsx/util';
import { plainToClass } from 'class-transformer';
// tslint:disable-next-line:no-submodule-imports
import { ClassType } from 'class-transformer/ClassTransformer';
import { Brackets, ObjectLiteral, Repository, SelectQueryBuilder } from 'typeorm';
// tslint:disable-next-line:no-submodule-imports
import { RelationMetadata } from 'typeorm/metadata/RelationMetadata';
import { TypeormOperatorService } from './typeorm-operator.service';

export class TypeOrmCrudService<T> extends CrudService<T> {
protected operators = new TypeormOperatorService();

private entityColumns: string[];
private entityPrimaryColumns: string[];
private entityColumnsHash: ObjectLiteral = {};
Expand Down Expand Up @@ -530,6 +536,7 @@ export class TypeOrmCrudService<T> extends CrudService<T> {

return true;
}

private setAndWhere(cond: QueryFilter, i: any, builder: SelectQueryBuilder<T>) {
this.validateHasColumn(cond.field);
const { str, params } = this.mapOperatorsToQuery(cond, `andWhere${i}`);
Expand Down Expand Up @@ -594,6 +601,7 @@ export class TypeOrmCrudService<T> extends CrudService<T> {
? this.mapSort(options.sort)
: {};
}

private mapSort(sort: QuerySort[]) {
const params: ObjectLiteral = {};

Expand All @@ -614,94 +622,13 @@ export class TypeOrmCrudService<T> extends CrudService<T> {
let str: string;
let params: ObjectLiteral;

switch (cond.operator) {
case 'eq':
str = `${field} = :${param}`;
break;

case 'ne':
str = `${field} != :${param}`;
break;

case 'gt':
str = `${field} > :${param}`;
break;

case 'lt':
str = `${field} < :${param}`;
break;

case 'gte':
str = `${field} >= :${param}`;
break;

case 'lte':
str = `${field} <= :${param}`;
break;

case 'starts':
str = `${field} LIKE :${param}`;
params = { [param]: `${cond.value}%` };
break;

case 'ends':
str = `${field} LIKE :${param}`;
params = { [param]: `%${cond.value}` };
break;

case 'cont':
str = `${field} LIKE :${param}`;
params = { [param]: `%${cond.value}%` };
break;

case 'excl':
str = `${field} NOT LIKE :${param}`;
params = { [param]: `%${cond.value}%` };
break;

case 'in':
/* istanbul ignore if */
if (!Array.isArray(cond.value) || !cond.value.length) {
this.throwBadRequestException(`Invalid column '${cond.field}' value`);
}
str = `${field} IN (:...${param})`;
break;
const template = this.operators[cond.operator] || this.operators[CondOperator.EQUALS];
// TODO for feature operator override
// if (!isFunction(template)) {
// throw new BadRequestException(`No template for operator[${cond.operator}] in TypeormOperatorService`);
// }

case 'notin':
/* istanbul ignore if */
if (!Array.isArray(cond.value) || !cond.value.length) {
this.throwBadRequestException(`Invalid column '${cond.field}' value`);
}
str = `${field} NOT IN (:...${param})`;
break;

case 'isnull':
str = `${field} IS NULL`;
params = {};
break;

case 'notnull':
str = `${field} IS NOT NULL`;
params = {};
break;

case 'between':
/* istanbul ignore if */
if (!Array.isArray(cond.value) || !cond.value.length || cond.value.length !== 2) {
this.throwBadRequestException(`Invalid column '${cond.field}' value`);
}
str = `${field} BETWEEN :${param}0 AND :${param}1`;
params = {
[`${param}0`]: cond.value[0],
[`${param}1`]: cond.value[1],
};
break;

/* istanbul ignore next */
default:
str = `${field} = :${param}`;
break;
}
[str, params] = template(field, param, cond.value);

if (typeof params === 'undefined') {
params = { [param]: cond.value };
Expand Down
59 changes: 59 additions & 0 deletions packages/crud-typeorm/src/typeorm-operator.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { CondOperator } from '@nestjsx/crud-request';

type Cond = [string, any?];
type TemplateFn = (field: string, param?: string, value?: any) => Cond;

interface IOperatorService {
[CondOperator.EQUALS]: TemplateFn;
[CondOperator.NOT_EQUALS]: TemplateFn;
[CondOperator.GREATER_THAN]: TemplateFn;
[CondOperator.LOWER_THAN]: TemplateFn;
[CondOperator.GREATER_THAN_EQUALS]: TemplateFn;
[CondOperator.LOWER_THAN_EQAULS]: TemplateFn;
[CondOperator.STARTS]: TemplateFn;
[CondOperator.ENDS]: TemplateFn;
[CondOperator.CONTAINS]: TemplateFn;
[CondOperator.EXCLUDES]: TemplateFn;
[CondOperator.IN]: TemplateFn;
[CondOperator.NOT_IN]: TemplateFn;
[CondOperator.IS_NULL]: TemplateFn;
[CondOperator.NOT_NULL]: TemplateFn;
[CondOperator.BETWEEN]: TemplateFn;
}

export class TypeormOperatorService implements IOperatorService {
[CondOperator.EQUALS] = (field: string, param: string) =>
[`${field} = :${param}`] as Cond;
[CondOperator.NOT_EQUALS] = (field: string, param: string) =>
[`${field} != :${param}`] as Cond;
[CondOperator.GREATER_THAN] = (field: string, param: string) =>
[`${field} > :${param}`] as Cond;
[CondOperator.LOWER_THAN] = (field: string, param: string) =>
[`${field} < :${param}`] as Cond;
[CondOperator.GREATER_THAN_EQUALS] = (field: string, param: string) =>
[`${field} >= :${param}`] as Cond;
[CondOperator.LOWER_THAN_EQAULS] = (field: string, param: string) =>
[`${field} <= :${param}`] as Cond;
[CondOperator.STARTS] = (field: string, param: string, value: any) =>
[`${field} LIKE :${param}`, { [param]: `${value}%` }] as Cond;
[CondOperator.ENDS] = (field: string, param: string, value: any) =>
[`${field} LIKE :${param}`, { [param]: `%${value}` }] as Cond;
[CondOperator.CONTAINS] = (field: string, param: string, value: any) =>
[`${field} LIKE :${param}`, { [param]: `%${value}%` }] as Cond;
[CondOperator.EXCLUDES] = (field: string, param: string, value: any) =>
[`${field} NOT LIKE :${param}`, { [param]: `%${value}%` }] as Cond;
[CondOperator.IN] = (field: string, param: string) =>
[`${field} IN (:...${param})`] as Cond;
[CondOperator.NOT_IN] = (field: string, param: string) =>
[`${field} NOT IN (:...${param})`] as Cond;
[CondOperator.IS_NULL] = (field: string) => [`${field} IS NULL`, {}] as Cond;
[CondOperator.NOT_NULL] = (field: string) => [`${field} IS NOT NULL`, {}] as Cond;
[CondOperator.BETWEEN] = (field: string, param: string, value: any[]) =>
[
`${field} BETWEEN :${param}0 AND :${param}1`,
{
[`${param}0`]: value[0],
[`${param}1`]: value[1],
},
] as Cond;
}
2 changes: 1 addition & 1 deletion packages/crud-typeorm/test/1.query-params.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Controller, INestApplication } from '@nestjs/common';
import { APP_FILTER } from '@nestjs/core';
import { Test } from '@nestjs/testing';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Crud } from '@nestjsx/crud';
import { RequestQueryBuilder } from '@nestjsx/crud-request';
import * as request from 'supertest';

Expand All @@ -11,7 +12,6 @@ import { Project } from '../../../integration/crud-typeorm/projects';
import { User } from '../../../integration/crud-typeorm/users';
import { UserProfile } from '../../../integration/crud-typeorm/users-profiles';
import { HttpExceptionFilter } from '../../../integration/shared/https-exception.filter';
import { Crud } from '../../crud/src/decorators/crud.decorator';
import { CompaniesService } from './__fixture__/companies.service';
import { ProjectsService } from './__fixture__/projects.service';
import { UsersService } from './__fixture__/users.service';
Expand Down

0 comments on commit 80fea99

Please sign in to comment.