diff --git a/README.md b/README.md index 47b8042..b754a50 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,44 @@ priority cache(s) first. First, it includes a `wrap` function that lets you wrap any function in cache. (Note, this was inspired by [node-caching](https://github.com/mape/node-caching).) +This is probably the feature you're looking for. As an example, where you might have to do this + +```javascript +function get_cached_user(id, cb) { + memory_cache.get(id, function (err, result) { + if (err) { return cb(err); } + + if (result) { + return cb(null, result); + } + + get_user(id, function (err, result) { + if (err) { return cb(err); } + memory_cache.set(id, result); + cb(null, result); + }); + }); +} +``` +... you can instead use the `wrap` function: + +```javascript +function get_cached_user(id, cb) { + memory_cache.wrap(id, function (cache_callback) { + get_user(id, cache_callback); + }, cb); +} + +get_cached_user(user_id, function (err, user) { + // First time fetches the user from the (fake) database: + console.log(user); + + get_cached_user(user_id, function (err, user) { + // Second time fetches from cache. + console.log(user); + }); +}); +``` Second, node-cache-manager features a built-in memory cache (using [node-lru-cache](https://github.com/isaacs/node-lru-cache)), with the standard functions you'd expect in most caches: @@ -53,49 +91,69 @@ Redis cache store with connection pooling. ### Single Store ```javascript - var cache_manager = require('cache-manager'); - var memory_cache = cache_manager.caching({store: 'memory', max: 100, ttl: 10/*seconds*/}); - - // Note: callback is optional in set() and del(). - - memory_cache.set('foo', 'bar', function(err) { - if (err) { throw err; } - - memory_cache.get('foo', function(err, result) { - console.log(result); - // >> 'bar' - memory_cache.del('foo', function(err) {}); - }); - }); - - function get_user(id, cb) { - setTimeout(function () { - console.log("Returning user from slow database."); - cb(null, {id: id, name: 'Bob'}); - }, 100); - } - - var user_id = 123; - var key = 'user_' + user_id; - - memory_cache.wrap(key, function (cb) { - get_user(user_id, cb); - }, function (err, user) { - console.log(user); - - // Second time fetches user from memory_cache - memory_cache.wrap(key, function (cb) { - get_user(user_id, cb); - }, function (err, user) { - console.log(user); - }); - }); +var cache_manager = require('cache-manager'); +var memory_cache = cache_manager.caching({store: 'memory', max: 100, ttl: 10/*seconds*/}); + +// Note: callback is optional in set() and del(). + +memory_cache.set('foo', 'bar', function(err) { + if (err) { throw err; } + + memory_cache.get('foo', function(err, result) { + console.log(result); + // >> 'bar' + memory_cache.del('foo', function(err) {}); + }); +}); + +function get_user(id, cb) { + setTimeout(function () { + console.log("Returning user from slow database."); + cb(null, {id: id, name: 'Bob'}); + }, 100); +} + +var user_id = 123; +var key = 'user_' + user_id; + +memory_cache.wrap(key, function (cb) { + get_user(user_id, cb); +}, function (err, user) { + console.log(user); + + // Second time fetches user from memory_cache + memory_cache.wrap(key, function (cb) { + get_user(user_id, cb); + }, function (err, user) { + console.log(user); + }); +}); + +// Outputs: +// Returning user from slow database. +// { id: 123, name: 'Bob' } +// { id: 123, name: 'Bob' } +``` - // Outputs: - // Returning user from slow database. - // { id: 123, name: 'Bob' } - // { id: 123, name: 'Bob' } +Here's a very basic example of how you could use this in an Express app: +```javascript +function respond(res, err, data) { + if (err) { + res.json(500, err); + } else { + res.json(200, data); + } +} + +app.get('/foo/bar', function(req, res) { + var cache_key = 'foo-bar:' + JSON.stringify(req.query); + memory_cache.wrap(cache_key, function(cache_cb) { + DB.find(req.query, cache_cb); + }, function(err, result) { + respond(res, err, result); + }); +}); ``` #### Custom Stores @@ -107,47 +165,47 @@ in an instance of it, or pass in the path to the module. E.g., ```javascript - var my_store = require('your-homemade-store'); - var cache = cache_manager.caching({store: my_store}); - // or - var cache = cache_manager.caching({store: '/path/to/your/store'}); +var my_store = require('your-homemade-store'); +var cache = cache_manager.caching({store: my_store}); +// or +var cache = cache_manager.caching({store: '/path/to/your/store'}); ``` ### Multi-Store ```javascript - var multi_cache = cache_manager.multi_caching([memory_cache, some_other_cache]); - user_id2 = 456; - key2 = 'user_' + user_id; - - // Sets in all caches. - multi_cache.set('foo2', 'bar2', function(err) { - if (err) { throw err; } - - // Fetches from highest priority cache that has the key. - multi_cache.get('foo2', function(err, result) { - console.log(result); - // >> 'bar2' - - // Delete from all caches - multi_cache.del('foo2'); - }); - }); - - multi_cache.wrap(key2, function (cb) { - get_user(user_id2, cb); - }, function (err, user) { - console.log(user); - - // Second time fetches user from memory_cache, since it's highest priority. - // If the data expires in the memory cache, the next fetch would pull it from - // the 'some_other_cache', and set the data in memory again. - multi_cache.wrap(key2, function (cb) { - get_user(user_id2, cb); - }, function (err, user) { - console.log(user); - }); - }); +var multi_cache = cache_manager.multi_caching([memory_cache, some_other_cache]); +user_id2 = 456; +key2 = 'user_' + user_id; + +// Sets in all caches. +multi_cache.set('foo2', 'bar2', function(err) { + if (err) { throw err; } + + // Fetches from highest priority cache that has the key. + multi_cache.get('foo2', function(err, result) { + console.log(result); + // >> 'bar2' + + // Delete from all caches + multi_cache.del('foo2'); + }); +}); + +multi_cache.wrap(key2, function (cb) { + get_user(user_id2, cb); +}, function (err, user) { + console.log(user); + + // Second time fetches user from memory_cache, since it's highest priority. + // If the data expires in the memory cache, the next fetch would pull it from + // the 'some_other_cache', and set the data in memory again. + multi_cache.wrap(key2, function (cb) { + get_user(user_id2, cb); + }, function (err, user) { + console.log(user); + }); +}); ``` ## Tests diff --git a/examples/example.js b/examples/example.js index 1d9fd58..1ab3d28 100644 --- a/examples/example.js +++ b/examples/example.js @@ -1,3 +1,4 @@ +/*jshint unused:false*/ var cache_manager = require('../'); var memory_cache = cache_manager.caching({store: 'memory', max: 100, ttl: 10/*seconds*/}); var memory_cache2 = cache_manager.caching({store: 'memory', max: 100, ttl: 100/*seconds*/}); @@ -5,19 +6,23 @@ var memory_cache2 = cache_manager.caching({store: 'memory', max: 100, ttl: 100/* // // Basic usage // -memory_cache2.set('foo', 'bar', function (err) { +memory_cache.set('foo', 'bar', function (err) { if (err) { throw err; } - memory_cache2.get('foo', function (err, result) { + memory_cache.get('foo', function (err, result) { console.log(result); // >> 'bar' - memory_cache2.del('foo', function (err) { console.log(err); }); + memory_cache.del('foo', function (err) { + if (err) { + console.log(err); + } + }); }); }); function get_user(id, cb) { setTimeout(function () { - console.log("Returning user from slow database."); + console.log("Fetching user from slow database."); cb(null, {id: id, name: 'Bob'}); }, 100); } @@ -28,15 +33,37 @@ var key = 'user_' + user_id; // // wrap() example // -memory_cache2.wrap(key, function (cb) { - get_user(user_id, cb); -}, function (err, user) { + +// Instead of manually managing the cache like this: +function get_cached_user_manually(id, cb) { + memory_cache.get(id, function (err, result) { + if (err) { return cb(err); } + + if (result) { + return cb(null, result); + } + + get_user(id, function (err, result) { + if (err) { return cb(err); } + memory_cache.set(id, result); + cb(null, result); + }); + }); +} + +// ... you can instead use the `wrap` function: +function get_cached_user(id, cb) { + memory_cache.wrap(id, function (cache_callback) { + get_user(id, cache_callback); + }, cb); +} + +get_cached_user(user_id, function (err, user) { + // First time fetches the user from the (fake) database: console.log(user); - // Second time fetches user from memory_cache2 - memory_cache2.wrap(key, function (cb) { - get_user(user_id, cb); - }, function (err, user) { + get_cached_user(user_id, function (err, user) { + // Second time fetches from cache. console.log(user); }); }); @@ -47,6 +74,23 @@ memory_cache2.wrap(key, function (cb) { // { id: 123, name: 'Bob' } +// Same as above, but written differently: +memory_cache.wrap(key, function (cb) { + get_user(user_id, cb); +}, function (err, user) { + console.log(user); + + // Second time fetches user from memory_cache + memory_cache.wrap(key, function (cb) { + get_user(user_id, cb); + }, function (err, user) { + console.log(user); + }); +}); + +// +// multi-cache example +// var multi_cache = cache_manager.multi_caching([memory_cache, memory_cache2]); var user_id2 = 456; var key2 = 'user_' + user_id; @@ -76,7 +120,9 @@ multi_cache.wrap(key2, function (cb) { // Delete from all caches multi_cache.del('foo2', function (err) { - console.log(err); + if (err) { + console.log(err); + } process.exit(); }); });