19 changed files with 1005 additions and 243 deletions
@ -1 +1,2 @@ |
|||
node_module |
|||
node_modules |
|||
coverage |
|||
|
@ -0,0 +1,88 @@ |
|||
{ |
|||
// Settings |
|||
"passfail" : false, // Stop on first error. |
|||
"maxerr" : 500, // Maximum errors before stopping. |
|||
"multistr" : true, |
|||
|
|||
|
|||
// Predefined globals whom JSHint will ignore. |
|||
"browser" : true, // Standard browser globals e.g. `window`, `document`. |
|||
|
|||
"node" : false, |
|||
"rhino" : false, |
|||
"couch" : false, |
|||
"wsh" : true, // Windows Scripting Host. |
|||
|
|||
"jquery" : true, |
|||
"prototypejs" : false, |
|||
"mootools" : false, |
|||
"dojo" : false, |
|||
|
|||
"predef" : [ // Extra globals. |
|||
"__dirname", |
|||
"Buffer", |
|||
"event", |
|||
"exports", |
|||
"global", |
|||
"module", |
|||
"process", |
|||
"require", |
|||
"daisyjs", |
|||
"after", |
|||
"afterEach", |
|||
"before", |
|||
"beforeEach", |
|||
"context", |
|||
"describe", |
|||
"it" |
|||
], |
|||
|
|||
// Development. |
|||
"debug" : false, // Allow debugger statements e.g. browser breakpoints. |
|||
"devel" : true, // Allow development statements e.g. `console.log();`. |
|||
|
|||
|
|||
// EcmaScript 5. |
|||
"es5" : true, // Allow EcmaScript 5 syntax. |
|||
"strict" : false, // Require `use strict` pragma in every file. |
|||
"globalstrict" : false, // Allow global "use strict" (also enables 'strict'). |
|||
|
|||
|
|||
"asi" : false, // Tolerate Automatic Semicolon Insertion (no semicolons). |
|||
"laxbreak" : false, // Tolerate unsafe line breaks e.g. `return [\n] x` without semicolons. |
|||
"bitwise" : true, // Prohibit bitwise operators (&, |, ^, etc.). |
|||
"boss" : false, // Tolerate assignments inside if, for & while. Usually conditions & loops are for comparison, not assignments. |
|||
"curly" : true, // Require {} for every new block or scope. |
|||
"eqeqeq" : false, // Require triple equals i.e. `===`. |
|||
"eqnull" : false, // Tolerate use of `== null`. |
|||
"evil" : false, // Tolerate use of `eval`. |
|||
"expr" : false, // Tolerate `ExpressionStatement` as Programs. |
|||
"forin" : false, // Tolerate `for in` loops without `hasOwnProperty`. |
|||
"immed" : true, // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );` |
|||
"latedef" : true, // Prohibit variable use before definition. |
|||
"loopfunc" : true, // Allow functions to be defined within loops. |
|||
"maxparams" : 4, |
|||
"maxdepth" : 5, |
|||
"maxcomplexity" : 8, |
|||
"maxstatements" : 40, |
|||
"noarg" : true, // Prohibit use of `arguments.caller` and `arguments.callee`. |
|||
"regexp" : false, // Prohibit `.` and `[^...]` in regular expressions. |
|||
"regexdash" : false, // Tolerate unescaped last dash i.e. `[-...]`. |
|||
"scripturl" : true, // Tolerate script-targeted URLs. |
|||
"shadow" : false, // Allows re-define variables later in code e.g. `var x=1; x=2;`. |
|||
"supernew" : false, // Tolerate `new function () { ... };` and `new Object;`. |
|||
"undef" : true, // Require all non-global variables be declared before they are used. |
|||
|
|||
|
|||
"newcap" : false, // Require capitalization of all constructor functions e.g. `new F()`. |
|||
"noempty" : true, // Prohibit use of empty blocks. |
|||
"nonew" : false, // Prohibit use of constructors for side-effects. |
|||
"nomen" : false, // Prohibit use of initial or trailing underbars in names. |
|||
"onevar" : false, // Allow only one `var` statement per function. |
|||
"plusplus" : false, // Prohibit use of `++` & `--`. |
|||
"sub" : true, // Tolerate all forms of subscript notation besides dot notation e.g. `dict['key']` instead of `dict.key`. |
|||
"trailing" : true, // Prohibit trailing whitespaces. (only works if white is 'true') |
|||
"white" : true, // Check against strict whitespace and indentation rules. |
|||
"indent" : 4, |
|||
"unused" : true |
|||
} |
@ -0,0 +1,23 @@ |
|||
Copyrights for code authored by MOG Inc. is licensed under the following terms: |
|||
|
|||
MIT License |
|||
|
|||
Copyright (c) 2011 MOG Inc. All Rights Reserved. |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
of this software and associated documentation files (the "Software"), to |
|||
deal in the Software without restriction, including without limitation the |
|||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
|||
sell copies of the Software, and to permit persons to whom the Software is |
|||
furnished to do so, subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in |
|||
all copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|||
DEALINGS IN THE SOFTWARE. |
@ -0,0 +1,25 @@ |
|||
BASE = . |
|||
|
|||
ISTANBUL = ./node_modules/.bin/istanbul |
|||
COVERAGE_OPTS = --lines 99 --statements 95 --branches 90 --functions 95 |
|||
|
|||
main: lint test |
|||
|
|||
cover: |
|||
$(ISTANBUL) cover test/run.js |
|||
|
|||
check-coverage: |
|||
$(ISTANBUL) check-coverage $(COVERAGE_OPTS) |
|||
|
|||
test: cover check-coverage |
|||
|
|||
|
|||
test-cov: cover check-coverage |
|||
open coverage/lcov-report/index.html |
|||
|
|||
lint: |
|||
./node_modules/.bin/jshint ./lib --config $(BASE)/.jshintrc && \
|
|||
./node_modules/.bin/jshint ./test --config $(BASE)/.jshintrc |
|||
|
|||
|
|||
.PHONY: test |
@ -0,0 +1,146 @@ |
|||
node-cashew |
|||
====================== |
|||
|
|||
# Flexible NodeJS cache module |
|||
|
|||
A cache module for nodejs that allows easy wrapping of functions in cache, |
|||
tiered caches, and a consistent interface. |
|||
|
|||
## Features |
|||
|
|||
* Easy way to wrap any function in cache. |
|||
* Tiered caches -- data gets stored in each cache and fetched from the highest |
|||
priority cache(s) first. |
|||
* Use any cache you want, as long as it has the same API. |
|||
* 100% test coverage via [mocha](https://github.com/visionmedia/mocha), |
|||
[istanbul](https://github.com/yahoo/istanbul), and [sinon](http://sinonjs.org). |
|||
|
|||
|
|||
## Installation |
|||
|
|||
npm install node-cashew |
|||
|
|||
## Overview |
|||
|
|||
First, node-cashew features the standard functions you'd expect in most caches: |
|||
|
|||
set(key, val, cb) |
|||
get(key, cb) |
|||
del(key, cb) |
|||
|
|||
Second, 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).) |
|||
|
|||
Third, node-cashew lets you set up a tiered cache strategy. This may be of |
|||
limited use in most cases, but imagine a scenario where you expect tons of |
|||
traffic, and don't want to hit Redis for every request. You decide to store |
|||
the most commonly-requested data in an in-memory cache (like [node-lru-cache](https://github.com/isaacs/node-lru-cache)), |
|||
perhaps with a very short timeout and/or a small data size limit. But you |
|||
still want to store the data in Redis for backup, and for the requests that |
|||
aren't as common as the ones you want to store in memory. This is something |
|||
node-cashew handles easily and transparently. |
|||
|
|||
|
|||
## Usage Examples |
|||
|
|||
### Single Store |
|||
|
|||
var cashew = require('cashew'); |
|||
var redis_cache = cashew.caching({store: 'redis', db: 1, ttl: 100/*seconds*/}); |
|||
var memory_cache = cashew.caching({store: 'memory', max: 100, ttl: 10/*seconds*/}); |
|||
|
|||
redis_cache.set('foo', 'bar', function(err) { |
|||
if (err) { throw err; } |
|||
|
|||
redis_cache.get('foo', function(err, result) { |
|||
console.log(result); |
|||
// >> 'bar' |
|||
redis_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; |
|||
|
|||
redis_cache.wrap(key, function (cb) { |
|||
get_user(user_id, cb); |
|||
}, function (err, user) { |
|||
console.log(user); |
|||
|
|||
// Second time fetches user from redis_cache |
|||
redis_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' } |
|||
|
|||
|
|||
### Multi-Store |
|||
|
|||
var multi_cache = cashew.multi_caching([memory_cache, redis_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 Redis 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 |
|||
|
|||
To run tests, first run: |
|||
|
|||
npm install -d |
|||
|
|||
Run the tests and JShint: |
|||
|
|||
make |
|||
|
|||
|
|||
## Contribute |
|||
|
|||
If you would like to contribute to the project, please fork it and send us a pull request. Please add tests |
|||
for any new features or bug fixes. Also run ``make`` before submitting the pull request. |
|||
|
|||
|
|||
## License |
|||
|
|||
node-cashew is licensed under the MIT license. |
@ -0,0 +1,77 @@ |
|||
var cashew = require('cashew'); |
|||
var redis_cache = cashew.caching({store: 'redis', db: 1, ttl: 100/*seconds*/}); |
|||
var memory_cache = cashew.caching({store: 'memory', max: 100, ttl: 10/*seconds*/}); |
|||
|
|||
redis_cache.set('foo', 'bar', function(err) { |
|||
if (err) { throw err; } |
|||
|
|||
redis_cache.get('foo', function(err, result) { |
|||
console.log(result); |
|||
// >> 'bar'
|
|||
redis_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; |
|||
|
|||
redis_cache.wrap(key, function (cb) { |
|||
get_user(user_id, cb); |
|||
}, function (err, user) { |
|||
console.log(user); |
|||
|
|||
// Second time fetches user from redis_cache
|
|||
redis_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' }
|
|||
|
|||
|
|||
var multi_cache = cashew.multi_caching([memory_cache, redis_cache]); |
|||
user_id2 = 456; |
|||
key2 = 'user_' + user_id; |
|||
|
|||
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 Redis 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); |
|||
}); |
|||
|
|||
// 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', function(err) { |
|||
process.exit(); |
|||
}); |
|||
}); |
|||
}); |
|||
}); |
@ -0,0 +1,147 @@ |
|||
<h1>node-cashew</h1> |
|||
|
|||
<h1>Flexible NodeJS cache module</h1> |
|||
|
|||
<p>A cache module for nodejs that allows easy wrapping of functions in cache, |
|||
tiered caches, and a consistent interface.</p> |
|||
|
|||
<h2>Features</h2> |
|||
|
|||
<ul> |
|||
<li>Easy way to wrap any function in cache.</li> |
|||
<li>Tiered caches -- data gets stored in each cache and fetched from the highest |
|||
priority cache(s) first.</li> |
|||
<li>Use any cache you want, as long as it has the same API.</li> |
|||
<li>100% test coverage via <a href="https://github.com/visionmedia/mocha">mocha</a>, |
|||
<a href="https://github.com/yahoo/istanbul">istanbul</a>, and <a href="http://sinonjs.org">sinon</a>.</li> |
|||
</ul> |
|||
|
|||
<h2>Installation</h2> |
|||
|
|||
<pre><code>npm install node-cashew |
|||
</code></pre> |
|||
|
|||
<h2>Overview</h2> |
|||
|
|||
<p>First, node-cashew features the standard functions you'd expect in most caches:</p> |
|||
|
|||
<pre><code>set(key, val, cb) |
|||
get(key, cb) |
|||
del(key, cb) |
|||
</code></pre> |
|||
|
|||
<p>Second, it includes a <code>wrap</code> function that lets you wrap any function in cache. |
|||
(Note, this was inspired by <a href="https://github.com/mape/node-caching">node-caching</a>.)</p> |
|||
|
|||
<p>Third, node-cashew lets you set up a tiered cache strategy. This may be of |
|||
limited use in most cases, but imagine a scenario where you expect tons of |
|||
traffic, and don't want to hit Redis for every request. You decide to store |
|||
the most commonly-requested data in an in-memory cache (like <a href="https://github.com/isaacs/node-lru-cache">node-lru-cache</a>), |
|||
perhaps with a very short timeout and/or a small data size limit. But you |
|||
still want to store the data in Redis for backup, and for the requests that |
|||
aren't as common as the ones you want to store in memory. This is something |
|||
node-cashew handles easily and transparently.</p> |
|||
|
|||
<h2>Usage Examples</h2> |
|||
|
|||
<h3>Single Store</h3> |
|||
|
|||
<pre><code> var cashew = require('cashew'); |
|||
var redis_cache = cashew.caching({store: 'redis', db: 1, ttl: 100/*seconds*/}); |
|||
var memory_cache = cashew.caching({store: 'memory', max: 100, ttl: 10/*seconds*/}); |
|||
|
|||
redis_cache.set('foo', 'bar', function(err) { |
|||
if (err) { throw err; } |
|||
|
|||
redis_cache.get('foo', function(err, result) { |
|||
console.log(result); |
|||
// >> 'bar' |
|||
redis_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; |
|||
|
|||
redis_cache.wrap(key, function (cb) { |
|||
get_user(user_id, cb); |
|||
}, function (err, user) { |
|||
console.log(user); |
|||
|
|||
// Second time fetches user from redis_cache |
|||
redis_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' } |
|||
</code></pre> |
|||
|
|||
<h3>Multi-Store</h3> |
|||
|
|||
<pre><code> var multi_cache = cashew.multi_caching([memory_cache, redis_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 Redis 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); |
|||
}); |
|||
}); |
|||
</code></pre> |
|||
|
|||
<h2>Tests</h2> |
|||
|
|||
<p>To run tests, first run:</p> |
|||
|
|||
<pre><code>npm install -d |
|||
</code></pre> |
|||
|
|||
<p>Run the tests and JShint:</p> |
|||
|
|||
<pre><code>make |
|||
</code></pre> |
|||
|
|||
<h2>Contribute</h2> |
|||
|
|||
<p>If you would like to contribute to the project, please fork it and send us a pull request. Please add tests |
|||
for any new features or bug fixes. Also run <code>make</code> before submitting the pull request.</p> |
|||
|
|||
<h2>License</h2> |
|||
|
|||
<p>node-easy-mysql is licensed under the MIT license.</p> |
@ -0,0 +1,73 @@ |
|||
#!/usr/bin/env node
|
|||
process.env.NODE_ENV = 'test'; |
|||
require('../index'); |
|||
|
|||
var Mocha = require('mocha'); |
|||
var optimist = require('optimist'); |
|||
var walk_dir = require('./support').walk_dir; |
|||
|
|||
var argv = optimist |
|||
.usage("Usage: $0 -t [types] --reporter [reporter] --timeout [timeout]") |
|||
.default({types: 'unit,functional', reporter: 'spec', timeout: 6000}) |
|||
.describe('types', 'The types of tests to run, separated by commas. E.g., unit,functional,acceptance') |
|||
.describe('reporter', 'The mocha test reporter to use.') |
|||
.describe('timeout', 'The mocha timeout to use per test (ms).') |
|||
.boolean('help') |
|||
.alias('types', 'T') |
|||
.alias('timeout', 't') |
|||
.alias('reporter', 'R') |
|||
.alias('help', 'h') |
|||
.argv; |
|||
|
|||
var mocha = new Mocha({timeout: argv.timeout, reporter: argv.reporter, ui: 'bdd'}); |
|||
|
|||
var valid_test_types = ['unit', 'functional', 'acceptance', 'integration']; |
|||
var requested_types = argv.types.split(','); |
|||
var types_to_use = []; |
|||
|
|||
valid_test_types.forEach(function (valid_test_type) { |
|||
if (requested_types.indexOf(valid_test_type) !== -1) { |
|||
types_to_use.push(valid_test_type); |
|||
} |
|||
}); |
|||
|
|||
if (argv.help || types_to_use.length === 0) { |
|||
console.log('\n' + optimist.help()); |
|||
process.exit(); |
|||
} |
|||
|
|||
var is_valid_file = function (file) { |
|||
if (file.match(/buster/)) { |
|||
return false; |
|||
} |
|||
|
|||
for (var i = 0; i < types_to_use.length; i++) { |
|||
var test_type = types_to_use[i]; |
|||
var ext = test_type + ".js"; |
|||
|
|||
if (file.indexOf(ext) !== -1) { |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
}; |
|||
|
|||
function run(cb) { |
|||
walk_dir('test', is_valid_file, function (err, files) { |
|||
if (err) { return cb(err); } |
|||
|
|||
files.forEach(function (file) { |
|||
mocha.addFile(file); |
|||
}); |
|||
|
|||
cb(); |
|||
}); |
|||
} |
|||
|
|||
run(function (err) { |
|||
if (err) { throw err; } |
|||
mocha.run(function (failures) { |
|||
process.exit(failures); |
|||
}); |
|||
}); |
@ -0,0 +1,11 @@ |
|||
var support = require('../support'); |
|||
var memory_store = require('../../lib/stores/memory'); |
|||
|
|||
describe("memory store", function () { |
|||
describe("instantiating", function () { |
|||
it("lets us pass in no args", function (done) { |
|||
var memory_cache = memory_store.create(); |
|||
support.test_set_get_del(memory_cache, done); |
|||
}); |
|||
}); |
|||
}); |
@ -0,0 +1,18 @@ |
|||
var support = require('../support'); |
|||
var redis_store = require('../../lib/stores/redis'); |
|||
|
|||
describe("redis store", function () { |
|||
describe("instantiating", function () { |
|||
it("lets us pass in a db arg", function (done) { |
|||
// Not sure how to prove that it uses the specified db in this test,
|
|||
// but it does.
|
|||
var redis_cache = redis_store.create({db: 2}); |
|||
support.test_set_get_del(redis_cache, done); |
|||
}); |
|||
|
|||
it("lets us pass in no args", function (done) { |
|||
var redis_cache = redis_store.create(); |
|||
support.test_set_get_del(redis_cache, done); |
|||
}); |
|||
}); |
|||
}); |
Loading…
Reference in new issue