Browse Source

chore: improve query filtering

e22m4u 2 years ago
parent
commit
056dee41b5
2 changed files with 63 additions and 4 deletions
  1. 7 3
      src/mongodb-adapter.js
  2. 56 1
      src/mongodb-adapter.spec.js

+ 7 - 3
src/mongodb-adapter.js

@@ -376,8 +376,12 @@ export class MongodbAdapter extends Adapter {
       let cond = clause[key];
       let cond = clause[key];
       // and/or/nor clause
       // and/or/nor clause
       if (key === 'and' || key === 'or' || key === 'nor') {
       if (key === 'and' || key === 'or' || key === 'nor') {
-        if (Array.isArray(cond))
-          cond = cond.map(c => this._buildQuery(modelName, c));
+        if (cond == null) return;
+        if (!Array.isArray(cond))
+          throw new InvalidOperatorValueError(key, 'an Array', cond);
+        if (cond.length === 0) return;
+        cond = cond.map(c => this._buildQuery(modelName, c));
+        cond = cond.filter(c => c != null);
         query['$' + key] = cond;
         query['$' + key] = cond;
         return;
         return;
       }
       }
@@ -532,7 +536,7 @@ export class MongodbAdapter extends Adapter {
       // unknown
       // unknown
       query[key] = cond;
       query[key] = cond;
     });
     });
-    return query;
+    return Object.keys(query).length ? query : undefined;
   }
   }
 
 
   /**
   /**

+ 56 - 1
src/mongodb-adapter.spec.js

@@ -7,6 +7,7 @@ import {DataType} from '@e22m4u/js-repository';
 import {createMongodbUrl} from './utils/index.js';
 import {createMongodbUrl} from './utils/index.js';
 import {MongodbAdapter} from './mongodb-adapter.js';
 import {MongodbAdapter} from './mongodb-adapter.js';
 import {AdapterRegistry} from '@e22m4u/js-repository';
 import {AdapterRegistry} from '@e22m4u/js-repository';
+import {InvalidOperatorValueError} from '@e22m4u/js-repository';
 import {DEFAULT_PRIMARY_KEY_PROPERTY_NAME as DEF_PK} from '@e22m4u/js-repository';
 import {DEFAULT_PRIMARY_KEY_PROPERTY_NAME as DEF_PK} from '@e22m4u/js-repository';
 
 
 const CONFIG = {
 const CONFIG = {
@@ -451,7 +452,7 @@ describe('MongodbAdapter', function () {
       expect(throwable(true)).to.throw(error('true'));
       expect(throwable(true)).to.throw(error('true'));
       expect(throwable(false)).to.throw(error('false'));
       expect(throwable(false)).to.throw(error('false'));
       expect(throwable({foo: 'bar'})()).to.be.eql({foo: 'bar'});
       expect(throwable({foo: 'bar'})()).to.be.eql({foo: 'bar'});
-      expect(throwable({})()).to.be.eql({});
+      expect(throwable({})()).to.be.undefined;
       expect(throwable(undefined)()).to.be.undefined;
       expect(throwable(undefined)()).to.be.undefined;
       expect(throwable(null)()).to.be.undefined;
       expect(throwable(null)()).to.be.undefined;
     });
     });
@@ -491,6 +492,60 @@ describe('MongodbAdapter', function () {
       expect(res.foo).to.be.eql(oid1);
       expect(res.foo).to.be.eql(oid1);
       expect(res.bar).to.be.eql(oid2);
       expect(res.bar).to.be.eql(oid2);
     });
     });
+
+    it('adds "$" prefix to the "and", "or" and "nor" operator keys', async function () {
+      const input = {
+        and: [{foo: 'a1'}],
+        or: [{foo: 'a2'}],
+        nor: [{foo: 'a3'}],
+      };
+      const schema = createSchema();
+      schema.defineModel({name: 'model', datasource: 'mongodb'});
+      const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
+      const res = A._buildQuery('model', input);
+      expect(res).to.be.eql({
+        $and: [{foo: 'a1'}],
+        $or: [{foo: 'a2'}],
+        $nor: [{foo: 'a3'}],
+      });
+    });
+
+    it('does not include an empty array of "and", "or" and "nor" operators', async function () {
+      const input1 = {foo: 'a1', and: [], or: [], nor: []};
+      const input2 = {foo: 'a2', and: undefined, or: undefined, nor: undefined};
+      const input3 = {foo: 'a3', and: null, or: null, nor: null};
+      const schema = createSchema();
+      schema.defineModel({name: 'model', datasource: 'mongodb'});
+      const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
+      const res1 = A._buildQuery('model', input1);
+      const res2 = A._buildQuery('model', input2);
+      const res3 = A._buildQuery('model', input3);
+      expect(res1).to.be.eql({foo: 'a1'});
+      expect(res2).to.be.eql({foo: 'a2'});
+      expect(res3).to.be.eql({foo: 'a3'});
+    });
+
+    it('operators "and", "or" and "nor" are require an array of objects', async function () {
+      const schema = createSchema();
+      schema.defineModel({name: 'model', datasource: 'mongodb'});
+      const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
+      const throwable = (k, v) => () => A._buildQuery('model', {[k]: v});
+      const error = (k, v) => {
+        const e = new InvalidOperatorValueError(k, 'an Array', v);
+        return e.message;
+      };
+      const testOf = v => {
+        expect(throwable('and', v)).to.throw(error('and', v));
+        expect(throwable('or', v)).to.throw(error('or', v));
+        expect(throwable('nor', v)).to.throw(error('nor', v));
+      };
+      testOf('str');
+      testOf('');
+      testOf(10);
+      testOf(0);
+      testOf(true);
+      testOf(false);
+    });
   });
   });
 
 
   describe('create', function () {
   describe('create', function () {