loopback-connector-mongodb
Advanced tools
Comparing version
@@ -6,2 +6,4 @@ // Copyright IBM Corp. 2015,2016. All Rights Reserved. | ||
'use strict'; | ||
var DataSource = require('loopback-datasource-juggler').DataSource; | ||
@@ -17,3 +19,3 @@ var connector = require('..'); | ||
var Todo = ds.define('Todo', { | ||
content: { type: String }, | ||
content: {type: String}, | ||
}); | ||
@@ -30,3 +32,3 @@ | ||
var suite = new Benchmark.Suite; | ||
var suite = new Benchmark.Suite(); | ||
suite | ||
@@ -39,3 +41,3 @@ .on('start', function() { | ||
fn: function(deferred) { | ||
Todo.create({ content: 'Buy eggs, ' + (uniqVal++) }, function() { | ||
Todo.create({content: 'Buy eggs, ' + uniqVal++}, function() { | ||
deferred.resolve(); | ||
@@ -55,5 +57,5 @@ }); | ||
Todo.create([ | ||
{ content: 'Buy eggs' }, | ||
{ content: 'Buy milk' }, | ||
{ content: 'Buy cheese' }, | ||
{content: 'Buy eggs'}, | ||
{content: 'Buy milk'}, | ||
{content: 'Buy cheese'}, | ||
]); | ||
@@ -66,3 +68,3 @@ }, | ||
fn: function(deferred) { | ||
Todo.find({ where: { content: 'Buy milk' }}, function() { | ||
Todo.find({where: {content: 'Buy milk'}}, function() { | ||
deferred.resolve(); | ||
@@ -73,5 +75,5 @@ }); | ||
Todo.create([ | ||
{ content: 'Buy eggs' }, | ||
{ content: 'Buy milk' }, | ||
{ content: 'Buy cheese' }, | ||
{content: 'Buy eggs'}, | ||
{content: 'Buy milk'}, | ||
{content: 'Buy cheese'}, | ||
]); | ||
@@ -89,2 +91,2 @@ }, | ||
}) | ||
.run({ async: true }); | ||
.run({async: true}); |
@@ -0,1 +1,9 @@ | ||
2018-07-24, Version 3.5.0 | ||
========================= | ||
* chore: drop node 4 and update deps (Taranveer Virk) | ||
* [WebFM] cs/pl/ru translation (candytangnb) | ||
2018-06-05, Version 3.4.4 | ||
@@ -2,0 +10,0 @@ ========================= |
@@ -6,2 +6,4 @@ // Copyright IBM Corp. 2013,2016. All Rights Reserved. | ||
'use strict'; | ||
var g = require('strong-globalize')(); | ||
@@ -11,39 +13,52 @@ | ||
var config = require('rc')('loopback', { dev: { mongodb: {}}}).dev.mongodb; | ||
var config = require('rc')('loopback', {dev: {mongodb: {}}}).dev.mongodb; | ||
var ds = new DataSource(require('../'), config); | ||
var Customer = ds.createModel('customer', { seq: { type: Number, id: true }, name: String, emails: [ | ||
{ label: String, email: String }, | ||
], age: Number }); | ||
var Customer = ds.createModel('customer', { | ||
seq: {type: Number, id: true}, | ||
name: String, | ||
emails: [{label: String, email: String}], | ||
age: Number, | ||
}); | ||
Customer.destroyAll(function(err) { | ||
Customer.create({ | ||
seq: 1, | ||
name: 'John1', | ||
emails: [ | ||
{ label: 'work', email: 'john@x.com' }, | ||
{ label: 'home', email: 'john@y.com' }, | ||
], | ||
age: 30, | ||
}, function(err, customer1) { | ||
console.log(customer1.toObject()); | ||
Customer.create({ | ||
seq: 2, | ||
name: 'John2', | ||
Customer.create( | ||
{ | ||
seq: 1, | ||
name: 'John1', | ||
emails: [ | ||
{ label: 'work', email: 'john2@x.com' }, | ||
{ label: 'home', email: 'john2@y.com' }, | ||
{label: 'work', email: 'john@x.com'}, | ||
{label: 'home', email: 'john@y.com'}, | ||
], | ||
age: 35, | ||
}, function(err, customer2) { | ||
Customer.find({ where: { 'emails.email': 'john@x.com' }}, function(err, customers) { | ||
g.log('{{Customers}} matched by {{emails.email}} %s', customers); | ||
}); | ||
age: 30, | ||
}, | ||
function(err, customer1) { | ||
console.log(customer1.toObject()); | ||
Customer.find({ where: { 'emails.0.label': 'work' }}, function(err, customers) { | ||
g.log('{{Customers}} matched by {{emails.0.label}} %s', customers); | ||
}); | ||
/* | ||
Customer.create( | ||
{ | ||
seq: 2, | ||
name: 'John2', | ||
emails: [ | ||
{label: 'work', email: 'john2@x.com'}, | ||
{label: 'home', email: 'john2@y.com'}, | ||
], | ||
age: 35, | ||
}, | ||
function(err, customer2) { | ||
Customer.find({where: {'emails.email': 'john@x.com'}}, function( | ||
err, | ||
customers | ||
) { | ||
g.log('{{Customers}} matched by {{emails.email}} %s', customers); | ||
}); | ||
Customer.find({where: {'emails.0.label': 'work'}}, function( | ||
err, | ||
customers | ||
) { | ||
g.log('{{Customers}} matched by {{emails.0.label}} %s', customers); | ||
}); | ||
/* | ||
customer1.updateAttributes({name: 'John'}, function(err, result) { | ||
@@ -53,3 +68,2 @@ console.log(err, result); | ||
customer1.delete(function(err, result) { | ||
@@ -63,15 +77,15 @@ customer1.updateAttributes({name: 'JohnX'}, function(err, result) { | ||
Customer.findById(customer1.seq, function(err, customer1) { | ||
console.log(customer1.toObject()); | ||
Customer.findById(customer1.seq, function(err, customer1) { | ||
console.log(customer1.toObject()); | ||
customer1.name = 'John'; | ||
customer1.save(function(err, customer1) { | ||
console.log(customer1.toObject()); | ||
ds.disconnect(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
customer1.name = 'John'; | ||
customer1.save(function(err, customer1) { | ||
console.log(customer1.toObject()); | ||
ds.disconnect(); | ||
}); | ||
}); | ||
} | ||
); | ||
} | ||
); | ||
}); | ||
@@ -6,2 +6,4 @@ // Copyright IBM Corp. 2012. All Rights Reserved. | ||
'use strict'; | ||
var SG = require('strong-globalize'); | ||
@@ -8,0 +10,0 @@ SG.SetRootDir(__dirname); |
@@ -6,2 +6,4 @@ // Copyright IBM Corp. 2015,2016. All Rights Reserved. | ||
'use strict'; | ||
var DataSource = require('loopback-datasource-juggler').DataSource; | ||
@@ -16,5 +18,5 @@ var connector = require('../..'); | ||
var Todo = db.define('Todo', { | ||
content: { type: String }, | ||
content: {type: String}, | ||
}); | ||
module.exports = Todo; |
@@ -6,4 +6,5 @@ // Copyright IBM Corp. 2015. All Rights Reserved. | ||
global.sinon = require('sinon'); | ||
'use strict'; | ||
global.ITERATIONS = process.env.ITERATIONS || 100; | ||
require('should'); |
@@ -6,3 +6,6 @@ // Copyright IBM Corp. 2015. All Rights Reserved. | ||
'use strict'; | ||
var memwatch = require('memwatch-next'); | ||
var sinon = require('sinon'); | ||
@@ -20,4 +23,4 @@ describe('leak detector', function() { | ||
var interval = setInterval(function() { | ||
if (test.iterations >= ITERATIONS || test.spy.called) { | ||
test.spy.called.should.be.true; | ||
if (test.iterations >= global.ITERATIONS || test.spy.called) { | ||
test.spy.called.should.be.True(); | ||
clearInterval(interval); | ||
@@ -24,0 +27,0 @@ return done(); |
@@ -6,3 +6,6 @@ // Copyright IBM Corp. 2015,2016. All Rights Reserved. | ||
'use strict'; | ||
var memwatch = require('memwatch-next'); | ||
var sinon = require('sinon'); | ||
var Todo = require('./fixtures/todo'); | ||
@@ -33,4 +36,4 @@ | ||
var interval = setInterval(function() { | ||
if (ctx.iterations >= ITERATIONS || ctx.spy.called) { | ||
ctx.spy.called.should.be.false; | ||
if (ctx.iterations >= global.ITERATIONS || ctx.spy.called) { | ||
ctx.spy.called.should.be.False(); | ||
clearInterval(interval); | ||
@@ -40,2 +43,3 @@ return done(); | ||
ctx.iterations++; | ||
// eslint-disable-next-line | ||
hasOptions ? Todo[func](options) : Todo[func]; | ||
@@ -51,11 +55,14 @@ }, 0); | ||
beforeEach(function createFixtures(done) { | ||
Todo.create([ | ||
{ content: 'Buy eggs' }, | ||
{ content: 'Buy milk' }, | ||
{ content: 'Buy cheese' }, | ||
], done); | ||
Todo.create( | ||
[ | ||
{content: 'Buy eggs'}, | ||
{content: 'Buy milk'}, | ||
{content: 'Buy cheese'}, | ||
], | ||
done | ||
); | ||
}); | ||
it('should not leak when retrieving a specific item', function(done) { | ||
execute(this, 'find', { where: { content: 'Buy eggs' }}, done); | ||
execute(this, 'find', {where: {content: 'Buy eggs'}}, done); | ||
}); | ||
@@ -74,13 +81,18 @@ | ||
it('should not leak when creating an item', function(done) { | ||
execute(this, 'create', { content: 'Buy eggs' }, done); | ||
execute(this, 'create', {content: 'Buy eggs'}, done); | ||
}); | ||
it('should not leak when creating multiple items', function(done) { | ||
execute(this, 'create', [ | ||
{ content: 'Buy eggs' }, | ||
{ content: 'Buy milk' }, | ||
{ content: 'Buy cheese' }, | ||
], done); | ||
execute( | ||
this, | ||
'create', | ||
[ | ||
{content: 'Buy eggs'}, | ||
{content: 'Buy milk'}, | ||
{content: 'Buy cheese'}, | ||
], | ||
done | ||
); | ||
}); | ||
}); | ||
}); |
@@ -6,2 +6,4 @@ // Copyright IBM Corp. 2012,2016. All Rights Reserved. | ||
'use strict'; | ||
/*! | ||
@@ -51,10 +53,28 @@ * Module dependencies | ||
function generateMongoDBURL(options) { | ||
options.hostname = (options.hostname || options.host || '127.0.0.1'); | ||
options.port = (options.port || 27017); | ||
options.database = (options.database || options.db || 'test'); | ||
options.hostname = options.hostname || options.host || '127.0.0.1'; | ||
options.port = options.port || 27017; | ||
options.database = options.database || options.db || 'test'; | ||
var username = options.username || options.user; | ||
if (username && options.password) { | ||
return 'mongodb://' + username + ':' + options.password + '@' + options.hostname + ':' + options.port + '/' + options.database; | ||
return ( | ||
'mongodb://' + | ||
username + | ||
':' + | ||
options.password + | ||
'@' + | ||
options.hostname + | ||
':' + | ||
options.port + | ||
'/' + | ||
options.database | ||
); | ||
} else { | ||
return 'mongodb://' + options.hostname + ':' + options.port + '/' + options.database; | ||
return ( | ||
'mongodb://' + | ||
options.hostname + | ||
':' + | ||
options.port + | ||
'/' + | ||
options.database | ||
); | ||
} | ||
@@ -75,3 +95,3 @@ } | ||
s.safe = (s.safe !== false); | ||
s.safe = s.safe !== false; | ||
s.w = s.w || 1; | ||
@@ -95,3 +115,3 @@ s.url = s.url || generateMongoDBURL(s); | ||
/** | ||
/** | ||
* The constructor for MongoDB connector | ||
@@ -112,6 +132,8 @@ * @param {Object} settings The settings object | ||
this.dataSource = dataSource; | ||
if (this.settings.enableOptimisedfindOrCreate === true || | ||
if ( | ||
this.settings.enableOptimisedfindOrCreate === true || | ||
this.settings.enableOptimisedFindOrCreate === true || | ||
this.settings.enableOptimizedfindOrCreate === true || | ||
this.settings.enableOptimizedFindOrCreate === true) { | ||
this.settings.enableOptimizedFindOrCreate === true | ||
) { | ||
MongoDB.prototype.findOrCreate = optimizedFindOrCreate; | ||
@@ -140,3 +162,3 @@ } | ||
process.nextTick(function() { | ||
callback && callback(null, self.db); | ||
if (callback) callback(null, self.db); | ||
}); | ||
@@ -146,3 +168,3 @@ } else if (self.dataSource.connecting) { | ||
process.nextTick(function() { | ||
callback && callback(null, self.db); | ||
if (callback) callback(null, self.db); | ||
}); | ||
@@ -227,3 +249,6 @@ }); | ||
debug('Valid options: %j', validOptions); | ||
new mongodb.MongoClient(self.settings.url, validOptions).connect(function(err, client) { | ||
new mongodb.MongoClient(self.settings.url, validOptions).connect(function( | ||
err, | ||
client | ||
) { | ||
if (!err) { | ||
@@ -236,10 +261,17 @@ if (self.debug) { | ||
return urlParser(self.settings.url, self.settings, function(err, url) { | ||
self.db = client.db(url.dbName || self.settings.database, url.db_options || self.settings); | ||
callback && callback(err, self.db); | ||
self.db = client.db( | ||
url.dbName || self.settings.database, | ||
url.db_options || self.settings | ||
); | ||
if (callback) callback(err, self.db); | ||
}); | ||
} else { | ||
if (self.debug || !callback) { | ||
g.error('{{MongoDB}} connection is failed: %s %s', self.settings.url, err); | ||
g.error( | ||
'{{MongoDB}} connection is failed: %s %s', | ||
self.settings.url, | ||
err | ||
); | ||
} | ||
callback && callback(err, self.db); | ||
if (callback) callback(err, self.db); | ||
} | ||
@@ -307,4 +339,9 @@ }); | ||
} | ||
} else if (data[p] && prop && prop.type && prop.type.name === 'GeoPoint' && | ||
this.settings.enableGeoIndexing === true) { | ||
} else if ( | ||
data[p] && | ||
prop && | ||
prop.type && | ||
prop.type.name === 'GeoPoint' && | ||
this.settings.enableGeoIndexing === true | ||
) { | ||
data[p] = { | ||
@@ -376,3 +413,8 @@ lat: data[p].coordinates[1], | ||
if (err) { | ||
debug('Connection not established - MongoDB: model=%s command=%s -- error=%s', model, command, err); | ||
debug( | ||
'Connection not established - MongoDB: model=%s command=%s -- error=%s', | ||
model, | ||
command, | ||
err | ||
); | ||
} | ||
@@ -387,3 +429,4 @@ doExecute(); | ||
model: model, | ||
collection: collection, req: { | ||
collection: collection, | ||
req: { | ||
command: command, | ||
@@ -395,3 +438,3 @@ params: args, | ||
try { | ||
var collection = self.collection(model); | ||
collection = self.collection(model); | ||
} catch (err) { | ||
@@ -403,15 +446,20 @@ debug('Error: ', err); | ||
self.notifyObserversAround('execute', context, function(context, done) { | ||
args[args.length - 1] = function(err, result) { | ||
if (err) { | ||
debug('Error: ', err); | ||
} else { | ||
context.res = result; | ||
debug('Result: ', result); | ||
} | ||
done(err, result); | ||
}; | ||
debug('MongoDB: model=%s command=%s', model, command, args); | ||
return collection[command].apply(collection, args); | ||
}, callback); | ||
self.notifyObserversAround( | ||
'execute', | ||
context, | ||
function(context, done) { | ||
args[args.length - 1] = function(err, result) { | ||
if (err) { | ||
debug('Error: ', err); | ||
} else { | ||
context.res = result; | ||
debug('Result: ', result); | ||
} | ||
done(err, result); | ||
}; | ||
debug('MongoDB: model=%s command=%s', model, command, args); | ||
return collection[command].apply(collection, args); | ||
}, | ||
callback | ||
); | ||
} | ||
@@ -464,3 +512,5 @@ }; | ||
data._id = oid; // Set it to _id | ||
idName !== '_id' && delete data[idName]; | ||
if (idName !== '_id') { | ||
delete data[idName]; | ||
} | ||
} | ||
@@ -470,3 +520,3 @@ | ||
this.execute(model, 'insert', data, { safe: true }, function(err, result) { | ||
this.execute(model, 'insert', data, {safe: true}, function(err, result) { | ||
if (self.debug) { | ||
@@ -507,3 +557,5 @@ debug('create.callback', model, err, result); | ||
data._id = oid; | ||
idName !== '_id' && delete data[idName]; | ||
if (idName !== '_id') { | ||
delete data[idName]; | ||
} | ||
@@ -515,3 +567,5 @@ data = self.toDatabase(model, data); | ||
self.setIdValue(model, data, idValue); | ||
idName !== '_id' && delete data._id; | ||
if (idName !== '_id') { | ||
delete data._id; | ||
} | ||
} | ||
@@ -538,3 +592,5 @@ if (self.debug) { | ||
callback && callback(err, result && result.ops, info); | ||
if (callback) { | ||
callback(err, result && result.ops, info); | ||
} | ||
}); | ||
@@ -556,3 +612,3 @@ }; | ||
id = self.coerceId(model, id); | ||
this.execute(model, 'findOne', { _id: id }, function(err, data) { | ||
this.execute(model, 'findOne', {_id: id}, function(err, data) { | ||
if (self.debug) { | ||
@@ -578,3 +634,3 @@ debug('exists.callback', model, id, err, data); | ||
var oid = self.coerceId(model, id); | ||
this.execute(model, 'findOne', { _id: oid }, function(err, data) { | ||
this.execute(model, 'findOne', {_id: oid}, function(err, data) { | ||
if (self.debug) { | ||
@@ -585,9 +641,12 @@ debug('find.callback', model, id, err, data); | ||
data = self.fromDatabase(model, data); | ||
data && idName !== '_id' && delete data._id; | ||
callback && callback(err, data); | ||
if (data && idName !== '_id') { | ||
delete data._id; | ||
} | ||
if (callback) { | ||
callback(err, data); | ||
} | ||
}); | ||
}; | ||
Connector.defineAliases(MongoDB.prototype, 'find', | ||
'findById'); | ||
Connector.defineAliases(MongoDB.prototype, 'find', 'findById'); | ||
@@ -610,5 +669,9 @@ /** | ||
allowExtendedOperators = options.allowExtendedOperators === true; | ||
} else if (allowExtendedOperators !== false && modelClass.settings.mongodb && | ||
modelClass.settings.mongodb.hasOwnProperty('allowExtendedOperators')) { | ||
allowExtendedOperators = modelClass.settings.mongodb.allowExtendedOperators === true; | ||
} else if ( | ||
allowExtendedOperators !== false && | ||
modelClass.settings.mongodb && | ||
modelClass.settings.mongodb.hasOwnProperty('allowExtendedOperators') | ||
) { | ||
allowExtendedOperators = | ||
modelClass.settings.mongodb.allowExtendedOperators === true; | ||
} else if (allowExtendedOperators === true) { | ||
@@ -622,5 +685,18 @@ allowExtendedOperators = true; | ||
// Field operators | ||
'$currentDate', '$inc', '$max', '$min', '$mul', '$rename', '$setOnInsert', '$set', '$unset', | ||
'$currentDate', | ||
'$inc', | ||
'$max', | ||
'$min', | ||
'$mul', | ||
'$rename', | ||
'$setOnInsert', | ||
'$set', | ||
'$unset', | ||
// Array operators | ||
'$addToSet', '$pop', '$pullAll', '$pull', '$pushAll', '$push', | ||
'$addToSet', | ||
'$pop', | ||
'$pullAll', | ||
'$pull', | ||
'$pushAll', | ||
'$push', | ||
// Bitwise operator | ||
@@ -658,3 +734,8 @@ '$bit', | ||
*/ | ||
MongoDB.prototype.updateOrCreate = function updateOrCreate(model, data, options, callback) { | ||
MongoDB.prototype.updateOrCreate = function updateOrCreate( | ||
model, | ||
data, | ||
options, | ||
callback | ||
) { | ||
var self = this; | ||
@@ -675,29 +756,39 @@ if (self.debug) { | ||
this.execute(model, 'findAndModify', { | ||
_id: oid, | ||
}, [ | ||
['_id', 'asc'], | ||
], data, { upsert: true, new: true }, function(err, result) { | ||
if (self.debug) { | ||
debug('updateOrCreate.callback', model, id, err, result); | ||
} | ||
var object = result && result.value; | ||
if (!err && !object) { | ||
// No result | ||
err = 'No ' + model + ' found for id ' + id; | ||
} | ||
if (!err) { | ||
self.setIdValue(model, object, oid); | ||
object && idName !== '_id' && delete object._id; | ||
} | ||
this.execute( | ||
model, | ||
'findAndModify', | ||
{ | ||
_id: oid, | ||
}, | ||
[['_id', 'asc']], | ||
data, | ||
{upsert: true, new: true}, | ||
function(err, result) { | ||
if (self.debug) { | ||
debug('updateOrCreate.callback', model, id, err, result); | ||
} | ||
var object = result && result.value; | ||
if (!err && !object) { | ||
// No result | ||
err = 'No ' + model + ' found for id ' + id; | ||
} | ||
if (!err) { | ||
self.setIdValue(model, object, oid); | ||
if (object && idName !== '_id') { | ||
delete object._id; | ||
} | ||
} | ||
var info; | ||
if (result && result.lastErrorObject) { | ||
info = { isNewInstance: !result.lastErrorObject.updatedExisting }; | ||
} else { | ||
debug('updateOrCreate result format not recognized: %j', result); | ||
var info; | ||
if (result && result.lastErrorObject) { | ||
info = {isNewInstance: !result.lastErrorObject.updatedExisting}; | ||
} else { | ||
debug('updateOrCreate result format not recognized: %j', result); | ||
} | ||
if (callback) { | ||
callback(err, object, info); | ||
} | ||
} | ||
callback && callback(err, object, info); | ||
}); | ||
); | ||
}; | ||
@@ -721,3 +812,3 @@ | ||
delete data[idName]; | ||
this.replaceWithOptions(model, oid, data, { upsert: true }, cb); | ||
this.replaceWithOptions(model, oid, data, {upsert: true}, cb); | ||
}; | ||
@@ -737,3 +828,3 @@ | ||
id = self.coerceId(model, id); | ||
this.execute(model, 'remove', { _id: id }, function(err, result) { | ||
this.execute(model, 'remove', {_id: id}, function(err, result) { | ||
if (self.debug) { | ||
@@ -744,5 +835,7 @@ debug('delete.callback', model, id, err, result); | ||
if (res) { | ||
res = { count: res.n }; | ||
res = {count: res.n}; | ||
} | ||
callback && callback(err, res); | ||
if (callback) { | ||
callback(err, res); | ||
} | ||
}); | ||
@@ -768,3 +861,3 @@ }; | ||
} | ||
if ((idName in fields) && !fields[idName]) { | ||
if (idName in fields && !fields[idName]) { | ||
// Excluded | ||
@@ -782,3 +875,3 @@ return false; | ||
var query = {}; | ||
if (where === null || (typeof where !== 'object')) { | ||
if (where === null || typeof where !== 'object') { | ||
return query; | ||
@@ -821,3 +914,3 @@ } | ||
if (spec === 'between') { | ||
query[k] = { $gte: cond[0], $lte: cond[1] }; | ||
query[k] = {$gte: cond[0], $lte: cond[1]}; | ||
} else if (spec === 'inq') { | ||
@@ -841,14 +934,14 @@ cond = [].concat(cond || []); | ||
if (cond instanceof RegExp) { | ||
query[k] = { $regex: cond }; | ||
query[k] = {$regex: cond}; | ||
} else { | ||
query[k] = { $regex: new RegExp(cond, options) }; | ||
query[k] = {$regex: new RegExp(cond, options)}; | ||
} | ||
} else if (spec === 'nlike') { | ||
if (cond instanceof RegExp) { | ||
query[k] = { $not: cond }; | ||
query[k] = {$not: cond}; | ||
} else { | ||
query[k] = { $not: new RegExp(cond, options) }; | ||
query[k] = {$not: new RegExp(cond, options)}; | ||
} | ||
} else if (spec === 'neq') { | ||
query[k] = { $ne: cond }; | ||
query[k] = {$ne: cond}; | ||
} else if (spec === 'regexp') { | ||
@@ -858,3 +951,3 @@ if (cond.global) | ||
query[k] = { $regex: cond }; | ||
query[k] = {$regex: cond}; | ||
} else { | ||
@@ -868,3 +961,3 @@ query[k] = {}; | ||
// Null: 10 | ||
query[k] = { $type: 10 }; | ||
query[k] = {$type: 10}; | ||
} else { | ||
@@ -913,3 +1006,3 @@ if (self.isObjectIDProperty(model, prop, cond)) { | ||
// order by _id by default | ||
sort = { _id: 1 }; | ||
sort = {_id: 1}; | ||
} | ||
@@ -930,3 +1023,7 @@ return sort; | ||
default: | ||
console.warn('unsupported unit ' + unit + ', fallback to mongodb default unit \'meters\''); | ||
console.warn( | ||
'unsupported unit ' + | ||
unit + | ||
", fallback to mongodb default unit 'meters'" | ||
); | ||
return distance; | ||
@@ -986,3 +1083,5 @@ } | ||
if (!property.hasOwnProperty(subKey)) { | ||
property[subKey] = Number.isInteger(near.mongoKey[i + 1]) ? [] : {}; | ||
property[subKey] = Number.isInteger(near.mongoKey[i + 1]) ? | ||
[] : | ||
{}; | ||
} | ||
@@ -1001,3 +1100,3 @@ | ||
}); | ||
}; | ||
} | ||
@@ -1064,5 +1163,10 @@ function hasNearFilter(where) { | ||
if (prop.mongodb) { | ||
propName = prop.mongodb.fieldName || prop.mongodb.field || | ||
prop.mongodb.columnName || prop.mongodb.column || | ||
prop.columnName || prop.column || propName; | ||
propName = | ||
prop.mongodb.fieldName || | ||
prop.mongodb.field || | ||
prop.mongodb.columnName || | ||
prop.mongodb.column || | ||
prop.columnName || | ||
prop.column || | ||
propName; | ||
} else { | ||
@@ -1150,3 +1254,3 @@ // Try top level overrides | ||
// convert the array of fields into a projection object see http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#find | ||
var findOpts = { projection: fields }; | ||
var findOpts = {projection: fields}; | ||
this.execute(model, 'find', query, findOpts, processResponse); | ||
@@ -1200,3 +1304,8 @@ } else { | ||
if (filter && filter.include) { | ||
self._models[model].model.include(objs, filter.include, options, callback); | ||
self._models[model].model.include( | ||
objs, | ||
filter.include, | ||
options, | ||
callback | ||
); | ||
} else { | ||
@@ -1215,3 +1324,8 @@ callback(null, objs); | ||
*/ | ||
MongoDB.prototype.destroyAll = function destroyAll(model, where, options, callback) { | ||
MongoDB.prototype.destroyAll = function destroyAll( | ||
model, | ||
where, | ||
options, | ||
callback | ||
) { | ||
var self = this; | ||
@@ -1229,8 +1343,9 @@ if (self.debug) { | ||
if (self.debug) | ||
debug('destroyAll.callback', model, where, err, info); | ||
if (self.debug) debug('destroyAll.callback', model, where, err, info); | ||
var affectedCount = info.result ? info.result.n : undefined; | ||
callback && callback(err, { count: affectedCount }); | ||
if (callback) { | ||
callback(err, {count: affectedCount}); | ||
} | ||
}); | ||
@@ -1257,3 +1372,5 @@ }; | ||
} | ||
callback && callback(err, count); | ||
if (callback) { | ||
callback(err, count); | ||
} | ||
}); | ||
@@ -1273,3 +1390,6 @@ }; | ||
var oid = this.coerceId(model, id); | ||
this.replaceWithOptions(model, oid, data, { upsert: false }, function(err, data) { | ||
this.replaceWithOptions(model, oid, data, {upsert: false}, function( | ||
err, | ||
data | ||
) { | ||
cb(err, data); | ||
@@ -1298,5 +1418,8 @@ }); | ||
delete data[idName]; | ||
this.execute(model, 'update', { _id: id }, data, options, function(err, info) { | ||
if (this.debug) debug('updateWithOptions.callback', model, { _id: id }, data, err, info); | ||
if (err) return cb && cb(err); | ||
this.execute(model, 'update', {_id: id}, data, options, function( | ||
err, | ||
info | ||
) { | ||
debug('updateWithOptions.callback', model, {_id: id}, data, err, info); | ||
if (err) return cb && cb(err); | ||
var result; | ||
@@ -1322,3 +1445,5 @@ var cbInfo = {}; | ||
} | ||
cb && cb(err, result, cbInfo); | ||
if (cb) { | ||
cb(err, result, cbInfo); | ||
} | ||
}); | ||
@@ -1333,3 +1458,9 @@ }; | ||
*/ | ||
MongoDB.prototype.updateAttributes = function updateAttrs(model, id, data, options, cb) { | ||
MongoDB.prototype.updateAttributes = function updateAttrs( | ||
model, | ||
id, | ||
data, | ||
options, | ||
cb | ||
) { | ||
var self = this; | ||
@@ -1347,3 +1478,7 @@ | ||
if (Object.keys(data).length === 0) { | ||
cb && process.nextTick(function() { cb(null, {}); }); | ||
if (cb) { | ||
process.nextTick(function() { | ||
cb(null, {}); | ||
}); | ||
} | ||
return; | ||
@@ -1355,17 +1490,27 @@ } | ||
this.execute(model, 'findAndModify', { _id: oid }, [ | ||
['_id', 'asc'], | ||
], data, {}, function(err, result) { | ||
if (self.debug) { | ||
debug('updateAttributes.callback', model, id, err, result); | ||
this.execute( | ||
model, | ||
'findAndModify', | ||
{_id: oid}, | ||
[['_id', 'asc']], | ||
data, | ||
{}, | ||
function(err, result) { | ||
if (self.debug) { | ||
debug('updateAttributes.callback', model, id, err, result); | ||
} | ||
var object = result && result.value; | ||
if (!err && !object) { | ||
// No result | ||
err = errorIdNotFoundForUpdate(model, id); | ||
} | ||
self.setIdValue(model, object, id); | ||
if (object && idName !== '_id') { | ||
delete object._id; | ||
} | ||
if (cb) { | ||
cb(err, object); | ||
} | ||
} | ||
var object = result && result.value; | ||
if (!err && !object) { | ||
// No result | ||
err = errorIdNotFoundForUpdate(model, id); | ||
} | ||
self.setIdValue(model, object, id); | ||
object && idName !== '_id' && delete object._id; | ||
cb && cb(err, object); | ||
}); | ||
); | ||
}; | ||
@@ -1387,30 +1532,43 @@ | ||
*/ | ||
MongoDB.prototype.update = | ||
MongoDB.prototype.updateAll = function updateAll(model, where, data, options, cb) { | ||
var self = this; | ||
if (self.debug) { | ||
debug('updateAll', model, where, data); | ||
} | ||
var idName = this.idName(model); | ||
MongoDB.prototype.update = MongoDB.prototype.updateAll = function updateAll( | ||
model, | ||
where, | ||
data, | ||
options, | ||
cb | ||
) { | ||
var self = this; | ||
if (self.debug) { | ||
debug('updateAll', model, where, data); | ||
} | ||
var idName = this.idName(model); | ||
where = self.buildWhere(model, where); | ||
delete data[idName]; | ||
where = self.buildWhere(model, where); | ||
delete data[idName]; | ||
data = self.toDatabase(model, data); | ||
data = self.toDatabase(model, data); | ||
// Check for other operators and sanitize the data obj | ||
data = self.parseUpdateData(model, data, options); | ||
// Check for other operators and sanitize the data obj | ||
data = self.parseUpdateData(model, data, options); | ||
this.execute(model, 'update', where, data, { multi: true, upsert: false }, | ||
function(err, info) { | ||
if (err) return cb && cb(err); | ||
this.execute( | ||
model, | ||
'update', | ||
where, | ||
data, | ||
{multi: true, upsert: false}, | ||
function(err, info) { | ||
if (err) return cb && cb(err); | ||
if (self.debug) | ||
debug('updateAll.callback', model, where, data, err, info); | ||
if (self.debug) | ||
debug('updateAll.callback', model, where, data, err, info); | ||
var affectedCount = info.result ? info.result.n : undefined; | ||
var affectedCount = info.result ? info.result.n : undefined; | ||
cb && cb(err, { count: affectedCount }); | ||
}); | ||
}; | ||
if (cb) { | ||
cb(err, {count: affectedCount}); | ||
} | ||
} | ||
); | ||
}; | ||
@@ -1447,3 +1605,3 @@ /** | ||
} | ||
if ((!cb) && ('function' === typeof models)) { | ||
if (!cb && 'function' === typeof models) { | ||
cb = models; | ||
@@ -1461,85 +1619,105 @@ models = undefined; | ||
async.each(models, function(model, modelCallback) { | ||
var indexes = self._models[model].settings.indexes || []; | ||
var indexList = []; | ||
var index = {}; | ||
var options = {}; | ||
async.each( | ||
models, | ||
function(model, modelCallback) { | ||
var indexes = self._models[model].settings.indexes || []; | ||
var indexList = []; | ||
var index = {}; | ||
var options = {}; | ||
if (typeof indexes === 'object') { | ||
for (var indexName in indexes) { | ||
index = indexes[indexName]; | ||
if (index.keys) { | ||
// The index object has keys | ||
options = index.options || {}; | ||
options.name = options.name || indexName; | ||
index.options = options; | ||
} else { | ||
options = { name: indexName }; | ||
index = { | ||
keys: index, | ||
options: options, | ||
}; | ||
if (typeof indexes === 'object') { | ||
for (var indexName in indexes) { | ||
index = indexes[indexName]; | ||
if (index.keys) { | ||
// The index object has keys | ||
options = index.options || {}; | ||
options.name = options.name || indexName; | ||
index.options = options; | ||
} else { | ||
options = {name: indexName}; | ||
index = { | ||
keys: index, | ||
options: options, | ||
}; | ||
} | ||
indexList.push(index); | ||
} | ||
indexList.push(index); | ||
} else if (Array.isArray(indexes)) { | ||
indexList = indexList.concat(indexes); | ||
} | ||
} else if (Array.isArray(indexes)) { | ||
indexList = indexList.concat(indexes); | ||
} | ||
var properties = self._models[model].properties; | ||
/* eslint-disable one-var */ | ||
for (var p in properties) { | ||
if (properties[p].index) { | ||
index = {}; | ||
index[p] = 1; // Add the index key | ||
if (typeof properties[p].index === 'object') { | ||
// If there is a mongodb key for the index, use it | ||
if (typeof properties[p].index.mongodb === 'object') { | ||
options = properties[p].index.mongodb; | ||
index[p] = options.kind || 1; | ||
var properties = self._models[model].properties; | ||
/* eslint-disable one-var */ | ||
for (var p in properties) { | ||
if (properties[p].index) { | ||
index = {}; | ||
index[p] = 1; // Add the index key | ||
if (typeof properties[p].index === 'object') { | ||
// If there is a mongodb key for the index, use it | ||
if (typeof properties[p].index.mongodb === 'object') { | ||
options = properties[p].index.mongodb; | ||
index[p] = options.kind || 1; | ||
// If 'kind' is set delete it so it isn't accidentally inserted as an index option | ||
if (options.kind) { | ||
delete options.kind; | ||
// If 'kind' is set delete it so it isn't accidentally inserted as an index option | ||
if (options.kind) { | ||
delete options.kind; | ||
} | ||
// Backwards compatibility for former type of indexes | ||
if (properties[p].index.unique === true) { | ||
options.unique = true; | ||
} | ||
} else { | ||
// If there isn't an properties[p].index.mongodb object, we read the properties from properties[p].index | ||
options = properties[p].index; | ||
} | ||
// Backwards compatibility for former type of indexes | ||
if (properties[p].index.unique === true) { | ||
if (options.background === undefined) { | ||
options.background = true; | ||
} | ||
} else if ( | ||
enableGeoIndexing && | ||
properties[p].type && | ||
properties[p].type.name === 'GeoPoint' | ||
) { | ||
var indexType = | ||
typeof properties[p].index === 'string' ? | ||
properties[p].index : | ||
'2dsphere'; | ||
options = {name: 'index' + indexType + p}; | ||
index[p] = indexType; | ||
} else { | ||
options = {background: true}; | ||
if (properties[p].unique) { | ||
options.unique = true; | ||
} | ||
} else { | ||
// If there isn't an properties[p].index.mongodb object, we read the properties from properties[p].index | ||
options = properties[p].index; | ||
} | ||
if (options.background === undefined) { | ||
options.background = true; | ||
} | ||
} else if (enableGeoIndexing && properties[p].type && properties[p].type.name === 'GeoPoint') { | ||
var indexType = typeof properties[p].index === 'string' ? | ||
properties[p].index : '2dsphere'; | ||
options = { name: 'index' + indexType + p }; | ||
index[p] = indexType; | ||
} else { | ||
options = { background: true }; | ||
if (properties[p].unique) { | ||
options.unique = true; | ||
} | ||
indexList.push({keys: index, options: options}); | ||
} | ||
indexList.push({ keys: index, options: options }); | ||
} | ||
} | ||
/* eslint-enable one-var */ | ||
/* eslint-enable one-var */ | ||
if (self.debug) { | ||
debug('create indexes: ', indexList); | ||
} | ||
async.each(indexList, function(index, indexCallback) { | ||
if (self.debug) { | ||
debug('createIndex: ', index); | ||
debug('create indexes: ', indexList); | ||
} | ||
self.collection(model).createIndex(index.fields || index.keys, index.options, indexCallback); | ||
}, modelCallback); | ||
}, cb); | ||
async.each( | ||
indexList, | ||
function(index, indexCallback) { | ||
if (self.debug) { | ||
debug('createIndex: ', index); | ||
} | ||
self | ||
.collection(model) | ||
.createIndex( | ||
index.fields || index.keys, | ||
index.options, | ||
indexCallback | ||
); | ||
}, | ||
modelCallback | ||
); | ||
}, | ||
cb | ||
); | ||
} else { | ||
@@ -1564,3 +1742,3 @@ self.dataSource.once('connected', function() { | ||
} | ||
if ((!cb) && ('function' === typeof models)) { | ||
if (!cb && 'function' === typeof models) { | ||
cb = models; | ||
@@ -1577,29 +1755,43 @@ models = undefined; | ||
// Make it serial as multiple models might map to the same collection | ||
async.eachSeries(models, function(model, modelCallback) { | ||
var collectionName = self.collectionName(model); | ||
if (self.debug) { | ||
debug('drop collection %s for model %s', collectionName, model); | ||
} | ||
async.eachSeries( | ||
models, | ||
function(model, modelCallback) { | ||
var collectionName = self.collectionName(model); | ||
if (self.debug) { | ||
debug('drop collection %s for model %s', collectionName, model); | ||
} | ||
self.db.dropCollection(collectionName, function(err, collection) { | ||
self.db.dropCollection(collectionName, function(err, collection) { | ||
if (err) { | ||
debug( | ||
'Error dropping collection %s for model %s: ', | ||
collectionName, | ||
model, | ||
err | ||
); | ||
if ( | ||
!( | ||
err.name === 'MongoError' && | ||
err.ok === 0 && | ||
err.errmsg === 'ns not found' | ||
) | ||
) { | ||
// For errors other than 'ns not found' (collection doesn't exist) | ||
return modelCallback(err); | ||
} | ||
} | ||
// Recreate the collection | ||
if (self.debug) { | ||
debug('create collection %s for model %s', collectionName, model); | ||
} | ||
self.db.createCollection(collectionName, modelCallback); | ||
}); | ||
}, | ||
function(err) { | ||
if (err) { | ||
debug('Error dropping collection %s for model %s: ', collectionName, model, err); | ||
if (!(err.name === 'MongoError' && err.ok === 0 && | ||
err.errmsg === 'ns not found')) { | ||
// For errors other than 'ns not found' (collection doesn't exist) | ||
return modelCallback(err); | ||
} | ||
return cb && cb(err); | ||
} | ||
// Recreate the collection | ||
if (self.debug) { | ||
debug('create collection %s for model %s', collectionName, model); | ||
} | ||
self.db.createCollection(collectionName, modelCallback); | ||
}); | ||
}, function(err) { | ||
if (err) { | ||
return cb && cb(err); | ||
self.autoupdate(models, cb); | ||
} | ||
self.autoupdate(models, cb); | ||
}); | ||
); | ||
} else { | ||
@@ -1615,3 +1807,3 @@ self.dataSource.once('connected', function() { | ||
if (self.db) { | ||
this.db.collection('dummy').findOne({ _id: 1 }, cb); | ||
this.db.collection('dummy').findOne({_id: 1}, cb); | ||
} else { | ||
@@ -1633,7 +1825,13 @@ self.dataSource.once('connected', function() { | ||
MongoDB.prototype.isObjectIDProperty = function(model, prop, value) { | ||
if (prop && ((prop.type === ObjectID) || (Array.isArray(prop.type) && prop.type[0] === ObjectID))) { | ||
if ( | ||
prop && | ||
(prop.type === ObjectID || | ||
(Array.isArray(prop.type) && prop.type[0] === ObjectID)) | ||
) { | ||
return true; | ||
} else if ('string' === typeof value) { | ||
var settings = this._models[model] && this._models[model].settings; | ||
var strict = (settings && settings.strictObjectIDCoercion) || this.settings.strictObjectIDCoercion; | ||
var strict = | ||
(settings && settings.strictObjectIDCoercion) || | ||
this.settings.strictObjectIDCoercion; | ||
if (strict) return false; // unless explicitly typed, don't coerce | ||
@@ -1670,3 +1868,5 @@ return /^[0-9a-fA-F]{24}$/.test(value); | ||
data._id = oid; // Set it to _id | ||
idName !== '_id' && delete data[idName]; | ||
if (idName !== '_id') { | ||
delete data[idName]; | ||
} | ||
} | ||
@@ -1690,4 +1890,4 @@ | ||
query, | ||
{ $setOnInsert: data }, | ||
{ projection: filter.fields, sort: sort, upsert: true }, | ||
{$setOnInsert: data}, | ||
{projection: filter.fields, sort: sort, upsert: true}, | ||
function(err, result) { | ||
@@ -1712,6 +1912,11 @@ if (self.debug) { | ||
value && idName !== '_id' && delete value._id; | ||
if (value && idName !== '_id') { | ||
delete value._id; | ||
} | ||
if (filter && filter.include) { | ||
self._models[model].model.include([value], filter.include, function(err, data) { | ||
self._models[model].model.include([value], filter.include, function( | ||
err, | ||
data | ||
) { | ||
callback(err, data[0], created); | ||
@@ -1722,3 +1927,4 @@ }); | ||
} | ||
}); | ||
}; | ||
} | ||
); | ||
} |
@@ -6,10 +6,17 @@ // Copyright IBM Corp. 2014. All Rights Reserved. | ||
exports.getDistanceBetweenPoints = function getDistanceBetweenPoints(point1, point2) { | ||
'use strict'; | ||
exports.getDistanceBetweenPoints = function getDistanceBetweenPoints( | ||
point1, | ||
point2 | ||
) { | ||
var R = 6371; // Radius of the earth in km | ||
var dLat = deg2rad(point2.lat - point1.lat); // deg2rad below | ||
var dLat = deg2rad(point2.lat - point1.lat); // deg2rad below | ||
var dLon = deg2rad(point2.lng - point1.lng); | ||
var a = | ||
Math.sin(dLat / 2) * Math.sin(dLat / 2) + | ||
Math.cos(deg2rad(point1.lat)) * Math.cos(deg2rad(point2.lat)) * | ||
Math.sin(dLon / 2) * Math.sin(dLon / 2); | ||
Math.cos(deg2rad(point1.lat)) * | ||
Math.cos(deg2rad(point2.lat)) * | ||
Math.sin(dLon / 2) * | ||
Math.sin(dLon / 2); | ||
@@ -16,0 +23,0 @@ var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); |
{ | ||
"name": "loopback-connector-mongodb", | ||
"version": "3.4.4", | ||
"version": "3.5.0", | ||
"description": "The official MongoDB connector for the LoopBack framework.", | ||
"engines": { | ||
"node": ">=4" | ||
"node": ">=6" | ||
}, | ||
@@ -12,3 +12,3 @@ "main": "index.js", | ||
"leak-detection": "make leak-detection", | ||
"test": "mocha -G --timeout 10000 --require test/init.js test/*.test.js", | ||
"test": "mocha", | ||
"lint": "eslint .", | ||
@@ -33,5 +33,5 @@ "posttest": "npm run lint" | ||
"debug": "^3.1.0", | ||
"loopback-connector": "^4.0.0", | ||
"loopback-connector": "^4.5.0", | ||
"mongodb": "^3.0.1", | ||
"strong-globalize": "^3.1.0" | ||
"strong-globalize": "^4.1.1" | ||
}, | ||
@@ -41,12 +41,12 @@ "devDependencies": { | ||
"bluebird": "^3.5.1", | ||
"eslint": "^2.7.0", | ||
"eslint-config-loopback": "^1.0.0", | ||
"eslint": "^5.1.0", | ||
"eslint-config-loopback": "^10.0.0", | ||
"loopback-datasource-juggler": "^3.0.0", | ||
"memwatch-next": "^0.3.0", | ||
"mocha": "^2.1.0", | ||
"rc": "^1.0.0", | ||
"mocha": "^5.2.0", | ||
"rc": "^1.2.8", | ||
"semver": "^5.5.0", | ||
"should": "^8.0.2", | ||
"sinon": "^1.15.4" | ||
"should": "^13.2.1", | ||
"sinon": "^6.1.3" | ||
} | ||
} |
104610
3.8%42
7.69%2123
14.2%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated
Updated