diff --git a/.jscs.json b/.jscs.json index e9fdff3..84ebddd 100644 --- a/.jscs.json +++ b/.jscs.json @@ -2,6 +2,12 @@ "requireCurlyBraces": ["if", "else", "for", "while", "do", "try", "catch"], "requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try", "catch"], + "requireSpaceBeforeKeywords": [ + "else", + "while", + "catch" + ], + "requireSpaceBeforeBinaryOperators": ["?", "+", "/", "*", "=", "==", "===", "!=", "!==", ">", ">=", "<", "<="], "requireSpaceAfterBinaryOperators": ["?", "+", "/", "*", "=", "==", "===", "!=", "!==", ">", ">=", "<", "<="], "disallowSpaceAfterBinaryOperators": ["!"], diff --git a/History.md b/History.md index 1cf529b..01135fe 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,7 @@ +- 0.17.0 2015-02-05 + Add Additional Options Parameter (#20) - @seanzx85 + Fixing bug with nested calls to wrap() (#21) + - 0.16.0 2015-01-07 Get and pass up feature to update higher caches. (#19) - raadad Minor style tweaks/jscs update. diff --git a/examples/redis_example/example.js b/examples/redis_example/example.js index ee769c5..7de00bf 100644 --- a/examples/redis_example/example.js +++ b/examples/redis_example/example.js @@ -10,7 +10,8 @@ var redis_cache = cache_manager.caching({store: redis_store, db: 0, ttl: 100}); var ttl = 60; console.log("set/get/del example:"); -redis_cache.set('foo', 'bar', ttl, function(err) { + +redis_cache.set('foo', 'bar', {ttl: ttl}, function(err) { if (err) { throw err; } redis_cache.get('foo', function(err, result) { @@ -23,6 +24,34 @@ redis_cache.set('foo', 'bar', ttl, function(err) { }); }); +// TTL defaults to what we passed into the caching function (100) +redis_cache.set('foo-no-ttl', 'bar-no-ttl', function(err) { + if (err) { throw err; } + + redis_cache.get('foo-no-ttl', function(err, result) { + if (err) { throw err; } + console.log("result fetched from cache: " + result); + // >> 'bar' + redis_cache.del('foo-no-ttl', function(err) { + if (err) { throw err; } + }); + }); +}); + +// Calls Redis 'set' instead of 'setex' +redis_cache.set('foo-zero-ttl', 'bar-zero-ttl', {ttl: 0}, function(err) { + if (err) { throw err; } + + redis_cache.get('foo-zero-ttl', function(err, result) { + if (err) { throw err; } + console.log("result fetched from cache: " + result); + // >> 'bar' + redis_cache.del('foo-zero-ttl', function(err) { + if (err) { throw err; } + }); + }); +}); + var user_id = 123; function create_key(id) { @@ -40,7 +69,7 @@ function get_user_from_cache(id, cb) { var key = create_key(id); redis_cache.wrap(key, function(cache_cb) { get_user(user_id, cache_cb); - }, ttl, cb); + }, {ttl: ttl}, cb); } get_user_from_cache(user_id, function(err, user) { diff --git a/examples/redis_example/redis_store.js b/examples/redis_example/redis_store.js index 30c5822..e4b0bd6 100644 --- a/examples/redis_example/redis_store.js +++ b/examples/redis_example/redis_store.js @@ -34,7 +34,11 @@ function redis_store(args) { }); } - self.get = function(key, cb) { + self.get = function(key, options, cb) { + if (typeof options === 'function') { + cb = options; + } + connect(function(err, conn) { if (err) { return cb(err); } @@ -46,13 +50,20 @@ function redis_store(args) { }); }; - self.set = function(key, value, ttl, cb) { - var ttlToUse = ttl || ttlDefault; + self.set = function(key, value, options, cb) { + if (typeof options === 'function') { + cb = options; + options = {}; + } + options = options || {}; + + var ttl = (options.ttl || options.ttl === 0) ? options.ttl : ttlDefault; + connect(function(err, conn) { if (err) { return cb(err); } - if (ttlToUse) { - conn.setex(key, ttlToUse, JSON.stringify(value), function(err, result) { + if (ttl) { + conn.setex(key, ttl, JSON.stringify(value), function(err, result) { pool.release(conn); cb(err, result); }); diff --git a/lib/caching.js b/lib/caching.js index 1a145af..6cb1841 100644 --- a/lib/caching.js +++ b/lib/caching.js @@ -51,11 +51,13 @@ var caching = function(args) { self.queues[key] = [{cb: cb, domain: process.domain}]; function fillCallbacks(err, data) { - self.queues[key].forEach(function(task) { + var waiting = self.queues[key]; + delete self.queues[key]; + + waiting.forEach(function(task) { var taskDomain = task.domain || domain.create(); taskDomain.bind(task.cb)(err, data); }); - delete self.queues[key]; } self.store.get(key, options, function(err, result) { diff --git a/lib/multi_caching.js b/lib/multi_caching.js index 22d7b57..18bfe5e 100644 --- a/lib/multi_caching.js +++ b/lib/multi_caching.js @@ -34,7 +34,7 @@ var multi_caching = function(caches) { }; if (typeof options === 'object') { cache.store.get(key, options, callback); - }else { + } else { cache.store.get(key, callback); } }, cb); @@ -96,11 +96,13 @@ var multi_caching = function(caches) { self.queues[key] = [{cb: cb, domain: process.domain}]; function fillCallbacks(err, data) { - self.queues[key].forEach(function(task) { + var waiting = self.queues[key]; + delete self.queues[key]; + + waiting.forEach(function(task) { var taskDomain = task.domain || domain.create(); taskDomain.bind(task.cb)(err, data); }); - delete self.queues[key]; } get_from_highest_priority_cache(key, function(err, result, index) { @@ -181,7 +183,7 @@ var multi_caching = function(caches) { async.forEach(caches, function(cache, async_cb) { if (typeof options === 'object') { cache.store.del(key, options, async_cb); - }else { + } else { cache.store.del(key, async_cb); } }, cb); diff --git a/package.json b/package.json index 9b6b761..cc91086 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cache-manager", - "version": "0.16.0", + "version": "0.17.0", "description": "Cache module for Node.js", "main": "index.js", "scripts": { diff --git a/test/caching.unit.js b/test/caching.unit.js index 498545f..dc2d167 100644 --- a/test/caching.unit.js +++ b/test/caching.unit.js @@ -327,6 +327,30 @@ describe("caching", function() { }); }); + it("lets us make nested calls", function(done) { + function get_cached_widget(name, cb) { + cache.wrap(key, function(cache_cb) { + methods.get_widget(name, cache_cb); + }, cb); + } + + get_cached_widget(name, function(err, widget) { + check_err(err); + assert.equal(widget.name, name); + + get_cached_widget(name, function(err, widget) { + check_err(err); + assert.equal(widget.name, name); + + get_cached_widget(name, function(err, widget) { + check_err(err); + assert.equal(widget.name, name); + done(); + }); + }); + }); + }); + it("expires cached result after ttl seconds", function(done) { cache.wrap(key, function(cb) { methods.get_widget(name, cb); diff --git a/test/multi_caching.unit.js b/test/multi_caching.unit.js index 706c76e..3387ee9 100644 --- a/test/multi_caching.unit.js +++ b/test/multi_caching.unit.js @@ -519,6 +519,30 @@ describe("multi_caching", function() { }); }); }); + + it("lets us make nested calls", function(done) { + function get_cached_widget(name, cb) { + multi_cache.wrap(key, function(cache_cb) { + methods.get_widget(name, cache_cb); + }, cb); + } + + get_cached_widget(name, function(err, widget) { + check_err(err); + assert.equal(widget.name, name); + + get_cached_widget(name, function(err, widget) { + check_err(err); + assert.equal(widget.name, name); + + get_cached_widget(name, function(err, widget) { + check_err(err); + assert.equal(widget.name, name); + done(); + }); + }); + }); + }); }); context("error handling", function() { diff --git a/test/stores/options.unit.js b/test/stores/options.unit.js index aec6d1f..a201af2 100644 --- a/test/stores/options.unit.js +++ b/test/stores/options.unit.js @@ -85,17 +85,16 @@ var testStore = function(args) { }; describe("Methods with options", function() { + var testInstance = caching.caching({store: testStore()}); + var testCache; + before(function() { key = support.random.string(20); value = support.random.string(20); + testCache = caching.multi_caching([testInstance]); }); - describe("get with options", function() { - var testInstance = caching.caching({store: testStore()}); - var testCache; - before(function() { - testCache = caching.multi_caching([testInstance]); - }); + describe("get with options", function() { it("lets us pass options by value", function(done) { var options = {value: value}; testCache.get(key, options, function(err, response) { @@ -116,13 +115,9 @@ describe("Methods with options", function() { }); }); }); + 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}; @@ -143,13 +138,8 @@ describe("Methods with options", function() { 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]); - }); + describe("delete with options", function() { it("lets us pass options by value", function(done) { var options = {value: value}; testCache.del(key, options, function() { @@ -169,12 +159,14 @@ describe("Methods with options", function() { }); }); }); + 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); @@ -197,6 +189,7 @@ describe("Multiple stores with options", function() { }); }); }); + it("lets us not pass options which only one store uses", function() { testCache.set(key, value, ttl, function(err) { check_err(err);