Skip to content

Commit

Permalink
Merge pull request nestjsx#351 from nestjsx/feature/serialization
Browse files Browse the repository at this point in the history
Feature/serialization
  • Loading branch information
michaelyali authored Dec 18, 2019
2 parents f4e634d + fbc5fe2 commit 6c2aff6
Show file tree
Hide file tree
Showing 46 changed files with 905 additions and 164 deletions.
9 changes: 9 additions & 0 deletions integration/crud-typeorm/companies/companies.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,20 @@ import { Crud } from '@nestjsx/crud';

import { Company } from './company.entity';
import { CompaniesService } from './companies.service';
import { dto } from './dto';
import { serialize } from './response';

@Crud({
model: {
type: Company,
},
dto,
serialize,
routes: {
deleteOneBase: {
returnDeleted: false,
},
},
query: {
alwaysPaginate: true,
join: {
Expand Down
2 changes: 1 addition & 1 deletion integration/crud-typeorm/companies/company.entity.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { CrudValidationGroups } from '@nestjsx/crud';
import { Entity, Column, OneToMany } from 'typeorm';
import { IsOptional, IsString, MaxLength, IsNotEmpty } from 'class-validator';
import { Type } from 'class-transformer';
import { CrudValidationGroups } from '@nestjsx/crud';

import { BaseEntity } from '../base-entity';
import { User } from '../users/user.entity';
Expand Down
19 changes: 19 additions & 0 deletions integration/crud-typeorm/companies/dto/create-company.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, MaxLength } from 'class-validator';

export class CreateCompanyDto {
@ApiProperty({ type: 'string' })
@IsString()
@MaxLength(100)
name: string;

@ApiProperty({ type: 'string' })
@IsString()
@MaxLength(100)
domain: string;

@ApiProperty({ type: 'string' })
@IsString()
@MaxLength(100)
description: string;
}
5 changes: 5 additions & 0 deletions integration/crud-typeorm/companies/dto/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { CreateCompanyDto } from './create-company.dto';

export const dto = {
create: CreateCompanyDto,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ApiProperty } from '@nestjs/swagger';
import { Exclude } from 'class-transformer';

export class GetCompanyResponseDto {
@ApiProperty({ type: 'number' })
id: string;

@ApiProperty({ type: 'string' })
name: string;

@ApiProperty({ type: 'string' })
domain: string;

@ApiProperty({ type: 'string' })
description: string;

@Exclude()
createdAt: any;

@Exclude()
updatedAt: any;
}
6 changes: 6 additions & 0 deletions integration/crud-typeorm/companies/response/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { SerializeOptions } from '@nestjsx/crud';
import { GetCompanyResponseDto } from './get-company-response.dto';

export const serialize: SerializeOptions = {
get: GetCompanyResponseDto,
};
7 changes: 7 additions & 0 deletions integration/crud-typeorm/devices/devices.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,23 @@ import { Crud } from '@nestjsx/crud';

import { Device } from './device.entity';
import { DevicesService } from './devices.service';
import { serialize } from './response';

@Crud({
model: { type: Device },
serialize,
params: {
deviceKey: {
field: 'deviceKey',
type: 'uuid',
primary: true,
},
},
routes: {
deleteOneBase: {
returnDeleted: true,
},
},
})
@ApiTags('devices')
@Controller('/devices')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ApiProperty } from '@nestjs/swagger';
import { Exclude } from 'class-transformer';

export class DeleteDeviceResponseDto {
@ApiProperty({ type: 'string' })
deviceKey: string;

@Exclude()
description?: string;
}
6 changes: 6 additions & 0 deletions integration/crud-typeorm/devices/response/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { SerializeOptions } from '@nestjsx/crud';
import { DeleteDeviceResponseDto } from './delete-device-response.dto';

export const serialize: SerializeOptions = {
delete: DeleteDeviceResponseDto,
};
2 changes: 1 addition & 1 deletion integration/crud-typeorm/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ CrudConfigService.load({
property: USER_REQUEST_KEY,
},
routes: {
exclude: ['createManyBase'],
// exclude: ['createManyBase'],
},
});

Expand Down
4 changes: 2 additions & 2 deletions packages/crud-request/src/request-query.parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export class RequestQueryParser implements ParsedRequestParams {
}

setAuthPersist(persist: ObjectLiteral = {}) {
this.authPersist = persist || {};
this.authPersist = persist || /* istanbul ignore next */ {};
}

convertFilterToSearch(filter: QueryFilter): SFields | SConditionAND {
Expand All @@ -160,7 +160,7 @@ export class RequestQueryParser implements ParsedRequestParams {
: filter.value,
},
}
: {};
: /* istanbul ignore next */ {};
}

