diff --git a/packages/query-typegoose/__tests__/services/typegoose-query.service.spec.ts b/packages/query-typegoose/__tests__/services/typegoose-query.service.spec.ts index 42c8ed869..57fdce755 100644 --- a/packages/query-typegoose/__tests__/services/typegoose-query.service.spec.ts +++ b/packages/query-typegoose/__tests__/services/typegoose-query.service.spec.ts @@ -35,10 +35,94 @@ describe('TypegooseQueryService', () => { describe('#query', () => { it('call find and return the result', async () => { + const queryService = moduleRef.get(TestEntityService); + const queryResult = await queryService.query({}); + return expect(queryResult).toHaveLength(TEST_ENTITIES.length); + }); + + it('should support eq operator', async () => { const queryService = moduleRef.get(TestEntityService); const queryResult = await queryService.query({ filter: { stringType: { eq: 'foo1' } } }); return expect(queryResult).toEqual([TEST_ENTITIES[0]]); }); + + it('should support neq operator', async () => { + const queryService = moduleRef.get(TestEntityService); + const queryResult = await queryService.query({ filter: { stringType: { neq: 'foo1' } } }); + return expect(queryResult).toHaveLength(TEST_ENTITIES.length - 1); + }); + + it('should support gt operator', async () => { + const queryService = moduleRef.get(TestEntityService); + const queryResult = await queryService.query({ filter: { numberType: { gt: 5 } } }); + return expect(queryResult).toHaveLength(TEST_ENTITIES.length - 5); + }); + + it('should support gte operator', async () => { + const queryService = moduleRef.get(TestEntityService); + const queryResult = await queryService.query({ filter: { numberType: { gte: 5 } } }); + return expect(queryResult).toHaveLength(TEST_ENTITIES.length - 4); + }); + + it('should support lt operator', async () => { + const queryService = moduleRef.get(TestEntityService); + const queryResult = await queryService.query({ filter: { numberType: { lt: 10 } } }); + return expect(queryResult).toHaveLength(9); + }); + + it('should support lte operator', async () => { + const queryService = moduleRef.get(TestEntityService); + const queryResult = await queryService.query({ filter: { numberType: { lte: 10 } } }); + return expect(queryResult).toHaveLength(10); + }); + + it('should support in operator', async () => { + const queryService = moduleRef.get(TestEntityService); + const queryResult = await queryService.query({ filter: { numberType: { in: [1, 2, 3] } } }); + return expect(queryResult).toEqual([TEST_ENTITIES[0], TEST_ENTITIES[1], TEST_ENTITIES[2]]); + }); + + it('should support notIn operator', async () => { + const queryService = moduleRef.get(TestEntityService); + const queryResult = await queryService.query({ filter: { numberType: { notIn: [1, 2, 3] } } }); + return expect(queryResult).toHaveLength(12); + }); + + it('should support is operator', async () => { + const queryService = moduleRef.get(TestEntityService); + const queryResult = await queryService.query({ filter: { boolType: { is: true } } }); + return expect(queryResult).toHaveLength(7); + }); + + it('should support isNot operator', async () => { + const queryService = moduleRef.get(TestEntityService); + const queryResult = await queryService.query({ filter: { boolType: { isNot: true } } }); + return expect(queryResult).toHaveLength(8); + }); + + it('should support like operator', async () => { + const queryService = moduleRef.get(TestEntityService); + const queryResult = await queryService.query({ filter: { stringType: { like: 'foo%' } } }); + return expect(queryResult).toHaveLength(15); + }); + + it('should support notLike operator', async () => { + const queryService = moduleRef.get(TestEntityService); + const queryResult = await queryService.query({ filter: { stringType: { notLike: 'foo%' } } }); + return expect(queryResult).toHaveLength(0); + }); + + it('should support iLike operator', async () => { + const queryService = moduleRef.get(TestEntityService); + const queryResult = await queryService.query({ filter: { stringType: { iLike: 'FOO%' } } }); + return expect(queryResult).toHaveLength(15); + }); + + it('should support notILike operator', async () => { + const queryService = moduleRef.get(TestEntityService); + const queryResult = await queryService.query({ filter: { stringType: { notILike: 'FOO%' } } }); + return expect(queryResult).toHaveLength(0); + }); }); describe('#count', () => { diff --git a/packages/query-typegoose/package.json b/packages/query-typegoose/package.json index f04872f0b..5b7ed61bb 100644 --- a/packages/query-typegoose/package.json +++ b/packages/query-typegoose/package.json @@ -19,8 +19,7 @@ }, "dependencies": { "@nestjs-query/core": "0.18.1", - "lodash.filter": "^4.6.0", - "lodash.omit": "^4.5.0" + "lodash.escaperegexp": "^4.1.2" }, "peerDependencies": { "@nestjs/common": "^7.0.0", @@ -33,8 +32,7 @@ "@nestjs/common": "7.4.2", "@nestjs/testing": "7.4.2", "@typegoose/typegoose": "^7.3.3", - "@types/lodash.filter": "4.6.6", - "@types/lodash.omit": "4.5.6", + "@types/lodash.escaperegexp": "^4.1.6", "@types/mongodb": "^3.5.26", "@types/mongoose": "^5.7.36", "class-transformer": "0.3.1", diff --git a/packages/query-typegoose/src/services/typegoose-query.service.ts b/packages/query-typegoose/src/services/typegoose-query.service.ts index a2616cb46..55b0f7f47 100644 --- a/packages/query-typegoose/src/services/typegoose-query.service.ts +++ b/packages/query-typegoose/src/services/typegoose-query.service.ts @@ -12,6 +12,7 @@ import { import { Logger, NotFoundException } from '@nestjs/common'; import { FilterQuery, UpdateQuery } from 'mongoose'; import { ReturnModelType } from '@typegoose/typegoose'; +import escapeRegExp from 'lodash.escaperegexp'; const mongoOperatorMapper: { [k: string]: string } = { eq: '$eq', @@ -22,6 +23,8 @@ const mongoOperatorMapper: { [k: string]: string } = { lte: '$lte', in: '$in', notIn: '$nin', + is: '$eq', + isNot: '$ne', }; /** @@ -64,6 +67,20 @@ export class TypegooseQueryService implements QueryService { [mongoOperatorMapper[fieldKey]]: fieldValue, }; } + if (['like', 'notLike', 'iLike', 'notILike'].includes(fieldKey)) { + const regExpStr = (escapeRegExp as (str: string) => string)(fieldValue as string).replace('%', '.*'); + const regExp = new RegExp(regExpStr, fieldKey.toLowerCase().includes('ilike') ? 'i' : undefined); + if (fieldKey.startsWith('not')) { + return { + ...prevCondition, + $not: { $regex: regExp }, + }; + } + return { + ...prevCondition, + $regex: regExp, + }; + } this.logger.error(`Operator ${fieldKey} not supported yet`); return prevCondition; },