Source: nedb.js

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




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

    /** @method */
    objectStore: function(name, options) {
        return new NeStore(this, name, options);
    }

});

/** @class NeStore
    @extends BaseStore */
var NeStore = BaseBackend.BaseStore.extend(
/** @lends NeStore# */
{
    /** @method */
    initialize: function(backend, name, options) {
        options = _.extend({keyPath: 'id'}, options || {});
        BaseBackend.BaseStore.prototype.initialize.call(this, backend, name, options);
        var db = this._db = new Datastore(options);

        this._collection = Q.ninvoke(db, 'loadDatabase').then(function() {
            return db;
        });
    },

    /** @method */
    get: function(directives) {
        var search = {};
        search[this.keyPath] = this._getObjectKey({}, directives);
        return this.collection().then(function(collection) {
            return Q.ninvoke(collection, 'findOne', search);
        });
    },

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

        return this.collection().then(function(collection) {
            return Q.ninvoke(collection, 'insert', object)
                    .then(function(result) {
                        return result || object;
                    });
        });
    },

    /** @method */
    put: function(object, directives) {
        var key = this._getObjectKey(object, directives),
            selector = {};
        selector[this.keyPath] = key;
        return this.collection().then(function(collection) {
            return Q.ninvoke(collection, 'update', selector, object, {})
                    .then(function(result) {
                        return object;
                    });
        });
    },

    /** @method */
    'delete': function(directives) {
        var search = {};
        search[this.keyPath] = this._getObjectKey({}, directives);
        return this.collection().then(function(collection) {
            return Q.ninvoke(collection, 'remove', search);
        });
    },

    /** Execute RQL query */
    query: function(query) {
        var meta = {},
            search = {};
        if (query && !_.isEmpty(query)) {
            var x = this.parse(query);
            search = x.search;
            meta = x.meta;
        }

        return this.collection().then(function(collection) {
            return Q.ninvoke(collection, 'find', search||{}/*, meta||{}*/)
                    .then(function(result) {
                        // run through _.query to enable sorting which is not yet implemented in NeDB
                        // see https://github.com/louischatriot/nedb/issues/64
                        return _.query(result, query);
                    });
        });
    },

    /** Get native DB object */
    db: function() {
        return this.backend.open();
    },

    /** Get Collection object */
    collection: function() {
        return this._collection;
    },

    /** Delete all items */
    clear: function() {
        return this.collection().then(function(collection) {
            return Q.ninvoke(collection, 'remove', {}, {safe: true});
        });
    },

    /**
     * Parse RQL query
     * @function
     */
    parse: function(query) {
        return _.rql(query).toMongo();
    },

    _getObjectKey: function(obj, key) {
        if (typeof key === 'object') {
            key = key.key;
        }

        key =  key || obj[this.keyPath];

        var intKey = parseInt(key, 10);
        if (!isNaN(intKey) && intKey.toString() === key) {
            key = intKey;
        }

        return key;
    }
});

/** @module nedb */

NeBackend.NeStore = NeStore;
module.exports = NeBackend;