private getParamNames(
Expand Down
2 changes: 0 additions & 2 deletions packages/crud-request/src/types/request-query.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ export enum CondOperator {
CONTAINS_LOW = '$contL',
EXCLUDES_LOW = '$exclL',
IN_LOW = '$inL',
NOT_IN_LOW = '$betweenL',
}

export type ComparisonOperator = DeprecatedCondOperator | keyof SFieldOperator;
Expand Down Expand Up @@ -98,7 +97,6 @@ export type SFieldOperator = {
$exclL?: SFiledValues;
$inL?: SFiledValues;
$notinL?: SFiledValues;
$betweenL?: SFiledValues;
$or?: SFieldOperator;
$and?: never;
};
Expand Down
60 changes: 15 additions & 45 deletions packages/crud-typeorm/src/typeorm-crud.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,14 +170,20 @@ export class TypeOrmCrudService<T> extends CrudService<T> {
const [_, found] = await oO(this.getOneOrFail(req, returnShallow));
const toSave = !allowParamsOverride
? { ...(found || {}), ...dto, ...paramsFilters, ...req.parsed.authPersist }
: { ...(found || {}), ...paramsFilters, ...dto, ...req.parsed.authPersist };
: {
...(found || /* istanbul ignore next */ {}),
...paramsFilters,
...dto,
...req.parsed.authPersist,
};
const replaced = await this.repo.save(plainToClass(this.entityType, toSave));

if (returnShallow) {
return replaced;
} else {
const primaryParam = this.getPrimaryParam(req.options.params);

/* istanbul ignore if */
if (!primaryParam) {
return replaced;
}
Expand All @@ -194,7 +200,9 @@ export class TypeOrmCrudService<T> extends CrudService<T> {
public async deleteOne(req: CrudRequest): Promise<void | T> {
const { returnDeleted } = req.options.routes.deleteOneBase;
const found = await this.getOneOrFail(req, returnDeleted);
const toReturn = returnDeleted ? { ...found } : undefined;
const toReturn = returnDeleted
? plainToClass(this.entityType, { ...found })
: undefined;
const deleted = await this.repo.remove(found);

return toReturn;
Expand All @@ -213,17 +221,14 @@ export class TypeOrmCrudService<T> extends CrudService<T> {
return filters;
}

public requestHasPage(parsed: ParsedRequestParams): boolean {
return Number.isFinite(parsed.page) || Number.isFinite(parsed.offset);
}

public decidePagination(
parsed: ParsedRequestParams,
options: CrudRequestOptions,
): boolean {
return (
options.query.alwaysPaginate ||
(this.requestHasPage(parsed) && !!this.getTake(parsed, options.query))
((Number.isFinite(parsed.page) || Number.isFinite(parsed.offset)) &&
!!this.getTake(parsed, options.query))
);
}

Expand Down Expand Up @@ -746,34 +751,6 @@ export class TypeOrmCrudService<T> extends CrudService<T> {
return select;
}

protected getSkip(query: ParsedRequestParams, take: number): number | null {
return query.page && take
? take * (query.page - 1)
: query.offset
? query.offset
: null;
}

protected getTake(query: ParsedRequestParams, options: QueryOptions): number | null {
if (query.limit) {
return options.maxLimit
? query.limit <= options.maxLimit
? query.limit
: options.maxLimit
: query.limit;
}
/* istanbul ignore if */
if (options.limit) {
return options.maxLimit
? options.limit <= options.maxLimit
? options.limit
: options.maxLimit
: options.limit;
}

return options.maxLimit ? options.maxLimit : null;
}

protected getSort(query: ParsedRequestParams, options: QueryOptions) {
return query.sort && query.sort.length
? this.mapSort(query.sort)
Expand Down Expand Up @@ -810,7 +787,8 @@ export class TypeOrmCrudService<T> extends CrudService<T> {
param: any,
): { str: string; params: ObjectLiteral } {
const field = this.getFieldWithAlias(cond.field);
const likeOperator = this.dbName === 'postgres' ? 'ILIKE' : 'LIKE';
const likeOperator =
this.dbName === 'postgres' ? 'ILIKE' : /* istanbul ignore next */ 'LIKE';
let str: string;
let params: ObjectLiteral;

Expand Down Expand Up @@ -931,15 +909,6 @@ export class TypeOrmCrudService<T> extends CrudService<T> {
str = `LOWER(${field}) NOT IN (:...${param})`;
break;

case '$betweenL':
this.checkFilterIsArray(cond, cond.value.length !== 2);
str = `LOWER(${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}`;
Expand All @@ -954,6 +923,7 @@ export class TypeOrmCrudService<T> extends CrudService<T> {
}

private checkFilterIsArray(cond: QueryFilter, withLength?: boolean) {
/* istanbul ignore if */
if (
!Array.isArray(cond.value) ||
!cond.value.length ||
Expand Down
63 changes: 63 additions & 0 deletions packages/crud-typeorm/test/b.query-params.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,69 @@ describe('#crud-typeorm', () => {
.expect(200);
expect(res.body).toBeArrayOfSize(0);
});
it('should return with $eqL search operator', async () => {
const query = qb.search({ name: { $eqL: 'project1' } }).query();
const res = await projects4()
.query(query)
.expect(200);
expect(res.body).toBeArrayOfSize(1);
});
it('should return with $neL search operator', async () => {
const query = qb.search({ name: { $neL: 'project1' } }).query();
const res = await projects4()
.query(query)
.expect(200);
expect(res.body).toBeArrayOfSize(9);
});
it('should return with $startsL search operator', async () => {
const query = qb.search({ email: { $startsL: '2' } }).query();
const res = await request(server)
.get('/users')
.query(query)
.expect(200);
expect(res.body).toBeArrayOfSize(3);
});
it('should return with $endsL search operator', async () => {
const query = qb.search({ domain: { $endsL: '0' } }).query();
const res = await request(server)
.get('/companies')
.query(query)
.expect(200);
expect(res.body).toBeArrayOfSize(1);
});
it('should return with $contL search operator', async () => {
const query = qb.search({ email: { $contL: '1@' } }).query();
const res = await request(server)
.get('/users')
.query(query)
.expect(200);
expect(res.body).toBeArrayOfSize(3);
});
it('should return with $exclL search operator', async () => {
const query = qb.search({ email: { $exclL: '1@' } }).query();
const res = await request(server)
.get('/users')
.query(query)
.expect(200);
expect(res.body).toBeArrayOfSize(18);
});
it('should return with $inL search operator', async () => {
const query = qb.search({ name: { $inL: ['name2', 'name3'] } }).query();
const res = await request(server)
.get('/companies')
.query(query)
.expect(200);
expect(res.body).toBeArrayOfSize(2);
});
it('should return with $notinL search operator', async () => {
const query = qb
.search({ name: { $notinL: ['project7', 'project8', 'project9'] } })
.query();
const res = await projects4()
.query(query)
.expect(200);
expect(res.body).toBeArrayOfSize(7);
});
});

describe('#update', () => {
Expand Down
Loading

0 comments on commit 6c2aff6

Please sign in to comment.