Skip to content

Commit

Permalink
Merge pull request #1 from slaskis/master
Browse files Browse the repository at this point in the history
Added pattern matching to #remove() and tests.
  • Loading branch information
mape committed Sep 6, 2011
2 parents 2755e3e + 85f17d2 commit fbd3e8e
Show file tree
Hide file tree
Showing 5 changed files with 367 additions and 84 deletions.
90 changes: 18 additions & 72 deletions lib/caching.js
Original file line number Diff line number Diff line change
@@ -1,86 +1,32 @@
var MemoryStore = function() {
var cache = {};
return {
'get': function(key,callback) {
callback(null, cache[key] || null);
}
, 'set': function(key, ttl, result) {
cache[key] = result;
if (ttl) {
setTimeout(function() {
delete cache[key];
}, ttl);
}
}
, 'remove': function(key) {
delete cache[key];
}
};
};
var RedisStore = function() {
var redis = require('redis');
var redisClient = redis.createClient();
return {
'get': function(key,callback) {
redisClient.get(key, function(err, result) {
callback(err, JSON.parse(result));
});
}
, 'set': function(key, ttl, result) {
if (ttl) {
redisClient.SETEX(key, Math.ceil(ttl/1000), JSON.stringify(result));
} else {
redisClient.set(key, JSON.stringify(result));
}
}
, 'remove': function(key) {
redisClient.DEL(key);
}
};
};

module.exports = Caching = function Caching(store) {
if (!store) {
store = new MemoryStore;
} else if (typeof store === 'string') {
switch(store.toLowerCase().trim()) {
case 'memory':
store = new MemoryStore;
break;
case 'redis':
store = new RedisStore;
break;
case 'memcache':
store = new MemcacheStore;
break;
default:
throw new Error('No built in store named "'+store+'".');
return;
}
}
module.exports = function Caching(store) {
store = store || 'memory';

if( typeof store == 'string' )
store = require('./stores/'+store.toLowerCase().trim())(arguments[1]);

var queues = {};

var cacher = function(key, ttl, workCallback, callback) {
store.get(key, function(err, storageData) {
if (!err && storageData) {
callback.apply(null, storageData);
} else if (queues[key]) {
queues[key].push(callback);
var cacher = function(key, ttl, work, done){
store.get(key, function(err, args){
if( !err && args ){
done.apply(null, args);
} else if (queues[key]){
queues[key].push(done);
} else {
queues[key] = [callback];
workCallback(function() {
queues[key] = [done];
work(function(){
var args = Array.prototype.slice.call(arguments, 0);
store.set(key, ttl, args);
queues[key].forEach(function(queuedCallback) {
queuedCallback.apply(null, args);
store.set(key, ttl, args);
queues[key].forEach(function(done){
done.apply(null, args);
});
delete queues[key];
});
}
});
};
cacher.remove = store.remove;
cacher.remove = store.remove.bind(store);
cacher.store = store;

return cacher;
};
38 changes: 38 additions & 0 deletions lib/stores/memory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
function MemoryStore() {
if( !(this instanceof MemoryStore) )
return new MemoryStore;

this.cache = {};
}

MemoryStore.prototype.get = function(key,callback){
var self = this;
process.nextTick(function(){
callback(null, self.cache[key] || null);
})
}

MemoryStore.prototype.set = function(key,ttl,result){
this.cache[key] = result;
if( ttl ){
var self = this;
setTimeout(function(){
delete self.cache[key];
}, ttl)
}
}

MemoryStore.prototype.remove = function(pattern){
if( ~pattern.indexOf("*") ){
var self = this;
pattern = new RegExp(pattern.replace(/\*/g,".*"),"g")
Object.keys(this.cache).forEach(function(key){
if( pattern.test(key) )
delete self.cache[key];
})
} else {
delete this.cache[pattern];
}
}

module.exports = MemoryStore;
35 changes: 35 additions & 0 deletions lib/stores/redis.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
function RedisStore(opts){
if( !(this instanceof RedisStore) )
return new RedisStore(opts);

opts = opts || {}
this.client = require('redis').createClient(opts.port,opts.host,opts);
}

RedisStore.prototype.get = function(key,callback){
this.client.get(key, function(err, result) {
callback(err, JSON.parse(result));
});
}

RedisStore.prototype.set = function(key,ttl,result){
if (ttl) {
this.client.setex(key, Math.ceil(ttl/1000), JSON.stringify(result));
} else {
this.client.set(key, JSON.stringify(result));
}
}

RedisStore.prototype.remove = function(pattern){
if( ~pattern.indexOf("*") ){
var self = this;
this.client.keys(pattern,function(err,keys){
if( keys.length )
self.client.del(keys);
})
} else {
this.client.del(pattern);
}
}

module.exports = RedisStore;
37 changes: 25 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
{
"name" : "caching",
"description" : "Easier caching in node.js",
"version" : "0.0.2",
"author" : "Mathias Pettersson <mape@mape.me>",
"engines" : ["node"],
"directories" : { "lib" : "./lib" },
"main" : "./lib/caching",
"repositories" : [
{ "type":"git", "url":"http://github.com/mape/node-caching" }
"name": "caching",
"description": "Easier caching in node.js",
"version": "0.1.2",
"author": "Mathias Pettersson <mape@mape.me>",
"engines": [
"node"
],
"dependencies" : {
"directories": {
"lib": "./lib"
},
"main": "./lib/caching",
"repositories": [
{
"type": "git",
"url": "http://github.com/mape/node-caching"
}
],
"dependencies": {
"hiredis" : ">=0.1.12",
"redis" : ">=0.6.7"
"redis": ">=0.6.7"
},
"devDependencies": {
"expresso": "~0.8.1"
},
"scripts": {
"test": "expresso"
}
}
}
Loading

0 comments on commit fbd3e8e

Please sign in to comment.