Skip to content

Commit

Permalink
Reconfigured flattertree into mongoose plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
Gregory Thompson committed Dec 7, 2013
1 parent 71098ea commit 0e749cd
Show file tree
Hide file tree
Showing 4 changed files with 280 additions and 281 deletions.
52 changes: 23 additions & 29 deletions spec/flattertree.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,28 @@

describe("Manually ticking the Jasmine Mock Clock", function () {
'use strict';
var mongoose = require('mongoose');
var mongoose = require('mongoose'),
Schema,
NodeSchema,
Node;

beforeEach(function (done) {
mongoose.connect("mongodb://localhost/generic", function () {
mongoose.connection.db.dropDatabase(function () {
mongoose.disconnect(function () {
done();
});
});
});
});
mongoose.connect("mongodb://localhost/generic");

Schema = mongoose.Schema;
NodeSchema = new Schema({});

NodeSchema.plugin(require('../src/models/node'));
Node = mongoose.model('Node', NodeSchema);

afterEach(function (done) {

beforeEach(function (done) {
mongoose.connection.db.dropDatabase(function () {
mongoose.disconnect(function () {
done();
});
done();
});
});

it("should insert node", function (done) {
var flattertree = require('../src/flattertree'),
dataTree = flattertree.connect("mongodb://localhost/generic");

dataTree.insertNode(
Node.node().insert(
"directory",
null,
{
Expand All @@ -55,29 +52,26 @@ describe("Manually ticking the Jasmine Mock Clock", function () {
});

it("should do the operations specified", function (done) {
var flattertree = require('../src/flattertree'),
dataTree = flattertree.connect("mongodb://localhost/generic");

dataTree.insertNode(
Node.node().insert(
"directory",
null,
{hello: "world", object: {object: "stuff"}, arr: ["hello", "govener"], mormon: [{my: "name"}, {is: "elder"}, {price: "cunningham"}], good_data: [{id: 23, hello: "hello"}, {id: 34, hello: "world"}, {id: 45, hello: "neighbor"}]},
{},
function () {
dataTree.insertNode("more_stuff", ",directory,", {I: "like", data: "sir"}, {}, function () {
Node.node().insert("more_stuff", ",directory,", {I: "like", data: "sir"}, {}, function () {
console.log("about to find");
dataTree.fullNodeData(",directory,", function (err, data) {
Node.node().fullData(",directory,", function (err, data) {
if (err) {console.log(err); }
console.log("data = %j", data);
dataTree.findNode(",directory,", function (err, node) {
Node.node().find(",directory,", function (err, node) {
if (err) {console.log(err); }
console.log("node = %j", node);
dataTree.findFullNode(",directory,", function (err, data) {
Node.node().findFull(",directory,", function (err, data) {
if (err) {console.log(err); }
console.log("full data = %j", data);
dataTree.deleteNode(",directory,#arr,", function () {
dataTree.updateNode(",directory,", {i: "feel", great: "now"}, {}, function () {
dataTree.findNode(
Node.node().delete(",directory,#arr,", function () {
Node.node().update(",directory,", {i: "feel", great: "now"}, {}, function () {
Node.node().find(
",directory,",
function (err, node) {
if (err) {console.log(err); }
Expand Down
15 changes: 1 addition & 14 deletions src/flattertree.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,3 @@
/*jslint node: true, nomen: true */

function connect(mongoLocation) {
'use strict';

var mongoose = require('mongoose');

require(__dirname + '/models/node');
mongoose.connect(mongoLocation);

return require('./node_operations/node_operations').operations();
}

module.exports = {
connect: connect
};
module.exports = require('./models/node');
263 changes: 246 additions & 17 deletions src/models/node.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,250 @@
/*jslint node: true, nomen: true */
/*jslint node: true, nomen: true*/


(function () {
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
NodeSchema;

NodeSchema = new Schema({
//_id: String,
name: String,
path: String,
type: String,
tags: [],
created_at: {type: Date, default: Date.now},
data: { /*magic needs to happen in here*/ },
template: {/* will hold all the properties at current level (if array or array-like approximation), if array-like common elements one level deeper */}
});

mongoose.model('Node', NodeSchema);
var _ = require('lodash'),
async = require('async');



function tree(schema) {
schema.add({
name: String,
path: String,
type: String,
tags: [],
created_at: {type: Date, default: Date.now},
data: { /*magic needs to happen in here*/ },
template: {/* will hold all the properties at current level (if array or array-like approximation), if array-like common elements one level deeper */}
});


schema.static("node", function () {
var self = this,
insert;

function createNodeMetadata(name, parentNodePath, options) {
return {
name: name,
path: parentNodePath,
tags: options.tags,
type: options.type
};
}

function hasNode(name, path, callback) {
self.findOne({ path: path, name: name }).exec(function (err, parentNodeData) {
if (err) {return callback(err); }
return callback(null, !!parentNodeData);
});
}

function getPathParts(nodePath) {
var nodes = nodePath.slice(1, nodePath.length - 1).split(","),
pathToNodeUnfinished = nodes.slice(0, nodes.length - 1).join(",");

return {
pathToNode: nodes.length > 1 ? "," + pathToNodeUnfinished + "," : null,
nodeName: nodes[nodes.length - 1]
};
}

function nodeCanBeInserted(name, nodePath, callback) {
var pathParts;
if (nodePath === null) {return hasNode(name, nodePath, function (err, has) { callback(err, !has); }); }

pathParts = getPathParts(nodePath);

hasNode(pathParts.nodeName, pathParts.pathToNode, function (err, has) {
if (err) {return callback(err); }
if (!has) {return callback(null, false); }
return hasNode(name, nodePath, function (err, has) { callback(err, !has); });
});
}

function isArrayLike(data) {
var values = _.map(data, function (value) { return value; }),
keys;
if (values.length === 0) { return false; }
if (_.every(values, function (value) { return !_.isObject(value); })) { return true; }
if (_.some(values, function (value) { return !_.isObject(value); })) { return false; }

keys = _.keys(values[0]);

return _.every(values, function (value) {
return _.every(keys, function (key) {
return _.has(value, key);
});
});
}

function childPaths(node) { return (node.path !== null ? node.path : ",") + node.name + ","; }

function addDataObjects(nodeObject, objects, callback) {
async.each(
_.pairs(objects),
function (pairs, iterCallback) {
var objectKey = pairs[0],
objectValue = pairs[1],
dataName = objectKey;

insert(
dataName,
childPaths(nodeObject),
objectValue,
{
type: "data",
tags: []
},
iterCallback
);
},
callback
);
}

function createNode(nodeMetaData, data, callback) {
var dataKeyValuePairs = _.pairs(data),
primitives = _.object(_.filter(dataKeyValuePairs, function (pair) { return !_.isObject(pair[1]); })),
objects = _.object(_.filter(dataKeyValuePairs, function (pair) { return _.isObject(pair[1]); })),
properties = data !== undefined ? _.keys(data) : [];

nodeMetaData.data = primitives;
if (isArrayLike(data)) { nodeMetaData.type = nodeMetaData.type ? nodeMetaData.type + " array" : "array"; }

nodeMetaData.template = properties;

self.create(nodeMetaData, function (err, nodeObject) {
if (err || !nodeObject) {return callback(err); }
return addDataObjects(nodeObject, objects, callback);
});
}

function findNodeObject(currentNode, type, callback) {

var query = {};
query.path = childPaths(currentNode);
if (type !== null) { query.type = new RegExp("^" + type); }

self.find(query, function (err, childNodes) {
if (err) {return callback(err); }
async.map(
childNodes,
function (childNode, iterCallback) {
findNodeObject(
childNode,
type,
function (err, childData) {
var childDataObject = [];

if (err) {return callback(err); }
childDataObject.push(childNode.name);
childDataObject.push(childData);
return iterCallback(null, childDataObject);
},
iterCallback
);
},
function (err, objectArray) {
if (err) {return callback(err); }
return callback(null, _.object(objectArray.concat(_.pairs(currentNode.data))));
}
);
});
}

insert = function (name, parentNodePath, data, options, callback) {
var nodeMetaData = createNodeMetadata(name, parentNodePath, options);

nodeCanBeInserted(name, parentNodePath, function (err, canBeCreated) {
if (canBeCreated) {return createNode(nodeMetaData, data, callback); }
return callback(err);
});
};

function deleteN(path, callback) {
var pathParts = getPathParts(path);

hasNode(pathParts.nodeName, pathParts.pathToNode, function (err, hasNode) {
if (err) {return callback(err); }
if (hasNode) {
return self.remove({path: new RegExp("^" + path) }, function (err) {
if (err) {return callback(err); }
self.findOneAndRemove({name: pathParts.nodeName, path: pathParts.pathToNode}, function (err) {
if (err) {return callback(err); }
return callback(null);
});
});
}
return callback(null);

});
}

//////////////////////////////////visible functions//////////////////////////////////


function insertNode(name, parentNodePath, data, options, callback) {
insert(name, parentNodePath, data, options, callback);
}

function deleteNode(path, callback) {
deleteN(path, callback);
}

function findNode(path, callback) {
var pathParts = getPathParts(path);

self.findOne({name: pathParts.nodeName, path: pathParts.pathToNode}, callback);
}

function fullNodeData(path, callback) {
var pathParts = getPathParts(path);

self.findOne({name: pathParts.nodeName, path: pathParts.pathToNode}, function (err, node) {
if (err) {return callback(err); }
return findNodeObject(node, "data", callback);
});
}

function updateNode(path, data, options, callback) {
var pathParts = getPathParts(path);

deleteN(
path,
function (err) {
if (err) {return callback(err); }
return insert(
pathParts.nodeName,
pathParts.pathToNode,
data,
options,
callback
);
}
);
}

function findFullNode(path, callback) {
var pathParts = getPathParts(path);

self.findOne({name: pathParts.nodeName, path: pathParts.pathToNode}, function (err, node) {
if (err) {return callback(err); }
return findNodeObject(node, null, callback);
});
}

return {
insert: insertNode,
delete: deleteNode,
find: findNode,
fullData: fullNodeData,
update: updateNode,
findFull: findFullNode
};
});
}

module.exports = tree;
}());
Loading

0 comments on commit 0e749cd

Please sign in to comment.