diff --git a/packages/crud-request/src/request-query.builder.ts b/packages/crud-request/src/request-query.builder.ts index 89d675fb..a318e00c 100644 --- a/packages/crud-request/src/request-query.builder.ts +++ b/packages/crud-request/src/request-query.builder.ts @@ -6,7 +6,7 @@ import { isString, isUndefined, } from '@dataui/crud-util'; -import { stringify } from 'qs'; +import { IStringifyOptions, stringify } from 'qs'; import { CreateQueryParams, @@ -58,6 +58,11 @@ export class RequestQueryBuilder { private paramNames: { [key in keyof RequestQueryBuilderOptions['paramNamesMap']]: string; } = {}; + private joinConditionString: IStringifyOptions = { + encode: false, + delimiter: this.options.delimStr, + arrayFormat: 'indices', + }; public queryObject: { [key: string]: any } = {}; public queryString: string; @@ -203,13 +208,28 @@ export class RequestQueryBuilder { ); } - private addJoin(j: QueryJoin | QueryJoinArr): string { - const join = Array.isArray(j) ? { field: j[0], select: j[1] } : j; - validateJoin(join); - const d = this.options.delim; - const ds = this.options.delimStr; + private addJoin(join: QueryJoin | QueryJoinArr): string { + const { delim, delimStr } = this.options; + + const normalizedJoin = Array.isArray(join) + ? { field: join[0], select: join[1], on: join[2] } + : join; + + validateJoin(normalizedJoin); + + const conditions = isArrayFull(normalizedJoin.on) + ? { on: normalizedJoin.on.map((condition) => this.cond(condition, 'filter')) } + : ''; + + const fieldPart = normalizedJoin.field; + const selectPart = isArrayFull(normalizedJoin.select) + ? delim + normalizedJoin.select.join(delimStr) + : ''; + const conditionsPart = conditions + ? delim + stringify(conditions, this.joinConditionString) + : ''; - return join.field + (isArrayFull(join.select) ? d + join.select.join(ds) : ''); + return fieldPart + selectPart + conditionsPart; } private addSortBy(s: QuerySort | QuerySortArr): string { diff --git a/packages/crud-request/src/request-query.parser.ts b/packages/crud-request/src/request-query.parser.ts index 055510dd..20f474eb 100644 --- a/packages/crud-request/src/request-query.parser.ts +++ b/packages/crud-request/src/request-query.parser.ts @@ -40,6 +40,7 @@ import { SConditionAND, SFields, } from './types'; +import { IParseOptions, parse } from 'qs'; // tslint:disable:variable-name ban-types export class RequestQueryParser implements ParsedRequestParams { @@ -66,6 +67,10 @@ export class RequestQueryParser implements ParsedRequestParams { private _paramNames: string[]; private _paramsOptions: ParamsOptions; + private _joinConditionParseOptions: IParseOptions = { + delimiter: this._options.delimStr, + }; + private get _options(): RequestQueryBuilderOptions { return RequestQueryBuilder.getOptions(); } @@ -350,12 +355,25 @@ export class RequestQueryParser implements ParsedRequestParams { return condition; } + private parseJoinConditions(conditionsString: string): QueryFilter[] { + const conditions: string[] = parse(conditionsString, this._joinConditionParseOptions)[ + 'on' + ]; + return conditions.map((cond: string) => this.conditionParser('filter', {}, cond)); + } + private joinParser(data: string): QueryJoin { const param = data.split(this._options.delim); + const field = param[0]; + const selectString = param[1]; + const conditions = param.slice(2).join(this._options.delim); + const join: QueryJoin = { - field: param[0], - select: isStringFull(param[1]) ? param[1].split(this._options.delimStr) : undefined, + field, + select: selectString ? selectString.split(this._options.delimStr) : undefined, + on: isStringFull(conditions) ? this.parseJoinConditions(conditions) : undefined, }; + validateJoin(join); return join; diff --git a/packages/crud-request/src/request-query.validator.ts b/packages/crud-request/src/request-query.validator.ts index 0bbbbd8f..57b366aa 100644 --- a/packages/crud-request/src/request-query.validator.ts +++ b/packages/crud-request/src/request-query.validator.ts @@ -1,4 +1,5 @@ import { + isArrayFull, isArrayStrings, isEqual, isNil, @@ -89,6 +90,9 @@ export function validateJoin(join: QueryJoin): void { if (!isUndefined(join.select) && !isArrayStrings(join.select)) { throw new RequestQueryException('Invalid join select. Array of strings expected'); } + if (!isUndefined(join.on) && !isArrayFull(join.on)) { + join.on.map((condition) => validateCondition(condition, 'filter', {})); + } } export function validateSort(sort: QuerySort): void { diff --git a/packages/crud-request/src/types/request-query.types.ts b/packages/crud-request/src/types/request-query.types.ts index 37bcec5c..bbce3ebe 100644 --- a/packages/crud-request/src/types/request-query.types.ts +++ b/packages/crud-request/src/types/request-query.types.ts @@ -11,9 +11,10 @@ export type QueryFilterArr = [string, ComparisonOperator, any?]; export interface QueryJoin { field: string; select?: QueryFields; + on?: QueryFilter[]; } -export type QueryJoinArr = [string, QueryFields?]; +export type QueryJoinArr = [string, QueryFields?, QueryFilter[]?]; export interface QuerySort { field: string; diff --git a/packages/crud-request/test/request-query.builder.spec.ts b/packages/crud-request/test/request-query.builder.spec.ts index fdcf3c8d..c619df96 100644 --- a/packages/crud-request/test/request-query.builder.spec.ts +++ b/packages/crud-request/test/request-query.builder.spec.ts @@ -93,7 +93,10 @@ describe('#request-query', () => { expect(qb.queryObject.filter).toIncludeSameMembers(expected); }); it('should set filter, 4', () => { - qb.setFilter([['foo', 'eq', 'bar'], ['baz', 'ne', 'zoo']]); + qb.setFilter([ + ['foo', 'eq', 'bar'], + ['baz', 'ne', 'zoo'], + ]); const expected = ['foo||eq||bar', 'baz||ne||zoo']; expect(qb.queryObject.filter).toIncludeSameMembers(expected); }); @@ -155,6 +158,15 @@ describe('#request-query', () => { it('should throw an error, 3', () => { expect((qb.setJoin as any).bind(qb, [{}])).toThrowError(RequestQueryException); }); + it('should throw an error, 4', () => { + expect( + (qb.setJoin as any).bind(qb, { + field: 'bar', + select: ['a', 'b', 'c'], + on: [{}], + }), + ).toThrowError(RequestQueryException); + }); it('should set join, 1', () => { qb.setJoin({ field: 'foo' }); const expected = ['foo']; @@ -180,6 +192,40 @@ describe('#request-query', () => { const expected = ['baz', 'foo||a,b,c']; expect(qb.queryObject.join).toIncludeSameMembers(expected); }); + it('should set join, 6', () => { + qb.setJoin([ + ['baz'], + ['foo', ['a', 'b', 'c']], + ['boo', ['a', 'b', 'c'], [{ field: 'bar', operator: 'eq', value: 100 }]], + ]); + const expected = ['baz', 'foo||a,b,c', 'boo||a,b,c||on[0]=bar||eq||100']; + expect(qb.queryObject.join).toIncludeSameMembers(expected); + }); + it('should set join, 7', () => { + qb.setJoin([ + { + field: 'baz', + select: ['a', 'b', 'c'], + on: [{ field: 'bar', operator: 'eq', value: 100 }], + }, + ]); + const expected = ['baz||a,b,c||on[0]=bar||eq||100']; + expect(qb.queryObject.join).toIncludeSameMembers(expected); + }); + it('should set join, 8', () => { + qb.setJoin([ + { + field: 'baz', + select: ['a', 'b', 'c'], + on: [ + { field: 'bar', operator: 'eq', value: 100 }, + { field: 'foo', operator: 'isnull' }, + ], + }, + ]); + const expected = ['baz||a,b,c||on[0]=bar||eq||100,on[1]=foo||isnull']; + expect(qb.queryObject.join).toIncludeSameMembers(expected); + }); }); describe('#sortBy', () => { @@ -206,7 +252,10 @@ describe('#request-query', () => { expect(qb.queryObject.sort).toIncludeSameMembers(expected); }); it('should set sort, 2', () => { - qb.sortBy([{ field: 'foo', order: 'ASC' }, { field: 'bar', order: 'DESC' }]); + qb.sortBy([ + { field: 'foo', order: 'ASC' }, + { field: 'bar', order: 'DESC' }, + ]); const expected = ['foo,ASC', 'bar,DESC']; expect(qb.queryObject.sort).toIncludeSameMembers(expected); }); @@ -329,7 +378,14 @@ describe('#request-query', () => { .select(['foo', 'bar']) .setFilter(['is', 'notnull']) .setOr({ field: 'ok', operator: 'ne', value: false }) - .setJoin({ field: 'voo', select: ['h', 'data'] }) + .setJoin({ + field: 'voo', + select: ['h', 'data'], + on: [ + { field: 'foo', operator: 'eq', value: 'baz' }, + { field: 'bar', operator: 'isnull' }, + ], + }) .setLimit(1) .setOffset(2) .setPage(3) @@ -338,7 +394,7 @@ describe('#request-query', () => { .setIncludeDeleted(1) .query(false); const expected = - 'fields=foo,bar&filter[0]=is||notnull&or[0]=ok||ne||false&join[0]=voo||h,data&limit=1&offset=2&page=3&sort[0]=foo,DESC&cache=0&include_deleted=1'; + 'fields=foo,bar&filter[0]=is||notnull&or[0]=ok||ne||false&join[0]=voo||h,data||on[0]=foo||eq||baz,on[1]=bar||isnull&limit=1&offset=2&page=3&sort[0]=foo,DESC&cache=0&include_deleted=1'; expect(test).toBe(expected); }); }); @@ -375,7 +431,14 @@ describe('#request-query', () => { fields: ['foo', 'bar'], filter: ['is', 'notnull'], or: { field: 'ok', operator: 'ne', value: false }, - join: { field: 'voo', select: ['h', 'data'] }, + join: { + field: 'voo', + select: ['h', 'data'], + on: [ + { field: 'foo', operator: 'eq', value: 'baz' }, + { field: 'bar', operator: 'isnull' }, + ], + }, limit: 1, offset: 2, page: 3, @@ -383,7 +446,7 @@ describe('#request-query', () => { resetCache: true, }).query(false); const expected = - 'fields=foo,bar&filter[0]=is||notnull&or[0]=ok||ne||false&join[0]=voo||h,data&limit=1&offset=2&page=3&sort[0]=foo,DESC&cache=0'; + 'fields=foo,bar&filter[0]=is||notnull&or[0]=ok||ne||false&join[0]=voo||h,data||on[0]=foo||eq||baz,on[1]=bar||isnull&limit=1&offset=2&page=3&sort[0]=foo,DESC&cache=0'; expect(test).toBe(expected); }); it('should return a valid query string, 2', () => { diff --git a/packages/crud-request/test/request-query.parser.spec.ts b/packages/crud-request/test/request-query.parser.spec.ts index 0d7041d4..8f20f649 100644 --- a/packages/crud-request/test/request-query.parser.spec.ts +++ b/packages/crud-request/test/request-query.parser.spec.ts @@ -259,6 +259,32 @@ describe('#request-query', () => { expect(test.join[0]).toMatchObject(expected[0]); expect(test.join[1]).toMatchObject(expected[1]); }); + it('should set array, 3', () => { + const query = { + join: [ + 'foo', + 'bar||baz,boo', + 'bar||baz,boo||on[0]=name||eq||jhon,on[1]=foo||isnull', + ], + }; + const expected: QueryJoin[] = [ + { field: 'foo' }, + { field: 'bar', select: ['baz', 'boo'] }, + { + field: 'bar', + select: ['baz', 'boo'], + on: [ + { field: 'name', operator: 'eq', value: 'jhon' }, + { field: 'foo', operator: 'isnull', value: '' }, + ], + }, + ]; + const test = qp.parseQuery(query); + + expect(test.join[0]).toMatchObject(expected[0]); + expect(test.join[1]).toMatchObject(expected[1]); + expect(test.join[2]).toMatchObject(expected[2]); + }); }); describe('#parse sort', () => { diff --git a/packages/crud-typeorm/src/typeorm-crud.service.ts b/packages/crud-typeorm/src/typeorm-crud.service.ts index 1580f9ec..d5b7c54b 100644 --- a/packages/crud-typeorm/src/typeorm-crud.service.ts +++ b/packages/crud-typeorm/src/typeorm-crud.service.ts @@ -610,6 +610,24 @@ export class TypeOrmCrudService extends CrudService> { } } + private convertArrayToQuery(data: { str: string; params: { [key: string]: any } }[]): { + str: string; + params: { [key: string]: any }; + } { + const queryStringParts: string[] = []; + const params: { [key: string]: any } = {}; + + for (const item of data) { + const { str, params: itemParams } = item; + queryStringParts.push(str); + Object.assign(params, itemParams); + } + + const combinedString = queryStringParts.join(' AND '); + + return { str: combinedString, params }; + } + protected setJoin( cond: QueryJoin, joinOptions: JoinOptions, @@ -637,7 +655,15 @@ export class TypeOrmCrudService extends CrudService> { const relationType = options.required ? 'innerJoin' : 'leftJoin'; const alias = options.alias ? options.alias : allowedRelation.name; - builder[relationType](allowedRelation.path, alias); + if (cond.on) { + const conds = cond.on.map((condition, i) => + this.mapOperatorsToQuery(condition, `andCondition${i}`, {}), + ); + const { str, params } = this.convertArrayToQuery(conds); + builder[relationType](allowedRelation.path, alias, str, params); + } else { + builder[relationType](allowedRelation.path, alias); + } if (options.select !== false) { const columns = isArrayFull(cond.select) diff --git a/packages/crud-typeorm/test/__fixture__/UserProfile.service.ts b/packages/crud-typeorm/test/__fixture__/UserProfile.service.ts new file mode 100644 index 00000000..b77a0da4 --- /dev/null +++ b/packages/crud-typeorm/test/__fixture__/UserProfile.service.ts @@ -0,0 +1,12 @@ +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; + +import { TypeOrmCrudService } from '../../src/typeorm-crud.service'; +import { UserProfile } from '../../../../integration/crud-typeorm/users-profiles'; + +@Injectable() +export class UserProfilesService extends TypeOrmCrudService { + constructor(@InjectRepository(UserProfile) 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 ee22b0ca..ba8a8f29 100644 --- a/packages/crud-typeorm/test/b.query-params.spec.ts +++ b/packages/crud-typeorm/test/b.query-params.spec.ts @@ -18,6 +18,7 @@ import { CompaniesService } from './__fixture__/companies.service'; import { NotesService } from './__fixture__/notes.service'; import { ProjectsService } from './__fixture__/projects.service'; import { UsersService, UsersService2 } from './__fixture__/users.service'; +import { UserProfilesService } from './__fixture__/UserProfile.service'; // tslint:disable:max-classes-per-file describe('#crud-typeorm', () => { @@ -166,6 +167,19 @@ describe('#crud-typeorm', () => { constructor(public service: UsersService2) {} } + @Crud({ + model: { type: UserProfile }, + query: { + join: { + user: {}, + }, + }, + }) + @Controller('profiles') + class UserProfilesController { + constructor(public service: UserProfilesService) {} + } + @Crud({ model: { type: Note }, }) @@ -189,6 +203,7 @@ describe('#crud-typeorm', () => { UsersController, UsersController2, UsersController3, + UserProfilesController, NotesController, ], providers: [ @@ -197,6 +212,7 @@ describe('#crud-typeorm', () => { UsersService, UsersService2, ProjectsService, + UserProfilesService, NotesService, ], }).compile(); @@ -375,6 +391,24 @@ describe('#crud-typeorm', () => { done(); }); }); + it('should return joined entity, 3', (done) => { + const query = qb + .setJoin({ + field: 'user', + select: ['email'], + on: [{ field: 'user.id', operator: '$eq', value: 1 }], + }) + .query(); + return request(server) + .get('/profiles') + .query(query) + .end((_, res) => { + expect(res.status).toBe(200); + expect(res.body.length).not.toBe(0); + expect(res.body[0].user).toBeDefined(); + done(); + }); + }); it('should eager join without selection', (done) => { const query = qb.search({ 'userCompany.id': { $eq: 1 } }).query(); return request(server) @@ -543,10 +577,7 @@ describe('#crud-typeorm', () => { describe('#sort', () => { it('should sort by field', async () => { const query = qb.sortBy({ field: 'id', order: 'DESC' }).query(); - const res = await request(server) - .get('/users') - .query(query) - .expect(200); + const res = await request(server).get('/users').query(query).expect(200); expect(res.body[1].id).toBeLessThan(res.body[0].id); }); @@ -556,10 +587,7 @@ describe('#crud-typeorm', () => { .setJoin({ field: 'company' }) .sortBy({ field: 'company.id', order: 'DESC' }) .query(); - const res = await request(server) - .get('/users') - .query(query) - .expect(200); + const res = await request(server).get('/users').query(query).expect(200); expect(res.body[res.body.length - 1].company.id).toBeLessThan( res.body[0].company.id, ); @@ -574,10 +602,7 @@ describe('#crud-typeorm', () => { .setJoin({ field: 'company.projects' }) .sortBy({ field: 'projects.id', order: 'DESC' }) .query(); - const res = await request(server) - .get('/users') - .query(query) - .expect(200); + const res = await request(server).get('/users').query(query).expect(200); expect(res.body[0].company.projects[1].id).toBeLessThan( res.body[0].company.projects[0].id, ); @@ -592,10 +617,7 @@ describe('#crud-typeorm', () => { .setJoin({ field: 'company.projects' }) .sortBy({ field: 'company.projects.id', order: 'DESC' }) .query(); - const res = await request(server) - .get('/users') - .query(query) - .expect(200); + const res = await request(server).get('/users').query(query).expect(200); expect(res.body[0].company.projects[1].id).toBeLessThan( res.body[0].company.projects[0].id, ); @@ -626,57 +648,43 @@ describe('#crud-typeorm', () => { it('should return with search, 1', async () => { const query = qb.search({ id: 1 }).query(); - const res = await projects2() - .query(query) - .expect(200); + const res = await projects2().query(query).expect(200); expect(res.body).toBeArrayOfSize(1); expect(res.body[0].id).toBe(1); }); it('should return with search, 2', async () => { const query = qb.search({ id: 1, name: 'Project1' }).query(); - const res = await projects2() - .query(query) - .expect(200); + const res = await projects2().query(query).expect(200); expect(res.body).toBeArrayOfSize(1); expect(res.body[0].id).toBe(1); }); it('should return with search, 3', async () => { const query = qb.search({ id: 1, name: { $eq: 'Project1' } }).query(); - const res = await projects2() - .query(query) - .expect(200); + const res = await projects2().query(query).expect(200); expect(res.body).toBeArrayOfSize(1); expect(res.body[0].id).toBe(1); }); it('should return with search, 4', async () => { const query = qb.search({ name: { $eq: 'Project1' } }).query(); - const res = await projects2() - .query(query) - .expect(200); + const res = await projects2().query(query).expect(200); expect(res.body).toBeArrayOfSize(1); expect(res.body[0].id).toBe(1); }); it('should return with search, 5', async () => { const query = qb.search({ id: { $notnull: true, $eq: 1 } }).query(); - const res = await projects2() - .query(query) - .expect(200); + const res = await projects2().query(query).expect(200); expect(res.body).toBeArrayOfSize(1); expect(res.body[0].id).toBe(1); }); it('should return with search, 6', async () => { const query = qb.search({ id: { $or: { $isnull: true, $eq: 1 } } }).query(); - const res = await projects2() - .query(query) - .expect(200); + const res = await projects2().query(query).expect(200); expect(res.body).toBeArrayOfSize(1); expect(res.body[0].id).toBe(1); }); it('should return with search, 7', async () => { const query = qb.search({ id: { $or: { $eq: 1 } } }).query(); - const res = await projects2() - .query(query) - .expect(200); + const res = await projects2().query(query).expect(200); expect(res.body).toBeArrayOfSize(1); expect(res.body[0].id).toBe(1); }); @@ -684,77 +692,59 @@ describe('#crud-typeorm', () => { const query = qb .search({ id: { $notnull: true, $or: { $eq: 1, $in: [30, 31] } } }) .query(); - const res = await projects2() - .query(query) - .expect(200); + const res = await projects2().query(query).expect(200); expect(res.body).toBeArrayOfSize(1); expect(res.body[0].id).toBe(1); }); it('should return with search, 9', async () => { const query = qb.search({ id: { $notnull: true, $or: { $eq: 1 } } }).query(); - const res = await projects2() - .query(query) - .expect(200); + const res = await projects2().query(query).expect(200); expect(res.body).toBeArrayOfSize(1); expect(res.body[0].id).toBe(1); }); it('should return with search, 10', async () => { const query = qb.search({ id: null }).query(); - const res = await projects2() - .query(query) - .expect(200); + const res = await projects2().query(query).expect(200); expect(res.body).toBeArrayOfSize(0); }); it('should return with search, 11', async () => { const query = qb .search({ $and: [{ id: { $notin: [5, 6, 7, 8, 9, 10] } }, { isActive: true }] }) .query(); - const res = await projects2() - .query(query) - .expect(200); + const res = await projects2().query(query).expect(200); expect(res.body).toBeArrayOfSize(4); }); it('should return with search, 12', async () => { const query = qb .search({ $and: [{ id: { $notin: [5, 6, 7, 8, 9, 10] } }] }) .query(); - const res = await projects2() - .query(query) - .expect(200); + const res = await projects2().query(query).expect(200); expect(res.body).toBeArrayOfSize(14); }); it('should return with search, 13', async () => { const query = qb.search({ $or: [{ id: 54 }] }).query(); - const res = await projects2() - .query(query) - .expect(200); + const res = await projects2().query(query).expect(200); expect(res.body).toBeArrayOfSize(0); }); it('should return with search, 14', async () => { const query = qb .search({ $or: [{ id: 54 }, { id: 33 }, { id: { $in: [1, 2] } }] }) .query(); - const res = await projects2() - .query(query) - .expect(200); + const res = await projects2().query(query).expect(200); expect(res.body).toBeArrayOfSize(2); expect(res.body[0].id).toBe(1); expect(res.body[1].id).toBe(2); }); it('should return with search, 15', async () => { const query = qb.search({ $or: [{ id: 54 }], name: 'Project1' }).query(); - const res = await projects2() - .query(query) - .expect(200); + const res = await projects2().query(query).expect(200); expect(res.body).toBeArrayOfSize(0); }); it('should return with search, 16', async () => { const query = qb .search({ $or: [{ isActive: false }, { id: 3 }], name: 'Project3' }) .query(); - const res = await projects2() - .query(query) - .expect(200); + const res = await projects2().query(query).expect(200); expect(res.body).toBeArrayOfSize(1); expect(res.body[0].id).toBe(3); }); @@ -762,9 +752,7 @@ describe('#crud-typeorm', () => { const query = qb .search({ $or: [{ isActive: false }, { id: { $eq: 3 } }], name: 'Project3' }) .query(); - const res = await projects2() - .query(query) - .expect(200); + const res = await projects2().query(query).expect(200); expect(res.body).toBeArrayOfSize(1); expect(res.body[0].id).toBe(3); }); @@ -775,9 +763,7 @@ describe('#crud-typeorm', () => { name: { $eq: 'Project3' }, }) .query(); - const res = await projects2() - .query(query) - .expect(200); + const res = await projects2().query(query).expect(200); expect(res.body).toBeArrayOfSize(1); expect(res.body[0].id).toBe(3); }); @@ -796,9 +782,7 @@ describe('#crud-typeorm', () => { ], }) .query(); - const res = await projects2() - .query(query) - .expect(200); + const res = await projects2().query(query).expect(200); expect(res.body).toBeArrayOfSize(1); expect(res.body[0].id).toBe(3); }); @@ -808,145 +792,106 @@ describe('#crud-typeorm', () => { $not: [{ id: { $in: [5, 6, 7, 8, 9, 10] } }, { name: { $notnull: true } }], }) .query(); - const res = await projects2() - .query(query) - .expect(200); + const res = await projects2().query(query).expect(200); expect(res.body).toBeArrayOfSize(14); }); it('should return with search, 21', async () => { const query = qb - .search({ name: { $eq: 'Project1' }, companyId: { $or: { $notnull: true, $eq: 1 } } }) + .search({ + name: { $eq: 'Project1' }, + companyId: { $or: { $notnull: true, $eq: 1 } }, + }) .query(); - const res = await projects2() - .query(query) - .expect(200); + const res = await projects2().query(query).expect(200); expect(res.body).toBeArrayOfSize(1); expect(res.body[0].id).toBe(1); }); it('should return with default filter, 1', async () => { const query = qb.search({ name: 'Project11' }).query(); - const res = await projects3() - .query(query) - .expect(200); + const res = await projects3().query(query).expect(200); expect(res.body).toBeArrayOfSize(1); expect(res.body[0].id).toBe(11); }); it('should return with default filter, 2', async () => { const query = qb.search({ name: 'Project1' }).query(); - const res = await projects3() - .query(query) - .expect(200); + const res = await projects3().query(query).expect(200); expect(res.body).toBeArrayOfSize(0); }); it('should return with default filter, 3', async () => { const query = qb.search({ name: 'Project2' }).query(); - const res = await projects4() - .query(query) - .expect(200); + const res = await projects4().query(query).expect(200); expect(res.body).toBeArrayOfSize(1); expect(res.body[0].id).toBe(2); }); it('should return with default filter, 4', async () => { const query = qb.search({ name: 'Project11' }).query(); - const res = await projects4() - .query(query) - .expect(200); + const res = await projects4().query(query).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); + 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); + 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); + 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: 'AiN10' } }).query(); - const res = await request(server) - .get('/companies') - .query(query) - .expect(200); + const res = await request(server).get('/companies').query(query).expect(200); expect(res.body).toBeArrayOfSize(1); expect(res.body[0].domain).toBe('Domain10'); }); 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); + 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); + 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); + 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); + const res = await projects4().query(query).expect(200); expect(res.body).toBeArrayOfSize(7); }); it('should return with custom $customEqual search operator', async () => { const query = qb.search({ name: { $customEqual: 'Project7' } }).query(); - const res = await projects4() - .query(query) - .expect(200); + const res = await projects4().query(query).expect(200); expect(res.body[0].id).toBe(7); }); it('should return with custom $customArrayIn search operator', async () => { const query = qb .search({ name: { $customArrayIn: ['Project7', 'Project8', 'Project9'] } }) .query(); - const res = await projects4() - .query(query) - .expect(200); + const res = await projects4().query(query).expect(200); expect(res.body).toBeArrayOfSize(3); }); it("should throw an exception if custom search operator doesn't exist", async () => { const query = qb .search({ name: { $inexistentOperator: ['project7', 'project8', 'project9'] } }) .query(); - const res = projects4() - .query(query) - .expect(500); + const res = projects4().query(query).expect(500); }); it('should search by display column name, but use dbName in sql query', async () => { const query = qb.search({ revisionId: 2 }).query(); - const res = await request(server) - .get('/notes') - .query(query) - .expect(200); + const res = await request(server).get('/notes').query(query).expect(200); expect(res.body).toBeArrayOfSize(2); expect(res.body[0].revisionId).toBe(2); expect(res.body[1].revisionId).toBe(2); @@ -955,14 +900,9 @@ describe('#crud-typeorm', () => { describe('#update', () => { it('should update company id of project', async () => { - await request(server) - .patch('/projects/18') - .send({ companyId: 10 }) - .expect(200); - - const modified = await request(server) - .get('/projects/18') - .expect(200); + await request(server).patch('/projects/18').send({ companyId: 10 }).expect(200); + + const modified = await request(server).get('/projects/18').expect(200); expect(modified.body.companyId).toBe(10); });