@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 +2 -2
- package/src/mongodb-adapter.js +45 -20
- package/src/mongodb-adapter.spec.js +533 -14
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e22m4u/js-repository-mongodb-adapter",
|
|
3
|
-
"version": "0.0.
|
|
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.
|
|
41
|
+
"@e22m4u/js-repository": "~0.0.36"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@commitlint/cli": "^17.7.1",
|
package/src/mongodb-adapter.js
CHANGED
|
@@ -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 (
|
|
375
|
-
|
|
376
|
-
|
|
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
|
-
|
|
416
|
+
opConds.push({$eq: this._coerceId(cond.eq)});
|
|
400
417
|
}
|
|
401
418
|
// neq
|
|
402
419
|
if ('neq' in cond) {
|
|
403
|
-
|
|
420
|
+
opConds.push({$ne: this._coerceId(cond.neq)});
|
|
404
421
|
}
|
|
405
422
|
// gt
|
|
406
423
|
if ('gt' in cond) {
|
|
407
|
-
|
|
424
|
+
opConds.push({$gt: cond.gt});
|
|
408
425
|
}
|
|
409
426
|
// lt
|
|
410
427
|
if ('lt' in cond) {
|
|
411
|
-
|
|
428
|
+
opConds.push({$lt: cond.lt});
|
|
412
429
|
}
|
|
413
430
|
// gte
|
|
414
431
|
if ('gte' in cond) {
|
|
415
|
-
|
|
432
|
+
opConds.push({$gte: cond.gte});
|
|
416
433
|
}
|
|
417
434
|
// lte
|
|
418
435
|
if ('lte' in cond) {
|
|
419
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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('
|
|
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
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
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('
|
|
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
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
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();
|