Skip to content

Commit 6eaf113

Browse files
committed
Stable Version 0.3.0.
1 parent 4cb2f3f commit 6eaf113

File tree

8 files changed

+547
-361
lines changed

8 files changed

+547
-361
lines changed

dist/js-data-mongodb.js

+373-308
Large diffs are not rendered by default.

mocha.start.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,15 @@ test.globals(testGlobals);
4949

5050
beforeEach(function () {
5151
store = new JSData.DS({
52+
idAttribute: '_id',
5253
log: false
5354
});
5455
adapter = new DSMongoDBAdapter('mongodb://localhost:27017');
56+
store.registerAdapter('mongo', adapter, { 'default': true });
5557
DSUtils = JSData.DSUtils;
5658
DSErrors = JSData.DSErrors;
5759
globals.User = global.User = User = store.defineResource({
5860
name: 'user',
59-
idAttribute: '_id',
6061
relations: {
6162
hasMany: {
6263
post: {
@@ -68,7 +69,6 @@ beforeEach(function () {
6869
});
6970
globals.Post = global.Post = Post = store.defineResource({
7071
name: 'post',
71-
idAttribute: '_id',
7272
relations: {
7373
belongsTo: {
7474
user: {
@@ -86,7 +86,6 @@ beforeEach(function () {
8686
});
8787
globals.Comment = global.Comment = Comment = store.defineResource({
8888
name: 'comment',
89-
idAttribute: '_id',
9089
relations: {
9190
belongsTo: {
9291
post: {

package.json

+11-11
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "js-data-mongodb",
33
"description": "MongoDB adapter for js-data.",
4-
"version": "0.2.3",
4+
"version": "0.3.0",
55
"homepage": "http://www.js-data.io/docs/dsmongodbadapter",
66
"repository": {
77
"type": "git",
@@ -27,31 +27,31 @@
2727
"mongodb"
2828
],
2929
"devDependencies": {
30-
"babel-core": "4.7.16",
31-
"babel-loader": "4.2.0",
32-
"chai": "2.1.1",
30+
"babel-core": "5.4.7",
31+
"babel-loader": "5.1.3",
32+
"chai": "2.3.0",
3333
"grunt": "0.4.5",
3434
"grunt-contrib-watch": "0.6.1",
3535
"grunt-karma-coveralls": "2.5.3",
3636
"grunt-mocha-test": "0.12.7",
3737
"grunt-webpack": "1.0.8",
3838
"jit-grunt": "0.9.1",
39-
"jshint": "2.6.3",
39+
"jshint": "2.8.0",
4040
"jshint-loader": "0.8.3",
41-
"sinon": "1.13.0",
42-
"time-grunt": "1.1.0",
43-
"webpack": "1.7.3",
44-
"webpack-dev-server": "1.7.0"
41+
"sinon": "1.14.1",
42+
"time-grunt": "1.2.1",
43+
"webpack": "1.9.10",
44+
"webpack-dev-server": "1.9.0"
4545
},
4646
"scripts": {
4747
"test": "grunt test"
4848
},
4949
"dependencies": {
50-
"bson": "^0.3.2",
50+
"bson": "0.3.2",
5151
"mout": "0.11.0"
5252
},
5353
"peerDependencies": {
5454
"js-data": ">=1.5.7",
55-
"mongodb": ">= 1.3.x <= 2.x"
55+
"mongodb": ">= 1.3.x"
5656
}
5757
}

src/index.js

+76-33
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,21 @@ let reserved = [
1818
'where'
1919
];
2020

21+
class Defaults {
22+
23+
}
24+
25+
Defaults.prototype.translateId = true;
26+
2127
class DSMongoDBAdapter {
2228
constructor(uri) {
29+
if (typeof uri === 'string') {
30+
uri = {uri};
31+
}
32+
this.defaults = new Defaults();
33+
deepMixIn(this.defaults, uri);
2334
this.client = new DSUtils.Promise((resolve, reject) => {
24-
MongoClient.connect(uri, (err, db) => err ? reject(err) : resolve(db));
35+
MongoClient.connect(uri.uri, (err, db) => err ? reject(err) : resolve(db));
2536
});
2637
}
2738

@@ -174,51 +185,73 @@ class DSMongoDBAdapter {
174185
return queryOptions;
175186
}
176187

177-
find(resourceConfig, id, options) {
188+
translateId(r, options) {
189+
options = options || {};
190+
if (typeof options.translateId === 'boolean' ? options.translateId : this.defaults.translateId) {
191+
if (Array.isArray(r)) {
192+
r.forEach(_r => {
193+
let __id = _r._id ? _r._id.toString() : _r._id;
194+
_r._id = typeof __id === 'string' ? __id : _r._id;
195+
});
196+
} else if (DSUtils.isObject(r)) {
197+
let __id = r._id ? r._id.toString() : r._id;
198+
r._id = typeof __id === 'string' ? __id : r._id;
199+
}
200+
}
201+
return r;
202+
}
203+
204+
origify(options) {
178205
options = options || {};
206+
if (typeof options.orig === 'function') {
207+
return options.orig();
208+
}
209+
return options;
210+
}
211+
212+
find(resourceConfig, id, options) {
213+
options = this.origify(options);
179214
return this.getClient().then(client => {
180215
return new DSUtils.Promise((resolve, reject) => {
181216
let params = {};
182217
params[resourceConfig.idAttribute] = id;
183218
if (resourceConfig.idAttribute === '_id' && typeof id === 'string' && ObjectID.isValid(id)) {
184-
params[resourceConfig.idAttribute] = ObjectID.createFromHexString(id);
219+
params[resourceConfig.idAttribute] = ObjectID.createFromHexString(id);
185220
}
221+
options.fields = options.fields || {};
186222
client.collection(resourceConfig.table || underscore(resourceConfig.name)).findOne(params, options, (err, r) => {
187223
if (err) {
188224
reject(err);
189225
} else if (!r) {
190226
reject(new Error('Not Found!'));
191227
} else {
192-
r._id = r._id.valueOf();
193-
resolve(r);
228+
resolve(this.translateId(r, options));
194229
}
195230
});
196231
});
197232
});
198233
}
199234

200235
findAll(resourceConfig, params, options) {
201-
options = options ? copy(options) : {};
236+
options = this.origify(options ? copy(options) : {});
202237
deepMixIn(options, this.getQueryOptions(resourceConfig, params));
203238
let query = this.getQuery(resourceConfig, params);
204239
return this.getClient().then(client => {
205240
return new DSUtils.Promise((resolve, reject) => {
241+
options.fields = options.fields || {};
206242
client.collection(resourceConfig.table || underscore(resourceConfig.name)).find(query, options).toArray((err, r) => {
207243
if (err) {
208244
reject(err);
209245
} else {
210-
r.forEach(_r => {
211-
_r._id = _r._id.valueOf();
212-
});
213-
resolve(r);
246+
resolve(this.translateId(r, options));
214247
}
215248
});
216249
});
217250
});
218251
}
219252

220253
create(resourceConfig, attrs, options) {
221-
options = options || {};
254+
options = this.origify(options);
222255
attrs = removeCircular(omit(attrs, resourceConfig.relationFields || []));
223256
return this.getClient().then(client => {
224257
return new DSUtils.Promise((resolve, reject) => {
@@ -229,9 +262,7 @@ class DSMongoDBAdapter {
229262
reject(err);
230263
} else {
231264
r = r.ops ? r.ops : r;
232-
r.forEach(_r => {
233-
_r._id = _r._id.valueOf();
234-
});
265+
this.translateId(r, options);
235266
resolve(DSUtils.isArray(attrs) ? r : r[0]);
236267
}
237268
});
@@ -241,37 +272,46 @@ class DSMongoDBAdapter {
241272

242273
update(resourceConfig, id, attrs, options) {
243274
attrs = removeCircular(omit(attrs, resourceConfig.relationFields || []));
244-
options = options || {};
275+
options = this.origify(options);
245276
return this.find(resourceConfig, id, options).then(() => {
246-
return this.getClient().then(client => {
247-
return new DSUtils.Promise((resolve, reject) => {
248-
let params = {};
249-
params[resourceConfig.idAttribute] = id;
250-
let collection = client.collection(resourceConfig.table || underscore(resourceConfig.name));
251-
collection[collection.updateOne ? 'updateOne' : 'update'](params, { $set: attrs }, options, err => {
252-
if (err) {
253-
reject(err);
254-
} else {
255-
resolve();
256-
}
257-
});
258-
}).then(() => this.find(resourceConfig, id, options));
277+
return this.getClient();
278+
}).then(client => {
279+
return new DSUtils.Promise((resolve, reject) => {
280+
let params = {};
281+
params[resourceConfig.idAttribute] = id;
282+
if (resourceConfig.idAttribute === '_id' && typeof id === 'string' && ObjectID.isValid(id)) {
283+
params[resourceConfig.idAttribute] = ObjectID.createFromHexString(id);
284+
}
285+
let collection = client.collection(resourceConfig.table || underscore(resourceConfig.name));
286+
collection[collection.updateOne ? 'updateOne' : 'update'](params, {$set: attrs}, options, err => {
287+
if (err) {
288+
reject(err);
289+
} else {
290+
resolve();
291+
}
292+
});
259293
});
260-
});
294+
}).then(() => this.find(resourceConfig, id, options));
261295
}
262296

263297
updateAll(resourceConfig, attrs, params, options) {
264298
let ids = [];
265299
attrs = removeCircular(omit(attrs, resourceConfig.relationFields || []));
266-
options = options ? copy(options) : {};
300+
options = this.origify(options ? copy(options) : {});
267301
let _options = copy(options);
268302
_options.multi = true;
269303
return this.getClient().then(client => {
270304
let queryOptions = this.getQueryOptions(resourceConfig, params);
271305
queryOptions.$set = attrs;
272306
let query = this.getQuery(resourceConfig, params);
273307
return this.findAll(resourceConfig, params, options).then(items => {
274-
ids = map(items, item => item[resourceConfig.idAttribute]);
308+
ids = map(items, item => {
309+
let id = item[resourceConfig.idAttribute];
310+
if (resourceConfig.idAttribute === '_id' && typeof id === 'string' && ObjectID.isValid(id)) {
311+
return ObjectID.createFromHexString(id);
312+
}
313+
return id;
314+
});
275315
return new DSUtils.Promise((resolve, reject) => {
276316
let collection = client.collection(resourceConfig.table || underscore(resourceConfig.name));
277317
collection[collection.updateMany ? 'updateMany' : 'update'](query, queryOptions, _options, err => {
@@ -293,11 +333,14 @@ class DSMongoDBAdapter {
293333
}
294334

295335
destroy(resourceConfig, id, options) {
296-
options = options || {};
336+
options = this.origify(options);
297337
return this.getClient().then(client => {
298338
return new DSUtils.Promise((resolve, reject) => {
299339
let params = {};
300340
params[resourceConfig.idAttribute] = id;
341+
if (resourceConfig.idAttribute === '_id' && typeof id === 'string' && ObjectID.isValid(id)) {
342+
params[resourceConfig.idAttribute] = ObjectID.createFromHexString(id);
343+
}
301344
let collection = client.collection(resourceConfig.table || underscore(resourceConfig.name));
302345
collection[collection.deleteOne ? 'deleteOne' : 'remove'](params, options, err => {
303346
if (err) {
@@ -311,7 +354,7 @@ class DSMongoDBAdapter {
311354
}
312355

313356
destroyAll(resourceConfig, params, options) {
314-
options = options ? copy(options) : {};
357+
options = this.origify(options ? copy(options) : {});
315358
return this.getClient().then(client => {
316359
deepMixIn(options, this.getQueryOptions(resourceConfig, params));
317360
let query = this.getQuery(resourceConfig, params);

test/find.spec.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,32 @@ describe('DSMongoDBAdapter#find', function () {
66
name: 'John'
77
}).then(function (users) {
88
assert.equal(users.length, 0);
9-
return adapter.create(User, { name: 'John' });
9+
return adapter.create(User, {name: 'John'});
1010
}).then(function (user) {
1111
id = user._id;
1212
return adapter.find(User, id.toString());
1313
}).then(function (user) {
14-
assert.deepEqual(user, { _id: id, name: 'John' });
14+
assert.deepEqual(user, {_id: id, name: 'John'});
1515
return adapter.destroy(User, id);
1616
}).then(function (destroyedUser) {
1717
assert.isFalse(!!destroyedUser);
1818
});
1919
});
2020

21-
it('should not convert id if it is not a valid bson ObjectId hex string', function() {
21+
it('should not convert id if it is not a valid bson ObjectId hex string', function () {
2222
var id;
2323

2424
return adapter.findAll(User, {
2525
name: 'John'
2626
}).then(function (users) {
2727
assert.equal(users.length, 0);
28-
return adapter.create(User, { _id: 1, name: 'John' });
28+
return adapter.create(User, {_id: '1', name: 'John'});
2929
}).then(function (user) {
3030
id = user._id;
31-
assert.equal(typeof id, 'number');
31+
assert.equal(typeof id, 'string');
3232
return adapter.find(User, id);
3333
}).then(function (user) {
34-
assert.deepEqual(user, { _id: id, name: 'John' });
34+
assert.deepEqual(user, {_id: id, name: 'John'});
3535
return adapter.destroy(User, id);
3636
}).then(function (destroyedUser) {
3737
assert.isFalse(!!destroyedUser);

test/store/create.spec.js

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
describe('DS#create', function () {
2+
it('should create a user in MongoDB and inject it into the store', function () {
3+
var id;
4+
return User.create({name: 'John'}, {cacheResponse: true}).then(function (user) {
5+
id = user._id;
6+
assert.equal(user.name, 'John');
7+
assert.isDefined(user._id);
8+
assert.isTrue(user === User.get(user._id));
9+
return User.find(user._id, {bypassCache: true, cacheResponse: true});
10+
})
11+
.then(function (user) {
12+
assert.equal(user.name, 'John');
13+
assert.isDefined(user._id);
14+
assert.strictEqual(user, User.get(user._id));
15+
return User.destroy(user._id);
16+
})
17+
.then(function () {
18+
return User.find(id, {bypassCache: true}).catch(function (err) {
19+
assert.equal(err.message, 'Not Found!');
20+
});
21+
});
22+
});
23+
});

test/store/destroy.spec.js

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
describe('DS#destroy', function () {
2+
it('should destroy a user from MongoDB and eject it from the store', function () {
3+
var id;
4+
return User.create({name: 'John'}, {cacheResponse: true})
5+
.then(function (user) {
6+
id = user._id;
7+
assert.equal(user.name, 'John');
8+
assert.isDefined(user._id);
9+
assert.isTrue(user === User.get(user._id));
10+
return User.destroy(user._id);
11+
})
12+
.then(function () {
13+
assert.isUndefined(User.get(id));
14+
return User.find(id, {bypassCache: true}).catch(function (err) {
15+
assert.equal(err.message, 'Not Found!');
16+
});
17+
});
18+
});
19+
});

0 commit comments

Comments
 (0)