Skip to content

Commit 52ade62

Browse files
committed
Stable Version 1.1.0.
#3, #4
1 parent e50f5b1 commit 52ade62

File tree

6 files changed

+195
-8
lines changed

6 files changed

+195
-8
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
##### 1.1.0 - 05 February 2015
2+
3+
- #3, #4 - Added the `with` option to `DSRethinkDBAdapter#find` which allows for loading relations.
4+
15
##### 1.0.0 - 03 February 2015
26

37
Stable Version 1.0.0

Gruntfile.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ module.exports = function (grunt) {
3636
mochaTest: {
3737
all: {
3838
options: {
39+
timeout: 20000,
3940
reporter: 'spec'
4041
},
4142
src: ['mocha.start.js', 'test/**/*.js']

mocha.start.js

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ var mocha = require('mocha');
66
var sinon = require('sinon');
77
var DSRethinkDBAdapter = require('./');
88
var JSData = require('js-data');
9+
var Promise = require('bluebird');
910

10-
var adapter, store, DSUtils, DSErrors, User;
11+
var adapter, store, DSUtils, DSErrors, User, Post, Comment;
1112

1213
var globals = module.exports = {
1314
fail: function (msg) {
@@ -52,7 +53,49 @@ beforeEach(function () {
5253
adapter = new DSRethinkDBAdapter();
5354
DSUtils = JSData.DSUtils;
5455
DSErrors = JSData.DSErrors;
55-
globals.User = global.User = User = store.defineResource('user');
56+
globals.User = global.User = User = store.defineResource({
57+
name: 'user',
58+
relations: {
59+
hasMany: {
60+
post: {
61+
localField: 'posts',
62+
foreignKey: 'post'
63+
}
64+
}
65+
}
66+
});
67+
globals.Post = global.Post = Post = store.defineResource({
68+
name: 'post',
69+
relations: {
70+
belongsTo: {
71+
user: {
72+
localField: 'user',
73+
localKey: 'userId'
74+
}
75+
},
76+
hasMany: {
77+
comment: {
78+
localField: 'comments',
79+
foreignKey: 'postId'
80+
}
81+
}
82+
}
83+
});
84+
globals.Comment = global.Comment = Comment = store.defineResource({
85+
name: 'comment',
86+
relations: {
87+
belongsTo: {
88+
post: {
89+
localField: 'post',
90+
localKey: 'postId'
91+
},
92+
user: {
93+
localField: 'user',
94+
localKey: 'userId'
95+
}
96+
}
97+
}
98+
});
5699

57100
globals.adapter = adapter;
58101
global.adapter = globals.adapter;

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "js-data-rethinkdb",
33
"description": "RethinkDB adapter for js-data.",
4-
"version": "1.0.0",
4+
"version": "1.1.0",
55
"homepage": "http://www.js-data.io/docs/dsrethinkdbadapter",
66
"repository": {
77
"type": "git",
@@ -42,7 +42,7 @@
4242
"test": "grunt test"
4343
},
4444
"dependencies": {
45-
"js-data": ">=1.0.0",
45+
"js-data": ">=1.2.0",
4646
"mout": "0.11.0",
4747
"rethinkdbdash": ">=1.15.0"
4848
}

src/index.js

Lines changed: 101 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
var rethinkdbdash = require('rethinkdbdash');
2+
var contains = require('mout/array/contains');
3+
var map = require('mout/array/map');
24
var forOwn = require('mout/object/forOwn');
35
var keys = require('mout/object/keys');
46
var deepMixIn = require('mout/object/deepMixIn');
57
var forEach = require('mout/array/forEach');
6-
var contains = require('mout/array/contains');
78
var isObject = require('mout/lang/isObject');
9+
var isArray = require('mout/lang/isArray');
810
var isEmpty = require('mout/lang/isEmpty');
911
var isString = require('mout/lang/isString');
1012
var upperCase = require('mout/string/upperCase');
1113
var underscore = require('mout/string/underscore');
14+
var JSData = require('js-data');
1215

1316
function Defaults() {
1417

@@ -144,6 +147,7 @@ function DSRethinkDBAdapter(options) {
144147
this.r = rethinkdbdash(this.defaults);
145148
this.databases = {};
146149
this.tables = {};
150+
this.indices = {};
147151
}
148152

149153
var dsRethinkDBAdapterPrototype = DSRethinkDBAdapter.prototype;
@@ -171,15 +175,109 @@ dsRethinkDBAdapterPrototype.waitForTable = function waitForTable(table, options)
171175
});
172176
};
173177

178+
dsRethinkDBAdapterPrototype.waitForIndex = function waitForIndex(table, index, options) {
179+
var _this = this;
180+
options = options || {};
181+
var db = options.db || _this.defaults.db;
182+
return _this.waitForDb(options).then(function () {
183+
return _this.waitForTable(table, options);
184+
}).then(function () {
185+
_this.indices[db] = _this.indices[db] || {};
186+
_this.indices[db][table] = _this.indices[db][table] || {};
187+
if (!_this.tables[db][table][index]) {
188+
_this.tables[db][table][index] = _this.r.branch(_this.r.db(db).table(table).indexList().contains(index), true, _this.r.db(db).table(table).indexCreate(index)).run().then(function () {
189+
return _this.r.db(db).table(table).indexWait(index).run();
190+
});
191+
}
192+
return _this.tables[db][table][index];
193+
});
194+
};
195+
174196
dsRethinkDBAdapterPrototype.find = function find(resourceConfig, id, options) {
175197
var _this = this;
198+
var newModels = {};
199+
var models = {};
200+
var merge = {};
176201
options = options || {};
177-
return _this.waitForTable(resourceConfig.table || underscore(resourceConfig.name), options).then(function () {
178-
return _this.r.db(options.db || _this.defaults.db).table(resourceConfig.table || underscore(resourceConfig.name)).get(id).run();
202+
var table = resourceConfig.table || underscore(resourceConfig.name);
203+
var tasks = [_this.waitForTable(table, options)];
204+
forEach(resourceConfig.relationList, function (def) {
205+
var relationName = def.relation;
206+
var relationDef = resourceConfig.getResource(relationName);
207+
if (!relationDef) {
208+
throw new JSData.DSErrors.NER(relationName);
209+
}
210+
if (def.foreignKey) {
211+
tasks.push(_this.waitForIndex(relationDef.table || underscore(relationDef.name), def.foreignKey, options));
212+
} else if (def.localKey) {
213+
tasks.push(_this.waitForIndex(resourceConfig.table || underscore(resourceConfig.name), def.localKey, options));
214+
}
215+
});
216+
return JSData.DSUtils.Promise.all(tasks).then(function () {
217+
return _this.r.do(_this.r.table(table).get(id), function (doc) {
218+
forEach(resourceConfig.relationList, function (def) {
219+
var relationName = def.relation;
220+
models[relationName] = resourceConfig.getResource(relationName);
221+
if (!options.with || !options.with.length || !contains(options.with, relationName)) {
222+
return;
223+
}
224+
if (!models[relationName]) {
225+
throw new JSData.DSErrors.NER(relationName);
226+
}
227+
var localKey = def.localKey;
228+
var localField = def.localField;
229+
var foreignKey = def.foreignKey;
230+
if (def.type === 'belongsTo') {
231+
merge[localField] = _this.r.table(models[relationName].table || underscore(models[relationName].name)).get(doc(localKey).default(''));
232+
newModels[localField] = {
233+
modelName: relationName,
234+
relation: 'belongsTo'
235+
};
236+
} else if (def.type === 'hasMany') {
237+
merge[localField] = _this.r.table(models[relationName].table || underscore(models[relationName].name)).getAll(id, { index: foreignKey }).coerceTo('ARRAY');
238+
239+
newModels[localField] = {
240+
modelName: relationName,
241+
relation: 'hasMany'
242+
};
243+
} else if (def.type === 'hasOne') {
244+
merge[localField] = _this.r.table(models[relationName].table || underscore(models[relationName].name));
245+
246+
if (localKey) {
247+
merge[localField] = merge[localField].get(localKey);
248+
} else {
249+
merge[localField] = merge[localField].getAll(id, { index: foreignKey }).coerceTo('ARRAY');
250+
}
251+
252+
newModels[localField] = {
253+
modelName: relationName,
254+
relation: 'hasOne'
255+
};
256+
}
257+
});
258+
259+
if (!isEmpty(merge)) {
260+
return doc.merge(merge);
261+
}
262+
return doc;
263+
}).run();
179264
}).then(function (item) {
180265
if (!item) {
181266
throw new Error('Not Found!');
182267
} else {
268+
forOwn(item, function (localValue, localKey) {
269+
if (localKey in newModels) {
270+
if (isObject(localValue)) {
271+
item[localKey] = item[localKey];
272+
} else if (isArray(localValue)) {
273+
if (newModels[localKey].relation === 'hasOne' && localValue.length) {
274+
item[localKey] = localValue[0];
275+
} else {
276+
item[localKey] = localValue;
277+
}
278+
}
279+
}
280+
});
183281
return item;
184282
}
185283
});

test/find.spec.js

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
describe('DSRethinkDBAdapter#find', function () {
22
it('should find a user in RethinkDB', function (done) {
3-
var id;
3+
var id, id2, _user, _post, _comments;
44
adapter.create(User, { name: 'John' })
55
.then(function (user) {
6+
_user = user;
67
id = user.id;
78
assert.equal(user.name, 'John');
89
assert.isString(user.id);
@@ -12,12 +13,52 @@ describe('DSRethinkDBAdapter#find', function () {
1213
assert.equal(user.name, 'John');
1314
assert.isString(user.id);
1415
assert.deepEqual(user, { id: id, name: 'John' });
16+
return adapter.create(Post, {
17+
content: 'test',
18+
userId: user.id
19+
});
20+
})
21+
.then(function (post) {
22+
_post = post;
23+
id2 = post.id;
24+
assert.equal(post.content, 'test');
25+
assert.isString(post.id);
26+
assert.isString(post.userId);
27+
return Promise.all([
28+
adapter.create(Comment, {
29+
content: 'test2',
30+
postId: post.id,
31+
userId: _user.id
32+
}),
33+
adapter.create(Comment, {
34+
content: 'test3',
35+
postId: post.id,
36+
userId: _user.id
37+
})
38+
]);
39+
})
40+
.then(function (comments) {
41+
_comments = comments;
42+
_comments.sort(function (a, b) {
43+
return a.content > b.content;
44+
});
45+
return adapter.find(Post, _post.id, { with: ['user', 'comment'] });
46+
})
47+
.then(function (post) {
48+
post.comments.sort(function (a, b) {
49+
return a.content > b.content;
50+
});
51+
assert.equal(JSON.stringify(post.user), JSON.stringify(_user));
52+
assert.equal(JSON.stringify(post.comments), JSON.stringify(_comments));
1553
return adapter.destroy(User, id);
1654
})
1755
.then(function (user) {
1856
assert.isFalse(!!user);
1957
return adapter.find(User, id);
2058
})
59+
.then(function () {
60+
return adapter.destroy(Post, id2);
61+
})
2162
.then(function () {
2263
done('Should not have reached here!');
2364
})

0 commit comments

Comments
 (0)