Skip to content

Commit

Permalink
REF: flat-cache v.1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Roy Riojas committed Feb 26, 2015
1 parent d43cccf commit c984274
Show file tree
Hide file tree
Showing 8 changed files with 414 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@ node_modules

# Users Environment Variables
.lock-wscript

test/fixtures/
4 changes: 4 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
language: node_js
node_js:
- 0.12
- 0.10.33
22 changes: 22 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
The MIT License (MIT)

Copyright (c) 2015 Roy Riojas

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.

58 changes: 57 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,58 @@
# flat-cache
A stupidly simple key/value storage using files to persist the data
> A stupidly simple key/value storage using files to persist the data
[![NPM Version](http://img.shields.io/npm/v/flat-cache.svg?style=flat)](https://npmjs.org/package/flat-cache)
[![Build Status](http://img.shields.io/travis/royriojas/flat-cache.svg?style=flat)](https://travis-ci.org/royriojas/flat-cache)

## install

```bash
npm i --save flat-cache
```

## Usage

```js
// loads the cache, if one does not exists for the given
// Id a new one will be prepared to be created
var cache = require('flat-cache').load('cacheId');

// sets a key on the cache
cache.setKey('key', { foo: 'var' });

// get a key from the cache
cache.getKey('key') // { foo: 'var' }

// remove a key
cache.removeKey('key'); // removes a key from the cache

// save it to disk
cache.save(); // very important, if you don't save no changes will be persisted.

// loads the cache from a given directory, if one does
// not exists for the given Id a new one will be prepared to be created
var cache = require('flat-cache').load('cacheId', path.resolve('./path/to/folder'));
```

## Motivation for this module

I needed a super simple and dumb in memory cache with optional disk persistance in order to make
a script that formatted files with `esformatter` only execute on the files that were changed since the last run.
To make that possible we need to store the `fileSize` and `modificationTime` of the files. So a simple `key/value`
storage was needed and Bam! this module was born.

## Important notes

- when `cache.save` is called the values are persisted to disk, if you're committing your `node_modules` to any vcs, you
might want to ignore the default `.cache` folder, or specify a custom directory.
- The values set on the keys of the cache should be `stringify-able` ones, meaning no circular references
- All the changes to the cache state are done to memory
- I could have use a timer or `Object.observe` to deliver the changes to disk, but I wanted to keep this module
to be intentionally dumb and simple
- If no directory

## License

MIT


113 changes: 113 additions & 0 deletions cache.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
var path = require( 'path' );
var fs = require( 'graceful-fs' );
var readJSON = require( 'read-json-sync' );
var write = require( 'write' );

var cache = {
/**
* Load a cache identified by the given Id. If the element does not exists, then initialize an empty
* cache storage. If specified `cacheDir` will be used as the directory to persist the data to. If omitted
* then the cache module directory `./cache` will be used instead
*
* @method load
* @param docId {String} the id of the cache, would also be used as the name of the file cache
* @param [cacheDir] {String} directory for the cache entry
*/
load: function ( docId, cacheDir ) {
var me = this;

me._visited = {};
me._persisted = {};
me._pathToFile = cacheDir ? path.resolve(cacheDir, docId) : path.resolve( __dirname, './.cache/', docId );

if ( fs.existsSync( me._pathToFile ) ) {
this._persisted = readJSON( me._pathToFile );
}
},
keys: function () {
return Object.keys(this._persisted);
},
/**
* sets a key to a given value
* @method setKey
* @param key {string} the key to set
* @param value {object} the value of the key. Could be any object that can be serialized with JSON.stringify
*/
setKey: function ( key, value ) {
this._visited[ key ] = true;
this._persisted[ key ] = value;
},
/**
* remove a given key from the cache
* @method removeKey
* @param key {String} the key to remove from the object
*/
removeKey: function ( key ) {
delete this._visited[ key ];
delete this._persisted[ key ];
},
/**
* Return the value of the provided key
* @method getKey
* @param key {String} the name of the key to retrieve
* @returns {*} the value from the key
*/
getKey: function ( key ) {
this._visited[ key ] = true;
return this._persisted[ key ];
},

/**
* Remove keys that were not accessed/set since the
* last time the `prune` method was called.
* @method _prune
* @private
*/
_prune: function () {
var me = this;
var obj = {};

var keys = Object.keys( me._visited );

// no keys visited for either get or set value
if ( keys.length === 0 ) {
return;
}

keys.forEach( function ( key ) {
obj[ key ] = me._persisted[ key ];
} );

me._visited = {};
me._persisted = obj;
},

/**
* Save the state of the cache identified by the docId to disk
* as a JSON structure
* @method save
*/
save: function () {
var me = this;

me._prune();
write.sync( me._pathToFile, JSON.stringify( me._persisted) );
}
};

module.exports = {
/**
* Load a cache identified by the given Id. If the element does not exists, then initialize an empty
* cache storage.
*
* @method load
* @param docId {String} the id of the cache, would also be used as the name of the file cache
* @param [cacheDir] {String} directory for the cache entry
* @returns {cache} cache instance
*/
load: function ( docId, cacheDir ) {
var obj = Object.create( cache );
obj.load( docId, cacheDir );
return obj;
}
};
47 changes: 47 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"name": "flat-cache",
"version": "1.0.0",
"description": "A stupidly simple key/value storage using files to persist the data",
"repository": "royriojas/flat-cache",
"license": "MIT",
"author": {
"name": "Roy Riojas",
"url": "http://royriojas.com"
},
"main": "cache.js",
"files": [
"cache.js"
],
"engines": {
"node": ">=0.10.0"
},
"scripts": {
"test": "mocha -R spec test/specs",
"cover": "istanbul cover test/runner.js html text-summary",
"watch": "watch-run -i -p 'test/specs/**/*.js' istanbul cover test/runner.js html text-summary"
},
"keywords": [
"json cache",
"simple cache",
"file cache",
"key par",
"key value",
"cache"
],
"devDependencies": {
"chai": "^2.1.0",
"del": "^1.1.1",
"glob-expand": "0.0.2",
"istanbul": "^0.3.6",
"mocha": "^2.1.0",
"proxyquire": "^1.3.1",
"sinon": "^1.12.2",
"sinon-chai": "^2.7.0",
"watch-run": "^1.2.1"
},
"dependencies": {
"graceful-fs": "^3.0.5",
"read-json-sync": "^1.1.0",
"write": "^0.1.1"
}
}
44 changes: 44 additions & 0 deletions test/runner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"use strict";

// we run mocha manually otherwise istanbul coverage won't work
// run `npm test --coverage` to generate coverage report

var Mocha = require('mocha');


// ---



// to set these options run the test script like:
// > BAIL=true GREP=array_expression REPORTER=dot npm test
var opts = {
ui: 'bdd',
bail: !!(process.env.BAIL),
reporter:( process.env.REPORTER || 'spec'),
grep: process.env.GREP,
colors: true
};

// we use the dot reporter on travis since it works better
if (process.env.TRAVIS) {
opts.reporter = 'dot';
}

var m = new Mocha(opts);

if (process.env.INVERT) {
m.invert();
}

var expand = require('glob-expand');
expand('test/specs/**/*.js').forEach(function (file){
m.addFile(file);
});

m.run(function(err) {
var exitCode = err ? 1 : 0;
if (err) console.log('failed tests: ' + err);
process.exit(exitCode);
});

Loading

0 comments on commit c984274

Please sign in to comment.