Skip to content

Commit

Permalink
Add getAll contract and tests, implementation for redis.
Browse files Browse the repository at this point in the history
  • Loading branch information
GabeIsman committed Mar 22, 2016
1 parent 7b18da7 commit eb4c592
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 65 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
node_modules/*
.DS_Store
*~
.idea/
.idea/
.tags*
82 changes: 46 additions & 36 deletions lib/backend.js
Original file line number Diff line number Diff line change
@@ -1,78 +1,88 @@
/**
Backend Interface.
Implement this API for providing a backend for the acl module.
Backend Interface.
Implement this API for providing a backend for the acl module.
*/

var contract = require('./contract');

var Backend = {
/**
/**
Begins a transaction.
*/
begin : function(){
// returns a transaction object
},

/**
Ends a transaction (and executes it)
*/
end : function(transaction, cb){
contract(arguments).params('object', 'function').end();
contract(arguments).params('object', 'function').end();
// Execute transaction
},

/**
Cleans the whole storage.
*/
clean : function(cb){
contract(arguments).params('function').end();
},

/**
Gets the contents at the bucket's key.
*/
get : function(bucket, key, cb){
contract(arguments)
.params('string', 'string|number', 'function')
.end();
contract(arguments)
.params('string', 'string|number', 'function')
.end();
},

/**
Returns the union of the values in the given keys.
*/
/**
Gets the contents of the specified keys and returns them in the same order
passed.
*/
getAll : function(bucket, keys, cb){
contract(arguments)
.params('string', 'array', 'function')
.end();
},

/**
Returns the union of the values in the given keys.
*/
union : function(bucket, keys, cb){
contract(arguments)
.params('string', 'array', 'function')
.end();
},
.params('string', 'array', 'function')
.end();
},

/**
Adds values to a given key inside a bucket.
*/
add : function(transaction, bucket, key, values){
contract(arguments)
.params('object', 'string', 'string|number','string|array|number')
Adds values to a given key inside a bucket.
*/
add : function(transaction, bucket, key, values){
contract(arguments)
.params('object', 'string', 'string|number','string|array|number')
.end();
},
},

/**
Delete the given key(s) at the bucket
*/
del : function(transaction, bucket, keys){
contract(arguments)
.params('object', 'string', 'string|array')
.end();
contract(arguments)
.params('object', 'string', 'string|array')
.end();
},
/**
Removes values from a given key inside a bucket.
*/
remove : function(transaction, bucket, key, values){
contract(arguments)
.params('object', 'string', 'string|number','string|array|number')

/**
Removes values from a given key inside a bucket.
*/
remove : function(transaction, bucket, key, values){
contract(arguments)
.params('object', 'string', 'string|number','string|array|number')
.end();
},
},
}

exports = module.exports = Backend;
67 changes: 45 additions & 22 deletions lib/redis-backend.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
/**
Redis Backend.
Implementation of the storage backend using Redis
*/
"use strict";

var contract = require('./contract');
var _ = require('lodash');

function noop(){};

Expand All @@ -15,22 +16,22 @@ function RedisBackend(redis, prefix){
}

RedisBackend.prototype = {
/**

/**
Begins a transaction
*/
begin : function(){
return this.redis.multi();
},

/**
Ends a transaction (and executes it)
*/
end : function(transaction, cb){
contract(arguments).params('object', 'function').end();
transaction.exec(function(){cb()});
},

/**
Cleans the whole storage.
*/
Expand All @@ -45,7 +46,7 @@ RedisBackend.prototype = {
}
});
},

/**
Gets the contents at the bucket's key.
*/
Expand All @@ -55,32 +56,54 @@ RedisBackend.prototype = {
.end();

key = this.bucketKey(bucket, key);

this.redis.smembers(key, cb);
},


/**
Gets an array of the contents of the specified keys.
*/
getAll : function(bucket, keys, cb){
contract(arguments)
.params('string', 'array', 'function')
.end();

var redisKeys = this.bucketKey(bucket, keys);
var batch = this.redis.batch();
var self = this;

redisKeys.map(function(key) {
batch.smembers(key, self.redis.print);
});

batch.exec(function(err, replies) {
var result = Array.isArray(replies) ? _.zipObject(keys, replies) : replies;
cb(err, result);
});
},

/**
Returns the union of the values in the given keys.
*/
union : function(bucket, keys, cb){
contract(arguments)
.params('string', 'array', 'function')
.end();

keys = this.bucketKey(bucket, keys);
this.redis.sunion(keys, cb);
},

/**
Adds values to a given key inside a bucket.
*/
add : function(transaction, bucket, key, values){
contract(arguments)
.params('object', 'string', 'string|number','string|array|number')
.end();

key = this.bucketKey(bucket, key);

if (Array.isArray(values)){
values.forEach(function(value){
transaction.sadd(key, value);
Expand All @@ -89,36 +112,36 @@ RedisBackend.prototype = {
transaction.sadd(key, values);
}
},

/**
Delete the given key(s) at the bucket
*/
del : function(transaction, bucket, keys){
contract(arguments)
.params('object', 'string', 'string|array')
.end();

var self = this;

keys = Array.isArray(keys) ? keys : [keys]

keys = keys.map(function(key){
return self.bucketKey(bucket, key);
});

transaction.del(keys);
},

/**
Removes values from a given key inside a bucket.
*/
remove : function(transaction, bucket, key, values){
contract(arguments)
.params('object', 'string', 'string|number','string|array|number')
.end();

key = this.bucketKey(bucket, key);

if (Array.isArray(values)){
values.forEach(function(value){
transaction.srem(key, value);
Expand All @@ -127,11 +150,11 @@ RedisBackend.prototype = {
transaction.srem(key, values);
}
},

//
// Private methods
//

bucketKey : function(bucket, keys){
var self = this;
if(Array.isArray(keys)){
Expand Down
58 changes: 58 additions & 0 deletions test/backendtests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
var chai = require('chai');
var assert = chai.assert;
var expect = chai.expect;
var _ = require('lodash');

var testData = {
key1: ["1", "2", "3"],
key2: ["4", "5", "6"],
key3: ["7", "8", "9"]
};
var bucket = 'test-bucket';

exports.getAll = function() {
describe('getAll', function() {
before(function(done) {
var backend = this.backend;
if (!backend.getAll) {
this.skip();
}

backend.clean(function() {
var transaction = backend.begin();
Object.keys(testData).forEach(function(key) {
backend.add(transaction, bucket, key, testData[key]);
});
backend.end(transaction, done);
});
});

after(function(done) {
this.backend.clean(done);
});

it('should respond with an appropriate map', function(done) {
this.backend.getAll(bucket, Object.keys(testData), function(err, result) {
expect(err).to.be.null;
expect(result).to.be.eql(testData);
done();
});
});

it('should get only the specified keys', function(done) {
this.backend.getAll(bucket, ['key1'], function(err, result) {
expect(err).to.be.null;
expect(result).to.be.eql(_.pick(testData, 'key1'));
done();
});
});

it('should be order-independent', function(done) {
this.backend.getAll(bucket, Object.keys(testData).reverse(), function(err, result) {
expect(err).to.be.null;
expect(result).to.be.eql(testData);
done();
});
});
});
};
Loading

0 comments on commit eb4c592

Please sign in to comment.