Comparing version 6.0.1 to 6.1.0
@@ -7,7 +7,8 @@ const clone = require('clone'); | ||
* @name ImmutableArray | ||
* @param {object} data | ||
* @param {object} builder | ||
* @param {object} options | ||
* @param {object} data - Underlying array | ||
* @param {object} builder - Builder instance | ||
* @param {object} options - Optional settings | ||
* @returns {undefined} no return value | ||
*/ | ||
module.exports = function (data, builder, options) { | ||
module.exports = function(data, builder, options) { | ||
builder.type = 'Array'; | ||
@@ -17,10 +18,9 @@ | ||
const itemDefinition = options.definition ? options.definition.items || {} : {}; | ||
const itemDefinition = options?.definition?.items || {}; | ||
const itemOptions = { definition: itemDefinition, clone: false }; | ||
['forEach', 'map', 'filter', 'some', 'every'].forEach(function (name) { | ||
builder.defineMethod(name, function (cb, thisArg) { | ||
var immuArr = Immutable.create(data, options); | ||
return Immutable.create(Array.prototype[name].call(data, function (val, index) { | ||
['forEach', 'map', 'filter', 'some', 'every'].forEach(function(name) { | ||
builder.defineMethod(name, function(cb, thisArg) { | ||
const immuArr = Immutable.create(data, options); | ||
return Immutable.create(Array.prototype[name].call(data, function(val, index) { | ||
return cb.call(thisArg, Immutable.create(val, itemOptions), index, immuArr); | ||
@@ -31,6 +31,6 @@ })); | ||
['reduce', 'reduceRight'].forEach(function (name) { | ||
builder.defineMethod(name, function (cb, initialValue) { | ||
var immuArr = Immutable.create(data, options); | ||
return Immutable.create(Array.prototype[name].call(data, function (prev, cur, index) { | ||
['reduce', 'reduceRight'].forEach(function(name) { | ||
builder.defineMethod(name, function(cb, initialValue) { | ||
const immuArr = Immutable.create(data, options); | ||
return Immutable.create(Array.prototype[name].call(data, function(prev, cur, index) { | ||
return cb(Immutable.create(prev), Immutable.create(cur, itemOptions), index, immuArr); | ||
@@ -42,26 +42,22 @@ }), initialValue); | ||
['concat', 'join', 'slice', 'indexOf', 'lastIndexOf', 'reverse', | ||
'toString', 'toLocaleString'].forEach(function (name) { | ||
builder.defineMethod(name, function () { | ||
return Immutable.create(Array.prototype[name].apply(data, arguments), options); | ||
'toString', 'toLocaleString'].forEach(function(name) { | ||
builder.defineMethod(name, function(...rest) { | ||
return Immutable.create(Array.prototype[name].apply(data, rest), options); | ||
}); | ||
}); | ||
builder.defineMethod('push', function () { | ||
return Immutable.create(Array.prototype.concat.apply(data, arguments), options); | ||
builder.defineMethod('push', function(...rest) { | ||
return Immutable.create(Array.prototype.concat.apply(data, rest), options); | ||
}); | ||
builder.defineMethod('unshift', function () { | ||
var args = Array(arguments.length); | ||
for (var i = 0, l = arguments.length; i < l; i++) { | ||
args[i] = arguments[i]; | ||
} | ||
return Immutable.create(args.concat(data), options); | ||
builder.defineMethod('unshift', function(...rest) { | ||
return Immutable.create(rest.concat(data), options); | ||
}); | ||
builder.defineMethod('sort', function (cb) { | ||
var newArr = clone(data); | ||
builder.defineMethod('sort', function(cb) { | ||
const newArr = clone(data); | ||
if (!cb) { | ||
return Immutable.create(newArr.sort(), options); | ||
} | ||
return Immutable.create(newArr.sort(function (a, b) { | ||
return Immutable.create(newArr.sort(function(a, b) { | ||
return cb(Immutable.create(a, itemOptions), Immutable.create(b, itemOptions)); | ||
@@ -71,19 +67,15 @@ })); | ||
builder.defineMethod('splice', function () { | ||
var args = Array(arguments.length); | ||
for (var i = 0, l = arguments.length; i < l; i++) { | ||
args[i] = arguments[i]; | ||
} | ||
var start = args[0]; | ||
var deleteCount = args[1]; | ||
var items = args.slice(2) || []; | ||
var front = data.slice(0, start); | ||
var back = data.slice(start + deleteCount); | ||
builder.defineMethod('splice', function(...rest) { | ||
const start = rest[0]; | ||
const deleteCount = rest[1]; | ||
const items = rest.slice(2) || []; | ||
const front = data.slice(0, start); | ||
const back = data.slice(start + deleteCount); | ||
return Immutable.create(front.concat(items, back), options); | ||
}); | ||
builder.defineMethod('reverse', function () { | ||
var newArr = clone(data); | ||
builder.defineMethod('reverse', function() { | ||
const newArr = clone(data); | ||
return Immutable.create(newArr.reverse(), options); | ||
}); | ||
}; |
@@ -1,2 +0,2 @@ | ||
var Immutable = require('./immutable'); | ||
const Immutable = require('./immutable'); | ||
@@ -6,11 +6,12 @@ /** | ||
* @name ImmutableDate | ||
* @param {object} data | ||
* @param {object} builder | ||
* @param {object} options | ||
* @param {object} data - Underlying date | ||
* @param {object} builder - Builder instance | ||
* @param {object} options - Optional settings | ||
* @returns {undefined} no return value | ||
*/ | ||
module.exports = function (data, builder, options) { | ||
module.exports = function(data, builder, options) { | ||
builder.type = 'Date'; | ||
builder.defineMethod('mutate', function (cb) { | ||
var newDate = new Date(data.valueOf()); | ||
builder.defineMethod('mutate', function(cb) { | ||
const newDate = new Date(data.valueOf()); | ||
cb.apply(newDate); | ||
@@ -21,14 +22,10 @@ return Immutable.create(newDate, { clone: false }); | ||
['toString', 'toISOString', 'toUTCString', 'toDateString', 'toTimeString', | ||
'toLocaleString', 'toLocaleDateString', 'toLocaleTimeString', 'valueOf', | ||
'getTime', 'getFullYear', 'getUTCFullYear', 'toGMTString', 'getMonth', | ||
'getUTCMonth', 'getDate', 'getUTCDate', 'getDay', 'getUTCDay', 'getHours', | ||
'getUTCHours', 'getMinutes', 'getUTCMinutes', 'getSeconds', 'getUTCSeconds', | ||
'getMilliseconds', 'getUTCMilliseconds', 'getTimezoneOffset', 'getYear', | ||
'toJSON'].forEach(function (name) { | ||
builder.defineMethod(name, function () { | ||
var args = Array(arguments.length); | ||
for (var i = 0, l = args.length; i < l; i++) { | ||
args[i] = arguments[i]; | ||
} | ||
return Date.prototype[name].apply(data, args); | ||
'toLocaleString', 'toLocaleDateString', 'toLocaleTimeString', 'valueOf', | ||
'getTime', 'getFullYear', 'getUTCFullYear', 'toGMTString', 'getMonth', | ||
'getUTCMonth', 'getDate', 'getUTCDate', 'getDay', 'getUTCDay', 'getHours', | ||
'getUTCHours', 'getMinutes', 'getUTCMinutes', 'getSeconds', 'getUTCSeconds', | ||
'getMilliseconds', 'getUTCMilliseconds', 'getTimezoneOffset', 'getYear', | ||
'toJSON'].forEach(function(name) { | ||
builder.defineMethod(name, function(...rest) { | ||
return Date.prototype[name].apply(data, rest); | ||
}); | ||
@@ -38,12 +35,8 @@ }); | ||
['setTime', 'setMilliseconds', 'setUTCMilliseconds', 'setSeconds', | ||
'setUTCSeconds', 'setMinutes', 'setUTCMinutes', 'setHours', 'setUTCHours', | ||
'setDate', 'setUTCDate', 'setMonth', 'setUTCMonth', 'setFullYear', | ||
'setUTCFullYear', 'setYear'].forEach(function (name) { | ||
builder.defineMethod(name, function () { | ||
var args = Array(arguments.length); | ||
for (var i = 0, l = args.length; i < l; i++) { | ||
args[i] = arguments[i]; | ||
} | ||
var newDate = new Date(data.valueOf()); | ||
newDate[name].apply(newDate, args); | ||
'setUTCSeconds', 'setMinutes', 'setUTCMinutes', 'setHours', 'setUTCHours', | ||
'setDate', 'setUTCDate', 'setMonth', 'setUTCMonth', 'setFullYear', | ||
'setUTCFullYear', 'setYear'].forEach(function(name) { | ||
builder.defineMethod(name, function(...rest) { | ||
const newDate = new Date(data.valueOf()); | ||
newDate[name].apply(newDate, rest); | ||
return Immutable.create(newDate, options); | ||
@@ -50,0 +43,0 @@ }); |
146
lib/db.js
const debug = require('debug')('cosa:db'); | ||
const defaults = require('defaults'); | ||
const { ObjectId } = require('bson'); | ||
@@ -183,2 +182,5 @@ const { EventEmitter } = require('events'); | ||
* @param {object} [options.readPreference] - the read preference for the query with one of the read constants | ||
* @param {number} [options.batchSize] - number of items per batch (default in mongo driver is 1000) | ||
* @param {boolean} [options.noCursorTimeout] - boolan, if the cursor can time out after being idle, mongo driver default is false | ||
* @param {number} [options.maxTimeMS] - maximum amount of time (in ms) this cursor is allowed to live | ||
* @returns {Cursor} returns Cursor object | ||
@@ -189,25 +191,28 @@ * @see {@link https://mongodb.github.io/node-mongodb-native/4.0/classes/findcursor.html} | ||
* @see {@link https://mongodb.github.io/node-mongodb-native/4.0/classes/collection.html#count} | ||
* @see {@link https://github.com/mongodb/node-mongodb-native/blob/357cbf689735c2447bfb05d73c142f1a5b88ca91/lib/read_preference.js#L69} | ||
* @see {@link https://mongodb.github.io/node-mongodb-native/4.0/interfaces/findoptions.html#readpreference} | ||
* @see {@link https://mongodb.github.io/node-mongodb-native/4.0/interfaces/findoptions.html#batchsize} | ||
* @see {@link https://mongodb.github.io/node-mongodb-native/4.0/interfaces/findoptions.html#nocursortimeout} | ||
* @see {@link https://mongodb.github.io/node-mongodb-native/4.0/interfaces/findoptions.html#maxtimems} | ||
*/ | ||
async find(collectionName, query, options) { | ||
options = defaults(options, { | ||
projection: undefined, | ||
sort: undefined, | ||
skip: undefined, | ||
limit: options && options.count ? null : 1000, | ||
count: false, | ||
findOne: false, | ||
readPreference: undefined | ||
}); | ||
async find(collectionName, query, options = {}) { | ||
query = deserialize(query); | ||
debug('getting db collection'); | ||
const collection = await this.collection(collectionName); | ||
if (options.count) { | ||
const countOptions = { limit: options.limit, skip: options.skip }; | ||
debug(`db.${collection.collectionName}.countDocuments`, query, countOptions); | ||
if (!query || isEmpty(query)) { | ||
const count = await collection.estimatedDocumentCount(); | ||
const countOptions = { | ||
readPreference: options.readPreference, | ||
maxTimeMS: options.maxTimeMS | ||
}; | ||
debug(`db.${collection.collectionName}.estimatedDocumentCount`, query, countOptions); | ||
const count = await collection.estimatedDocumentCount(countOptions); | ||
return clamp(0, options.limit || Infinity, count - (options.skip || 0)); | ||
} else { | ||
return collection.countDocuments(query, options); | ||
const countOptions = { | ||
limit: options.limit, | ||
skip: options.skip, | ||
readPreference: options.readPreference, | ||
maxTimeMS: options.maxTimeMS | ||
}; | ||
debug(`db.${collection.collectionName}.countDocuments`, query, countOptions); | ||
return collection.countDocuments(query, countOptions); | ||
} | ||
@@ -217,6 +222,7 @@ } else if (options.findOne) { | ||
projection: options.projection || options.fields, | ||
limit: options.limit, | ||
skip: options.skip, | ||
sort: options.sort, | ||
readPreference: options.readPreference | ||
readPreference: options.readPreference, | ||
noCursorTimeout: options.noCursorTimeout, | ||
maxTimeMS: options.maxTimeMS | ||
}; | ||
@@ -228,8 +234,11 @@ debug(`db.${collection.collectionName}.findOne`, query, findOptions); | ||
projection: options.projection || options.fields, | ||
limit: options.limit, | ||
limit: options.limit === undefined ? 1000 : options.limit, | ||
skip: options.skip, | ||
sort: options.sort, | ||
readPreference: options.readPreference | ||
readPreference: options.readPreference, | ||
batchSize: options.batchSize, | ||
noCursorTimeout: options.noCursorTimeout, | ||
maxTimeMS: options.maxTimeMS | ||
}; | ||
debug(`db.${collection.collectionName}.find (toArray)`, query, findOptions); | ||
debug(`db.${collection.collectionName}.find`, query, findOptions); | ||
return collection.find(query, options); | ||
@@ -244,16 +253,12 @@ } | ||
* @param {object} options - options on insert | ||
* @param {object} [options.writeConcern] - the write conern options https://mongodb.github.io/node-mongodb-native/4.0/classes/writeconcern.html | ||
* @param {object} [options.writeConcern] - the write concern | ||
* @returns {Promise} resolves with an object with results, and ops as keys | ||
* @see {@link https://mongodb.github.io/node-mongodb-native/4.0/classes/collection.html#insertmany} | ||
* @see {@link https://mongodb.github.io/node-mongodb-native/4.0/classes/collection.html#insertOne} | ||
* @see {@link https://mongodb.github.io/node-mongodb-native/4.0/interfaces/insertoneoptions.html#writeconcern} | ||
*/ | ||
async insert(collectionName, docs, options) { | ||
debug('getting db collection'); | ||
async insert(collectionName, docs, { writeConcern } = {}) { | ||
docs = deserialize(docs); | ||
const collection = await this.collection(collectionName); | ||
let insertOpts; | ||
if (options?.writeConcern) { | ||
insertOpts = { writeConcern: options.writeConcern }; | ||
} | ||
const results = await insertOneOrMany(collection, Array.isArray(docs), docs, insertOpts); | ||
const results = await insertOneOrMany(collection, Array.isArray(docs), docs, { writeConcern }); | ||
@@ -279,22 +284,17 @@ if (Array.isArray(docs)) { | ||
* @param {boolean} [options.multiple=false] - Should multiple documents be updated. | ||
* @param {boolean} [options.upsert=false] - Should documents be inserted if they don't already exist.. | ||
* @param {object} [options.writeConcern] - the write conern options https://mongodb.github.io/node-mongodb-native/4.0/classes/writeconcern.html | ||
* @param {boolean} [options.upsert=false] - Should documents be inserted if they don't already exist. | ||
* @param {object} [options.writeConcern] - the write concern options | ||
* @returns {Promise} resolves with an object with results, and ops as keys | ||
* @see {@link https://mongodb.github.io/node-mongodb-native/4.0/classes/collection.html#updateMany} | ||
* @see {@link https://mongodb.github.io/node-mongodb-native/4.0/classes/collection.html#updateOne} | ||
* @see {@link https://mongodb.github.io/node-mongodb-native/4.0/interfaces/updateoptions.html#writeconcern} | ||
*/ | ||
async update(collectionName, query, update, options) { | ||
options = defaults(options, { | ||
multiple: false, | ||
upsert: false | ||
}); | ||
debug('getting db collection'); | ||
async update(collectionName, query, update, options = {}) { | ||
query = deserialize(query); | ||
update = deserialize(update); | ||
const collection = await this.collection(collectionName); | ||
const updateOptions = { upsert: options.upsert }; | ||
if (options.writeConcern) { | ||
updateOptions.writeConcern = options.writeConcern; | ||
} | ||
return updateOneOrMany(collection, options.multiple, query, update, updateOptions); | ||
return updateOneOrMany(collection, options.multiple, query, update, { | ||
upsert: options.upsert, | ||
writeConcern: options.writeConcern | ||
}); | ||
} | ||
@@ -308,19 +308,12 @@ | ||
* @param {boolean} [options.multiple=false] - Should multiple documents be removed. | ||
* @param {object} [options.writeConcern] - the write conern options https://mongodb.github.io/node-mongodb-native/4.0/classes/writeconcern.html | ||
* @param {object} [options.writeConcern] - the write concern options | ||
* @returns {Promise} resolves with an object with results, and ops as keys | ||
* @see {@link https://mongodb.github.io/node-mongodb-native/4.0/classes/collection.html#deleteMany} | ||
* @see {@link https://mongodb.github.io/node-mongodb-native/4.0/classes/collection.html#deleteOne} | ||
* @see {@link https://mongodb.github.io/node-mongodb-native/4.0/interfaces/deleteoptions.html#writeconcern} | ||
*/ | ||
async remove(collectionName, query, options) { | ||
options = defaults(options, { | ||
multiple: false | ||
}); | ||
debug('getting db collection'); | ||
async remove(collectionName, query, options = {}) { | ||
query = deserialize(query); | ||
const collection = await this.collection(collectionName); | ||
let removeOpts; | ||
if (options.writeConcern) { | ||
removeOpts = { writeConcern: options.writeConcern }; | ||
} | ||
return deleteOneOrMany(collection, options.multiple, query, removeOpts); | ||
return deleteOneOrMany(collection, options.multiple, query, { writeConcern: options.writeConcern }); | ||
} | ||
@@ -333,15 +326,18 @@ | ||
* @param {object} [options] - Optional settings see mongo documentation | ||
* @param {boolean} [options.explain=false] - Should should the execution plan be returned. | ||
* @param {object} [options.readPreference] - the read preference for the query | ||
* @param {object} [options.readPreference] - the read preference for the query with one of the read constants | ||
* @param {number} [options.batchSize] - number of items per batch (default in mongo driver is 1000) | ||
* @param {number} [options.maxTimeMS] - maximum amount of time (in ms) this cursor is allowed to live | ||
* @returns {Promise} resolves with the result of the aggregation from mongo | ||
* @see {@link https://mongodb.github.io/node-mongodb-native/4.0/classes/collection.html#aggregate} | ||
* @see {@link https://github.com/mongodb/node-mongodb-native/blob/357cbf689735c2447bfb05d73c142f1a5b88ca91/lib/read_preference.js#L69} | ||
* @see {@link https://mongodb.github.io/node-mongodb-native/4.0/interfaces/aggregateoptions.html#readpreference} | ||
* @see {@link https://mongodb.github.io/node-mongodb-native/4.0/interfaces/aggregateoptions.html#batchsize} | ||
* @see {@link https://mongodb.github.io/node-mongodb-native/4.0/interfaces/aggregateoptions.html#maxtimems} | ||
*/ | ||
async aggregate(collectionName, pipeline, options) { | ||
options = defaults(options, { | ||
explain: undefined // do not use false that will actually cause an explain. https://github.com/mongodb/node-mongodb-native/pull/2626/files#diff-17118eb51bf767027b48c4456850f1b0b9efcd4be4322b5f26898a42731e4621R28 | ||
async aggregate(collectionName, pipeline, options = {}) { | ||
const collection = await this.collection(collectionName); | ||
return collection.aggregate(pipeline, { | ||
readPreference: options.readPreference, | ||
batchSize: options.batchSize, | ||
maxTimeMS: options.maxTimeMS | ||
}); | ||
debug('getting db collection'); | ||
const collection = await this.collection(collectionName); | ||
return collection.aggregate(pipeline, options); | ||
} | ||
@@ -356,11 +352,15 @@ | ||
* @param {string} [options.readPreference] - the read preference for the query | ||
* @param {number} [options.maxTimeMS] - maximum amount of time (in ms) this cursor is allowed to live | ||
* @returns {Promise} resolves with the result of the distinct query from mongo | ||
* @see {@link https://mongodb.github.io/node-mongodb-native/4.0/classes/collection.html#distinct} | ||
* @see {@link https://github.com/mongodb/node-mongodb-native/blob/357cbf689735c2447bfb05d73c142f1a5b88ca91/lib/read_preference.js#L69} | ||
* @see {@link https://mongodb.github.io/node-mongodb-native/4.0/interfaces/commandoperationoptions.html#readpreference} | ||
* @see {@link https://mongodb.github.io/node-mongodb-native/4.0/interfaces/commandoperationoptions.html#maxtimems} | ||
*/ | ||
async distinct(collectionName, key, query, options) { | ||
debug('getting db collection'); | ||
async distinct(collectionName, key, query, options = {}) { | ||
query = deserialize(query); | ||
const collection = await this.collection(collectionName); | ||
return collection.distinct(key, query, options); | ||
return collection.distinct(key, query, { | ||
readPreference: options.readPreference, | ||
maxTimeMS: options.maxTimeMS | ||
}); | ||
} | ||
@@ -374,7 +374,8 @@ | ||
* @param {object} [options] - Optional settings see mongo documentation | ||
* @param {object} [options.writeConcern] - the write conern options https://mongodb.github.io/node-mongodb-native/4.0/classes/writeconcern.html | ||
* @param {object} [options.writeConcern] - the write concern options | ||
* @returns {Promise} resolves with the result of the distinct query from mongo | ||
* @see {@link http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#replace} | ||
* @see {@link https://mongodb.github.io/node-mongodb-native/4.0/interfaces/replaceoptions.html#writeconcern} | ||
*/ | ||
async replace(collectionName, query, replace, options) { | ||
async replace(collectionName, query, replace, { writeConcern } = {}) { | ||
const collection = await this.collection(collectionName); | ||
@@ -384,7 +385,3 @@ query = deserialize(query); | ||
debug(`db.${collection.collectionName}.replaceOne`, query, replace); | ||
let replaceOpts; | ||
if (options?.writeConcern) { | ||
replaceOpts = { writeConcern: options.writeConcern }; | ||
} | ||
const r = await collection.replaceOne(query, replace, replaceOpts); | ||
const r = await collection.replaceOne(query, replace, { writeConcern }); | ||
r.ops = replace; | ||
@@ -394,5 +391,4 @@ return normalizeResult(r); | ||
} | ||
module.exports = new Database(); |
@@ -1,19 +0,20 @@ | ||
var Immutable = require('./immutable'); | ||
const Immutable = require('./immutable'); | ||
/** | ||
* Immutable handler used to create an immutable object based on definition | ||
* Immutable handler used to create an immutable object based on definition | ||
* describing the object properties and methods. | ||
* @name ImmutableDefinedObject | ||
* @param {object} data | ||
* @param {object} builder | ||
* @param {object} options | ||
* @param {object} options.definition | ||
* @param {object} data - Underlying defined object | ||
* @param {object} builder - Builder instance | ||
* @param {object} options - Optional settings | ||
* @param {object} options.definition - Defintion settings | ||
* @param {object} [options.definition.properties] - Describes the properties of the immutable object. | ||
* @param {object} [options.definition.virtuals] - Describes the virtual properties of the immutable object. | ||
* @param {object} [options.definition.methods] - Describes the methods of the immutable object. | ||
* @returns {undefined} no return value | ||
*/ | ||
module.exports = function (data, builder, options) { | ||
module.exports = function(data, builder, options) { | ||
if (options.definition) { | ||
var definition = options.definition; | ||
const definition = options.definition; | ||
if (definition.name) { | ||
@@ -24,23 +25,23 @@ builder.type = definition.name; | ||
if (definition.properties) { | ||
Object.keys(definition.properties).forEach(function (prop) { | ||
var propertyDef = definition.properties[prop]; | ||
var defaultVal = propertyDef.default; | ||
Object.keys(definition.properties).forEach(function(prop) { | ||
const propertyDef = definition.properties[prop]; | ||
const defaultVal = propertyDef.default; | ||
if ('undefined' === typeof data[prop] && 'undefined' !== typeof defaultVal) { | ||
data[prop] = 'function' === typeof defaultVal ? defaultVal.apply(data) : defaultVal; | ||
} | ||
var value = data[prop]; | ||
var getter = function () { | ||
let value = data[prop]; | ||
const getter = function() { | ||
return (value = Immutable.create(value, { definition: propertyDef, clone: false })); | ||
}; | ||
var options = {}; | ||
const getterOptions = {}; | ||
if (propertyDef && 'undefined' !== typeof propertyDef.enumerable) { | ||
options.enumerable = propertyDef.enumerable; | ||
getterOptions.enumerable = propertyDef.enumerable; | ||
} | ||
builder.defineProperty(prop, getter, options); | ||
builder.defineProperty(prop, getter, getterOptions); | ||
}); | ||
} | ||
if (definition.virtuals) { | ||
Object.keys(definition.virtuals).forEach(function (virtual) { | ||
var virtualFunc = definition.virtuals[virtual]; | ||
builder.defineProperty(virtual, function () { | ||
Object.keys(definition.virtuals).forEach(function(virtual) { | ||
const virtualFunc = definition.virtuals[virtual]; | ||
builder.defineProperty(virtual, function() { | ||
return Immutable.create(virtualFunc.call(data)); | ||
@@ -51,4 +52,4 @@ }); | ||
if (definition.methods) { | ||
Object.keys(definition.methods).forEach(function (method) { | ||
var methodFunc = definition.methods[method]; | ||
Object.keys(definition.methods).forEach(function(method) { | ||
const methodFunc = definition.methods[method]; | ||
builder.defineMethod(method, methodFunc); | ||
@@ -55,0 +56,0 @@ }); |
@@ -1,9 +0,31 @@ | ||
var defaults = require('defaults'); | ||
var assign = require('object-assign'); | ||
var clone = require('clone'); | ||
const clone = require('clone'); | ||
var IMMUTABLE_TYPES = [ 'function', 'string', 'boolean', 'number', 'undefined' ]; | ||
const IMMUTABLE_TYPES = [ 'function', 'string', 'boolean', 'number', 'undefined' ]; | ||
var typeHandlers = []; | ||
const typeHandlers = []; | ||
let Immutable; | ||
const Builder = function(type, props) { | ||
this.type = type || 'object'; | ||
this.props = props || {}; | ||
this.defineProperty = function(name, getterOrValue, options = {}) { | ||
options = { enumerable: true, ...options }; | ||
options.get = ('function' === typeof getterOrValue) ? | ||
getterOrValue : function() { return Immutable.create(getterOrValue); }; | ||
options.set = function() { | ||
throw new Error(`Cannot modify ${name} of immutable ${this.type}`); | ||
}; | ||
this.props[name] = options; | ||
}; | ||
this.defineMethod = function(name, func, options = {}) { | ||
this.props[name] = { | ||
enumerable: false, | ||
...options, | ||
value: func | ||
}; | ||
}; | ||
}; | ||
/** | ||
@@ -13,11 +35,12 @@ * Static class for working with immutable data types. | ||
*/ | ||
var Immutable = { | ||
Immutable = { | ||
/** | ||
* Registers an immutable handler for the given data type. Handlers are used | ||
* Registers an immutable handler for the given data type. Handlers are used | ||
* to wrap specific data types. For example BSON ObjectIds or Dates. | ||
* @param {string} [type=*] | ||
* @param {function} handler | ||
* @param {string} [type=*] - the name of the type | ||
* @param {function} handler - the handler for the type | ||
* @returns {undefined} - no return value | ||
*/ | ||
use: function (type, handler) { | ||
use: function(type, handler) { | ||
if (!handler) { | ||
@@ -35,6 +58,6 @@ handler = type; | ||
* Returns `true` if the given value is an Immutable. | ||
* @param {object} value | ||
* @returns {boolean} | ||
* @param {object} value - a value to check | ||
* @returns {boolean} - if it is an immutable instance | ||
*/ | ||
isImmutable: function (value) { | ||
isImmutable: function(value) { | ||
if ('undefined' === typeof value || value === null) { return true; } | ||
@@ -46,7 +69,7 @@ return (IMMUTABLE_TYPES.indexOf(typeof value) > -1 || !!value.__immutable); | ||
* Returns `true` if the given value is an Immutable of the given type. | ||
* @param {object} value | ||
* @param {string} type | ||
* @returns {boolean} | ||
* @param {object} value - a value to check | ||
* @param {string} type - type to check against | ||
* @returns {boolean} - if the value is an immutable instance of that type | ||
*/ | ||
isImmutableType: function (value, type) { | ||
isImmutableType: function(value, type) { | ||
return value && value.__immutable && value.__type.toLowerCase() === type.toLowerCase(); | ||
@@ -59,5 +82,5 @@ }, | ||
* @param {object} [options] - Options passed to the immutable handler for the given data type. | ||
* @return {object} | ||
* @return {object} - the immutable wrapped object | ||
*/ | ||
create: function (data, options) { | ||
create: function(data, options = {}) { | ||
if (Immutable.isImmutable(data)) { | ||
@@ -67,5 +90,3 @@ return data; | ||
options = defaults(options, { | ||
clone: true | ||
}); | ||
options = { clone: true, ...options }; | ||
@@ -76,17 +97,16 @@ if (options.clone) { | ||
var builder = new Builder('object', {}); | ||
const builder = new Builder('object', {}); | ||
builder.defineProperty('__immutable', true, { enumerable: false }); | ||
builder.defineMethod('toObject', function () { | ||
builder.defineMethod('toObject', function() { | ||
return data; | ||
}); | ||
builder.defineMethod('mutate', function (cb) { | ||
var obj = clone(data); | ||
var newOptions = assign({}, options, { clone: false }); | ||
builder.defineMethod('mutate', function(cb) { | ||
const obj = clone(data); | ||
cb.apply(obj); | ||
return Immutable.create(obj, newOptions); | ||
return Immutable.create(obj, { ...options, clone: false }); | ||
}); | ||
typeHandlers.forEach(function (typeHandler) { | ||
typeHandlers.forEach(function(typeHandler) { | ||
if ('string' === typeof typeHandler.type) { | ||
@@ -111,29 +131,5 @@ if (typeHandler.type === '*' || typeof data === typeHandler.type) { | ||
); | ||
} | ||
}; | ||
module.exports = Immutable; | ||
var Builder = function (type, props) { | ||
this.type = type || 'object'; | ||
this.props = props || {}; | ||
this.defineProperty = function (name, getterOrValue, options) { | ||
options = defaults(options, { enumerable: true }); | ||
options.get = ('function' === typeof getterOrValue) ? | ||
getterOrValue : function () { return Immutable.create(getterOrValue); }; | ||
options.set = function () { | ||
throw new Error('Cannot modify ' + name + ' of immutable ' + this.type); | ||
}; | ||
this.props[name] = options; | ||
}; | ||
this.defineMethod = function (name, func, options) { | ||
options = defaults(options, { enumerable: false }); | ||
options.value = func; | ||
this.props[name] = options; | ||
}; | ||
}; |
@@ -1,2 +0,1 @@ | ||
const assign = require('object-assign'); | ||
const joi = require('@hapi/joi'); | ||
@@ -6,3 +5,2 @@ const etag = require('etag'); | ||
const objectPath = require('object-path'); | ||
const defaults = require('defaults'); | ||
const clone = require('clone'); | ||
@@ -24,10 +22,2 @@ const { EJSON } = require('bson'); | ||
const removeMeta = omit(['__modified', '__original']); | ||
const onlyJoiOptions = pick(['abortEarly', 'convert', 'allowUnknown', 'skipFunctions', 'stripUnknown']); | ||
const defaultJoiOptions = { | ||
abortEarly: false, | ||
convert: false, | ||
allowUnknown: false, | ||
skipFunctions: true, | ||
stripUnknown: false | ||
}; | ||
@@ -123,3 +113,2 @@ const db = require('./db'); | ||
const _saveHelper = async function(context, options = {}, explicitId) { | ||
options = defaults(options, { waitAfterSave: false }); | ||
if (!context.isNew() && !context.isModified()) { | ||
@@ -219,7 +208,6 @@ return context; | ||
if ('object' === typeof pathOrObj && !Array.isArray(pathOrObj)) { | ||
options = defaults(value, { silent: false }); | ||
assign(this, pathOrObj); | ||
options = value; | ||
Object.assign(this, pathOrObj); | ||
paths = Object.keys(pathOrObj); | ||
} else { | ||
options = defaults(options, { silent: false }); | ||
objectPath.set(this, pathOrObj, value); | ||
@@ -229,3 +217,3 @@ paths = [pathOrObj]; | ||
if (!options.silent) { | ||
if (!options?.silent) { | ||
_markAsModified(this, paths, original); | ||
@@ -248,31 +236,20 @@ } | ||
definition.methods.toJSON = function(options) { | ||
// can only have include or exclude not both, should there be an error thrown if both are given? | ||
// probably not | ||
options = defaults(options, { | ||
virtuals: true, | ||
extended: true, | ||
exclude: undefined, // array of properties to exclude from the json object | ||
include: undefined, // array of white listed properties to include in the json object | ||
transform: undefined // function that accepts json object and returns a transformed version | ||
}); | ||
// TODO move this out of here, there are no references to this, it's just mutation...recursive | ||
definition.methods.toJSON = function({ virtuals = true, extended = true, exclude, include, transform } = {}) { | ||
let json = removeMeta(this.toObject()); | ||
json = clone(json); // not 100% sure we need to clone | ||
if (options.virtuals) { | ||
if (virtuals) { | ||
addVirtuals(definition, json); | ||
} | ||
if (options.extended) { | ||
if (extended) { | ||
json = EJSON.serialize(json); | ||
} | ||
json = _serialize(json); | ||
if (options.exclude) { | ||
json = omit(options.exclude, json); | ||
} else if (options.include) { | ||
json = pick(options.include, json); | ||
if (exclude) { | ||
json = omit(exclude, json); | ||
} else if (include) { | ||
json = pick(include, json); | ||
} | ||
if (options.transform) { | ||
json = options.transform.call(null, json); | ||
if (transform) { | ||
json = transform(json); | ||
} | ||
@@ -286,6 +263,17 @@ return json; | ||
definition.methods._validate = async function(obj, options = {}) { | ||
const joiOptions = defaults(onlyJoiOptions(options), defaultJoiOptions); | ||
definition.methods._validate = async function(obj, { | ||
abortEarly = false, | ||
convert = false, | ||
allowUnknown = false, | ||
skipFunctions = true, | ||
stripUnknown = false | ||
} = {} ) { | ||
try { | ||
return await definition._schema.validateAsync(obj, joiOptions); | ||
return await definition._schema.validateAsync(obj, { | ||
abortEarly, | ||
convert, | ||
allowUnknown, | ||
skipFunctions, | ||
stripUnknown | ||
}); | ||
} catch (err) { | ||
@@ -307,4 +295,3 @@ throw errors.Validation(err); | ||
definition.methods.remove = async function(options) { | ||
options = defaults(options, { waitAfterRemove: false }); | ||
definition.methods.remove = async function(options = {}) { | ||
const collection = definition.collection; | ||
@@ -353,7 +340,8 @@ const query = { _id: this._id, _etag: this._etag }; | ||
definition = defaults(definition, { | ||
definition = { | ||
properties: {}, | ||
methods: {}, | ||
virtuals: {} | ||
}); | ||
virtuals: {}, | ||
...definition | ||
}; | ||
@@ -388,3 +376,3 @@ if (!definition.collection && !definition.abstract) { | ||
return options.bypassGlobalWhere || !definition.where ? | ||
query : assign({}, definition.where, query); | ||
query : { ...definition.where, ...(query || {}) }; | ||
}; | ||
@@ -411,7 +399,6 @@ | ||
count: (query, options = {}) => { | ||
options = assign({}, options, { count: true }); | ||
query = applyGlobalWhere(query, options); | ||
const collection = definition.collection; | ||
debug(`counting ${JSON.stringify(query)} in ${collection}`); | ||
return db.find(collection, query, options); | ||
return db.find(collection, query, { ...options, count: true }); | ||
}, | ||
@@ -431,15 +418,13 @@ | ||
findOne: async (query, options = {}) => { | ||
options = assign({}, options, { findOne: true }); | ||
query = applyGlobalWhere(query, options); | ||
const collection = definition.collection; | ||
debug(`finding one${JSON.stringify(query)} in ${collection}`); | ||
const result = await db.find(collection, query, options); | ||
const result = await db.find(collection, query, { ...options, findOne: true }); | ||
return !result ? null : _create(result, definition); | ||
}, | ||
update: (query, update, options = {}) => { | ||
options = defaults(options, { autoSet: true }); | ||
update: (query, update, { autoSet = true, ...options } = {}) => { | ||
query = applyGlobalWhere(query, options); | ||
const collection = definition.collection; | ||
if (options.autoSet) { | ||
if (autoSet) { | ||
update = { $set: update }; | ||
@@ -489,5 +474,5 @@ } | ||
} | ||
newDef.properties = defaults(newDef.properties, superDef.properties || {}); | ||
newDef.methods = defaults(newDef.methods, superDef.methods || {}); | ||
newDef.virtuals = defaults(newDef.virtuals, superDef.virtuals || {}); | ||
newDef.properties = { ...(superDef.properties || {}), ...(newDef.properties || {}) }; | ||
newDef.methods = { ...(superDef.methods || {}), ...(newDef.methods || {}) }; | ||
newDef.virtuals = { ...(superDef.virtuals || {}), ...(newDef.virtuals || {}) }; | ||
return define(newDef); | ||
@@ -494,0 +479,0 @@ }; |
@@ -7,7 +7,7 @@ const Immutable = require('./immutable'); | ||
if ('function' === typeof value) { return; } | ||
const getter = function () { | ||
const getter = function() { | ||
return (value = Immutable.create(value, { clone: false })); | ||
}; | ||
builder.defineProperty(name, getter); | ||
} | ||
}; | ||
@@ -17,9 +17,12 @@ /** | ||
* @name ImmutableObject | ||
* @param {object} data | ||
* @param {object} builder | ||
* @param {object} data - Underlying array | ||
* @param {object} builder - Builder instance | ||
* @returns {undefined} no return value | ||
*/ | ||
module.exports = function (data, builder) { | ||
for (let p in data) { | ||
addProp(p, builder, data); | ||
module.exports = function(data, builder) { | ||
for (const p in data) { | ||
if (Object.prototype.hasOwnProperty.call(data, p)) { | ||
addProp(p, builder, data); | ||
} | ||
} | ||
}; |
{ | ||
"name": "cosa", | ||
"version": "6.0.1", | ||
"version": "6.1.0", | ||
"description": "Cosa Models for MongoDB", | ||
@@ -38,12 +38,10 @@ "main": "lib/index.js", | ||
"dependencies": { | ||
"bson": "~4.5.1", | ||
"bson": "~4.5.2", | ||
"clone": "^2.1.2", | ||
"debug": "^4.3.2", | ||
"defaults": "^1.0.3", | ||
"error": "^7.0.2", | ||
"etag": "^1.8.1", | ||
"@hapi/joi": "^17.1.1", | ||
"mongodb": "~4.1.1", | ||
"object-assign": "^4.1.1", | ||
"object-path": "^0.11.7", | ||
"mongodb": "~4.1.2", | ||
"object-path": "^0.11.8", | ||
"omnibelt": "^2.1.0" | ||
@@ -65,9 +63,2 @@ }, | ||
}, | ||
"eslintIgnore": [ | ||
"lib/array.js", | ||
"lib/date.js", | ||
"lib/defined-object.js", | ||
"lib/immutable.js", | ||
"lib/object.js" | ||
], | ||
"mocha": { | ||
@@ -74,0 +65,0 @@ "require": "chai", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
9
61789
1456
- Removeddefaults@^1.0.3
- Removedobject-assign@^4.1.1
- Removedclone@1.0.4(transitive)
- Removeddefaults@1.0.4(transitive)
- Removedobject-assign@4.1.1(transitive)
Updatedbson@~4.5.2
Updatedmongodb@~4.1.2
Updatedobject-path@^0.11.8