@e22m4u/js-repository-mongodb-adapter 0.0.20 → 0.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@e22m4u/js-repository-mongodb-adapter",
3
- "version": "0.0.20",
3
+ "version": "0.0.22",
4
4
  "description": "MongoDB адаптер для @e22m4u/js-repository",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -38,7 +38,7 @@
38
38
  "peerDependencies": {
39
39
  "@e22m4u/js-format": "*",
40
40
  "@e22m4u/js-service": "*",
41
- "@e22m4u/js-repository": "~0.0.34"
41
+ "@e22m4u/js-repository": "~0.0.36"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@commitlint/cli": "^17.7.1",
@@ -364,16 +364,32 @@ export class MongodbAdapter extends Adapter {
364
364
  * @private
365
365
  */
366
366
  _buildQuery(modelName, clause) {
367
+ if (clause == null) return;
368
+ if (typeof clause !== 'object' || Array.isArray(clause))
369
+ throw new InvalidArgumentError(
370
+ 'The provided option "where" should be an Object, but %v given.',
371
+ clause,
372
+ );
367
373
  const query = {};
368
- if (!clause || typeof clause !== 'object') return query;
369
374
  const idPropName = this._getIdPropName(modelName);
370
375
  Object.keys(clause).forEach(key => {
376
+ if (String(key).indexOf('$') !== -1)
377
+ throw new InvalidArgumentError(
378
+ 'The symbol "$" is not supported, but %v given.',
379
+ key,
380
+ );
371
381
  let cond = clause[key];
372
382
  // and/or/nor clause
373
383
  if (key === 'and' || key === 'or' || key === 'nor') {
374
- if (Array.isArray(cond))
375
- cond = cond.map(c => this._buildQuery(modelName, c));
376
- query['$' + key] = cond;
384
+ if (cond == null) return;
385
+ if (!Array.isArray(cond))
386
+ throw new InvalidOperatorValueError(key, 'an Array', cond);
387
+ if (cond.length === 0) return;
388
+ cond = cond.map(c => this._buildQuery(modelName, c));
389
+ cond = cond.filter(c => c != null);
390
+ const opKey = '$' + key;
391
+ query[opKey] = query[opKey] ?? [];
392
+ query[opKey] = [...query[opKey], ...cond];
377
393
  return;
378
394
  }
379
395
  // id
@@ -394,29 +410,30 @@ export class MongodbAdapter extends Adapter {
394
410
  }
395
411
  // operator
396
412
  if (cond && cond.constructor && cond.constructor.name === 'Object') {
413
+ const opConds = [];
397
414
  // eq
398
415
  if ('eq' in cond) {
399
- query[key] = this._coerceId(cond.eq);
416
+ opConds.push({$eq: this._coerceId(cond.eq)});
400
417
  }
401
418
  // neq
402
419
  if ('neq' in cond) {
403
- query[key] = {$ne: this._coerceId(cond.neq)};
420
+ opConds.push({$ne: this._coerceId(cond.neq)});
404
421
  }
405
422
  // gt
406
423
  if ('gt' in cond) {
407
- query[key] = {$gt: cond.gt};
424
+ opConds.push({$gt: cond.gt});
408
425
  }
409
426
  // lt
410
427
  if ('lt' in cond) {
411
- query[key] = {$lt: cond.lt};
428
+ opConds.push({$lt: cond.lt});
412
429
  }
413
430
  // gte
414
431
  if ('gte' in cond) {
415
- query[key] = {$gte: cond.gte};
432
+ opConds.push({$gte: cond.gte});
416
433
  }
417
434
  // lte
418
435
  if ('lte' in cond) {
419
- query[key] = {$lte: cond.lte};
436
+ opConds.push({$lte: cond.lte});
420
437
  }
421
438
  // inq
422
439
  if ('inq' in cond) {
@@ -426,7 +443,7 @@ export class MongodbAdapter extends Adapter {
426
443
  'an Array of possible values',
427
444
  cond.inq,
428
445
  );
429
- query[key] = {$in: cond.inq.map(v => this._coerceId(v))};
446
+ opConds.push({$in: cond.inq.map(v => this._coerceId(v))});
430
447
  }
431
448
  // nin
432
449
  if ('nin' in cond) {
@@ -436,7 +453,7 @@ export class MongodbAdapter extends Adapter {
436
453
  'an Array of possible values',
437
454
  cond,
438
455
  );
439
- query[key] = {$nin: cond.nin.map(v => this._coerceId(v))};
456
+ opConds.push({$nin: cond.nin.map(v => this._coerceId(v))});
440
457
  }
441
458
  // between
442
459
  if ('between' in cond) {
@@ -446,7 +463,7 @@ export class MongodbAdapter extends Adapter {
446
463
  'an Array of 2 elements',
447
464
  cond.between,
448
465
  );
449
- query[key] = {$gte: cond.between[0], $lte: cond.between[1]};
466
+ opConds.push({$gte: cond.between[0], $lte: cond.between[1]});
450
467
  }
451
468
  // exists
452
469
  if ('exists' in cond) {
@@ -456,7 +473,7 @@ export class MongodbAdapter extends Adapter {
456
473
  'a Boolean',
457
474
  cond.exists,
458
475
  );
459
- query[key] = {$exists: cond.exists};
476
+ opConds.push({$exists: cond.exists});
460
477
  }
461
478
  // like
462
479
  if ('like' in cond) {
@@ -466,7 +483,7 @@ export class MongodbAdapter extends Adapter {
466
483
  'a String or RegExp',
467
484
  cond.like,
468
485
  );
469
- query[key] = {$regex: stringToRegexp(cond.like)};
486
+ opConds.push({$regex: stringToRegexp(cond.like)});
470
487
  }
471
488
  // nlike
472
489
  if ('nlike' in cond) {
@@ -476,7 +493,7 @@ export class MongodbAdapter extends Adapter {
476
493
  'a String or RegExp',
477
494
  cond.nlike,
478
495
  );
479
- query[key] = {$not: stringToRegexp(cond.nlike)};
496
+ opConds.push({$not: stringToRegexp(cond.nlike)});
480
497
  }
481
498
  // ilike
482
499
  if ('ilike' in cond) {
@@ -486,7 +503,7 @@ export class MongodbAdapter extends Adapter {
486
503
  'a String or RegExp',
487
504
  cond.ilike,
488
505
  );
489
- query[key] = {$regex: stringToRegexp(cond.ilike, 'i')};
506
+ opConds.push({$regex: stringToRegexp(cond.ilike, 'i')});
490
507
  }
491
508
  // nilike
492
509
  if ('nilike' in cond) {
@@ -500,7 +517,7 @@ export class MongodbAdapter extends Adapter {
500
517
  cond.nilike,
501
518
  );
502
519
  }
503
- query[key] = {$not: stringToRegexp(cond.nilike, 'i')};
520
+ opConds.push({$not: stringToRegexp(cond.nilike, 'i')});
504
521
  }
505
522
  // regexp and flags (optional)
506
523
  if ('regexp' in cond) {
@@ -520,14 +537,22 @@ export class MongodbAdapter extends Adapter {
520
537
  'RegExp flags must be a String, but %v given.',
521
538
  cond.flags,
522
539
  );
523
- query[key] = {$regex: stringToRegexp(cond.regexp, flags)};
540
+ opConds.push({$regex: stringToRegexp(cond.regexp, flags)});
541
+ }
542
+ // adds a single operator condition
543
+ if (opConds.length === 1) {
544
+ query[key] = opConds[0];
545
+ // adds multiple operator conditions
546
+ } else if (opConds.length > 1) {
547
+ query['$and'] = query['$and'] ?? [];
548
+ opConds.forEach(c => query['$and'].push({[key]: c}));
524
549
  }
525
550
  return;
526
551
  }
527
552
  // unknown
528
553
  query[key] = cond;
529
554
  });
530
- return query;
555
+ return Object.keys(query).length ? query : undefined;
531
556
  }
532
557
 
533
558
  /**
@@ -7,6 +7,7 @@ import {DataType} from '@e22m4u/js-repository';
7
7
  import {createMongodbUrl} from './utils/index.js';
8
8
  import {MongodbAdapter} from './mongodb-adapter.js';
9
9
  import {AdapterRegistry} from '@e22m4u/js-repository';
10
+ import {InvalidOperatorValueError} from '@e22m4u/js-repository';
10
11
  import {DEFAULT_PRIMARY_KEY_PROPERTY_NAME as DEF_PK} from '@e22m4u/js-repository';
11
12
 
12
13
  const CONFIG = {
@@ -274,18 +275,34 @@ describe('MongodbAdapter', function () {
274
275
  expect(throwable(null)()).to.be.undefined;
275
276
  });
276
277
 
277
- it('recognizes direction by the given direction flag', async function () {
278
+ it('uses ascending direction by default', async function () {
278
279
  const schema = createSchema();
279
280
  schema.defineModel({name: 'model', datasource: 'mongodb'});
280
281
  const A = await schema
281
282
  .getService(AdapterRegistry)
282
283
  .getAdapter('mongodb');
283
- const res1 = A._buildSort('model', 'foo');
284
- const res2 = A._buildSort('model', 'foo DESC');
285
- const res3 = A._buildSort('model', 'foo ASC');
286
- expect(res1).to.be.eql({foo: 1});
287
- expect(res2).to.be.eql({foo: -1});
288
- expect(res3).to.be.eql({foo: 1});
284
+ const res = A._buildSort('model', 'foo');
285
+ expect(res).to.be.eql({foo: 1});
286
+ });
287
+
288
+ it('uses descending direction by the "DESC" flag', async function () {
289
+ const schema = createSchema();
290
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
291
+ const A = await schema
292
+ .getService(AdapterRegistry)
293
+ .getAdapter('mongodb');
294
+ const res = A._buildSort('model', 'foo DESC');
295
+ expect(res).to.be.eql({foo: -1});
296
+ });
297
+
298
+ it('uses ascending direction by the "ASC" flag', async function () {
299
+ const schema = createSchema();
300
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
301
+ const A = await schema
302
+ .getService(AdapterRegistry)
303
+ .getAdapter('mongodb');
304
+ const res = A._buildSort('model', 'foo ASC');
305
+ expect(res).to.be.eql({foo: 1});
289
306
  });
290
307
 
291
308
  it('converts the given property name to the column name', async function () {
@@ -348,18 +365,44 @@ describe('MongodbAdapter', function () {
348
365
  expect(throwable(['bar', 'baz'])()).to.be.eql({bar: 1, baz: 1});
349
366
  });
350
367
 
351
- it('recognizes direction by the given direction flag', async function () {
368
+ it('uses ascending direction by default', async function () {
369
+ const schema = createSchema();
370
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
371
+ const A = await schema
372
+ .getService(AdapterRegistry)
373
+ .getAdapter('mongodb');
374
+ const res = A._buildSort('model', ['foo', 'bar']);
375
+ expect(res).to.be.eql({foo: 1, bar: 1});
376
+ });
377
+
378
+ it('uses descending direction by the "DESC" flag', async function () {
379
+ const schema = createSchema();
380
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
381
+ const A = await schema
382
+ .getService(AdapterRegistry)
383
+ .getAdapter('mongodb');
384
+ const res = A._buildSort('model', ['foo DESC', 'bar DESC']);
385
+ expect(res).to.be.eql({foo: -1, bar: -1});
386
+ });
387
+
388
+ it('uses ascending direction by the "ASC" flag', async function () {
352
389
  const schema = createSchema();
353
390
  schema.defineModel({name: 'model', datasource: 'mongodb'});
354
391
  const A = await schema
355
392
  .getService(AdapterRegistry)
356
393
  .getAdapter('mongodb');
357
- const res1 = A._buildSort('model', ['foo', 'bar']);
358
- const res2 = A._buildSort('model', ['foo DESC', 'bar ASC']);
359
- const res3 = A._buildSort('model', ['foo ASC', 'bar DESC']);
360
- expect(res1).to.be.eql({foo: 1, bar: 1});
361
- expect(res2).to.be.eql({foo: -1, bar: 1});
362
- expect(res3).to.be.eql({foo: 1, bar: -1});
394
+ const res = A._buildSort('model', ['foo ASC', 'bar ASC']);
395
+ expect(res).to.be.eql({foo: 1, bar: 1});
396
+ });
397
+
398
+ it('uses multiple directions by the multiple fields', async function () {
399
+ const schema = createSchema();
400
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
401
+ const A = await schema
402
+ .getService(AdapterRegistry)
403
+ .getAdapter('mongodb');
404
+ const res = A._buildSort('model', ['foo', 'bar DESC', 'baz ASC']);
405
+ expect(res).to.be.eql({foo: 1, bar: -1, baz: 1});
363
406
  });
364
407
 
365
408
  it('converts the given property names to column names', async function () {
@@ -391,6 +434,482 @@ describe('MongodbAdapter', function () {
391
434
  });
392
435
  });
393
436
 
437
+ describe('_buildQuery', function () {
438
+ it('requires the second argument to be an object', async function () {
439
+ const schema = createSchema();
440
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
441
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
442
+ const throwable = v => () => A._buildQuery('model', v);
443
+ const error = v =>
444
+ format(
445
+ 'The provided option "where" should be an Object, but %s given.',
446
+ v,
447
+ );
448
+ expect(throwable('str')).to.throw(error('"str"'));
449
+ expect(throwable('')).to.throw(error('""'));
450
+ expect(throwable(10)).to.throw(error('10'));
451
+ expect(throwable(0)).to.throw(error('0'));
452
+ expect(throwable(true)).to.throw(error('true'));
453
+ expect(throwable(false)).to.throw(error('false'));
454
+ expect(throwable({foo: 'bar'})()).to.be.eql({foo: 'bar'});
455
+ expect(throwable({})()).to.be.undefined;
456
+ expect(throwable(undefined)()).to.be.undefined;
457
+ expect(throwable(null)()).to.be.undefined;
458
+ });
459
+
460
+ it('converts the property names to column names', async function () {
461
+ const schema = createSchema();
462
+ schema.defineModel({
463
+ name: 'model',
464
+ datasource: 'mongodb',
465
+ properties: {
466
+ foo: {
467
+ type: DataType.STRING,
468
+ columnName: 'bar',
469
+ },
470
+ baz: {
471
+ type: DataType.STRING,
472
+ columnName: 'qux',
473
+ },
474
+ },
475
+ });
476
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
477
+ const res = A._buildQuery('model', {foo: 'a1', baz: null});
478
+ expect(res).to.be.eql({bar: 'a1', qux: null});
479
+ });
480
+
481
+ it('throws an error when using "$" character', async function () {
482
+ const schema = createSchema();
483
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
484
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
485
+ const throwable = () => A._buildQuery('model', {$and: []});
486
+ expect(throwable).to.throw(
487
+ 'The symbol "$" is not supported, but "$and" given.',
488
+ );
489
+ });
490
+
491
+ it('the "and" operator requires an array of objects', async function () {
492
+ const schema = createSchema();
493
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
494
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
495
+ const throwable = v => () => A._buildQuery('model', {and: v});
496
+ const error = v => {
497
+ v = v.replace(/"/g, '$');
498
+ const e = new InvalidOperatorValueError('and', 'an Array', v);
499
+ return e.message.replace(/"/g, '').replace(/\$/g, '"');
500
+ };
501
+ expect(throwable('str')).to.throw(error('"str"'));
502
+ expect(throwable('')).to.throw(error('""'));
503
+ expect(throwable(10)).to.throw(error('10'));
504
+ expect(throwable(0)).to.throw(error('0'));
505
+ expect(throwable(true)).to.throw(error('true'));
506
+ expect(throwable(false)).to.throw(error('false'));
507
+ });
508
+
509
+ it('the "or" operator requires an array of objects', async function () {
510
+ const schema = createSchema();
511
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
512
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
513
+ const throwable = v => () => A._buildQuery('model', {or: v});
514
+ const error = v => {
515
+ v = v.replace(/"/g, '$');
516
+ const e = new InvalidOperatorValueError('or', 'an Array', v);
517
+ return e.message.replace(/"/g, '').replace(/\$/g, '"');
518
+ };
519
+ expect(throwable('str')).to.throw(error('"str"'));
520
+ expect(throwable('')).to.throw(error('""'));
521
+ expect(throwable(10)).to.throw(error('10'));
522
+ expect(throwable(0)).to.throw(error('0'));
523
+ expect(throwable(true)).to.throw(error('true'));
524
+ expect(throwable(false)).to.throw(error('false'));
525
+ });
526
+
527
+ it('the "nor" operator requires an array of objects', async function () {
528
+ const schema = createSchema();
529
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
530
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
531
+ const throwable = v => () => A._buildQuery('model', {nor: v});
532
+ const error = v => {
533
+ v = v.replace(/"/g, '$');
534
+ const e = new InvalidOperatorValueError('nor', 'an Array', v);
535
+ return e.message.replace(/"/g, '').replace(/\$/g, '"');
536
+ };
537
+ expect(throwable('str')).to.throw(error('"str"'));
538
+ expect(throwable('')).to.throw(error('""'));
539
+ expect(throwable(10)).to.throw(error('10'));
540
+ expect(throwable(0)).to.throw(error('0'));
541
+ expect(throwable(true)).to.throw(error('true'));
542
+ expect(throwable(false)).to.throw(error('false'));
543
+ });
544
+
545
+ it('does not include an empty value of "and" operator', async function () {
546
+ const input1 = {foo: 'a1', and: []};
547
+ const input2 = {foo: 'a2', and: undefined};
548
+ const input3 = {foo: 'a3', and: null};
549
+ const schema = createSchema();
550
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
551
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
552
+ const res1 = A._buildQuery('model', input1);
553
+ const res2 = A._buildQuery('model', input2);
554
+ const res3 = A._buildQuery('model', input3);
555
+ expect(res1).to.be.eql({foo: 'a1'});
556
+ expect(res2).to.be.eql({foo: 'a2'});
557
+ expect(res3).to.be.eql({foo: 'a3'});
558
+ });
559
+
560
+ it('does not include an empty value of "or" operator', async function () {
561
+ const input1 = {foo: 'a1', or: []};
562
+ const input2 = {foo: 'a2', or: undefined};
563
+ const input3 = {foo: 'a3', or: null};
564
+ const schema = createSchema();
565
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
566
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
567
+ const res1 = A._buildQuery('model', input1);
568
+ const res2 = A._buildQuery('model', input2);
569
+ const res3 = A._buildQuery('model', input3);
570
+ expect(res1).to.be.eql({foo: 'a1'});
571
+ expect(res2).to.be.eql({foo: 'a2'});
572
+ expect(res3).to.be.eql({foo: 'a3'});
573
+ });
574
+
575
+ it('does not include an empty value of "nor" operator', async function () {
576
+ const input1 = {foo: 'a1', nor: []};
577
+ const input2 = {foo: 'a2', nor: undefined};
578
+ const input3 = {foo: 'a3', nor: null};
579
+ const schema = createSchema();
580
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
581
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
582
+ const res1 = A._buildQuery('model', input1);
583
+ const res2 = A._buildQuery('model', input2);
584
+ const res3 = A._buildQuery('model', input3);
585
+ expect(res1).to.be.eql({foo: 'a1'});
586
+ expect(res2).to.be.eql({foo: 'a2'});
587
+ expect(res3).to.be.eql({foo: 'a3'});
588
+ });
589
+
590
+ it('converts the "and" operator to "$and"', async function () {
591
+ const input = {and: [{foo: 'bar'}, {baz: 'qux'}]};
592
+ const schema = createSchema();
593
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
594
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
595
+ const res = A._buildQuery('model', input);
596
+ expect(res).to.be.eql({$and: [{foo: 'bar'}, {baz: 'qux'}]});
597
+ });
598
+
599
+ it('converts the "or" operator to "$or"', async function () {
600
+ const input = {or: [{foo: 'bar'}, {baz: 'qux'}]};
601
+ const schema = createSchema();
602
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
603
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
604
+ const res = A._buildQuery('model', input);
605
+ expect(res).to.be.eql({$or: [{foo: 'bar'}, {baz: 'qux'}]});
606
+ });
607
+
608
+ it('converts the "nor" operator to "$nor"', async function () {
609
+ const input = {nor: [{foo: 'bar'}, {baz: 'qux'}]};
610
+ const schema = createSchema();
611
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
612
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
613
+ const res = A._buildQuery('model', input);
614
+ expect(res).to.be.eql({$nor: [{foo: 'bar'}, {baz: 'qux'}]});
615
+ });
616
+
617
+ it('converts the "eq" operator to "$eq"', async function () {
618
+ const input = {foo: {eq: 'bar'}};
619
+ const schema = createSchema();
620
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
621
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
622
+ const res = A._buildQuery('model', input);
623
+ expect(res).to.be.eql({foo: {$eq: 'bar'}});
624
+ });
625
+
626
+ it('converts the "neq" operator to "$ne"', async function () {
627
+ const input = {foo: {neq: 'bar'}};
628
+ const schema = createSchema();
629
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
630
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
631
+ const res = A._buildQuery('model', input);
632
+ expect(res).to.be.eql({foo: {$ne: 'bar'}});
633
+ });
634
+
635
+ it('converts the "gt" operator to "$gt"', async function () {
636
+ const input = {foo: {gt: 5}};
637
+ const schema = createSchema();
638
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
639
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
640
+ const res = A._buildQuery('model', input);
641
+ expect(res).to.be.eql({foo: {$gt: 5}});
642
+ });
643
+
644
+ it('converts the "lt" operator to "$lt"', async function () {
645
+ const input = {foo: {lt: 5}};
646
+ const schema = createSchema();
647
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
648
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
649
+ const res = A._buildQuery('model', input);
650
+ expect(res).to.be.eql({foo: {$lt: 5}});
651
+ });
652
+
653
+ it('converts the "gte" operator to "$gte"', async function () {
654
+ const input = {foo: {gte: 5}};
655
+ const schema = createSchema();
656
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
657
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
658
+ const res = A._buildQuery('model', input);
659
+ expect(res).to.be.eql({foo: {$gte: 5}});
660
+ });
661
+
662
+ it('converts the "lte" operator to "$lte"', async function () {
663
+ const input = {foo: {lte: 5}};
664
+ const schema = createSchema();
665
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
666
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
667
+ const res = A._buildQuery('model', input);
668
+ expect(res).to.be.eql({foo: {$lte: 5}});
669
+ });
670
+
671
+ it('converts the "inq" operator to "$in"', async function () {
672
+ const input = {foo: {inq: [1, 2, 3]}};
673
+ const schema = createSchema();
674
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
675
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
676
+ const res = A._buildQuery('model', input);
677
+ expect(res).to.be.eql({foo: {$in: [1, 2, 3]}});
678
+ });
679
+
680
+ it('converts the "nin" operator to "$nin"', async function () {
681
+ const input = {foo: {nin: ['a', 'b', 'c']}};
682
+ const schema = createSchema();
683
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
684
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
685
+ const res = A._buildQuery('model', input);
686
+ expect(res).to.be.eql({foo: {$nin: ['a', 'b', 'c']}});
687
+ });
688
+
689
+ it('converts the "between" operator to "$gte" and "$lte"', async function () {
690
+ const input = {foo: {between: [1, 10]}};
691
+ const schema = createSchema();
692
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
693
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
694
+ const res = A._buildQuery('model', input);
695
+ const expected = {foo: {$gte: 1, $lte: 10}};
696
+ expect(res).to.be.eql(expected);
697
+ });
698
+
699
+ it('converts the "exists" operator to "$exists"', async function () {
700
+ const input1 = {foo: {exists: true}};
701
+ const input2 = {foo: {exists: false}};
702
+ const schema = createSchema();
703
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
704
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
705
+ const res1 = A._buildQuery('model', input1);
706
+ const res2 = A._buildQuery('model', input2);
707
+ expect(res1).to.be.eql({foo: {$exists: true}});
708
+ expect(res2).to.be.eql({foo: {$exists: false}});
709
+ });
710
+
711
+ it('converts the "like" operator to "$regex"', async function () {
712
+ const input = {foo: {like: 'test'}};
713
+ const schema = createSchema();
714
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
715
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
716
+ const res = A._buildQuery('model', input);
717
+ expect(res).to.be.eql({foo: {$regex: /test/}});
718
+ });
719
+
720
+ it('converts the "nlike" operator to "$not"', async function () {
721
+ const input = {foo: {nlike: 'test'}};
722
+ const schema = createSchema();
723
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
724
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
725
+ const res = A._buildQuery('model', input);
726
+ expect(res).to.be.eql({foo: {$not: /test/}});
727
+ });
728
+
729
+ it('converts the "ilike" operator to "$regex" with "i" flag', async function () {
730
+ const input = {foo: {ilike: 'test'}};
731
+ const schema = createSchema();
732
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
733
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
734
+ const res = A._buildQuery('model', input);
735
+ expect(res).to.be.eql({foo: {$regex: /test/i}});
736
+ });
737
+
738
+ it('converts the "nilike" operator to "$not" with "i" flag', async function () {
739
+ const input = {foo: {nilike: 'test'}};
740
+ const schema = createSchema();
741
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
742
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
743
+ const res = A._buildQuery('model', input);
744
+ expect(res).to.be.eql({foo: {$not: /test/i}});
745
+ });
746
+
747
+ it('converts property value to an instance of ObjectId', async function () {
748
+ const oid = new ObjectId();
749
+ const id = String(oid);
750
+ const input = {foo: id};
751
+ const schema = createSchema();
752
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
753
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
754
+ const res = A._buildQuery('model', input);
755
+ expect(res.foo).to.be.instanceof(ObjectId);
756
+ expect(res.foo).to.be.eql(oid);
757
+ });
758
+
759
+ it('the "eq" operator converts ObjectId string to an instance', async function () {
760
+ const oid = new ObjectId();
761
+ const id = oid.toString();
762
+ const input = {foo: {eq: id}};
763
+ const schema = createSchema();
764
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
765
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
766
+ const {
767
+ foo: {$eq: res},
768
+ } = A._buildQuery('model', input);
769
+ expect(res).to.be.instanceOf(ObjectId);
770
+ expect(res).to.be.eql(oid);
771
+ });
772
+
773
+ it('the "neq" operator converts ObjectId string to an instance', async function () {
774
+ const oid = new ObjectId();
775
+ const id = oid.toString();
776
+ const input = {foo: {neq: id}};
777
+ const schema = createSchema();
778
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
779
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
780
+ const {
781
+ foo: {$ne: res},
782
+ } = A._buildQuery('model', input);
783
+ expect(res).to.be.instanceOf(ObjectId);
784
+ expect(res).to.be.eql(oid);
785
+ });
786
+
787
+ it('the "inq" operator converts ObjectId string to an instance', async function () {
788
+ const oid = new ObjectId();
789
+ const id = oid.toString();
790
+ const input = {foo: {inq: [id]}};
791
+ const schema = createSchema();
792
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
793
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
794
+ const {
795
+ foo: {$in: res},
796
+ } = A._buildQuery('model', input);
797
+ expect(res[0]).to.be.instanceOf(ObjectId);
798
+ expect(res[0]).to.be.eql(oid);
799
+ });
800
+
801
+ it('the "nin" operator converts ObjectId string to an instance', async function () {
802
+ const oid = new ObjectId();
803
+ const id = oid.toString();
804
+ const input = {foo: {nin: [id]}};
805
+ const schema = createSchema();
806
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
807
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
808
+ const {
809
+ foo: {$nin: res},
810
+ } = A._buildQuery('model', input);
811
+ expect(res[0]).to.be.instanceOf(ObjectId);
812
+ expect(res[0]).to.be.eql(oid);
813
+ });
814
+
815
+ it('combines the given operators by the "and" clause', async function () {
816
+ const input = {
817
+ foo: {
818
+ eq: 'bar',
819
+ neq: 'baz',
820
+ gt: 5,
821
+ lt: 10,
822
+ gte: 6,
823
+ lte: 9,
824
+ inq: ['qux'],
825
+ nin: ['qwe'],
826
+ between: [100, 200],
827
+ exists: true,
828
+ like: 'asd',
829
+ nlike: 'zxc',
830
+ ilike: 'rty',
831
+ nilike: 'fgh',
832
+ regexp: 'vbn',
833
+ flags: 'i',
834
+ },
835
+ };
836
+ const expected = {
837
+ $and: [
838
+ {foo: {$eq: 'bar'}},
839
+ {foo: {$ne: 'baz'}},
840
+ {foo: {$gt: 5}},
841
+ {foo: {$lt: 10}},
842
+ {foo: {$gte: 6}},
843
+ {foo: {$lte: 9}},
844
+ {foo: {$in: ['qux']}},
845
+ {foo: {$nin: ['qwe']}},
846
+ {foo: {$gte: 100, $lte: 200}},
847
+ {foo: {$exists: true}},
848
+ {foo: {$regex: /asd/}},
849
+ {foo: {$not: /zxc/}},
850
+ {foo: {$regex: /rty/i}},
851
+ {foo: {$not: /fgh/i}},
852
+ {foo: {$regex: /vbn/i}},
853
+ ],
854
+ };
855
+ const schema = createSchema();
856
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
857
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
858
+ const res = A._buildQuery('model', input);
859
+ expect(res).to.be.eql(expected);
860
+ });
861
+
862
+ it('combines the given operators by the existing "and" clause', async function () {
863
+ const input = {
864
+ and: [{featured: true}, {removed: false}],
865
+ foo: {
866
+ eq: 'bar',
867
+ neq: 'baz',
868
+ gt: 5,
869
+ lt: 10,
870
+ gte: 6,
871
+ lte: 9,
872
+ inq: ['qux'],
873
+ nin: ['qwe'],
874
+ between: [100, 200],
875
+ exists: true,
876
+ like: 'asd',
877
+ nlike: 'zxc',
878
+ ilike: 'rty',
879
+ nilike: 'fgh',
880
+ regexp: 'vbn',
881
+ flags: 'i',
882
+ },
883
+ };
884
+ const expected = {
885
+ $and: [
886
+ {featured: true},
887
+ {removed: false},
888
+ {foo: {$eq: 'bar'}},
889
+ {foo: {$ne: 'baz'}},
890
+ {foo: {$gt: 5}},
891
+ {foo: {$lt: 10}},
892
+ {foo: {$gte: 6}},
893
+ {foo: {$lte: 9}},
894
+ {foo: {$in: ['qux']}},
895
+ {foo: {$nin: ['qwe']}},
896
+ {foo: {$gte: 100, $lte: 200}},
897
+ {foo: {$exists: true}},
898
+ {foo: {$regex: /asd/}},
899
+ {foo: {$not: /zxc/}},
900
+ {foo: {$regex: /rty/i}},
901
+ {foo: {$not: /fgh/i}},
902
+ {foo: {$regex: /vbn/i}},
903
+ ],
904
+ };
905
+ const schema = createSchema();
906
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
907
+ const A = await schema.getService(AdapterRegistry).getAdapter('mongodb');
908
+ const res = A._buildQuery('model', input);
909
+ expect(res).to.be.eql(expected);
910
+ });
911
+ });
912
+
394
913
  describe('create', function () {
395
914
  it('generates a new identifier when a value of a primary key is not provided', async function () {
396
915
  const schema = createSchema();