From a24e5839a2a30e145c5aa5c42575cb57fe2007d8 Mon Sep 17 00:00:00 2001 From: Konstantin Bodnia Date: Fri, 9 Dec 2022 13:07:24 +0100 Subject: [PATCH] feat(loadrelationids): @Crud decorator accepts loadRelationIds query param Allows `@Crud` decorator accept `loadRelationIds` query param that is later accepted by TypeORM. --- .../crud-typeorm/src/typeorm-crud.service.ts | 7 +++- .../test/__fixture__/user.license.service.ts | 12 +++++++ .../crud-typeorm/test/b.query-params.spec.ts | 33 ++++++++++++++++++- .../src/interfaces/query-options.interface.ts | 11 ++++--- 4 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 packages/crud-typeorm/test/__fixture__/user.license.service.ts diff --git a/packages/crud-typeorm/src/typeorm-crud.service.ts b/packages/crud-typeorm/src/typeorm-crud.service.ts index 60f36856..818b3b00 100644 --- a/packages/crud-typeorm/src/typeorm-crud.service.ts +++ b/packages/crud-typeorm/src/typeorm-crud.service.ts @@ -282,6 +282,11 @@ export class TypeOrmCrudService extends CrudService { // search this.setSearchCondition(builder, parsed.search); + // set loadRelationIds + if (options.query.loadRelationIds) { + builder.loadAllRelationIds(options.query.loadRelationIds); + } + // set joins const joinOptions = options.query.join || {}; const allowedJoins = objKeys(joinOptions); @@ -810,7 +815,7 @@ export class TypeOrmCrudService extends CrudService { protected getFieldWithAlias(field: string, sort = false) { /* istanbul ignore next */ - const i = ['mysql','mariadb'].includes(this.dbName) ? '`' : '"'; + const i = ['mysql', 'mariadb'].includes(this.dbName) ? '`' : '"'; const cols = field.split('.'); switch (cols.length) { diff --git a/packages/crud-typeorm/test/__fixture__/user.license.service.ts b/packages/crud-typeorm/test/__fixture__/user.license.service.ts new file mode 100644 index 00000000..994b207a --- /dev/null +++ b/packages/crud-typeorm/test/__fixture__/user.license.service.ts @@ -0,0 +1,12 @@ +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; + +import { TypeOrmCrudService } from '../../../crud-typeorm/src/typeorm-crud.service'; +import { UserLicense } from '../../../../integration/crud-typeorm/users-licenses'; + +@Injectable() +export class UserLicenseService extends TypeOrmCrudService { + constructor(@InjectRepository(UserLicense) repo) { + super(repo); + } +} diff --git a/packages/crud-typeorm/test/b.query-params.spec.ts b/packages/crud-typeorm/test/b.query-params.spec.ts index 4915a9e2..388efce7 100644 --- a/packages/crud-typeorm/test/b.query-params.spec.ts +++ b/packages/crud-typeorm/test/b.query-params.spec.ts @@ -12,12 +12,14 @@ import { Project } from '../../../integration/crud-typeorm/projects'; import { User } from '../../../integration/crud-typeorm/users'; import { UserProfile } from '../../../integration/crud-typeorm/users-profiles'; import { Note } from '../../../integration/crud-typeorm/notes'; +import { UserLicense } from '../../../integration/crud-typeorm/users-licenses'; import { HttpExceptionFilter } from '../../../integration/shared/https-exception.filter'; import { Crud } from '../../crud/src/decorators'; import { CompaniesService } from './__fixture__/companies.service'; import { ProjectsService } from './__fixture__/projects.service'; import { UsersService, UsersService2 } from './__fixture__/users.service'; import { NotesService } from './__fixture__/notes.service'; +import { UserLicenseService } from './__fixture__/user.license.service'; // tslint:disable:max-classes-per-file describe('#crud-typeorm', () => { @@ -163,11 +165,25 @@ describe('#crud-typeorm', () => { constructor(public service: NotesService) {} } + @Crud({ + model: { type: UserLicense }, + query: { + loadRelationIds: { + relations: ['license'], + disableMixedMap: true, + }, + }, + }) + @Controller('user.licenses') + class UserLicenseController { + constructor(public service: UserLicenseService) {} + } + beforeAll(async () => { const fixture = await Test.createTestingModule({ imports: [ TypeOrmModule.forRoot({ ...withCache, logging: false }), - TypeOrmModule.forFeature([Company, Project, User, UserProfile, Note]), + TypeOrmModule.forFeature([Company, Project, User, UserProfile, Note, UserLicense]), ], controllers: [ CompaniesController, @@ -179,6 +195,7 @@ describe('#crud-typeorm', () => { UsersController2, UsersController3, NotesController, + UserLicenseController, ], providers: [ { provide: APP_FILTER, useClass: HttpExceptionFilter }, @@ -187,6 +204,7 @@ describe('#crud-typeorm', () => { UsersService2, ProjectsService, NotesService, + UserLicenseService, ], }).compile(); @@ -376,6 +394,19 @@ describe('#crud-typeorm', () => { }); }); + describe('#query loadRelationIds', () => { + it('should return relation objects with only ids', (done) => { + request(server) + .get('/user.licenses') + .end((_, res) => { + expect(res.status).toBe(200); + expect(res.body[0].license.name).toBeUndefined(); + expect(res.body[0].license.id).toBeDefined(); + done(); + }); + }); + }); + describe('#query nested join', () => { it('should return status 400, 1', (done) => { const query = qb diff --git a/packages/crud/src/interfaces/query-options.interface.ts b/packages/crud/src/interfaces/query-options.interface.ts index cfb9515f..4fa4da9c 100644 --- a/packages/crud/src/interfaces/query-options.interface.ts +++ b/packages/crud/src/interfaces/query-options.interface.ts @@ -1,7 +1,4 @@ -import { - QueryFields, - QuerySort, -} from '@nestjsx/crud-request/lib/types/request-query.types'; +import { QueryFields, QuerySort } from '@nestjsx/crud-request/lib/types/request-query.types'; import { QueryFilterOption } from '../types'; @@ -11,6 +8,7 @@ export interface QueryOptions { persist?: QueryFields; filter?: QueryFilterOption; join?: JoinOptions; + loadRelationIds?: LoadRelationIdsOptions; sort?: QuerySort[]; limit?: number; maxLimit?: number; @@ -32,3 +30,8 @@ export interface JoinOption { select?: false; required?: boolean; } + +export interface LoadRelationIdsOptions { + relations?: string[]; + disableMixedMap?: boolean; +}