diff --git a/README.md b/README.md index 1298187..c2d4e4f 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ This library allows you to transfrom automatically Express.js _req.query_ into T ## How it works? -![](typeorm-express-pipeline.png) +![](https://raw.githubusercontent.com/rjlopezdev/typeorm-express-query-builder/master/typeorm-express-pipeline.png) ## Usage @@ -118,6 +118,11 @@ __gte__ | Return entries with value greater than or equal to provided | `foo__gt __in__ | Return entries that match with values in list | `foo__in=admin,common` __between__ | Return entries in range | `foo__between=1,27` +**Notice**: you can use negative logic prefixing lookup with `__not`. + +*Example:* +`foo__not__contains=value` + ## Options | Option | Default | Behaviour | Example | diff --git a/package.json b/package.json index 8a82262..2fc7e24 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "typeorm-express-query-builder", - "version": "1.0.1", + "version": "1.1.1", "description": "Easily transform an Express req.query into TypeORM query", "main": "index.js", "scripts": { diff --git a/src/field-filter.ts b/src/field-filter.ts index 919c3ad..32ee055 100644 --- a/src/field-filter.ts +++ b/src/field-filter.ts @@ -1,11 +1,14 @@ import { AbstractFilter } from './filter'; import { LookupFilter } from './lookup.enum'; -import { Like, IsNull, LessThan, LessThanOrEqual, MoreThan, MoreThanOrEqual, In, Between } from 'typeorm'; +import { Like, IsNull, LessThan, LessThanOrEqual, MoreThan, MoreThanOrEqual, In, Between, Not } from 'typeorm'; export class FieldFilter extends AbstractFilter { - constructor(query: any, prop: string, lookup: LookupFilter, value: string) { + private notOperator: boolean; + + constructor(query: any, prop: string, lookup: LookupFilter, value: string, notOperator: boolean = false) { super(query, prop, lookup, value); + this.notOperator = notOperator; } public buildQuery() { @@ -48,6 +51,9 @@ export class FieldFilter extends AbstractFilter { queryToAdd = { [this.prop]: Between(+rangeValues[0], +rangeValues[1]) }; break; } + if(this.notOperator) { + queryToAdd[this.prop] = Not(queryToAdd[this.prop]); + } this.query['where'] = { ...this.query['where'], ...queryToAdd diff --git a/src/filter-factory.ts b/src/filter-factory.ts index 0a3d69c..089ac13 100644 --- a/src/filter-factory.ts +++ b/src/filter-factory.ts @@ -7,10 +7,11 @@ export class FilterFactory { public get(query: any, key: string, value: string): AbstractFilter { if (this.isFieldFilter(key)) { const field = key.split(LookupDelimiter.LOOKUP_DELIMITER)[0]; + const notQuery = key.includes(`${LookupDelimiter.LOOKUP_DELIMITER}${LookupFilter.NOT}`); const lookup = key.includes(LookupDelimiter.LOOKUP_DELIMITER) - ? key.split(LookupDelimiter.LOOKUP_DELIMITER)[1] as LookupFilter + ? key.split(LookupDelimiter.LOOKUP_DELIMITER)[notQuery ? 2 : 1] as LookupFilter : LookupFilter.EXACT; - return new FieldFilter(query, field, lookup, value); + return new FieldFilter(query, field, lookup, value, notQuery); } } diff --git a/src/lookup.enum.ts b/src/lookup.enum.ts index f65b2dc..03ac090 100644 --- a/src/lookup.enum.ts +++ b/src/lookup.enum.ts @@ -9,7 +9,8 @@ export enum LookupFilter { STARTS_WITH = 'startswith', ENDS_WITH = 'endswith', IN = 'in', - BETWEEN = 'between' + BETWEEN = 'between', + NOT = 'not', } export enum LookupDelimiter { diff --git a/test/unit/field-filter.spec.ts b/test/unit/field-filter.spec.ts index 74ae710..3180944 100644 --- a/test/unit/field-filter.spec.ts +++ b/test/unit/field-filter.spec.ts @@ -1,4 +1,4 @@ -import { Like, IsNull, MoreThan, MoreThanOrEqual, LessThanOrEqual, LessThan, Between, In } from 'typeorm'; +import { Like, IsNull, MoreThan, MoreThanOrEqual, LessThanOrEqual, LessThan, Between, In, Not } from 'typeorm'; import { FieldFilter } from '../../src/field-filter'; import { LookupFilter } from '../../src/lookup.enum'; @@ -72,4 +72,10 @@ describe('Test FieldFilter #buildQuery', () => { expect(built['where']['name']).toEqual(In(['1', '2', '3', '4', 'foo'])); }); + it('should return a filter', () => { + const fieldFilter = new FieldFilter(built, 'name', LookupFilter.EXACT, 'value', true); + fieldFilter.buildQuery(); + expect(built['where']['name']).toEqual(Not('value')); + }); + }); diff --git a/test/unit/filter-factory.spec.ts b/test/unit/filter-factory.spec.ts index 0c83463..25929bd 100644 --- a/test/unit/filter-factory.spec.ts +++ b/test/unit/filter-factory.spec.ts @@ -9,6 +9,18 @@ describe('Test FilterFactory #get', () => { const filter = factory.get({}, 'field', 'value'); expect(filter).toBeInstanceOf(FieldFilter); }); + + it('should return an instance of FieldFilter with notOperator equals to true', () => { + const filter = factory.get({}, 'field__not', 'value') as any; + expect(filter).toBeInstanceOf(FieldFilter); + expect(filter.notOperator).toBeTruthy(); + }); + + it('should return an instance of FieldFilter with notOperator equals to false', () => { + const filter = factory.get({}, 'field', 'value') as any; + expect(filter).toBeInstanceOf(FieldFilter); + expect(filter.notOperator).toBeFalsy(); + }); })