Source: fs.js

var fs = require('fs'),
    path = require('path'),
    Q = require('q'),
    _ = require('underscore-data'),
    BaseBackend = require('./base');

function resolvedPromise(val) {
    var d = Q.defer();
    d.resolve(val);
    return d.promise;
}

/** @class FsBackend
    @extends BaseBackend */
var FsBackend = BaseBackend.extend(
/** @lends FsBackend# */
{
    /** @method */
    initialize: function(options) {
        BaseBackend.prototype.initialize.call(this, options);
    },

    /** @method */
    objectStoreNames: function() {
        return Q.ninvoke(fs, 'readdir', this.options.path);
    },

    /** @method */
    objectStore: function(name, options) {
        name = path.basename(name);
        return new FsStore(this, name, options);
    },

    /** @method */
    createObjectStore: function(name, options) {
        var d = Q.defer();
        name = path.basename(name);
        fs.mkdir(path.join(this.options.path, name), function() {
            d.resolve(this.objectStore(name, options));
        }.bind(this));
        return d.promise;
    },

    /** @method */
    deleteObjectStore: function(name) {
        name = path.basename(name);
        this.objectStore(name).clear().then(function() {
            return Q.ninvoke(fs, 'rmdir', path.join(this.options.path, name));
        });
    },
    /** Encode object into string, by default uses JSON.stringify
        Override to use different serialization
        @method */
    encode: JSON.stringify,
    /** Decode string into object, by default uses JSON.parse
        Override to use different serialization
        @method */
    decode: JSON.parse
});



/** @class FsStore
    @extends BaseStore */
var FsStore = BaseBackend.BaseStore.extend(
/** @lends FsStore# */
{
    /** @method */
    initialize: function(backend, name, options) {
        BaseBackend.BaseStore.prototype.initialize.call(this, backend, name, options);
    },

    /** @method */
    get: function(directives) {
        var key = this._getObjectKey({}, directives);
        return Q.ninvoke(fs, 'readFile', this.filename(key), 'utf-8')
            .then(function(x) {
                return this.backend.decode(x);
            }.bind(this));
    },

    /** @method */
    add: function(object, directives) {
        var key = this._getObjectKey(object, directives);

        return Q.ninvoke(fs, 'writeFile', this.filename(key), this.backend.encode(object), {flag: 'wx'}).then(function() {
            return object;
        });
    },

    /** @method */
    put: function(object, directives) {
        var key = this._getObjectKey(object, directives);

        return Q.ninvoke(fs, 'writeFile', this.filename(key), this.backend.encode(object), {flag: 'w'}).then(function() {
            return object;
        });
    },

    /** @method */
    'delete': function(directives) {
        var key = this._getObjectKey({}, directives),
            d = Q.defer();

        Q.ninvoke(fs, 'unlink', this.filename(key))
            .then(function() {
                d.resolve(1);
            })
            .fail(function() {
                d.resolve(0);
            });

        return d.promise;
    },

    /** Execute RQL query */
    query: function(query) {
        var self = this;
        return Q.ninvoke(fs, 'readdir', path.join(this.backend.options.path, this.name))
            .then(function(files) {
                return Q.all(files.map(function(f) {
                    return self.get(f);
                }));
            })
            .then(function(vals) {
                return _.query(vals, query);
            });
    },

    /** Delete all items */
    clear: function() {
        var self = this;
        return Q.ninvoke(fs, 'readdir', path.join(this.backend.options.path, this.name))
            .then(function(files) {
                return Q.all(files.map(function(f) {
                    return self.delete(f);
                }));
            })
            .then(function() {
                return true;
            });
    },

    /** Get absolute filename for given key */
    filename: function(file) {
        return path.join(this.backend.options.path, this.name, ''+path.basename(file));
    } 
});

/** @module fs */

FsBackend.FsStore = FsStore;
module.exports = FsBackend;