cosa 6.4.0 → 7.0.0

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2022 Losant IoT, Inc.
3
+ Copyright (c) 2023 Losant IoT, Inc.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/lib/db.js CHANGED
@@ -342,6 +342,7 @@ class Database extends EventEmitter {
342
342
  * @see {@link https://mongodb.github.io/node-mongodb-native/4.0/interfaces/aggregateoptions.html#maxtimems}
343
343
  */
344
344
  async aggregate(collectionName, pipeline, options = {}) {
345
+ pipeline = deserialize(pipeline);
345
346
  const collection = await this.collection(collectionName);
346
347
  return collection.aggregate(pipeline, {
347
348
  readPreference: options.readPreference,
package/lib/model.js CHANGED
@@ -7,7 +7,9 @@ const { EJSON } = require('bson');
7
7
  const Cursor = require('./cursor');
8
8
  const errors = require('./errors');
9
9
  const { ObjectId } = require('bson');
10
- const { pathEq, complement, pick, omit, has } = require('omnibelt');
10
+ const {
11
+ pathEq, complement, pick, omit, has, isEmpty, isPlainObject
12
+ } = require('omnibelt');
11
13
  const { buildPropertySchema } = require('./utils');
12
14
  const Immutable = require('./immutable');
13
15
  Immutable.use(require('./defined-object'));
@@ -243,11 +245,16 @@ const _create = (data, definition) => {
243
245
  });
244
246
  };
245
247
 
246
- definition.methods.del = function(path) {
248
+ definition.methods.del = function(toDelete) {
247
249
  const original = this;
248
250
  return this.mutate(function() {
249
- objectPath.del(this, path);
250
- _markAsModified(this, [path], original);
251
+ if (!Array.isArray(toDelete)) {
252
+ toDelete = [toDelete];
253
+ }
254
+ toDelete.forEach((path) => {
255
+ objectPath.del(this, path);
256
+ });
257
+ _markAsModified(this, toDelete, original);
251
258
  });
252
259
  };
253
260
 
@@ -409,9 +416,17 @@ const define = (definition) => {
409
416
 
410
417
  definition._schema = _buildSchema(definition);
411
418
 
412
- const applyGlobalWhere = (query, options) => {
419
+ const makeSafeQuery = (query, options) => {
420
+ if (!query || !isPlainObject(query)) {
421
+ throw new Error('Query must be an object.');
422
+ }
423
+
424
+ if (!options.allowGlobalQuery && isEmpty(query)) {
425
+ throw new Error('To make an unrestricted query, please set the allowGlobalQuery option.');
426
+ }
427
+
413
428
  return options.bypassGlobalWhere || !definition.where ?
414
- query : { ...definition.where, ...(query || {}) };
429
+ query : { ...definition.where, ...query };
415
430
  };
416
431
 
417
432
  return {
@@ -432,15 +447,15 @@ const define = (definition) => {
432
447
  return Immutable.isImmutableType(obj, definition.name || 'object');
433
448
  },
434
449
 
435
- count: (query, options = {}) => {
436
- query = applyGlobalWhere(query, options);
450
+ count: async (query, options = {}) => {
451
+ query = makeSafeQuery(query, options);
437
452
  const collection = definition.collection;
438
453
  debug(`counting ${JSON.stringify(query)} in ${collection}`);
439
454
  return db.find(collection, query, { ...options, count: true });
440
455
  },
441
456
 
442
457
  find: async (query, options = {}) => {
443
- query = applyGlobalWhere(query, options);
458
+ query = makeSafeQuery(query, options);
444
459
  const collection = definition.collection;
445
460
  debug(`finding ${JSON.stringify(query)} in ${collection}`);
446
461
  const dbCursor = await db.find(collection, query, options);
@@ -450,16 +465,22 @@ const define = (definition) => {
450
465
  return options.array ? cursor.toArray() : cursor;
451
466
  },
452
467
 
468
+ exists: async (query, options = {}) => {
469
+ query = makeSafeQuery(query, options);
470
+ const collection = definition.collection;
471
+ return !!(await db.find(collection, query, { ...options, count: true, limit: 1 }));
472
+ },
473
+
453
474
  findOne: async (query, options = {}) => {
454
- query = applyGlobalWhere(query, options);
475
+ query = makeSafeQuery(query, options);
455
476
  const collection = definition.collection;
456
477
  debug(`finding one${JSON.stringify(query)} in ${collection}`);
457
478
  const result = await db.find(collection, query, { ...options, findOne: true });
458
479
  return !result ? null : _create(result, definition);
459
480
  },
460
481
 
461
- update: (query, update, { autoSet = true, ...options } = {}) => {
462
- query = applyGlobalWhere(query, options);
482
+ update: async (query, update, { autoSet = true, ...options } = {}) => {
483
+ query = makeSafeQuery(query, options);
463
484
  const collection = definition.collection;
464
485
  if (autoSet) {
465
486
  update = { $set: update };
@@ -468,28 +489,40 @@ const define = (definition) => {
468
489
  return db.update(collection, query, update, options);
469
490
  },
470
491
 
471
- remove: (query, options = {}) => {
472
- query = applyGlobalWhere(query, options);
492
+ remove: async (query, options = {}) => {
493
+ query = makeSafeQuery(query, options);
473
494
  const collection = definition.collection;
474
495
  debug(`removing ${JSON.stringify(query)} from ${collection}`);
475
496
  return db.remove(collection, query, options);
476
497
  },
477
498
 
478
- distinct: (key, query, options = {}) => {
479
- query = applyGlobalWhere(query, options);
499
+ distinct: async (key, query, options = {}) => {
500
+ query = makeSafeQuery(query, options);
480
501
  const collection = definition.collection;
481
502
  debug(`finding distinct "${key}" ${JSON.stringify(query)} from ${collection}`);
482
503
  return db.distinct(collection, key, query, options);
483
504
  },
484
505
 
485
- aggregate: (pipeline, options = {}) => {
506
+ aggregate: async (pipeline, options = {}) => {
507
+ if (!Array.isArray(pipeline)) {
508
+ throw new Error('Aggregation pipeline must be an array.');
509
+ }
510
+
511
+ pipeline = pipeline.slice();
512
+ if (pipeline[0]?.$match) {
513
+ pipeline[0] = { ...pipeline[0], $match: makeSafeQuery(pipeline[0].$match, options) };
514
+ } else {
515
+ pipeline.unshift({ $match: makeSafeQuery({}, options) });
516
+ }
517
+
486
518
  const collection = definition.collection;
487
519
  debug(`aggregating ${JSON.stringify(pipeline)} from ${collection}`);
488
- return db.aggregate(collection, pipeline, options);
520
+ const dbCursor = await db.aggregate(collection, pipeline, options);
521
+ return options.array ? dbCursor.toArray() : dbCursor;
489
522
  },
490
523
 
491
524
  project: async (query, value, options = {}) => {
492
- query = applyGlobalWhere(query, options);
525
+ query = makeSafeQuery(query, options);
493
526
  const collection = definition.collection;
494
527
  debug(`project ${value}, ${JSON.stringify(query)} in ${collection}`);
495
528
  let dbCursor = await db.find(collection, query, options);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cosa",
3
- "version": "6.4.0",
3
+ "version": "7.0.0",
4
4
  "description": "Cosa Models for MongoDB",
5
5
  "main": "lib/index.js",
6
6
  "engines": {
@@ -35,25 +35,25 @@
35
35
  "lib"
36
36
  ],
37
37
  "dependencies": {
38
- "bson": "~4.7.0",
38
+ "bson": "~4.7.2",
39
39
  "clone": "^2.1.2",
40
40
  "debug": "^4.3.4",
41
41
  "error": "^7.0.2",
42
42
  "etag": "^1.8.1",
43
- "joi": "^17.6.4",
44
- "mongodb": "~4.11.0",
43
+ "joi": "^17.8.3",
44
+ "mongodb": "~4.14.0",
45
45
  "object-path": "^0.11.8",
46
46
  "omnibelt": "^2.1.0"
47
47
  },
48
48
  "devDependencies": {
49
- "@losant/eslint-config-losant": "^1.5.0",
50
- "husky": "^8.0.2",
51
- "lint-staged": "^13.0.3",
49
+ "@losant/eslint-config-losant": "^1.6.0",
50
+ "husky": "^8.0.3",
51
+ "lint-staged": "^13.1.2",
52
52
  "chai": "^4.3.7",
53
53
  "chai-as-promised": "^7.1.1",
54
54
  "chai-datetime": "^1.8.0",
55
- "documentation": "^14.0.0",
56
- "mocha": "^10.1.0",
55
+ "documentation": "^14.0.1",
56
+ "mocha": "^10.2.0",
57
57
  "string-template": "^1.0.0"
58
58
  },
59
59
  "eslintConfig": {