Browse Source

Merge branch 'master' into develop

feature/specify-what-to-cache
Bryan Donovan 10 years ago
parent
commit
df9744505d
  1. 13
      lib/caching.js
  2. 88
      lib/multi_caching.js
  3. 12
      lib/stores/memory.js
  4. 4
      test/caching.unit.js
  5. 4
      test/multi_caching.unit.js
  6. 216
      test/stores/options.unit.js

13
lib/caching.js

@ -1,4 +1,5 @@
/*jshint maxcomplexity:15*/
/*jshint -W072 */
var domain = require('domain');
var caching = function(args) {
@ -36,10 +37,10 @@ var caching = function(args) {
* console.log(user);
* });
*/
self.wrap = function(key, work, ttl, cb) {
if (typeof ttl === 'function') {
cb = ttl;
ttl = undefined;
self.wrap = function(key, work, options, cb) {
if (typeof options === 'function') {
cb = options;
options = undefined;
}
if (self.queues[key]) {
@ -59,7 +60,7 @@ var caching = function(args) {
});
}
self.store.get(key, function(err, result) {
self.store.get(key, options, function(err, result) {
if (err && (!self.ignoreCacheErrors)) {
fillCallbacks(err);
} else if (result) {
@ -75,7 +76,7 @@ var caching = function(args) {
fillCallbacks(err);
return;
}
self.store.set(key, data, ttl, function(err) {
self.store.set(key, data, options, function(err) {
if (err && (!self.ignoreCacheErrors)) {
fillCallbacks(err);
} else {

88
lib/multi_caching.js

@ -6,15 +6,24 @@ var domain = require('domain');
*/
var multi_caching = function(caches) {
var self = {};
if (!Array.isArray(caches)) { throw new Error('multi_caching requires an array of caches'); }
if (!Array.isArray(caches)) {
throw new Error('multi_caching requires an array of caches');
}
self.queues = {};
function get_from_highest_priority_cache(key, cb) {
function get_from_highest_priority_cache(key, options, cb) {
if (typeof options === 'function') {
cb = options;
options = undefined;
}
var i = 0;
async.forEachSeries(caches, function(cache, async_cb) {
cache.store.get(key, function(err, result) {
if (err) { return cb(err); }
var callback = function(err, result) {
if (err) {
return cb(err);
}
if (result) {
// break out of async loop.
return cb(err, result, i);
@ -22,13 +31,22 @@ var multi_caching = function(caches) {
i += 1;
async_cb(err);
});
};
if (typeof options === 'object') {
cache.store.get(key, options, callback);
}else {
cache.store.get(key, callback);
}
}, cb);
}
function set_in_multiple_caches(caches, opts, cb) {
async.forEach(caches, function(cache, async_cb) {
cache.store.set(opts.key, opts.value, opts.ttl, async_cb);
if (typeof opts.options !== 'object') {
cache.store.set(opts.key, opts.value, opts.ttl, async_cb);
} else {
cache.store.set(opts.key, opts.value, opts.options, async_cb);
}
}, cb);
}
@ -64,10 +82,10 @@ var multi_caching = function(caches) {
* If a key doesn't exist in a higher-priority cache but exists in a lower-priority
* cache, it gets set in all higher-priority caches.
*/
self.wrap = function(key, work, ttl, cb) {
if (typeof ttl === 'function') {
cb = ttl;
ttl = undefined;
self.wrap = function(key, work, options, cb) {
if (typeof options === 'function') {
cb = options;
options = undefined;
}
if (self.queues[key]) {
@ -95,18 +113,23 @@ var multi_caching = function(caches) {
var opts = {
key: key,
value: result,
ttl: ttl
options: options
};
if (typeof options !== 'object') {
opts.ttl = options;
}
set_in_multiple_caches(caches_to_update, opts, function(err) {
fillCallbacks(err, result);
});
} else {
domain
.create()
.on('error', function(err) {
fillCallbacks(err);
})
.bind(work)(function(err, data) {
.create()
.on('error', function(err) {
fillCallbacks(err);
})
.bind(work)(function(err, data) {
if (err) {
fillCallbacks(err);
return;
@ -114,8 +137,12 @@ var multi_caching = function(caches) {
var opts = {
key: key,
value: data,
ttl: ttl
options: options
};
if (typeof options !== 'object') {
opts.ttl = options;
}
set_in_multiple_caches(caches, opts, function(err) {
if (err) {
fillCallbacks(err);
@ -128,22 +155,37 @@ var multi_caching = function(caches) {
});
};
self.set = function(key, value, ttl, cb) {
self.set = function(key, value, options, cb) {
var opts = {
key: key,
value: value,
ttl: ttl
options: options
};
if (typeof options !== 'object') {
opts.ttl = options;
}
set_in_multiple_caches(caches, opts, cb);
};
self.get = function(key, cb) {
get_from_highest_priority_cache(key, cb);
self.get = function(key, options, cb) {
if (typeof options === 'function') {
cb = options;
options = false;
}
get_from_highest_priority_cache(key, options, cb);
};
self.del = function(key, cb) {
self.del = function(key, options, cb) {
if (typeof options === 'function') {
cb = options;
options = false;
}
async.forEach(caches, function(cache, async_cb) {
cache.store.del(key, async_cb);
if (typeof options === 'object') {
cache.store.del(key, options, async_cb);
}else {
cache.store.del(key, async_cb);
}
}, cb);
};

12
lib/stores/memory.js

@ -12,14 +12,17 @@ var memory_store = function(args) {
var lru_cache = new Lru(lru_opts);
self.set = function(key, value, ttl, cb) {
self.set = function(key, value, options, cb) {
lru_cache.set(key, value);
if (cb) {
process.nextTick(cb);
}
};
self.get = function(key, cb) {
self.get = function(key, options, cb) {
if (typeof options === 'function') {
cb = options;
}
var value = lru_cache.get(key);
if (cb) {
process.nextTick(function() {
@ -30,7 +33,10 @@ var memory_store = function(args) {
}
};
self.del = function(key, cb) {
self.del = function(key, options, cb) {
if (typeof options === 'function') {
cb = options;
}
lru_cache.del(key);
if (cb) {
process.nextTick(cb);

4
test/caching.unit.js

@ -403,7 +403,7 @@ describe("caching", function() {
it("bubbles up that error", function(done) {
var fake_error = new Error(support.random.string());
sinon.stub(memory_store_stub, 'get', function(key, cb) {
sinon.stub(memory_store_stub, 'get', function(key, options, cb) {
cb(fake_error);
});
@ -423,7 +423,7 @@ describe("caching", function() {
var fake_error = new Error(support.random.string());
sinon.stub(memory_store_stub, 'get', function(key, cb) {
sinon.stub(memory_store_stub, 'get', function(key, options, cb) {
cb(fake_error);
});

4
test/multi_caching.unit.js

@ -172,8 +172,8 @@ describe("multi_caching", function() {
});
});
});
});
}, 10);
}, 10);
});
});
});
});

216
test/stores/options.unit.js

@ -0,0 +1,216 @@
var caching = require("../../index");
var assert = require("assert");
var support = require("../support");
var check_err = support.check_err;
var memoryFlag = "";
var key;
var value;
var testStore = function(args) {
args = args || {};
var self = {};
self.name = "options";
self.store = {};
self.get = function(key, options, cb) {
var optionsMapped = false;
if (typeof options === "function") {
cb = options;
options = false;
optionsMapped = true;
}
if (options && options.value) {
return cb(null, options.value + "ValueOption");
} else if (options && options.fn) {
options.fn("GetFunctionOption");
return cb(null, "GetFunctionOption");
} else if (options && options.runNormal) {
return cb(null, self.store[key]);
} else if (optionsMapped) {
return cb();
}
return cb("Error No Options");
};
self.set = function(key, value, options, cb) {
var optionsMapped = false;
if (typeof options === "function") {
cb = options;
options = false;
optionsMapped = true;
} else if (typeof options !== "object") {
options = {ttl: options, runNormal: true};
}
if (options && options.value) {
memoryFlag = options.value + "ValueOption";
return cb();
} else if (options && options.fn) {
options.fn("SetFunctionOption");
return cb();
} else if (options && options.runNormal) {
self.store[key] = value;
return cb(null, self.store[key]);
} else if (optionsMapped) {
return cb();
}
return cb("Error No Options");
};
self.del = function(key, options, cb) {
var optionsMapped = false;
if (typeof options === "function") {
cb = options;
options = false;
optionsMapped = true;
}
if (options && options.value) {
memoryFlag = options.value + "ValueOption";
return cb();
} else if (options && options.fn) {
options.fn("DeleteFunctionOption");
return cb();
} else if (options && options.runNormal) {
delete self.store[key];
return cb(null, "");
} else if (optionsMapped) {
return cb();
}
return cb("Error No Options");
};
return {
create: function() {
return self;
}
};
};
describe("Methods with options", function() {
before(function() {
key = support.random.string(20);
value = support.random.string(20);
});
describe("get with options", function() {
var testInstance = caching.caching({store: testStore()});
var testCache;
before(function() {
testCache = caching.multi_caching([testInstance]);
});
it("lets us pass options by value", function(done) {
var options = {value: value};
testCache.get(key, options, function(err, response) {
assert.equal(response, value + "ValueOption");
done();
});
});
it("lets us pass options by function", function(done) {
var options = {
fn: function(response) {
assert.equal(response, "GetFunctionOption");
done();
}
};
testCache.get(key, options, function(err, response) {
assert.equal(response, "GetFunctionOption");
});
});
});
describe("set with options", function() {
var testInstance = caching.caching({store: testStore()});
var testCache;
var ttl = 60;
before(function() {
testCache = caching.multi_caching([testInstance]);
});
it("lets us pass options by value", function(done) {
var options = {ttl: ttl, value: value};
testCache.set(key, value, options, function() {
assert.equal(memoryFlag, value + "ValueOption");
done();
});
});
it("lets us pass options by function", function(done) {
var options = {
ttl: ttl,
fn: function(response) {
assert.equal(response, "SetFunctionOption");
done();
}
};
testCache.set(key, value, options, function() {}, options);
});
});
describe("delete with options", function() {
var testInstance = caching.caching({store: testStore()});
var testCache;
before(function() {
testCache = caching.multi_caching([testInstance]);
});
it("lets us pass options by value", function(done) {
var options = {value: value};
testCache.del(key, options, function() {
assert.equal(memoryFlag,value + "ValueOption");
done();
});
});
it("lets us pass options by function", function(done) {
var options = {
fn: function(response) {
assert.equal(response, "DeleteFunctionOption");
done();
}
};
testCache.del(key, options, function() {}, options);
});
});
});
describe("Multiple stores with options", function() {
var testInstance = caching.caching({store: testStore()});
var memInstance = caching.caching({store: "memory"});
var testCache;
var options = {runNormal: true};
var ttl = 1;
before(function() {
key = support.random.string(20);
value = support.random.string(20);
testCache = caching.multi_caching([testInstance, memInstance]);
});
it("lets us pass options which only one store uses", function() {
testCache.set(key, value, options, function(err) {
check_err(err);
testCache.get(key, options, function(err, response) {
check_err(err);
assert.equal(response, value);
testCache.del(key, options, function(err) {
check_err(err);
testCache.get(key, options, function(err, response) {
check_err(err);
assert.equal(response, undefined);
});
});
});
});
});
it("lets us not pass options which only one store uses", function() {
testCache.set(key, value, ttl, function(err) {
check_err(err);
testCache.get(key, function(err, response) {
check_err(err);
assert.equal(response, value);
testCache.del(key, function(err) {
check_err(err);
testCache.get(key, function(err, response) {
check_err(err);
assert.equal(response, undefined);
});
});
});
});
});
});
Loading…
Cancel
Save