Browse Source

feat: allows to combine operators

e22m4u 1 month ago
parent
commit
7d8e85a766
3 changed files with 95 additions and 82 deletions
  1. 31 22
      dist/cjs/index.cjs
  2. 38 48
      src/filter/operator-clause-tool.js
  3. 26 12
      src/filter/operator-clause-tool.spec.js

+ 31 - 22
dist/cjs/index.cjs

@@ -738,28 +738,37 @@ var init_operator_clause_tool = __esm({
             "The first argument of OperatorUtils.testAll should be an Object, but %v was given.",
             "The first argument of OperatorUtils.testAll should be an Object, but %v was given.",
             clause
             clause
           );
           );
-        const eqNeqTest = this.testEqNeq(clause, value);
-        if (eqNeqTest !== void 0) return eqNeqTest;
-        const gtLtTest = this.testGtLt(clause, value);
-        if (gtLtTest !== void 0) return gtLtTest;
-        const incTest = this.testInq(clause, value);
-        if (incTest !== void 0) return incTest;
-        const ninTest = this.testNin(clause, value);
-        if (ninTest !== void 0) return ninTest;
-        const betweenTest = this.testBetween(clause, value);
-        if (betweenTest !== void 0) return betweenTest;
-        const existsTest = this.testExists(clause, value);
-        if (existsTest !== void 0) return existsTest;
-        const likeTest = this.testLike(clause, value);
-        if (likeTest !== void 0) return likeTest;
-        const nlikeTest = this.testNlike(clause, value);
-        if (nlikeTest !== void 0) return nlikeTest;
-        const ilikeTest = this.testIlike(clause, value);
-        if (ilikeTest !== void 0) return ilikeTest;
-        const nilikeTest = this.testNilike(clause, value);
-        if (nilikeTest !== void 0) return nilikeTest;
-        const regExpTest = this.testRegexp(clause, value);
-        if (regExpTest !== void 0) return regExpTest;
+        const operatorMap = {
+          eq: this.testEqNeq,
+          neq: this.testEqNeq,
+          gt: this.testGtLt,
+          gte: this.testGtLt,
+          lt: this.testGtLt,
+          lte: this.testGtLt,
+          inq: this.testInq,
+          nin: this.testNin,
+          between: this.testBetween,
+          exists: this.testExists,
+          like: this.testLike,
+          nlike: this.testNlike,
+          ilike: this.testIlike,
+          nilike: this.testNilike,
+          regexp: this.testRegexp
+        };
+        const clauseKeys = Object.keys(clause);
+        const knownOperators = clauseKeys.filter((key) => operatorMap[key]);
+        if (knownOperators.length === 0) {
+          return void 0;
+        }
+        return knownOperators.every((op) => {
+          const singleOpClause = { [op]: clause[op] };
+          if (op === "regexp" && "flags" in clause) {
+            singleOpClause.flags = clause.flags;
+          }
+          const testFn = operatorMap[op];
+          const result = testFn.call(this, singleOpClause, value);
+          return result;
+        });
       }
       }
       /**
       /**
        * Test eq/neq operator.
        * Test eq/neq operator.

+ 38 - 48
src/filter/operator-clause-tool.js

@@ -63,54 +63,44 @@ export class OperatorClauseTool extends Service {
           'should be an Object, but %v was given.',
           'should be an Object, but %v was given.',
         clause,
         clause,
       );
       );
-
-    // {eq: ...}
-    // {neq: ...}
-    const eqNeqTest = this.testEqNeq(clause, value);
-    if (eqNeqTest !== undefined) return eqNeqTest;
-
-    // {gt: ...}
-    // {gte: ...}
-    // {lt: ...}
-    // {lte: ...}
-    const gtLtTest = this.testGtLt(clause, value);
-    if (gtLtTest !== undefined) return gtLtTest;
-
-    // {inc: ...}
-    const incTest = this.testInq(clause, value);
-    if (incTest !== undefined) return incTest;
-
-    // {nin: ...}
-    const ninTest = this.testNin(clause, value);
-    if (ninTest !== undefined) return ninTest;
-
-    // {between: ...}
-    const betweenTest = this.testBetween(clause, value);
-    if (betweenTest !== undefined) return betweenTest;
-
-    // {exists: ...}
-    const existsTest = this.testExists(clause, value);
-    if (existsTest !== undefined) return existsTest;
-
-    // {like: ...}
-    const likeTest = this.testLike(clause, value);
-    if (likeTest !== undefined) return likeTest;
-
-    // {nlike: ...}
-    const nlikeTest = this.testNlike(clause, value);
-    if (nlikeTest !== undefined) return nlikeTest;
-
-    // {ilike: ...}
-    const ilikeTest = this.testIlike(clause, value);
-    if (ilikeTest !== undefined) return ilikeTest;
-
-    // {nilike: ...}
-    const nilikeTest = this.testNilike(clause, value);
-    if (nilikeTest !== undefined) return nilikeTest;
-
-    // {regexp: ...}
-    const regExpTest = this.testRegexp(clause, value);
-    if (regExpTest !== undefined) return regExpTest;
+    const operatorMap = {
+      eq: this.testEqNeq,
+      neq: this.testEqNeq,
+      gt: this.testGtLt,
+      gte: this.testGtLt,
+      lt: this.testGtLt,
+      lte: this.testGtLt,
+      inq: this.testInq,
+      nin: this.testNin,
+      between: this.testBetween,
+      exists: this.testExists,
+      like: this.testLike,
+      nlike: this.testNlike,
+      ilike: this.testIlike,
+      nilike: this.testNilike,
+      regexp: this.testRegexp,
+    };
+    const clauseKeys = Object.keys(clause);
+    // поиск ключей, которые являются известными операторами
+    const knownOperators = clauseKeys.filter(key => operatorMap[key]);
+    // если в объекте clause нет ни одного известного оператора,
+    // то возвращается undefined, чтобы _test() продолжил сравнение
+    if (knownOperators.length === 0) {
+      return undefined;
+    }
+    // проверка каждого из операторов
+    return knownOperators.every(op => {
+      // временный объект с текущим оператором для передачи в тестер
+      const singleOpClause = {[op]: clause[op]};
+      // обработка для regexp, для передачи флагов
+      if (op === 'regexp' && 'flags' in clause) {
+        singleOpClause.flags = clause.flags;
+      }
+      // вызов тестера с передачей контекста
+      const testFn = operatorMap[op];
+      const result = testFn.call(this, singleOpClause, value);
+      return result;
+    });
   }
   }
 
 
   /**
   /**

+ 26 - 12
src/filter/operator-clause-tool.spec.js

@@ -47,14 +47,14 @@ describe('OperatorClauseTool', function () {
   });
   });
 
 
   describe('testAll', function () {
   describe('testAll', function () {
-    it('tests "eq" and "neq" operators', function () {
+    it('should test "eq" and "neq" operators', function () {
       expect(S.testAll({eq: 10}, 10)).to.be.true;
       expect(S.testAll({eq: 10}, 10)).to.be.true;
       expect(S.testAll({eq: 10}, 9)).to.be.false;
       expect(S.testAll({eq: 10}, 9)).to.be.false;
       expect(S.testAll({neq: 10}, 9)).to.be.true;
       expect(S.testAll({neq: 10}, 9)).to.be.true;
       expect(S.testAll({neq: 10}, 10)).to.be.false;
       expect(S.testAll({neq: 10}, 10)).to.be.false;
     });
     });
 
 
-    it('tests "gt", "gte", "lt" and "lte" operators', function () {
+    it('should test "gt", "gte", "lt" and "lte" operators', function () {
       expect(S.testAll({gt: 5}, 6)).to.be.true;
       expect(S.testAll({gt: 5}, 6)).to.be.true;
       expect(S.testAll({gte: 5}, 5)).to.be.true;
       expect(S.testAll({gte: 5}, 5)).to.be.true;
       expect(S.testAll({lt: 5}, 4)).to.be.true;
       expect(S.testAll({lt: 5}, 4)).to.be.true;
@@ -65,54 +65,68 @@ describe('OperatorClauseTool', function () {
       expect(S.testAll({lte: 5}, 6)).to.be.false;
       expect(S.testAll({lte: 5}, 6)).to.be.false;
     });
     });
 
 
-    it('tests the "inq" operator', function () {
+    it('should test the "inq" operator', function () {
       expect(S.testAll({inq: [1, 2, 3]}, 2)).to.be.true;
       expect(S.testAll({inq: [1, 2, 3]}, 2)).to.be.true;
       expect(S.testAll({inq: [1, 2, 3]}, 'a')).to.be.false;
       expect(S.testAll({inq: [1, 2, 3]}, 'a')).to.be.false;
     });
     });
 
 
-    it('tests the "nin" operator', function () {
+    it('should test the "nin" operator', function () {
       expect(S.testAll({nin: [1, 2, 3]}, 'a')).to.be.true;
       expect(S.testAll({nin: [1, 2, 3]}, 'a')).to.be.true;
       expect(S.testAll({nin: [1, 2, 3]}, 2)).to.be.false;
       expect(S.testAll({nin: [1, 2, 3]}, 2)).to.be.false;
     });
     });
 
 
-    it('tests the "between" operator', function () {
+    it('should test the "between" operator', function () {
       expect(S.testAll({between: [-2, 2]}, 0)).to.be.true;
       expect(S.testAll({between: [-2, 2]}, 0)).to.be.true;
       expect(S.testAll({between: [-2, 2]}, 10)).to.be.false;
       expect(S.testAll({between: [-2, 2]}, 10)).to.be.false;
     });
     });
 
 
-    it('tests the "exists" operator', function () {
+    it('should test the "exists" operator', function () {
       expect(S.testAll({exists: true}, 10)).to.be.true;
       expect(S.testAll({exists: true}, 10)).to.be.true;
       expect(S.testAll({exists: false}, undefined)).to.be.true;
       expect(S.testAll({exists: false}, undefined)).to.be.true;
       expect(S.testAll({exists: true}, undefined)).to.be.false;
       expect(S.testAll({exists: true}, undefined)).to.be.false;
       expect(S.testAll({exists: false}, 10)).to.be.false;
       expect(S.testAll({exists: false}, 10)).to.be.false;
     });
     });
 
 
-    it('tests the "like" operator', function () {
+    it('should test the "like" operator', function () {
       expect(S.testAll({like: '%World%'}, 'Hello World!')).to.be.true;
       expect(S.testAll({like: '%World%'}, 'Hello World!')).to.be.true;
       expect(S.testAll({like: '%world%'}, 'Hello World!')).to.be.false;
       expect(S.testAll({like: '%world%'}, 'Hello World!')).to.be.false;
     });
     });
 
 
-    it('tests the "nlike" operator', function () {
+    it('should test the "nlike" operator', function () {
       expect(S.testAll({nlike: '%John%'}, 'Hello World!')).to.be.true;
       expect(S.testAll({nlike: '%John%'}, 'Hello World!')).to.be.true;
       expect(S.testAll({nlike: '%World%'}, 'Hello World!')).to.be.false;
       expect(S.testAll({nlike: '%World%'}, 'Hello World!')).to.be.false;
     });
     });
 
 
-    it('tests the "ilike" operator', function () {
+    it('should test the "ilike" operator', function () {
       expect(S.testAll({ilike: '%WORLD%'}, 'Hello World!')).to.be.true;
       expect(S.testAll({ilike: '%WORLD%'}, 'Hello World!')).to.be.true;
       expect(S.testAll({ilike: '%John%'}, 'Hello World!')).to.be.false;
       expect(S.testAll({ilike: '%John%'}, 'Hello World!')).to.be.false;
     });
     });
 
 
-    it('tests the "nilike" operator', function () {
+    it('should test the "nilike" operator', function () {
       expect(S.testAll({nilike: '%John%'}, 'Hello World!')).to.be.true;
       expect(S.testAll({nilike: '%John%'}, 'Hello World!')).to.be.true;
       expect(S.testAll({nilike: '%world%'}, 'Hello World!')).to.be.false;
       expect(S.testAll({nilike: '%world%'}, 'Hello World!')).to.be.false;
     });
     });
 
 
-    it('tests the "regexp" operator', function () {
+    it('should test the "regexp" operator', function () {
       expect(S.testAll({regexp: 'Wo.+'}, 'Hello World!')).to.be.true;
       expect(S.testAll({regexp: 'Wo.+'}, 'Hello World!')).to.be.true;
       expect(S.testAll({regexp: 'Fo.+'}, 'Hello World!')).to.be.false;
       expect(S.testAll({regexp: 'Fo.+'}, 'Hello World!')).to.be.false;
+      expect(S.testAll({regexp: 'wo.+', flags: 'i'}, 'World')).to.be.true;
+      expect(S.testAll({regexp: 'fo.+', flags: 'i'}, 'World')).to.be.false;
     });
     });
 
 
-    it('throws an error if a first argument is not an object', function () {
+    it('should allow to combine operators', function () {
+      const clause = {gt: 20, lt: 30};
+      expect(S.testAll(clause, 10)).to.be.false;
+      expect(S.testAll(clause, 25)).to.be.true;
+      expect(S.testAll(clause, 40)).to.be.false;
+    });
+
+    it('should return undefined for an empty clause or non-operator key', function () {
+      expect(S.testAll({}, 'value')).to.be.undefined;
+      expect(S.testAll({foo: 'bar'}, 'value')).to.be.undefined;
+    });
+
+    it('should throws an error if a first argument is not an object', function () {
       const throwable = () => S.testAll(10);
       const throwable = () => S.testAll(10);
       expect(throwable).to.throw(
       expect(throwable).to.throw(
         'The first argument of OperatorUtils.testAll ' +
         'The first argument of OperatorUtils.testAll ' +