cache-manager
Advanced tools
Comparing version 0.19.0 to 1.0.0
@@ -11,3 +11,3 @@ /*jshint unused:false*/ | ||
// | ||
memoryCache.set('foo', 'bar', ttl, function(err) { | ||
memoryCache.set('foo', 'bar', function(err) { | ||
if (err) { throw err; } | ||
@@ -116,3 +116,3 @@ | ||
// Sets in all caches. | ||
multiCache.set('foo2', 'bar2', ttl2, function(err) { | ||
multiCache.set('foo2', 'bar2', {ttl: ttl2}, function(err) { | ||
if (err) { throw err; } | ||
@@ -119,0 +119,0 @@ |
@@ -84,3 +84,6 @@ /** | ||
self.del = function(key, cb) { | ||
self.del = function(key, options, cb) { | ||
if (typeof options === 'function') { | ||
cb = options; | ||
} | ||
connect(function(err, conn) { | ||
@@ -87,0 +90,0 @@ if (err) { return cb(err); } |
@@ -0,1 +1,13 @@ | ||
- 1.0.0 2015-05-23 | ||
- Added JSDOC generation (`make docs`) | ||
- (Breaking change) By default, cache falsey values like `false`, `0`, and `null`, but not `undefined` (#25). | ||
- Allow users to pass in callback function `isCacheableValue` to specify what to cache. | ||
- (Breaking change) Removed deprecated lower-case `multi_caching` export (use `multiCaching` instead). | ||
- (Breaking change) Removed `multiCaching#get_and_pass_up` (use `getAndPassUp` instead). | ||
- (Breaking change) Cache store methods must accept an `options` param (which can be ignored). Eg., | ||
`function set(key, val, options, cb) { }` | ||
- (Breaking change) caching/multicaching methods no longer accept a `ttl` param. You must instead pass | ||
in an options object which will be passed to the cache store's `set` method. | ||
- (Breaking change) caching.js no longer accepts a path to cache store. Pass in an object or 'memory' instead. | ||
- 0.19.0 2015-03-29 | ||
@@ -2,0 +14,0 @@ - Pass dispose, length & stale options to lru-cache (#22). - @gmaclennan |
@@ -1,7 +0,1 @@ | ||
var cache = { | ||
caching: require('./lib/caching'), | ||
multi_caching: require('./lib/multi_caching'), //backward compat | ||
multiCaching: require('./lib/multi_caching') | ||
}; | ||
module.exports = cache; | ||
module.exports = require('./lib'); |
@@ -0,1 +1,2 @@ | ||
/** @module cacheManager/caching */ | ||
/*jshint maxcomplexity:15*/ | ||
@@ -5,2 +6,12 @@ var domain = require('domain'); | ||
/** | ||
* Generic caching interface that wraps any caching library with a compatible interface. | ||
* | ||
* @param {object} args | ||
* @param {object|string} args.store - The store must at least have `set` and a `get` functions. | ||
* @param {function} [args.isCacheableValue] - A callback function which is called | ||
* with every value returned from cache or from a wrapped function. This lets you specify | ||
* which values should and should not be cached. If the function returns true, it will be | ||
* stored in cache. By default it caches everything except undefined. | ||
*/ | ||
var caching = function(args) { | ||
@@ -15,4 +26,2 @@ args = args || {}; | ||
} | ||
} else if (typeof args.store === 'string' && args.store.match(/\//)) { | ||
self.store = require(args.store).create(args); | ||
} else { | ||
@@ -28,2 +37,10 @@ var storeName = args.store || 'memory'; | ||
if (typeof args.isCacheableValue === 'function') { | ||
self._isCacheableValue = args.isCacheableValue; | ||
} else { | ||
self._isCacheableValue = function(value) { | ||
return value !== undefined; | ||
}; | ||
} | ||
/** | ||
@@ -34,4 +51,11 @@ * Wraps a function in cache. I.e., the first time the function is run, | ||
* | ||
* @function | ||
* @name wrap | ||
* | ||
* @param {string} key - The cache key to use in cache operations | ||
* @param {function} work - The function to wrap | ||
* @param {object} [options] - options passed to `set` function | ||
* @param {function} cb | ||
* | ||
* @example | ||
* | ||
* var key = 'user_' + userId; | ||
@@ -47,3 +71,3 @@ * cache.wrap(key, function(cb) { | ||
cb = options; | ||
options = undefined; | ||
options = {}; | ||
} | ||
@@ -58,3 +82,3 @@ | ||
callbackFiller.fill(key, err); | ||
} else if (result) { | ||
} else if (self._isCacheableValue(result)) { | ||
callbackFiller.fill(key, null, result); | ||
@@ -72,2 +96,7 @@ } else { | ||
} | ||
if (!self._isCacheableValue(data)) { | ||
return cb(); | ||
} | ||
self.store.set(key, data, options, function(err) { | ||
@@ -85,6 +114,21 @@ if (err && (!self.ignoreCacheErrors)) { | ||
/** | ||
* Binds to the underlying store's `get` function. | ||
* @function | ||
* @name get | ||
*/ | ||
self.get = self.store.get.bind(self.store); | ||
/** | ||
* Binds to the underlying store's `set` function. | ||
* @function | ||
* @name set | ||
*/ | ||
self.set = self.store.set.bind(self.store); | ||
/** | ||
* Binds to the underlying store's `del` function if it exists. | ||
* @function | ||
* @name del | ||
*/ | ||
if (typeof self.store.del === 'function') { | ||
@@ -94,2 +138,7 @@ self.del = self.store.del.bind(self.store); | ||
/** | ||
* Binds to the underlying store's `setex` function if it exists. | ||
* @function | ||
* @name setex | ||
*/ | ||
if (typeof self.store.setex === 'function') { | ||
@@ -99,2 +148,7 @@ self.setex = self.store.setex.bind(self.store); | ||
/** | ||
* Binds to the underlying store's `reset` function if it exists. | ||
* @function | ||
* @name reset | ||
*/ | ||
if (typeof self.store.reset === 'function') { | ||
@@ -104,2 +158,7 @@ self.reset = self.store.reset.bind(self.store); | ||
/** | ||
* Binds to the underlying store's `keys` function if it exists. | ||
* @function | ||
* @name keys | ||
*/ | ||
if (typeof self.store.keys === 'function') { | ||
@@ -109,2 +168,7 @@ self.keys = self.store.keys.bind(self.store); | ||
/** | ||
* Binds to the underlying store's `ttl` function if it exists. | ||
* @function | ||
* @name ttl | ||
*/ | ||
if (typeof self.store.ttl === 'function') { | ||
@@ -111,0 +175,0 @@ self.ttl = self.store.ttl.bind(self.store); |
@@ -0,1 +1,2 @@ | ||
/** @module cacheManager/multiCaching */ | ||
var async = require('async'); | ||
@@ -7,5 +8,14 @@ var domain = require('domain'); | ||
* Module that lets you specify a hierarchy of caches. | ||
* | ||
* @param {array} caches - Array of caching objects. | ||
* @param {object} [options] | ||
* @param {function} [options.isCacheableValue] - A callback function which is called | ||
* with every value returned from cache or from a wrapped function. This lets you specify | ||
* which values should and should not be cached. If the function returns true, it will be | ||
* stored in cache. By default it caches everything except undefined. | ||
*/ | ||
var multiCaching = function(caches) { | ||
var multiCaching = function(caches, options) { | ||
var self = {}; | ||
options = options || {}; | ||
if (!Array.isArray(caches)) { | ||
@@ -17,6 +27,14 @@ throw new Error('multiCaching requires an array of caches'); | ||
if (typeof options.isCacheableValue === 'function') { | ||
self._isCacheableValue = options.isCacheableValue; | ||
} else { | ||
self._isCacheableValue = function(value) { | ||
return value !== undefined; | ||
}; | ||
} | ||
function getFromHighestPriorityCache(key, options, cb) { | ||
if (typeof options === 'function') { | ||
cb = options; | ||
options = undefined; | ||
options = {}; | ||
} | ||
@@ -39,7 +57,3 @@ | ||
if (typeof options === 'object') { | ||
cache.store.get(key, options, callback); | ||
} else { | ||
cache.store.get(key, callback); | ||
} | ||
cache.store.get(key, options, callback); | ||
}, cb); | ||
@@ -49,8 +63,5 @@ } | ||
function setInMultipleCaches(caches, opts, cb) { | ||
opts.options = opts.options || {}; | ||
async.each(caches, function(cache, next) { | ||
if (typeof opts.options === 'object') { | ||
cache.store.set(opts.key, opts.value, opts.options, next); | ||
} else { | ||
cache.store.set(opts.key, opts.value, opts.ttl, next); | ||
} | ||
cache.store.set(opts.key, opts.value, opts.options, next); | ||
}, cb); | ||
@@ -61,4 +72,6 @@ } | ||
* Looks for an item in cache tiers. | ||
* When a key is found in a lower cache, all higher levels are updated. | ||
* | ||
* When a key is found in a lower cache, all higher levels are updated | ||
* @param {string} key | ||
* @param {function} cb | ||
*/ | ||
@@ -84,9 +97,2 @@ self.getAndPassUp = function(key, cb) { | ||
/** | ||
* This is for backward-compatibility | ||
*/ | ||
//jscs:disable requireCamelCaseOrUpperCaseIdentifiers | ||
self.get_and_pass_up = self.getAndPassUp; | ||
//jscs:enable requireCamelCaseOrUpperCaseIdentifiers | ||
/** | ||
* Wraps a function in one or more caches. | ||
@@ -100,2 +106,7 @@ * Has same API as regular caching module. | ||
* cache, it gets set in all higher-priority caches. | ||
* | ||
* @param {string} key - The cache key to use in cache operations | ||
* @param {function} work - The function to wrap | ||
* @param {object} [options] - options passed to `set` function | ||
* @param {function} cb | ||
*/ | ||
@@ -105,17 +116,11 @@ self.wrap = function(key, work, options, cb) { | ||
cb = options; | ||
options = undefined; | ||
options = {}; | ||
} | ||
function getOptsForSet(result) { | ||
var opts = { | ||
function getOptsForSet(value) { | ||
return { | ||
key: key, | ||
value: result, | ||
value: value, | ||
options: options | ||
}; | ||
if (typeof options !== 'object') { | ||
opts.ttl = options; | ||
} | ||
return opts; | ||
} | ||
@@ -130,3 +135,3 @@ | ||
return callbackFiller.fill(key, err); | ||
} else if (result) { | ||
} else if (self._isCacheableValue(result)) { | ||
var cachesToUpdate = caches.slice(0, index); | ||
@@ -149,2 +154,6 @@ var opts = getOptsForSet(result); | ||
if (!self._isCacheableValue(data)) { | ||
return cb(); | ||
} | ||
var opts = getOptsForSet(data); | ||
@@ -160,3 +169,19 @@ | ||
/** | ||
* Set value in all caches | ||
* | ||
* @function | ||
* @name set | ||
* | ||
* @param {string} key | ||
* @param {*} value | ||
* @param {object} [options] to pass to underlying set function. | ||
* @param {function} [cb] | ||
*/ | ||
self.set = function(key, value, options, cb) { | ||
if (typeof options === 'function') { | ||
cb = options; | ||
options = {}; | ||
} | ||
var opts = { | ||
@@ -167,27 +192,43 @@ key: key, | ||
}; | ||
if (typeof options !== 'object') { | ||
opts.ttl = options; | ||
} | ||
setInMultipleCaches(caches, opts, cb); | ||
}; | ||
/** | ||
* Get value from highest level cache that has stored it. | ||
* | ||
* @function | ||
* @name get | ||
* | ||
* @param {string} key | ||
* @param {object} [options] to pass to underlying get function. | ||
* @param {function} cb | ||
*/ | ||
self.get = function(key, options, cb) { | ||
if (typeof options === 'function') { | ||
cb = options; | ||
options = false; | ||
options = {}; | ||
} | ||
getFromHighestPriorityCache(key, options, cb); | ||
}; | ||
/** | ||
* Delete value from all caches. | ||
* | ||
* @function | ||
* @name del | ||
* | ||
* @param {string} key | ||
* @param {object} [options] to pass to underlying del function. | ||
* @param {function} cb | ||
*/ | ||
self.del = function(key, options, cb) { | ||
if (typeof options === 'function') { | ||
cb = options; | ||
options = false; | ||
options = {}; | ||
} | ||
async.each(caches, function(cache, next) { | ||
if (typeof options === 'object') { | ||
cache.store.del(key, options, next); | ||
} else { | ||
cache.store.del(key, next); | ||
} | ||
cache.store.del(key, options, next); | ||
}, cb); | ||
@@ -194,0 +235,0 @@ }; |
@@ -19,2 +19,5 @@ var Lru = require("lru-cache"); | ||
self.set = function(key, value, options, cb) { | ||
if (typeof options === 'function') { | ||
cb = options; | ||
} | ||
lruCache.set(key, value); | ||
@@ -21,0 +24,0 @@ if (cb) { |
{ | ||
"name": "cache-manager", | ||
"version": "0.19.0", | ||
"version": "1.0.0", | ||
"description": "Cache module for Node.js", | ||
@@ -30,2 +30,3 @@ "main": "index.js", | ||
"jscs": "^1.9.0", | ||
"jsdoc": "^3.3.0", | ||
"jshint": "^2.5.4", | ||
@@ -32,0 +33,0 @@ "mocha": "^1.20.1", |
@@ -60,3 +60,3 @@ [![build status](https://secure.travis-ci.org/BryanDonovan/node-cache-manager.png)](http://travis-ci.org/BryanDonovan/node-cache-manager) | ||
getUser(id, cacheCallback); | ||
}, ttl, cb); | ||
}, {ttl: ttl}, cb); | ||
} | ||
@@ -151,3 +151,3 @@ ``` | ||
DB.find(req.query, cacheCallback); | ||
}, ttl, function(err, result) { | ||
}, {ttl: ttl}, function(err, result) { | ||
respond(res, err, result); | ||
@@ -182,3 +182,3 @@ }); | ||
// Sets in all caches. | ||
multiCache.set('foo2', 'bar2', ttl, function(err) { | ||
multiCache.set('foo2', 'bar2', {ttl: ttl}, function(err) { | ||
if (err) { throw err; } | ||
@@ -196,6 +196,6 @@ | ||
// Note: ttl is optional in wrap() | ||
// Note: options with ttl are optional in wrap() | ||
multiCache.wrap(key2, function (cb) { | ||
getUser(userId2, cb); | ||
}, ttl, function (err, user) { | ||
}, {ttl: ttl}, function (err, user) { | ||
console.log(user); | ||
@@ -214,2 +214,43 @@ | ||
### Specifying What to Cache | ||
Both the `caching` and `multicaching` modules allow you to pass in a callback function called | ||
`isCacheableValue` which is called with every value returned from cache or from a wrapped function. | ||
This lets you specify which values should and should not be cached. If the function returns true, it will be | ||
stored in cache. By default the caches cache everything except `undefined`. | ||
For example, if you don't want to cache `false` and `null`, you can pass in a function like this: | ||
```javascript | ||
var isCacheableValue = function(value) { | ||
return value !== null && value !== false && value !== undefined; | ||
}; | ||
``` | ||
Then pass it to `caching` like this: | ||
```javascript | ||
var memoryCache = cacheManager.caching({store: 'memory', isCacheableValue: isCacheableValue}; | ||
``` | ||
And pass it to `multicaching` like this: | ||
```javascript | ||
var multiCache = cacheManager.multiCaching([memoryCache, someOtherCache], { | ||
isCacheableValue: isCacheableValue | ||
}); | ||
``` | ||
## Docs | ||
To generate JSDOC 3 documentation: | ||
make docs | ||
## Tests | ||
@@ -216,0 +257,0 @@ |
@@ -13,3 +13,5 @@ // TODO: These are really a mix of unit and integration tests. | ||
getWidget: function(name, cb) { | ||
cb(null, {name: name}); | ||
process.nextTick(function() { | ||
cb(null, {name: name}); | ||
}); | ||
} | ||
@@ -21,3 +23,3 @@ }; | ||
var key; | ||
var ttl = 1; | ||
var defaultTtl = 1; | ||
var name; | ||
@@ -36,5 +38,7 @@ var value; | ||
it("lets us set and get data in cache", function(done) { | ||
cache.set(key, value, ttl, function(err) { | ||
cache.set(key, value, {ttl: defaultTtl}, function(err) { | ||
checkErr(err); | ||
cache.get(key, function(err, result) { | ||
checkErr(err); | ||
assert.equal(result, value); | ||
@@ -47,3 +51,4 @@ done(); | ||
it("lets us set and get data without a callback", function(done) { | ||
cache.set(key, value, ttl); | ||
cache.set(key, value, {ttl: defaultTtl}); | ||
setTimeout(function() { | ||
@@ -56,4 +61,5 @@ var result = cache.get(key); | ||
it("lets us set and get data without a ttl or callback", function(done) { | ||
it("lets us set and get data without options object or callback", function(done) { | ||
cache.set(key, value); | ||
setTimeout(function() { | ||
@@ -76,3 +82,3 @@ var result = cache.get(key); | ||
value = support.random.string(); | ||
cache.set(key, value, ttl, function(err) { | ||
cache.set(key, value, {ttl: defaultTtl}, function(err) { | ||
checkErr(err); | ||
@@ -124,3 +130,3 @@ done(); | ||
value = support.random.string(); | ||
cache.set(key, value, ttl, function(err) { | ||
cache.set(key, value, function(err) { | ||
checkErr(err); | ||
@@ -131,3 +137,3 @@ | ||
cache.set(key2, value2, ttl, done); | ||
cache.set(key2, value2, done); | ||
}); | ||
@@ -246,3 +252,3 @@ }); | ||
value = support.random.string(); | ||
cache.set(key, value, ttl, cb); | ||
cache.set(key, value, cb); | ||
}, done); | ||
@@ -268,10 +274,11 @@ }); | ||
var memoryStoreStub; | ||
var opts; | ||
beforeEach(function() { | ||
ttl = 0.1; | ||
memoryStoreStub = memoryStore.create({ttl: ttl}); | ||
opts = {ttl: 0.1}; | ||
memoryStoreStub = memoryStore.create(opts); | ||
sinon.stub(memoryStore, 'create').returns(memoryStoreStub); | ||
cache = caching({store: 'memory', ttl: ttl, ignoreCacheErrors: false}); | ||
cache = caching({store: 'memory', ttl: opts.ttl, ignoreCacheErrors: false}); | ||
key = support.random.string(20); | ||
@@ -297,6 +304,6 @@ name = support.random.string(); | ||
methods.getWidget(name, cb); | ||
}, ttl, function(err, widget) { | ||
}, opts, function(err, widget) { | ||
checkErr(err); | ||
assert.deepEqual(widget, {name: name}); | ||
sinon.assert.calledWith(memoryStoreStub.set, key, {name: name}, ttl); | ||
sinon.assert.calledWith(memoryStoreStub.set, key, {name: name}, opts); | ||
done(); | ||
@@ -312,3 +319,3 @@ }); | ||
assert.deepEqual(widget, {name: name}); | ||
sinon.assert.calledWith(memoryStoreStub.set, key, {name: name}, undefined); | ||
sinon.assert.calledWith(memoryStoreStub.set, key, {name: name}, {}); | ||
done(); | ||
@@ -323,3 +330,3 @@ }); | ||
methods.getWidget(name, cacheCb); | ||
}, ttl, cb); | ||
}, opts, cb); | ||
} | ||
@@ -355,3 +362,3 @@ | ||
}); | ||
}, ttl, function(err, widget) { | ||
}, function(err, widget) { | ||
checkErr(err); | ||
@@ -366,2 +373,112 @@ assert.deepEqual(widget, {name: name}); | ||
var falseyValues = [false, null, 0]; | ||
falseyValues.forEach(function(falseyValue) { | ||
context("when cached value is `" + falseyValue + "`", function() { | ||
function getFalseyValue(cb) { | ||
process.nextTick(function() { | ||
cb(null, falseyValue); | ||
}); | ||
} | ||
function getCachedFalseyValue(cb) { | ||
cache.wrap(key, function(cacheCb) { | ||
getFalseyValue(cacheCb); | ||
}, cb); | ||
} | ||
beforeEach(function(done) { | ||
getCachedFalseyValue(function(err, result) { | ||
checkErr(err); | ||
assert.strictEqual(result, falseyValue); | ||
memoryStoreStub.get(key, function(err, result) { | ||
checkErr(err); | ||
assert.strictEqual(result, falseyValue); | ||
sinon.spy(memoryStoreStub, 'get'); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
afterEach(function() { | ||
memoryStoreStub.get.restore(); | ||
}); | ||
it("retrieves data from cache", function(done) { | ||
getCachedFalseyValue(function(err, value) { | ||
checkErr(err); | ||
assert.strictEqual(value, falseyValue); | ||
assert.ok(memoryStoreStub.get.calledWith(key)); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
context("when we pass in an isCacheableValue function to the caching constructor", function() { | ||
var testCallbacks = { | ||
isCacheableValue: function(value) { | ||
return value !== 'do_not_store_this' && value !== undefined; | ||
} | ||
}; | ||
function getValue(name, cb) { | ||
process.nextTick(function() { | ||
if (name === 'foo') { | ||
cb(null, 'store_this'); | ||
} else { | ||
cb(null, 'do_not_store_this'); | ||
} | ||
}); | ||
} | ||
function getCachedValue(name, cb) { | ||
cache.wrap(key, function(cacheCb) { | ||
getValue(name, function(err, result) { | ||
cacheCb(err, result); | ||
}); | ||
}, {ttl: defaultTtl}, cb); | ||
} | ||
beforeEach(function() { | ||
sinon.spy(testCallbacks, 'isCacheableValue'); | ||
cache = caching({store: 'memory', isCacheableValue: testCallbacks.isCacheableValue}); | ||
sinon.spy(memoryStoreStub, 'set'); | ||
}); | ||
afterEach(function() { | ||
memoryStoreStub.set.restore(); | ||
testCallbacks.isCacheableValue.restore(); | ||
}); | ||
it("stores allowed values", function(done) { | ||
var name = 'foo'; | ||
getCachedValue(name, function(err) { | ||
checkErr(err); | ||
assert.ok(memoryStoreStub.set.called); | ||
assert.ok(testCallbacks.isCacheableValue.called); | ||
getCachedValue(name, function(err) { | ||
checkErr(err); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
it("does not store non-allowed values", function(done) { | ||
var name = 'bar'; | ||
getCachedValue(name, function(err) { | ||
checkErr(err); | ||
assert.ok(memoryStoreStub.set.notCalled); | ||
assert.ok(testCallbacks.isCacheableValue.called); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
it("lets us make nested calls", function(done) { | ||
@@ -392,5 +509,7 @@ function getCachedWidget(name, cb) { | ||
it("expires cached result after ttl seconds", function(done) { | ||
var ttl = 0.1; | ||
cache.wrap(key, function(cb) { | ||
methods.getWidget(name, cb); | ||
}, ttl, function(err, widget) { | ||
}, {ttl: ttl}, function(err, widget) { | ||
checkErr(err); | ||
@@ -432,3 +551,3 @@ assert.deepEqual(widget, {name: name}); | ||
throw fakeError; | ||
}, ttl, function(err) { | ||
}, function(err) { | ||
assert.equal(err, fakeError); | ||
@@ -451,3 +570,3 @@ done(); | ||
methods.getWidget(name, cb); | ||
}, ttl, function(err) { | ||
}, function(err) { | ||
assert.equal(err, fakeError); | ||
@@ -462,3 +581,3 @@ memoryStoreStub.get.restore(); | ||
it("does not bubble up that error", function(done) { | ||
cache = caching({store: 'memory', ttl: ttl, ignoreCacheErrors: true}); | ||
cache = caching({store: 'memory', ttl: defaultTtl, ignoreCacheErrors: true}); | ||
@@ -473,3 +592,3 @@ var fakeError = new Error(support.random.string()); | ||
methods.getWidget(name, cb); | ||
}, ttl, function(err) { | ||
}, function(err) { | ||
assert.equal(err, null); | ||
@@ -494,3 +613,3 @@ memoryStoreStub.get.restore(); | ||
methods.getWidget(name, cb); | ||
}, ttl, function(err) { | ||
}, function(err) { | ||
assert.equal(err, fakeError); | ||
@@ -505,12 +624,10 @@ memoryStoreStub.set.restore(); | ||
it("does not bubbles up that error", function(done) { | ||
cache = caching({store: 'memory', ttl: ttl, ignoreCacheErrors: true}); | ||
cache = caching({store: 'memory', ttl: defaultTtl, ignoreCacheErrors: true}); | ||
var fakeError = new Error(support.random.string()); | ||
sinon.stub(memoryStoreStub, 'set', function(key, val, ttl, cb) { | ||
cb(fakeError); | ||
}); | ||
sinon.stub(memoryStoreStub, 'set').yields(fakeError); | ||
cache.wrap(key, function(cb) { | ||
methods.getWidget(name, cb); | ||
}, ttl, function(err) { | ||
}, function(err) { | ||
assert.equal(err, null); | ||
@@ -533,3 +650,3 @@ memoryStoreStub.set.restore(); | ||
methods.getWidget(name, cb); | ||
}, ttl, function(err, widget) { | ||
}, function(err, widget) { | ||
methods.getWidget.restore(); | ||
@@ -571,3 +688,3 @@ assert.equal(err, fakeError); | ||
construct(val, cb); | ||
}, ttl, function(err, result) { | ||
}, function(err, result) { | ||
assert.equal(result, 'value'); | ||
@@ -594,5 +711,5 @@ next(err); | ||
it("allows us to pass in our own store object", function(done) { | ||
var store = memoryStore.create({ttl: ttl}); | ||
var store = memoryStore.create({ttl: defaultTtl}); | ||
cache = caching({store: store}); | ||
cache.set(key, value, ttl, function(err) { | ||
cache.set(key, value, function(err) { | ||
checkErr(err); | ||
@@ -606,18 +723,6 @@ cache.get(key, function(err, result) { | ||
it("allows us to pass in a path to our own store", function(done) { | ||
var storePath = '../lib/stores/memory'; | ||
cache = caching({store: storePath}); | ||
cache.set(key, value, ttl, function(err) { | ||
checkErr(err); | ||
cache.get(key, function(err, result) { | ||
assert.equal(result, value); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
it("allows us to pass in a module (uninstantiated)", function(done) { | ||
var store = memoryStore; | ||
cache = caching({store: store}); | ||
cache.set(key, value, ttl, function(err) { | ||
cache.set(key, value, {ttl: defaultTtl}, function(err) { | ||
checkErr(err); | ||
@@ -624,0 +729,0 @@ cache.get(key, function(err, result) { |
@@ -12,3 +12,5 @@ var assert = require('assert'); | ||
getWidget: function(name, cb) { | ||
cb(null, {name: name}); | ||
process.nextTick(function() { | ||
cb(null, {name: name}); | ||
}); | ||
} | ||
@@ -25,6 +27,7 @@ }; | ||
var name; | ||
var ttl = 5; | ||
var defaultTtl; | ||
beforeEach(function() { | ||
memoryTtl = 0.1; | ||
defaultTtl = 5; | ||
@@ -50,3 +53,3 @@ memoryCache = caching({store: 'memory', ttl: memoryTtl}); | ||
it("lets us set data in all caches", function(done) { | ||
multiCache.set(key, value, ttl, function(err) { | ||
multiCache.set(key, value, {ttl: defaultTtl}, function(err) { | ||
checkErr(err); | ||
@@ -73,3 +76,3 @@ | ||
it("lets us set data without a callback", function(done) { | ||
multiCache.set(key, value, ttl); | ||
multiCache.set(key, value, {ttl: defaultTtl}); | ||
setTimeout(function() { | ||
@@ -99,3 +102,30 @@ multiCache.get(key, function(err, result) { | ||
it("lets us set data without a ttl or callback", function(done) { | ||
it("lets us set data without an options param", function(done) { | ||
multiCache.set(key, value, function(err) { | ||
checkErr(err); | ||
multiCache.get(key, function(err, result) { | ||
checkErr(err); | ||
assert.equal(result, value); | ||
memoryCache.get(key, function(err, result) { | ||
checkErr(err); | ||
assert.equal(result, value); | ||
memoryCache2.get(key, function(err, result) { | ||
checkErr(err); | ||
assert.equal(result, value); | ||
memoryCache3.get(key, function(err, result) { | ||
checkErr(err); | ||
assert.equal(result, value); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
it("lets us set data without options or callback", function(done) { | ||
multiCache.set(key, value); | ||
@@ -129,3 +159,3 @@ setTimeout(function() { | ||
it("gets data from first cache that has it", function(done) { | ||
memoryCache3.set(key, value, ttl, function(err) { | ||
memoryCache3.set(key, value, function(err) { | ||
checkErr(err); | ||
@@ -140,2 +170,22 @@ | ||
}); | ||
it("passes any options to underlying caches", function(done) { | ||
multiCache.set(key, value, function(err) { | ||
checkErr(err); | ||
sinon.spy(memoryCache.store, 'get'); | ||
var opts = {foo: 'bar'}; | ||
multiCache.get(key, opts, function(err, result) { | ||
checkErr(err); | ||
assert.equal(result, value); | ||
assert.ok(memoryCache.store.get.calledWith(key, opts)); | ||
memoryCache.store.get.restore(); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
@@ -145,3 +195,3 @@ | ||
it("lets us delete data in all caches", function(done) { | ||
multiCache.set(key, value, ttl, function(err) { | ||
multiCache.set(key, value, function(err) { | ||
checkErr(err); | ||
@@ -171,3 +221,3 @@ | ||
it("lets us delete data without a callback", function(done) { | ||
multiCache.set(key, value, ttl, function(err) { | ||
multiCache.set(key, value, function(err) { | ||
checkErr(err); | ||
@@ -211,3 +261,3 @@ | ||
it("gets data from first cache that has it", function(done) { | ||
memoryCache3.set(key, value, ttl, function(err) { | ||
memoryCache3.set(key, value, function(err) { | ||
checkErr(err); | ||
@@ -268,3 +318,3 @@ | ||
it("checks to see if higher levels have item", function(done) { | ||
memoryCache3.set(key, value, ttl, function(err) { | ||
memoryCache3.set(key, value, function(err) { | ||
checkErr(err); | ||
@@ -292,5 +342,5 @@ | ||
beforeEach(function() { | ||
memoryStoreStub = memoryStore.create({ttl: ttl}); | ||
memoryStoreStub = memoryStore.create({ttl: defaultTtl}); | ||
sinon.stub(memoryStore, 'create').returns(memoryStoreStub); | ||
memoryCache = caching({store: 'memory', ttl: ttl}); | ||
memoryCache = caching({store: 'memory', ttl: defaultTtl}); | ||
multiCache = multiCaching([memoryCache]); | ||
@@ -331,9 +381,13 @@ fakeError = new Error(support.random.string()); | ||
/** | ||
* Note: it's up to the underlying cache implementation to handle the ttl number. | ||
* We're just testing that the ttl gets passed to the underlying store. | ||
*/ | ||
it('when a ttl number is passed in', function(done) { | ||
multiCache.wrap(key, function(cb) { | ||
methods.getWidget(name, cb); | ||
}, ttl, function(err, widget) { | ||
}, defaultTtl, function(err, widget) { | ||
checkErr(err); | ||
assert.deepEqual(widget, {name: name}); | ||
sinon.assert.calledWith(memoryCache3.store.set, key, {name: name}, ttl); | ||
sinon.assert.calledWith(memoryCache3.store.set, key, {name: name}, defaultTtl); | ||
done(); | ||
@@ -346,6 +400,6 @@ }); | ||
methods.getWidget(name, cb); | ||
}, {ttl: ttl}, function(err, widget) { | ||
}, {ttl: defaultTtl}, function(err, widget) { | ||
checkErr(err); | ||
assert.deepEqual(widget, {name: name}); | ||
sinon.assert.calledWith(memoryCache3.store.set, key, {name: name}, {ttl: ttl}); | ||
sinon.assert.calledWith(memoryCache3.store.set, key, {name: name}, {ttl: defaultTtl}); | ||
done(); | ||
@@ -355,3 +409,3 @@ }); | ||
it('when a ttl is not passed in', function(done) { | ||
it('when no options are passed in', function(done) { | ||
multiCache.wrap(key, function(cb) { | ||
@@ -371,5 +425,3 @@ methods.getWidget(name, cb); | ||
var fakeError = new Error(support.random.string()); | ||
sinon.stub(methods, 'getWidget', function(name, cb) { | ||
cb(fakeError, {name: name}); | ||
}); | ||
sinon.stub(methods, 'getWidget').yields(fakeError, {name: name}); | ||
@@ -386,2 +438,117 @@ multiCache.wrap(key, function(cb) { | ||
}); | ||
var falseyValues = [false, null, 0]; | ||
falseyValues.forEach(function(falseyValue) { | ||
context("when cached value is `" + falseyValue + "`", function() { | ||
function getFalseyValue(cb) { | ||
process.nextTick(function() { | ||
cb(null, falseyValue); | ||
}); | ||
} | ||
function getCachedFalseyValue(cb) { | ||
multiCache.wrap(key, function(cacheCb) { | ||
getFalseyValue(cacheCb); | ||
}, cb); | ||
} | ||
beforeEach(function(done) { | ||
multiCache = multiCaching([memoryCache3]); | ||
sinon.spy(memoryCache3.store, 'set'); | ||
getCachedFalseyValue(function(err, result) { | ||
checkErr(err); | ||
assert.strictEqual(result, falseyValue); | ||
memoryCache3.get(key, function(err, result) { | ||
checkErr(err); | ||
assert.strictEqual(result, falseyValue); | ||
sinon.spy(memoryCache3.store, 'get'); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
afterEach(function() { | ||
memoryCache3.store.set.restore(); | ||
memoryCache3.store.get.restore(); | ||
}); | ||
it("sets data in and retrieves data from cache", function(done) { | ||
getCachedFalseyValue(function(err, value) { | ||
checkErr(err); | ||
assert.strictEqual(value, falseyValue); | ||
assert.ok(memoryCache3.store.set.calledWith(key)); | ||
assert.ok(memoryCache3.store.get.calledWith(key)); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
context("when we pass in an isCacheableValue function to the caching constructor", function() { | ||
var testCallbacks = { | ||
isCacheableValue: function(value) { | ||
return value !== 'do_not_store_this' && value !== undefined; | ||
} | ||
}; | ||
function getValue(name, cb) { | ||
process.nextTick(function() { | ||
if (name === 'foo') { | ||
cb(null, 'store_this'); | ||
} else { | ||
cb(null, 'do_not_store_this'); | ||
} | ||
}); | ||
} | ||
function getCachedValue(name, cb) { | ||
multiCache.wrap(key, function(cacheCb) { | ||
getValue(name, function(err, result) { | ||
cacheCb(err, result); | ||
}); | ||
}, cb); | ||
} | ||
beforeEach(function() { | ||
sinon.spy(testCallbacks, 'isCacheableValue'); | ||
multiCache = multiCaching([memoryCache3], {isCacheableValue: testCallbacks.isCacheableValue}); | ||
sinon.spy(memoryCache3.store, 'set'); | ||
}); | ||
afterEach(function() { | ||
memoryCache3.store.set.restore(); | ||
testCallbacks.isCacheableValue.restore(); | ||
}); | ||
it("stores allowed values", function(done) { | ||
var name = 'foo'; | ||
getCachedValue(name, function(err) { | ||
checkErr(err); | ||
assert.ok(memoryCache3.store.set.called); | ||
assert.ok(testCallbacks.isCacheableValue.called); | ||
getCachedValue(name, function(err) { | ||
checkErr(err); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
it("does not store non-allowed values", function(done) { | ||
var name = 'bar'; | ||
getCachedValue(name, function(err) { | ||
checkErr(err); | ||
assert.ok(memoryCache3.store.set.notCalled); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
@@ -426,3 +593,3 @@ | ||
it("returns value from first store, does not set it in second", function(done) { | ||
memoryCache.set(key, {name: name}, ttl, function(err) { | ||
memoryCache.set(key, {name: name}, function(err) { | ||
checkErr(err); | ||
@@ -448,3 +615,3 @@ | ||
it("returns value from second store, sets it in first store", function(done) { | ||
memoryCache3.set(key, {name: name}, ttl, function(err) { | ||
memoryCache3.set(key, {name: name}, function(err) { | ||
checkErr(err); | ||
@@ -511,3 +678,3 @@ | ||
it("returns value from first store, does not set it in second or third", function(done) { | ||
memoryCache.set(key, {name: name}, ttl, function(err) { | ||
memoryCache.set(key, {name: name}, function(err) { | ||
checkErr(err); | ||
@@ -538,3 +705,3 @@ | ||
it("returns value from second store, sets it in first store, does not set third store", function(done) { | ||
memoryCache3.set(key, {name: name}, ttl, function(err) { | ||
memoryCache3.set(key, {name: name}, function(err) { | ||
checkErr(err); | ||
@@ -565,3 +732,3 @@ | ||
it("returns value from third store, sets it in first and second stores", function(done) { | ||
memoryCache2.set(key, {name: name}, ttl, function(err) { | ||
memoryCache2.set(key, {name: name}, function(err) { | ||
checkErr(err); | ||
@@ -653,5 +820,3 @@ | ||
sinon.stub(memoryStoreStub, 'get', function(key, cb) { | ||
cb(fakeError); | ||
}); | ||
sinon.stub(memoryStoreStub, 'get').yields(fakeError); | ||
@@ -672,5 +837,3 @@ multiCache.wrap(key, function(cb) { | ||
sinon.stub(memoryStoreStub, 'set', function(key, val, ttl, cb) { | ||
cb(fakeError); | ||
}); | ||
sinon.stub(memoryStoreStub, 'set').yields(fakeError); | ||
@@ -693,5 +856,16 @@ multiCache.wrap(key, function(cb) { | ||
multiCache = multiCaching([memoryCache, memoryCache3]); | ||
var firstTimeout = 110; | ||
var firstTimeoutUsed = false; | ||
function getTimeout() { | ||
if (firstTimeoutUsed) { | ||
support.random.number(100); | ||
} else { | ||
firstTimeoutUsed = true; | ||
return firstTimeout; | ||
} | ||
} | ||
construct = sinon.spy(function(val, cb) { | ||
var timeout = support.random.number(100); | ||
var timeout = getTimeout(); | ||
setTimeout(function() { | ||
@@ -698,0 +872,0 @@ cb(null, 'value'); |
@@ -93,5 +93,4 @@ var fs = require('fs'); | ||
var val = support.random.string(); | ||
var ttl; | ||
cache.set(key, val, ttl, function(err) { | ||
cache.set(key, val, function(err) { | ||
if (err) { return cb(err); } | ||
@@ -98,0 +97,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
111239
2362
1
271
3
8