diff --git a/CHANGELOG.md b/CHANGELOG.md index a8a9a17..0265f42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.2] - 2022-07-17 + +- Added Not contains (https://github.com/AlexcastroDev/flexysearch/issues/7) + ## [0.1.1] - 2022-07-11 - [Docs] Update docs on NPM diff --git a/interfaces/index.ts b/interfaces/index.ts index 3e7f1c5..fb40dc1 100644 --- a/interfaces/index.ts +++ b/interfaces/index.ts @@ -5,11 +5,13 @@ export type IRuleType = 'string' | 'number'; export enum RuleStringOptions { contains = 'contains', + notContains = 'not_contains', equals = 'equals' } export enum RuleNumberOptions { contains = 'contains', + notContains = 'not_contains', equals = 'equals' } diff --git a/src/tests/numbers.test.ts b/src/tests/numbers.test.ts index 33dc0ca..04a1366 100644 --- a/src/tests/numbers.test.ts +++ b/src/tests/numbers.test.ts @@ -43,6 +43,70 @@ describe('Should match number', () => { } ]); }); + it('[Number]: Not Contains', () => { + const results = new SearchEngine(collection).search([ + { + field: 'year', + term: 2014, + role: RuleNumberOptions.notContains, + type: 'number', + operator: RuleOperator.AND + } + ]); + + expect(results).toStrictEqual([ + { + id: 1, + title: 'Film 1', + year: 2009 + }, + { + id: 2, + title: 'Film 2', + year: 2015 + }, + { + id: 5, + title: 'Film 5', + year: 2001 + }, + { + id: 6, + title: 'Film 6', + year: 2000 + }, + { + id: 7, + title: 'Film 7', + year: 2009 + }, + { + id: 8, + title: 'Film 8', + year: 2015 + }, + { + id: 9, + title: 'Film 9', + year: 2020 + }, + { + id: 10, + title: 'Film 10', + year: 1997 + }, + { + id: 11, + title: 'Film 11', + year: 1992 + }, + { + id: 12, + title: 'Film 12', + year: 1990 + } + ]); + }); it('[Number]: equals', () => { const results = new SearchEngine(collection).search([ { diff --git a/src/tests/strings.test.ts b/src/tests/strings.test.ts index e436ec1..852b8e5 100644 --- a/src/tests/strings.test.ts +++ b/src/tests/strings.test.ts @@ -66,4 +66,58 @@ describe('Should match strings', () => { { id: 6, title: 'Film 6', year: 2000 } ]); }); + it('[String]: Not Contains', () => { + const results = new SearchEngine(collection).search([ + { + field: 'title', + term: 'Film 1', + role: RuleStringOptions.notContains, + type: 'string', + operator: RuleOperator.AND + } + ]); + + expect(results).toStrictEqual([ + { + id: 2, + title: 'Film 2', + year: 2015 + }, + { + id: 3, + title: 'Film 3', + year: 2014 + }, + { + id: 4, + title: 'Film 4', + year: 2014 + }, + { + id: 5, + title: 'Film 5', + year: 2001 + }, + { + id: 6, + title: 'Film 6', + year: 2000 + }, + { + id: 7, + title: 'Film 7', + year: 2009 + }, + { + id: 8, + title: 'Film 8', + year: 2015 + }, + { + id: 9, + title: 'Film 9', + year: 2020 + } + ]); + }); }); diff --git a/src/utils/number.ts b/src/utils/number.ts index 1818757..fbb1051 100644 --- a/src/utils/number.ts +++ b/src/utils/number.ts @@ -14,14 +14,25 @@ export class NumberProcessor { return new RegExp(value, 'gi'); } + private checkContains(valueToBeCompared: string) { + const regexpMatches = ( + String(valueToBeCompared).match(this.getRegexValue(String(this.term))) || [] + ).length; + + if (this.role === RuleNumberOptions.notContains) { + return regexpMatches === 0; + } + + return regexpMatches > 0; + } + compareWith(valueToBeCompared: string) { switch (this.role) { case RuleNumberOptions.equals: return Number(valueToBeCompared) === Number(this.term); case RuleNumberOptions.contains: - return ( - (String(valueToBeCompared).match(this.getRegexValue(String(this.term))) || []).length > 0 - ); + case RuleNumberOptions.notContains: + return this.checkContains(valueToBeCompared); default: throw new Error('[flexysearch]: Invalid role in Numbers'); } diff --git a/src/utils/strings.ts b/src/utils/strings.ts index 2476ed2..e13de43 100644 --- a/src/utils/strings.ts +++ b/src/utils/strings.ts @@ -13,14 +13,25 @@ export class StringProcessor { return new RegExp(value, 'gi'); } + private checkContains(valueToBeCompared: string) { + const regexpMatches = ( + String(valueToBeCompared).match(this.getRegexValue(String(this.term))) || [] + ).length; + + if (this.role === RuleStringOptions.notContains) { + return regexpMatches === 0; + } + + return regexpMatches > 0; + } + compareWith(valueToBeCompared: string) { switch (this.role) { case RuleStringOptions.equals: return String(valueToBeCompared) === this.term; case RuleStringOptions.contains: - return ( - (String(valueToBeCompared).match(this.getRegexValue(String(this.term))) || []).length > 0 - ); + case RuleStringOptions.notContains: + return this.checkContains(valueToBeCompared); default: throw new Error('[flexysearch]: Invalid role in String'); }