Skip to content

Commit

Permalink
Adding persistent storage adapter supporting, incluiding mongo adapter
Browse files Browse the repository at this point in the history
Typo

Building..

Forgot `logging`
  • Loading branch information
avoidwork committed Jul 4, 2015
1 parent fcd092c commit 7663303
Show file tree
Hide file tree
Showing 10 changed files with 710 additions and 46 deletions.
1 change: 1 addition & 0 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ module.exports = function (grunt) {
src : [
"src/intro.js",
"src/utility.js",
"src/adapters.js",
"src/haro.js",
"src/factory.js",
"src/outro.js"
Expand Down
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,22 @@ testing time to 'search(regex, index)' for a record (first one is cold):
```

### Configuration
**adapters**
_Object_

Object of {(storage): (connection string)} pairs. Collection/table name is the value of `this.id`.

Available adapters: _mongo_

Example of specifying MongoDB as persistent storage:
```javascript
var store = haro(null, {
adapters: {
mongo: "mongo://localhost/mine"
}
});
```

**config**
_Object_

Expand Down Expand Up @@ -134,6 +150,11 @@ Example of specifying the primary key:
var store = haro(null, {key: 'field'});
```
**logging**
_Boolean_
Logs persistent storage messages to `console`, default is `true`.
**source**
_String_
Expand Down
216 changes: 212 additions & 4 deletions lib/haro.es6.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* @copyright 2015
* @license BSD-3-Clause
* @link http://haro.rocks
* @version 1.3.3
* @version 1.4.0
*/
"use strict";

Expand All @@ -20,6 +20,7 @@ const regex = {
querystring: /\?.*/,
endslash: /\/$/
};
const mongodb = typeof process !== "undefined" ? require("mongodb") : null;

function clone (arg) {
return JSON.parse(JSON.stringify(arg));
Expand Down Expand Up @@ -163,8 +164,160 @@ function uuid () {
return (s() + s() + "-" + s() + "-4" + s().substr(0, 3) + "-" + r[Math.floor(Math.random() * 4)] + s().substr(0, 3) + "-" + s() + s() + s());
}

const adapters = {
cmd: function (type, store, ...args) {
let defer = deferred();

if (!store.adapters[type]) {
defer.reject(new Error(type + " not configured for persistent storage"));
} else {
adapters[type].apply(adapters, [store].concat(args)).then(function (arg) {
defer.resolve(arg);
}, function (e) {
defer.reject(e);
});
}

return defer.promise;
},
mongo: function (store, op, key, data) {
let defer = deferred(),
record = key !== undefined && store.has(key);

mongodb.connect(store.adapters.mongo, function (e, db) {
function error (errr, arg) {
if (db) {
db.close();
}

if (errr) {
defer.reject(errr);
} else {
defer.resolve(arg);
}
}

if (e) {
error(e);
} else {
db.collection(store.id, function (err, collection) {
if (err) {
error(err);
} else {
if (op === "get") {
if (record) {
collection.find({_id: key}).limit(1).toArray(function (errr, recs) {
db.close();

if (errr) {
defer.reject(errr);
} else if (recs.length === 0) {
defer.resolve(null);
} else {
delete recs[0]._id;

store.set(key, recs[0], true).then(function (rec) {
defer.resolve(rec);
}, function (errrr) {
defer.reject(errrr);
});
}
});
} else {
collection.find({}).toArray(function (errr, recs) {
db.close();

if (errr) {
defer.reject(errr);
} else {
store.batch(recs.map(function (i) {
let o = i;

delete o._id;
return o;
}), "set", true).then(function (args) {
defer.resolve(args);
}, function (errrr) {
defer.reject(errrr);
});
}
});
}
}

if (op === "remove") {
collection.remove(record ? {_id: key} : {}, {safe: true}, function (errr, arg) {
db.close();

if (errr) {
defer.reject(errr);
} else {
defer.resolve(arg);
}
});
}

if (op === "set") {
if (record) {
collection.update({_id: key}, data, {
w: 1,
safe: true,
upsert: true
}, error);
} else {
// Removing all documents & re-inserting
collection.remove({}, {w: 1, safe: true}, function (errr) {
let deferreds;

if (errr) {
error(errr);
} else {
deferreds = [];

store.forEach(function (v, k) {
let defer2 = deferred();

deferreds.push(defer2.promise);

collection.update({_id: k}, v, {
w: 1,
safe: true,
upsert: true
}, function (errrr, arg) {
if (errrr) {
defer2.reject(errrr);
} else {
defer2.resolve(arg);
}
});
});

Promise.all(deferreds).then(function (result) {
db.close();
defer.resolve(result);
}, function (errrr) {
db.close();
defer.reject(errrr);
});
}
});
}
} else {
db.close();
defer.reject(null);
}
}
});
}
});

return defer.promise;
}
};

class Haro {
constructor (data, config = {}) {
this.adapters = {};
this.data = new Map();
this.delimiter = "|";
this.config = {
Expand All @@ -175,11 +328,13 @@ class Haro {
"content-type": "application/json"
}
};
this.id = uuid();
this.index = [];
this.indexes = new Map();
this.key = "";
this.logging = true;
this.patch = false;
this.registry = [];
this.key = "";
this.source = "";
this.total = 0;
this.uri = "";
Expand Down Expand Up @@ -292,6 +447,16 @@ class Haro {
if (this.versioning) {
this.versions.delete(key);
}

this.storage("remove", key).then(success => {
if (success && this.logging) {
console.log("Deleted", key, "from persistent storage");
}
}, e => {
if (this.logging) {
console.error("Error deleting", key, "from persistent storage:", (e.message || e.stack || e));
}
});
}

defer.resolve();
Expand Down Expand Up @@ -380,6 +545,10 @@ class Haro {
return output;
}

has (key) {
return this.data.has(key);
}

keys () {
return this.data.keys();
}
Expand Down Expand Up @@ -413,6 +582,10 @@ class Haro {
return tuple.apply(tuple, list);
}

load (type = "mongo") {
return adapters.cmd(type, this, "get");
}

map (fn) {
let result = [];

Expand All @@ -423,6 +596,27 @@ class Haro {
return tuple.apply(tuple, result);
}

storage (...args) {
let defer = deferred(),
deferreds = [];

Object.keys(this.adapters).forEach(i => {
deferreds.push(adapters.cmd.apply(adapters, [i, this].concat(args)));
});

if (deferreds.length > 0) {
Promise.all(deferreds).then(function () {
defer.resolve(true);
}, function (e) {
defer.reject(e);
});
} else {
defer.resolve(false);
}

return defer.promise;
}

reindex (index) {
if (!index) {
this.indexes.clear();
Expand Down Expand Up @@ -475,6 +669,10 @@ class Haro {
return defer.promise;
}

save (type = "mongo") {
return adapters.cmd(type, this, "set");
}

search (value, index) {
let indexes = index ? (this.index.indexOf(index) > -1 ? [index] : []) : this.index,
result = [],
Expand Down Expand Up @@ -546,6 +744,16 @@ class Haro {
this.data.set(lkey, ldata);
setIndex(this.index, this.indexes, this.delimiter, lkey, ldata);
defer.resolve(this.get(lkey));

this.storage("set", lkey, ldata).then(success => {
if (success && this.logging) {
console.log("Saved", lkey, "to persistent storage");
}
}, e => {
if (this.logging) {
console.error("Error saving", lkey, "to persistent storage:", (e.message || e.stack || e));
}
});
};

if (lkey === undefined || lkey === null) {
Expand All @@ -555,7 +763,7 @@ class Haro {
ogdata = this.data.get(lkey);

if (!override) {
ldata = merge(this.get(lkey)[1], ldata);
ldata = merge(ogdata, ldata);
}
}

Expand Down Expand Up @@ -703,7 +911,7 @@ function factory (data = null, config = {}, indexes = []) {
return new Haro(data, config, indexes);
}

factory.version = "1.3.3";
factory.version = "1.4.0";

// Node, AMD & window supported
if (typeof exports !== "undefined") {
Expand Down
Loading

0 comments on commit 7663303

Please sign in to comment.