diff --git a/lib/index.js b/lib/index.js index a34f30e..e43f054 100644 --- a/lib/index.js +++ b/lib/index.js @@ -6,7 +6,8 @@ var mongodb = require('mongodb') , Promise = require('./promise') - , noop = function () {}; + , noop = function () {} + , zlib = require('zlib'); /** * Export `MongoStore`. @@ -29,6 +30,7 @@ function MongoStore(options, bucket) { this.coll = options.collection || bucket._name || 'cacheman'; this.collection = null; this.connected = false; + this.compression = options.compression || false; var store = this , db = options.db || 'cache' @@ -82,6 +84,10 @@ MongoStore.prototype.get = function get(key, fn) { return fn(null, null); } try { + if(data.compressed){ + return decompressDataValue(data.value, fn); + } + fn(null, data.value); } catch (err) { fn(err); @@ -124,11 +130,13 @@ MongoStore.prototype.set = function set(key, val, ttl, fn) { fn(err); } - store.conn.then(function then(err, db){ - db.collection(store.coll).update(query, data, options, function update(err, data) { - if (err) return fn(err); - if (!data) return fn(null, null); - fn(null, val); + compressDataValue(store, data, function(err, data){ + store.conn.then(function then(err, db){ + db.collection(store.coll).update(query, data, options, function update(err, data) { + if (err) return fn(err); + if (!data) return fn(null, null); + fn(null, val); + }); }); }); }; @@ -170,3 +178,31 @@ MongoStore.prototype.clear = function clear(key, fn) { db.collection(store.coll).remove({}, { safe: true }, fn); }); }; + +/** + * Non-exported Helpers + */ + +var compressDataValue = function(opts, data, callback){ + // Compression option turned off + if(!opts.compression) return callback(null, data); + + // Data is not of a "compressable" type (currently only Buffer) + if(!Buffer.isBuffer(data.value)) return callback(null, data); + + zlib.gzip(data.value, function(err, compressedvalue){ + // If compression was successful, then use the compressed data. + // Otherwise, save the original data. + if(!err) { + data.value = compressedvalue; + data.compressed = true; + } + + callback(err, data); + }); +}; + +var decompressDataValue = function(value, callback){ + var v = (value.buffer && Buffer.isBuffer(value.buffer)) ? value.buffer : value; + zlib.gunzip(v, callback); +}; \ No newline at end of file diff --git a/test/large.bin b/test/large.bin new file mode 100644 index 0000000..37261a0 Binary files /dev/null and b/test/large.bin differ diff --git a/test/test.js b/test/test.js index 0840e0a..3202b1b 100644 --- a/test/test.js +++ b/test/test.js @@ -1,4 +1,6 @@ var assert = require('assert') + , fs = require('fs') + , crypto = require('crypto') , Cache = require('../') , cache; @@ -117,4 +119,57 @@ describe('cacheman-mongo', function () { }); }); +}); + +describe('cacheman-mongo compression', function () { + + before(function(done){ + cache = new Cache({ compression: true }, {}); + done(); + }); + + after(function(done){ + cache.clear('test'); + done(); + }); + + it('should store compressable item compressed', function (done) { + var value = Date.now().toString(); + + cache.set('test1', new Buffer(value), function (err) { + if (err) return done(err); + cache.get('test1', function (err, data) { + if (err) return done(err); + assert.equal(data.toString(), value); + done(); + }); + }); + }); + + it('should store non-compressable item normally', function (done) { + var value = Date.now().toString(); + + cache.set('test1', value, function (err) { + if (err) return done(err); + cache.get('test1', function (err, data) { + if (err) return done(err); + assert.equal(data, value); + done(); + }); + }); + }); + + it('should store large compressable item compressed', function (done) { + var value = fs.readFileSync('./test/large.bin'), // A file larger than the 16mb MongoDB document size limit + md5 = function(d){ return crypto.createHash('md5').update(d).digest('hex'); }; + + cache.set('test1', value, function (err) { + if (err) return done(err); + cache.get('test1', function (err, data) { + if (err) return done(err); + assert.equal(md5(data), md5(value)); + done(); + }); + }); + }); }); \ No newline at end of file