Skip to content

Commit

Permalink
Merge pull request #1 from fabito/master
Browse files Browse the repository at this point in the history
Update fork
  • Loading branch information
patrinhani-ciandt authored Sep 8, 2017
2 parents f2195fd + 2e0ea9e commit 6b8f76b
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 23 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"url": "https://github.com/fabito/botkit-storage-datastore/issues"
},
"dependencies": {
"gcloud": "^0.32.0"
"google-cloud": "^0.53.0"
},
"devDependencies": {
"coveralls": "^2.11.9",
Expand Down
56 changes: 38 additions & 18 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var gcloud = require('gcloud');
var gcloud = require('google-cloud');

/**
* The Botkit google cloud datastore driver
Expand All @@ -12,25 +12,26 @@ module.exports = function(config) {
}

var datastore = gcloud.datastore(config),
namespace = config.namespace,
teamKind = config.teamKind || 'BotkitTeam',
channelKind = config.channelKind || 'BotkitChannel',
userKind = config.userKind || 'BotkitUser';

return {
teams: {
get: get(datastore, teamKind),
save: save(datastore, teamKind),
all: all(datastore, teamKind)
get: get(datastore, teamKind, namespace),
save: save(datastore, teamKind, namespace),
all: all(datastore, teamKind, namespace)
},
channels: {
get: get(datastore, channelKind),
save: save(datastore, channelKind),
all: all(datastore, channelKind)
get: get(datastore, channelKind, namespace),
save: save(datastore, channelKind, namespace),
all: all(datastore, channelKind, namespace)
},
users: {
get: get(datastore, userKind),
save: save(datastore, userKind),
all: all(datastore, userKind)
get: get(datastore, userKind, namespace),
save: save(datastore, userKind, namespace),
all: all(datastore, userKind, namespace)
}
};
};
Expand All @@ -42,15 +43,22 @@ module.exports = function(config) {
* @param {String} kind The entity kind
* @returns {Function} The get function
*/
function get(datastore, kind) {
function get(datastore, kind, namespace) {
return function(id, cb) {
var key = datastore.key([kind, id]);
var keyParam = [kind, id];
if (namespace) {
keyParam = {
namespace: namespace,
path: keyParam
};
}
var key = datastore.key(keyParam);

datastore.get(key, function(err, entity) {
if (err)
return cb(err);

return cb(null, entity ? entity.data : null);
return cb(null, entity ? entity : null);
});
};
};
Expand All @@ -63,9 +71,16 @@ function get(datastore, kind) {
* @param {String} kind The entity kind
* @returns {Function} The save function
*/
function save(datastore, kind) {
function save(datastore, kind, namespace) {
return function(data, cb) {
var key = datastore.key([kind, data.id]);
var keyParam = [kind, data.id];
if (namespace) {
keyParam = {
namespace: namespace,
path: keyParam
};
}
var key = datastore.key(keyParam);
datastore.save({
key: key,
// @TODO: convert object to array so that we can exclude properties from indexes
Expand All @@ -88,16 +103,21 @@ function save(datastore, kind) {
* @param {String} kind The entity kind
* @returns {Function} The all function
*/
function all(datastore, kind) {
function all(datastore, kind, namespace) {
return function(cb) {
var query = datastore.createQuery(kind);
var query = null;
if (namespace) {
query = datastore.createQuery(namespace, kind);
} else {
query = datastore.createQuery(kind);
}

datastore.runQuery(query, function(err, entities) {
if (err)
return cb(err);

var list = (entities || []).map(function(entity) {
return entity.data;
return entity;
});

cb(null, list);
Expand Down
144 changes: 140 additions & 4 deletions tests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ describe('Datastore', function() {
};

Storage = proxyquire('../src/index', {
gcloud: gcloudMock
'google-cloud': gcloudMock
});

});
Expand Down Expand Up @@ -81,7 +81,6 @@ describe('Datastore', function() {
config = {
projectId: 'right_here'
};

entity = {
key: sinon.stub(),
data: sinon.stub()
Expand All @@ -96,7 +95,7 @@ describe('Datastore', function() {
datastoreMock.get.callsArgWith(1, null, entity);
Storage(config)[method].get('walterwhite', cb);
datastoreMock.key.should.be.calledWith([METHODS[method], 'walterwhite']);
cb.should.be.calledWith(null, entity.data);
cb.should.be.calledWith(null, entity);
});

it('should handle non existent entity', function() {
Expand All @@ -117,6 +116,60 @@ describe('Datastore', function() {
});
});

describe('get from namespace', function() {
var records,
entity,
config;

beforeEach(function() {
config = {
projectId: 'right_here',
namespace: 'my-space'
};
entity = {
key: sinon.stub(),
data: sinon.stub()
};
entities = [
sinon.stub().returns(entity)
];
});

it('should get entity', function() {
var cb = sinon.stub();
datastoreMock.get.callsArgWith(1, null, entity);
Storage(config)[method].get('walterwhite', cb);
datastoreMock.key.should.be.calledWith({
namespace: config.namespace,
path: [METHODS[method], 'walterwhite']
});
cb.should.be.calledWith(null, entity);
});

it('should handle non existent entity', function() {
var cb = sinon.stub();
datastoreMock.get.callsArgWith(1, null, null);
Storage(config)[method].get('walterwhite', cb);
datastoreMock.key.should.be.calledWith({
namespace: config.namespace,
path: [METHODS[method], 'walterwhite']
});
cb.should.be.calledWith(null, null);
});

it('should call callback on error', function() {
var cb = sinon.stub(),
err = new Error('OOPS');
datastoreMock.get.callsArgWith(1, err);
Storage(config)[method].get('walterwhite', cb);
datastoreMock.key.should.be.calledWith({
namespace: config.namespace,
path: [METHODS[method], 'walterwhite']
});
cb.should.be.calledWith(err);
});
});

describe('save', function() {
var config;

Expand All @@ -137,6 +190,30 @@ describe('Datastore', function() {
});
});

describe('save into namespace', function() {
var config;

beforeEach(function() {
config = {
projectId: 'right_here',
namespace: 'my-space'
};
});

it('should call datastore save', function() {
var cb = sinon.stub(),
data = {id: 'walterwhite'},
updateObj = { key: keyMock, data: data};

Storage(config)[method].save(data, cb);
datastoreMock.key.should.be.calledWith({
namespace: config.namespace,
path: [METHODS[method], data.id]
});
datastoreMock.save.should.be.calledWith(updateObj, cb);
});
});

describe('all', function() {

var records,
Expand Down Expand Up @@ -169,7 +246,7 @@ describe('Datastore', function() {

it('should get records', function() {
var cb = sinon.stub(),
result = [entities[0].data, entities[1].data];
result = [entities[0], entities[1]];

datastoreMock.runQuery.callsArgWith(1, null, entities);
Storage(config)[method].all(cb);
Expand All @@ -194,5 +271,64 @@ describe('Datastore', function() {
cb.should.be.calledWith(err);
});
});

describe('all from namespace', function() {

var records,
entities,
config;

beforeEach(function() {
config = {
projectId: 'right_here',
namespace: 'my-space'
};

entities = [
{
key: 'walterwhite',
data: {
id: 'walterwhite',
name: 'heisenberg'
}
},
{
key: 'jessepinkman',
data: {
id: 'jessepinkman',
name: 'capncook'
}
}
];

});

it('should get records', function() {
var cb = sinon.stub(),
result = [entities[0], entities[1]];

datastoreMock.runQuery.callsArgWith(1, null, entities);
Storage(config)[method].all(cb);
datastoreMock.createQuery.should.be.calledWith(config.namespace, METHODS[method]);
cb.should.be.calledWith(null, result);
});

it('should handle no records', function() {
var cb = sinon.stub();
datastoreMock.runQuery.callsArgWith(1, null, undefined);
Storage(config)[method].all(cb);
datastoreMock.createQuery.should.be.calledWith(config.namespace, METHODS[method]);
cb.should.be.calledWith(null, []);
});

it('should call callback on error', function() {
var cb = sinon.stub(),
err = new Error('OOPS');
datastoreMock.runQuery.callsArgWith(1, err);
Storage(config)[method].all(cb);
datastoreMock.createQuery.should.be.calledWith(config.namespace, METHODS[method]);
cb.should.be.calledWith(err);
});
});
});
});

0 comments on commit 6b8f76b

Please sign in to comment.