Skip to content

Commit

Permalink
Stable Version 1.1.0.
Browse files Browse the repository at this point in the history
  • Loading branch information
jmdobry committed Feb 5, 2015
1 parent e50f5b1 commit 52ade62
Show file tree
Hide file tree
Showing 6 changed files with 195 additions and 8 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
##### 1.1.0 - 05 February 2015

- #3, #4 - Added the `with` option to `DSRethinkDBAdapter#find` which allows for loading relations.

##### 1.0.0 - 03 February 2015

Stable Version 1.0.0
Expand Down
1 change: 1 addition & 0 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ module.exports = function (grunt) {
mochaTest: {
all: {
options: {
timeout: 20000,
reporter: 'spec'
},
src: ['mocha.start.js', 'test/**/*.js']
Expand Down
47 changes: 45 additions & 2 deletions mocha.start.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ var mocha = require('mocha');
var sinon = require('sinon');
var DSRethinkDBAdapter = require('./');
var JSData = require('js-data');
var Promise = require('bluebird');

var adapter, store, DSUtils, DSErrors, User;
var adapter, store, DSUtils, DSErrors, User, Post, Comment;

var globals = module.exports = {
fail: function (msg) {
Expand Down Expand Up @@ -52,7 +53,49 @@ beforeEach(function () {
adapter = new DSRethinkDBAdapter();
DSUtils = JSData.DSUtils;
DSErrors = JSData.DSErrors;
globals.User = global.User = User = store.defineResource('user');
globals.User = global.User = User = store.defineResource({
name: 'user',
relations: {
hasMany: {
post: {
localField: 'posts',
foreignKey: 'post'
}
}
}
});
globals.Post = global.Post = Post = store.defineResource({
name: 'post',
relations: {
belongsTo: {
user: {
localField: 'user',
localKey: 'userId'
}
},
hasMany: {
comment: {
localField: 'comments',
foreignKey: 'postId'
}
}
}
});
globals.Comment = global.Comment = Comment = store.defineResource({
name: 'comment',
relations: {
belongsTo: {
post: {
localField: 'post',
localKey: 'postId'
},
user: {
localField: 'user',
localKey: 'userId'
}
}
}
});

globals.adapter = adapter;
global.adapter = globals.adapter;
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "js-data-rethinkdb",
"description": "RethinkDB adapter for js-data.",
"version": "1.0.0",
"version": "1.1.0",
"homepage": "http://www.js-data.io/docs/dsrethinkdbadapter",
"repository": {
"type": "git",
Expand Down Expand Up @@ -42,7 +42,7 @@
"test": "grunt test"
},
"dependencies": {
"js-data": ">=1.0.0",
"js-data": ">=1.2.0",
"mout": "0.11.0",
"rethinkdbdash": ">=1.15.0"
}
Expand Down
104 changes: 101 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
var rethinkdbdash = require('rethinkdbdash');
var contains = require('mout/array/contains');
var map = require('mout/array/map');
var forOwn = require('mout/object/forOwn');
var keys = require('mout/object/keys');
var deepMixIn = require('mout/object/deepMixIn');
var forEach = require('mout/array/forEach');
var contains = require('mout/array/contains');
var isObject = require('mout/lang/isObject');
var isArray = require('mout/lang/isArray');
var isEmpty = require('mout/lang/isEmpty');
var isString = require('mout/lang/isString');
var upperCase = require('mout/string/upperCase');
var underscore = require('mout/string/underscore');
var JSData = require('js-data');

function Defaults() {

Expand Down Expand Up @@ -144,6 +147,7 @@ function DSRethinkDBAdapter(options) {
this.r = rethinkdbdash(this.defaults);
this.databases = {};
this.tables = {};
this.indices = {};
}

var dsRethinkDBAdapterPrototype = DSRethinkDBAdapter.prototype;
Expand Down Expand Up @@ -171,15 +175,109 @@ dsRethinkDBAdapterPrototype.waitForTable = function waitForTable(table, options)
});
};

dsRethinkDBAdapterPrototype.waitForIndex = function waitForIndex(table, index, options) {
var _this = this;
options = options || {};
var db = options.db || _this.defaults.db;
return _this.waitForDb(options).then(function () {
return _this.waitForTable(table, options);
}).then(function () {
_this.indices[db] = _this.indices[db] || {};
_this.indices[db][table] = _this.indices[db][table] || {};
if (!_this.tables[db][table][index]) {
_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 () {
return _this.r.db(db).table(table).indexWait(index).run();
});
}
return _this.tables[db][table][index];
});
};

dsRethinkDBAdapterPrototype.find = function find(resourceConfig, id, options) {
var _this = this;
var newModels = {};
var models = {};
var merge = {};
options = options || {};
return _this.waitForTable(resourceConfig.table || underscore(resourceConfig.name), options).then(function () {
return _this.r.db(options.db || _this.defaults.db).table(resourceConfig.table || underscore(resourceConfig.name)).get(id).run();
var table = resourceConfig.table || underscore(resourceConfig.name);
var tasks = [_this.waitForTable(table, options)];
forEach(resourceConfig.relationList, function (def) {
var relationName = def.relation;
var relationDef = resourceConfig.getResource(relationName);
if (!relationDef) {
throw new JSData.DSErrors.NER(relationName);
}
if (def.foreignKey) {
tasks.push(_this.waitForIndex(relationDef.table || underscore(relationDef.name), def.foreignKey, options));
} else if (def.localKey) {
tasks.push(_this.waitForIndex(resourceConfig.table || underscore(resourceConfig.name), def.localKey, options));
}
});
return JSData.DSUtils.Promise.all(tasks).then(function () {
return _this.r.do(_this.r.table(table).get(id), function (doc) {
forEach(resourceConfig.relationList, function (def) {
var relationName = def.relation;
models[relationName] = resourceConfig.getResource(relationName);
if (!options.with || !options.with.length || !contains(options.with, relationName)) {
return;
}
if (!models[relationName]) {
throw new JSData.DSErrors.NER(relationName);
}
var localKey = def.localKey;
var localField = def.localField;
var foreignKey = def.foreignKey;
if (def.type === 'belongsTo') {
merge[localField] = _this.r.table(models[relationName].table || underscore(models[relationName].name)).get(doc(localKey).default(''));
newModels[localField] = {
modelName: relationName,
relation: 'belongsTo'
};
} else if (def.type === 'hasMany') {
merge[localField] = _this.r.table(models[relationName].table || underscore(models[relationName].name)).getAll(id, { index: foreignKey }).coerceTo('ARRAY');

newModels[localField] = {
modelName: relationName,
relation: 'hasMany'
};
} else if (def.type === 'hasOne') {
merge[localField] = _this.r.table(models[relationName].table || underscore(models[relationName].name));

if (localKey) {
merge[localField] = merge[localField].get(localKey);
} else {
merge[localField] = merge[localField].getAll(id, { index: foreignKey }).coerceTo('ARRAY');
}

newModels[localField] = {
modelName: relationName,
relation: 'hasOne'
};
}
});

if (!isEmpty(merge)) {
return doc.merge(merge);
}
return doc;
}).run();
}).then(function (item) {
if (!item) {
throw new Error('Not Found!');
} else {
forOwn(item, function (localValue, localKey) {
if (localKey in newModels) {
if (isObject(localValue)) {
item[localKey] = item[localKey];
} else if (isArray(localValue)) {
if (newModels[localKey].relation === 'hasOne' && localValue.length) {
item[localKey] = localValue[0];
} else {
item[localKey] = localValue;
}
}
}
});
return item;
}
});
Expand Down
43 changes: 42 additions & 1 deletion test/find.spec.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
describe('DSRethinkDBAdapter#find', function () {
it('should find a user in RethinkDB', function (done) {
var id;
var id, id2, _user, _post, _comments;
adapter.create(User, { name: 'John' })
.then(function (user) {
_user = user;
id = user.id;
assert.equal(user.name, 'John');
assert.isString(user.id);
Expand All @@ -12,12 +13,52 @@ describe('DSRethinkDBAdapter#find', function () {
assert.equal(user.name, 'John');
assert.isString(user.id);
assert.deepEqual(user, { id: id, name: 'John' });
return adapter.create(Post, {
content: 'test',
userId: user.id
});
})
.then(function (post) {
_post = post;
id2 = post.id;
assert.equal(post.content, 'test');
assert.isString(post.id);
assert.isString(post.userId);
return Promise.all([
adapter.create(Comment, {
content: 'test2',
postId: post.id,
userId: _user.id
}),
adapter.create(Comment, {
content: 'test3',
postId: post.id,
userId: _user.id
})
]);
})
.then(function (comments) {
_comments = comments;
_comments.sort(function (a, b) {
return a.content > b.content;
});
return adapter.find(Post, _post.id, { with: ['user', 'comment'] });
})
.then(function (post) {
post.comments.sort(function (a, b) {
return a.content > b.content;
});
assert.equal(JSON.stringify(post.user), JSON.stringify(_user));
assert.equal(JSON.stringify(post.comments), JSON.stringify(_comments));
return adapter.destroy(User, id);
})
.then(function (user) {
assert.isFalse(!!user);
return adapter.find(User, id);
})
.then(function () {
return adapter.destroy(Post, id2);
})
.then(function () {
done('Should not have reached here!');
})
Expand Down

0 comments on commit 52ade62

Please sign in to comment.