Socket
Socket
Sign inDemoInstall

data

Package Overview
Dependencies
0
Maintainers
0
Versions
9
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.3.0 to 0.4.0

CHANGELOG

200

adapters/couch_adapter.js

@@ -6,2 +6,6 @@ var CouchClient = require('../lib/couch-client');

// Apply Filter Stack
// --------
var applyFilters = function(filters, nodes, mode, ctx, callback) {

@@ -44,3 +48,4 @@ var that = this;

function setupIndexes(node, callback) {
function setupType(node, callback) {
// Extract local typename

@@ -54,2 +59,12 @@ var typename = node._id.split('/')[2];

};
// Setup validation function
validatorFn = "function(newDoc, oldDoc, userCtx) {\n";
validatorFn += "if (newDoc.type.indexOf('"+node._id+"')>=0) {\n";
_.each(node.properties, function(property, key) {
if (property.required) validatorFn += "if (!newDoc['"+key+"']) throw({forbidden : '"+key+" is missing'});\n";
if (property.validator) validatorFn += "if (!new RegExp('"+property.validator+"').test(newDoc."+key+")) throw({forbidden: '"+key+" is invalid'});"
});
validatorFn += "}}";
if (node.indexes) {

@@ -64,5 +79,7 @@ _.each(node.indexes, function(properties, indexName) {

}
db.save({
_id: '_design/'+typename,
views: views
views: views,
validate_doc_update: validatorFn
}, {force: true}, function (err, doc) {

@@ -77,2 +94,3 @@ err ? callback(err) : callback();

// Flush the database
self.flush = function(callback) {

@@ -125,3 +143,3 @@ db.request("DELETE", db.uri.pathname, function (err) {

if (newDoc.type == "/type/type") {
setupIndexes(newDoc, function(err) {
setupType(newDoc, function(err) {
if (err) { console.log('Error during index creation:'); console.log(err); };

@@ -147,3 +165,2 @@ result[nodeId] = newDoc;

// read

@@ -155,3 +172,3 @@ // --------------

self.read = function(queries, options, callback, ctx) {
// Collects the subgraph that will be returned as a result
// Collects a subgraph that will be returned as a result
var result = {};

@@ -167,43 +184,153 @@ queries = _.isArray(queries) ? queries : [queries];

if (!qry.type) return callback('ERROR: No type attribute specified with query.');
if (!qry.type && !qry._id) return callback('ERROR: No type or _id attribute specified with query.');
var typeName = qry.type.split('/')[2];
var typeName = qry.type ? qry.type.split('/')[2] : null;
delete qry.type;
// Pull off relationship definitions (in case of eager loading relationships)
var relationships = {};
_.each(qry, function(val, property) {
if (typeof val === 'object' && !_.isArray(val)) {
relationships[property] = val;
delete qry[property];
}
});
// Just the properties
var properties = _.keys(qry);
// Holds the current traversal path in a nested query
var currentPath = [];
// Lookup view
db.get('_design/'+typeName, function(err, node) {
// Pick the right index based on query parameters
var viewName = null;
_.each(node.views, function(view, key) {
if (view.properties.length == properties.length && _.intersect(view.properties, properties).length == view.properties.length) viewName = key;
});
// Depending on the current working path, reveal relationships to be
// traversed for the node currently processed
function currentRelationships(currentPath) {
if (currentPath.length === 0) return relationships;
var path = _.clone(currentPath);
var res = relationships;
var key;
while (key = path.splice(0,1)[0]) {
res = res[key];
}
delete res._recursive; // Ignore directives
return res;
}
// Fetch associated nodes for a certain property
// --------
function fetchAssociatedProperty(node, property, recursive, callback) {
if (!node[property]) return callback(); // Done if null/undefined
if (viewName) {
// Use view to lookup for matching objects efficiently
var key = [];
_.each(node.views[viewName].properties, function(p) {
key.push(qry[p]);
// Update currentPath to be the current property traversed
currentPath.push(property);
var references = _.isArray(node[property]) ? node[property] : [node[property]];
var nodes = {};
async.forEachSeries(references, function(nodeId, callback) {
if (result[nodeId]) return callback(); // Skip if already in the result
db.get(nodeId, function(err, node) {
if (err) return callback(err);
if (!node) return callback(); // Ignore deleted nodes
result[node._id] = node;
nodes[node._id] = node;
fetchAssociated(node, callback);
});
db.view(typeName+'/'+viewName, {key: key}, function(err, res) {
if (err) callback(err);
_.each(res.rows, function(row) {
result[row.value._id] = row.value;
}, function(err) {
// Once ready remove that property from the currentPath
currentPath.pop();
// And dig deeper in a recursive scenario
if (recursive) {
async.forEachSeries(Object.keys(nodes), function(nodeId, callback) {
fetchAssociatedProperty(result[nodeId], property, true, callback);
}, callback);
} else {
callback(err);
}
});
}
function fetchAssociated(node, callback) {
var properties = currentRelationships(currentPath);
// Based on the current relationships fetch associated properties
async.forEachSeries(Object.keys(properties), function(property, callback) {
fetchAssociatedProperty(node, property, properties[property]._recursive, callback);
}, callback);
}
// Resolve references based on specified query paths
// --------
function resolveReferences(nodes, callback) {
// TODO: Can we do this in parallel?
async.forEachSeries(Object.keys(nodes), function(node, callback) {
fetchAssociated(nodes[node], callback);
}, callback);
}
// Typed Query based on CouchDB Views
// --------
function executeTypedQuery(callback) {
db.get('_design/'+typeName, function(err, node) {
// Pick the right index based on query parameters
var viewName = null;
_.each(node.views, function(view, key) {
if (view.properties.length == properties.length && _.intersect(view.properties, properties).length === view.properties.length) viewName = key;
});
if (viewName) {
// Use view to lookup matching objects efficiently
var key = [];
_.each(node.views[viewName].properties, function(p) {
key.push(qry[p]);
});
callback();
});
} else { // Fetch all objects of this type and check manually
console.log('WARNING: No index could be found for this query:');
console.log(qry);
qry["type|="] = "/type/"+typeName;
db.view(typeName+'/all', function(err, res) {
db.view(typeName+'/'+viewName, {key: key}, function(err, res) {
if (err) callback(err);
_.each(res.rows, function(row) {
result[row.value._id] = row.value;
});
callback();
});
} else { // Fetch all objects of this type and check manually
console.log('WARNING: No index could be found for this query:');
console.log(qry);
qry["type|="] = "/type/"+typeName;
db.view(typeName+'/all', function(err, res) {
if (err) return callback(err);
_.each(res.rows, function(row) {
if (Data.matches(row.value, qry)) result[row.value._id] = row.value;
});
callback();
});
}
});
}
// Untyped Query based on ids
// --------
function executeUntypedQuery(callback) {
var references = _.isArray(qry._id) ? qry._id : [qry._id];
async.forEach(references, function(nodeId, callback) {
if (result[nodeId]) callback(); // Skip if already included in the result
db.get(nodeId, function(err, node) {
if (err) return callback(err);
_.each(res.rows, function(row) {
if (Data.matches(row.value, qry)) result[row.value._id] = row.value;
});
if (!node) return callback(); // Ignore deleted nodes
result[node._id] = node;
callback();
});
}
});
}, function(err) {
callback(err);
});
}
// Execute query either typed (by id) or untyped (using a CouchDB View)
qry._id ? executeUntypedQuery(function() { resolveReferences(result, callback); })
: executeTypedQuery(function() { resolveReferences(result, callback); });
}

@@ -220,2 +347,3 @@

self.db = db;

@@ -222,0 +350,0 @@

246

data.js

@@ -23,3 +23,3 @@ // (c) 2011 Michael Aufreiter

// Current version of the library. Keep in sync with `package.json`.
Data.VERSION = '0.3.0';
Data.VERSION = '0.4.0';

@@ -59,6 +59,6 @@ // Require Underscore, if we're on the server, and it's not already present.

// Extract operator
var matches = key.match(/^([a-z_]{1,30})(!=|>|>=|<|<=|\|=|&=)?$/),
var matches = key.match(/^([a-z_]{1,30})(=|==|!=|>|>=|<|<=|\|=|&=)?$/),
property = matches[1],
operator = matches[2] || '==';
operator = matches[2] || (property == "type" || _.isArray(value) ? "|=" : "=");
if (operator === "|=") { // one of operator

@@ -336,3 +336,3 @@ var values = _.isArray(value) ? value : [value];

get: function (key) {
return this.data[key];
return this.data.hasOwnProperty(key) ? this.data[key] : undefined;
},

@@ -351,8 +351,15 @@

// Returns a sub-range of the current *hash*
range: function(start, end) {
var result = new Data.Hash();
for(var i=start; i<=end; i++) {
result.set(this.key(i), this.at(i));
}
return result;
},
// Returns the rest of the elements.
// Pass an index to return the items from that index onward.
rest: function(index) {
return this.select(function(value, key, i) {
return i >= index;
});
return this.range(index, this.length-1);
},

@@ -459,7 +466,10 @@

result = new Data.Hash();
this.each(function(value, key) {
hash.each(function(value2, key2) {
if (key === key2) result.set(key, value);
});
// Ensure that is the smaller one
if (hash.length < that.length) {
that = hash;
hash = this;
}
that.each(function(value,key) {
if (hash.get(key)) result.set(key, value);
});

@@ -475,8 +485,6 @@ return result;

this.each(function(value, key) {
if (!result.get(key))
result.set(key, value);
result.set(key, value);
});
hash.each(function(value, key) {
if (!result.get(key))
result.set(key, value);
if (!result.get(key)) result.set(key, value);
});

@@ -488,7 +496,6 @@ return result;

difference: function(hash) {
var that = this,
result = this.clone();
hash.each(function(value, key) {
if (result.get(key)) result.del(key);
var that = this;
result = new Data.Hash();
this.each(function(value, key) {
if (!hash.get(key)) result.set(key, value);
});

@@ -578,3 +585,2 @@ return result;

// Data.Transformers

@@ -590,3 +596,3 @@ // --------------

gspec[type._id] = {"type": "/type/type", "properties": {}};
gspec[type._id] = {"type": "/type/type", "properties": {}, indexes: type.indexes};

@@ -600,3 +606,3 @@ // Include group keys to the output graph

_.each(properties, function(options, key) {
var p = type.properties().get(key).toJSON();
var p = type.properties().get(options.property || key).toJSON();
if (options.name) p.name = options.name;

@@ -607,3 +613,3 @@ gspec[type._id].properties[key] = p;

var groupedGraph = new Data.Graph(gspec);
// Compute group memberships
_.each(keys, function(key) {

@@ -615,2 +621,3 @@ groups[key] = type.properties().get(key).all('values');

var members = new Data.Hash();
_.each(keys, function(k, index) {

@@ -621,2 +628,6 @@ var objects = groups[keys[index]].get(key[index]).referencedObjects;

// Empty group key
if (key.length === 0) members = g.objects();
if (members.length === 0) return null;
var res = {type: type._id};

@@ -628,5 +639,5 @@ _.each(gspec[type._id].properties, function(p, pk) {

var numbers = members.map(function(obj) {
return obj.get(pk);
return obj.get(properties[pk].property || pk);
});
var aggregator = properties[pk].aggregator || Data.Aggregators.SUM
var aggregator = properties[pk].aggregator || Data.Aggregators.SUM;
res[pk] = aggregator(numbers);

@@ -640,3 +651,4 @@ }

if (keyIndex === keys.length-1) {
groupedGraph.set(key.join('::'), aggregate(key));
var aggregatedItem = aggregate(key);
if (aggregatedItem) groupedGraph.set(key.join('::'), aggregatedItem);
} else {

@@ -649,3 +661,2 @@ keyIndex += 1;

}
extractGroups(-1, []);

@@ -823,7 +834,7 @@ return groupedGraph;

if (typeof v === 'object') v = that.type.g.set(null, v)._id;
val = that.type.g.get('objects', v);
val = that.type.g.get('nodes', v);
if (!val) {
// Register the object (even if not yet loaded)
val = new Data.Object(that.type.g, v);
that.type.g.set('objects', v, val);
that.type.g.set('nodes', v, val);
}

@@ -906,2 +917,3 @@ } else {

that.replace('properties', new Data.Hash);
// Extract properties

@@ -920,3 +932,3 @@ _.each(type.properties, function(property, key) {

objects: function() {
return this.all('objects');
return this.all('nodes');
},

@@ -970,3 +982,3 @@

this.html_id = id.replace(/\//g, '_');
this.dirty = true; // Every constructed node is dirty by default
this._dirty = true; // Every constructed node is dirty by default

@@ -1011,14 +1023,12 @@ this.errors = []; // Stores validation errors

// Pull off _id and _rev properties
delete this.data._id;
this._rev = this.data._rev; // delete this.data._rev;
this._rev = this.data._rev;
this._conflicted = this.data._conflicted;
this._deleted = this.data._deleted; // delete this.data._deleted;
this._deleted = this.data._deleted;
// Initialize primary type (backward compatibility)
this.type = this.g.get('objects', _.last(types));
this.type = this.g.get('nodes', _.last(types));
// Initialize types
_.each(types, function(type) {
that._types.set(type, that.g.get('objects', type));
that._types.set(type, that.g.get('nodes', type));
// Register properties for all types

@@ -1039,4 +1049,3 @@ that._types.get(type).all('properties').each(function(property, key) {

});
if (this.dirty) this.g.trigger('dirty');
if (this._dirty) this.g.trigger('dirty');
},

@@ -1137,3 +1146,3 @@

that.dirty = true;
that._dirty = true;
that.g.trigger('dirty');

@@ -1185,3 +1194,3 @@ });

this.watchers = {};
this.replace('objects', new Data.Hash());
this.replace('nodes', new Data.Hash());
if (!g) return;

@@ -1228,2 +1237,11 @@ this.merge(g, dirty);

// Empty graph
empty: function() {
var that = this;
_.each(this.objects().keys(), function(id) {
that.del(id);
that.all('nodes').del(id);
});
},
// Merges in another Graph

@@ -1236,5 +1254,5 @@ merge: function(g, dirty) {

if (node.type === '/type/type' || node.type === 'type') {
if (!that.get('objects', key)) {
that.set('objects', key, new Data.Type(that, key, node));
that.get(key).dirty = dirty;
if (!that.get('nodes', key)) {
that.set('nodes', key, new Data.Type(that, key, node));
that.get(key)._dirty = dirty;
}

@@ -1249,7 +1267,7 @@ return true;

if (node.type !== '/type/type' && node.type !== 'type') {
var res = that.get('objects', key);
var res = that.get('nodes', key);
var types = _.isArray(node.type) ? node.type : [node.type];
if (!res) {
res = new Data.Object(that, key, node);
that.set('objects', key, res);
that.set('nodes', key, res);
} else {

@@ -1261,8 +1279,9 @@ // Populate existing node with data in order to be rebuilt

_.each(types, function(type) {
if (!that.get('objects', type)) {
if (!that.get('nodes', type)) {
throw new Error("Type '"+type+"' not found for "+key+"...");
}
that.get('objects', type).set('objects', key, res);
that.get('nodes', type).set('nodes', key, res);
});
that.get(key).dirty = dirty;
that.get(key)._dirty = dirty;
if (!node._id) node._id = key;
return true;

@@ -1272,22 +1291,27 @@ }

});
// Now that all objects are registered we can build them
this.objects().each(function(r, key, index) {
if (r.data) r.build();
// Now that all new objects are registered we can build them
_.each(objects, function(o) {
var obj = that.get(o._id);
if (obj.data) obj.build();
});
return this;
},
// Set (add) a new node on the graph
set: function(id, properties) {
var that = this;
var types = _.isArray(properties.type) ? properties.type : [properties.type];
if (arguments.length === 2) {
id = id ? id : Data.uuid('/' + _.last(_.last(types).split('/')) + '/');
set: function(node) {
var id, that = this;
// Backward compatibility
if (arguments.length === 2) node = _.extend(arguments[1], {_id: arguments[0]});
var types = _.isArray(node.type) ? node.type : [node.type];
if (arguments.length <= 2) {
node._id = node._id ? node._id : Data.uuid('/' + _.last(_.last(types).split('/')) + '/');
// Recycle existing object if there is one
var res = that.get(id) ? that.get(id) : new Data.Object(that, id, properties, true);
res.data = properties;
res.dirty = true;
var res = that.get(node._id) ? that.get(node._id) : new Data.Object(that, node._id, _.clone(node), true);
res.data = node;
res._dirty = true;
res.build();
this.set('objects', id, res);
return this.get('objects', id);
this.set('nodes', node._id, res);
return res;
} else { // Delegate to Data.Node#set

@@ -1299,7 +1323,5 @@ return Data.Node.prototype.set.call(this, arguments[0], arguments[1], arguments[2]);

// API method for accessing objects in the graph space
// TODO: Ask the datastore if the node is not known in the local graph
// use async method queues for this!
get: function(id) {
if (arguments.length === 1) {
return this.get('objects', id);
return this.get('nodes', id);
} else {

@@ -1315,3 +1337,3 @@ return Data.Node.prototype.get.call(this, arguments[0], arguments[1]);

node._deleted = true;
node.dirty = true;
node._dirty = true;
// Remove registered values

@@ -1354,4 +1376,4 @@ node.properties().each(function(p, key) {

},
// Synchronize dirty nodes with the database
// Synchronize dirty nodes with the backend
sync: function(callback) {

@@ -1363,8 +1385,5 @@ callback = callback || function() {};

var validNodes = new Data.Hash();
var invalidNodes = nodes.select(function(node, key) {
nodes.select(function(node, key) {
if (!node.validate || (node.validate && node.validate())) {
validNodes.set(key, node);
return false;
} else {
return true;
}

@@ -1374,22 +1393,24 @@ });

this.adapter.write(validNodes.toJSON(), function(err, g) {
if (err) {
callback(err);
} else {
that.merge(g, false);
// Check for rejectedNodes
validNodes.each(function(n, key) {
if (g[key]) {
n.dirty = false;
n._rejected = false;
} else {
n._rejected = true;
}
});
if (that.conflictedNodes().length > 0) that.trigger('conflicted');
if (that.rejectedNodes().length > 0) that.trigger('rejected');
callback(invalidNodes.length > 0 ? 'Some invalid nodes' : null, invalidNodes);
}
if (err) return callback(err);
that.merge(g, false);
// Check for rejectedNodes / conflictedNodes
validNodes.each(function(n, key) {
if (g[key]) {
n._dirty = false;
n._rejected = false;
} else {
n._rejected = true;
}
});
if (that.invalidNodes().length > 0) that.trigger('invalid');
if (that.conflictedNodes().length > 0) that.trigger('conflicted');
if (that.rejectedNodes().length > 0) that.trigger('rejected');
var unsavedNodes = that.invalidNodes().union(that.conflictedNodes())
.union(that.rejectedNodes()).length;
callback(unsavedNodes > 0 ? unsavedNodes+' unsaved nodes' : null);
});

@@ -1407,3 +1428,3 @@ },

types: function() {
return this.all('objects').select(function(node, key) {
return this.all('nodes').select(function(node, key) {
return node.type === '/type/type' || node.type === 'type';

@@ -1415,3 +1436,3 @@ });

objects: function() {
return this.all('objects').select(function(node, key) {
return this.all('nodes').select(function(node, key) {
return node.type !== '/type/type' && node.type !== 'type' && node.data && !node._deleted;

@@ -1424,4 +1445,4 @@ });

dirtyNodes: function() {
return this.all('objects').select(function(obj, key) {
return (obj.dirty && (obj.data || obj instanceof Data.Type));
return this.all('nodes').select(function(obj, key) {
return (obj._dirty && (obj.data || obj instanceof Data.Type));
});

@@ -1432,3 +1453,3 @@ },

invalidNodes: function() {
return this.all('objects').select(function(obj, key) {
return this.all('nodes').select(function(obj, key) {
return (obj.errors && obj.errors.length > 0);

@@ -1440,3 +1461,3 @@ });

conflictedNodes: function() {
return this.all('objects').select(function(obj, key) {
return this.all('nodes').select(function(obj, key) {
return obj._conflicted;

@@ -1446,4 +1467,5 @@ });

// Nodes that got rejected during sync
rejectedNodes: function() {
return this.all('objects').select(function(obj, key) {
return this.all('nodes').select(function(obj, key) {
return obj._rejected;

@@ -1458,3 +1480,3 @@ });

// Serialize object nodes
this.all('objects').each(function(obj, key) {
this.all('nodes').each(function(obj, key) {
// Only serialize fetched nodes

@@ -1486,4 +1508,6 @@ if (obj.data || obj instanceof Data.Type) {

var that = this,
gspec = { "/type/item": {"type": "/type/type", "properties": {}}};
gspec = { "/type/item": { "type": "/type/type", "properties": {}} };
if (spec) gspec["/type/item"]["indexes"] = spec.indexes || {};
// Convert to Data.Graph serialization format

@@ -1517,2 +1541,3 @@ if (spec) {

find: function(query) {
query["type|="] = "/type/item";
return this.g.find(query);

@@ -1538,3 +1563,3 @@ },

properties: function() {
return this.g.get('objects', '/type/item').all('properties');
return this.g.get('nodes', '/type/item').all('properties');
},

@@ -1547,2 +1572,7 @@

// Convenience function for accessing indexes defined on the collection
indexes: function() {
return this.g.get('/type/item').indexes;
},
// Serialize

@@ -1549,0 +1579,0 @@ toJSON: function() {

@@ -1,33 +0,35 @@

(function(){var e;e=typeof exports!=="undefined"?exports:this.Data={};e.VERSION="0.3.0";var f=this._;if(!f&&typeof require!=="undefined")f=require("underscore");e.VALUE_TYPES=["string","object","number","boolean","date"];e.isValueType=function(a){return f.include(e.VALUE_TYPES,a)};e.matches=function(a,b){b=f.isArray(b)?b:[b];var c=false;f.each(b,function(d){if(!c){var g=false;f.each(d,function(h,j){if(!g){var k,i=j.match(/^([a-z_]{1,30})(!=|>|>=|<|<=|\|=|&=)?$/),l=i[1];i=i[2]||"==";if(i==="|="){i=
f.isArray(h)?h:[h];var m=f.isArray(a[l])?a[l]:[a[l]];k=false;f.each(i,function(o){if(f.include(m,o))k=true})}else if(i==="&="){i=f.isArray(h)?h:[h];m=f.isArray(a[l])?a[l]:[a[l]];k=f.intersect(m,i).length===i.length}else switch(i){case "!=":k=!f.isEqual(a[l],h);break;case ">":k=a[l]>h;break;case ">=":k=a[l]>=h;break;case "<":k=a[l]<h;break;case "<=":k=a[l]<=h;break;default:k=f.isEqual(a[l],h);break}if(!k)return g=true}});if(!g)return c=true}});return c};e.uuid=function(a){for(var b="0123456789abcdefghijklmnopqrstuvwxyz".split(""),
c=[],d=0;d<32;d++)c[d]=b[0|Math.random()*16];return(a?a:"")+c.join("")};f.Events={bind:function(a,b){this._callbacks||(this._callbacks={});(this._callbacks[a]||(this._callbacks[a]=[])).push(b);return this},unbind:function(a,b){var c;if(a){if(c=this._callbacks)if(b){c=c[a];if(!c)return this;for(var d=0,g=c.length;d<g;d++)if(b===c[d]){c.splice(d,1);break}}else c[a]=[]}else this._callbacks={};return this},trigger:function(a){var b,c,d,g;if(!(c=this._callbacks))return this;if(b=c[a]){d=0;for(g=b.length;d<
g;d++)b[d].apply(this,Array.prototype.slice.call(arguments,1))}if(b=c.all){d=0;for(g=b.length;d<g;d++)b[d].apply(this,arguments)}return this}};var q=function(){};f.inherits=function(a,b,c){var d;d=b&&b.hasOwnProperty("constructor")?b.constructor:function(){return a.apply(this,arguments)};q.prototype=a.prototype;d.prototype=new q;b&&f.extend(d.prototype,b);c&&f.extend(d,c);d.prototype.constructor=d;d.__super__=a.prototype;return d};e.Hash=function(a){var b=this;this.data={};this.keyOrder=[];this.length=
0;if(a instanceof Array)f.each(a,function(c,d){b.set(d,c)});else a instanceof Object&&f.each(a,function(c,d){b.set(d,c)});this.initialize&&this.initialize(attributes,options)};f.extend(e.Hash.prototype,f.Events,{clone:function(){var a=new e.Hash;a.length=this.length;f.each(this.data,function(b,c){a.data[c]=b});a.keyOrder=this.keyOrder.slice(0,this.keyOrder.length);return a},set:function(a,b,c){var d;if(a===undefined)return this;if(this.data[a])d=this.index(a);else{if(c!==undefined){d=this.select(function(h,
j,k){return k<c});var g=this.select(function(h,j,k){return k>=c});this.keyOrder=[].concat(d.keyOrder);this.keyOrder.push(a);this.keyOrder=this.keyOrder.concat(g.keyOrder)}else this.keyOrder.push(a);d=this.length;this.length+=1}this.data[a]=b;this[d]=this.data[a];this.trigger("set",a);return this},del:function(a){if(this.data[a]){var b=this.length,c=this.index(a);delete this.data[a];this.keyOrder.splice(c,1);Array.prototype.splice.call(this,c,1);this.length=b-1;this.trigger("del",a)}return this},get:function(a){return this.data[a]},
at:function(a){return this.data[this.keyOrder[a]]},first:function(){return this.at(0)},rest:function(a){return this.select(function(b,c,d){return d>=a})},last:function(){return this.at(this.length-1)},key:function(a){return this.keyOrder[a]},index:function(a){return this.keyOrder.indexOf(a)},each:function(a){var b=this;f.each(this.keyOrder,function(c,d){a.call(b,b.data[c],c,d)});return this},values:function(){var a=[];this.each(function(b){a.push(b)});return a},keys:function(){return this.keyOrder},
toArray:function(){var a=[];this.each(function(b,c){a.push({key:c,value:b})});return a},toJSON:function(){var a={};this.each(function(b,c){a[c]=b.toJSON?b.toJSON():b});return a},map:function(a){var b=this.clone(),c=this;b.each(function(d,g,h){b.data[c.key(h)]=a.call(b,d)});return b},select:function(a){var b=new e.Hash,c=this;this.each(function(d,g,h){a.call(c,d,g,h)&&b.set(g,d)});return b},sort:function(a){var b=this.clone();sortedKeys=b.toArray().sort(a);b.keyOrder=f.map(sortedKeys,function(c){return c.key});
return b},intersect:function(a){var b=new e.Hash;this.each(function(c,d){a.each(function(g,h){d===h&&b.set(d,c)})});return b},union:function(a){var b=new e.Hash;this.each(function(c,d){b.get(d)||b.set(d,c)});a.each(function(c,d){b.get(d)||b.set(d,c)});return b},difference:function(a){var b=this.clone();a.each(function(c,d){b.get(d)&&b.del(d)});return b}});e.Comparators={};e.Comparators.ASC=function(a,b){return a.value===b.value?0:a.value<b.value?-1:1};e.Comparators.DESC=function(a,b){return a.value===
b.value?0:a.value>b.value?-1:1};e.Aggregators={};e.Aggregators.SUM=function(a){var b=0;a.each(function(c){if(f.isNumber(c))b+=c});return b};e.Aggregators.MIN=function(a){var b=Infinity;a.each(function(c){if(f.isNumber(c)&&c<b)b=c});return b};e.Aggregators.MAX=function(a){var b=-Infinity;a.each(function(c){if(f.isNumber(c)&&c>b)b=c});return b};e.Aggregators.AVG=function(a){var b=0,c=0;a.each(function(d){if(f.isNumber(d)){b+=d;c+=1}});return b/c};e.Aggregators.COUNT=function(a){return a.length};e.Modifiers=
{};e.Modifiers.DEFAULT=function(a){return a};e.Modifiers.MONTH=function(a){return a.getMonth()};e.Modifiers.QUARTER=function(a){return Math.floor(a.getMonth()/3)+1};e.Transformers={group:function(a,b,c,d){function g(i){var l=new e.Hash;f.each(c,function(o,n){var p=k[c[n]].get(i[n]).referencedObjects;l=n===0?l.union(p):l.intersect(p)});var m={type:b._id};f.each(j[b._id].properties,function(o,n){if(f.include(c,n))m[n]=i[f.indexOf(c,n)];else{var p=l.map(function(r){return r.get(n)});m[n]=(d[n].aggregator||
e.Aggregators.SUM)(p)}});return m}function h(i,l){if(i===c.length-1)j[l.join("::")]=g(l);else{i+=1;k[c[i]].each(function(m,o){h(i,l.concat([o]))})}}var j={};b=a.get(b);var k={};j[b._id]={type:"/type/type",properties:{}};f.each(c,function(i){j[b._id].properties[i]=b.properties().get(i).toJSON()});f.each(d,function(i,l){var m=b.properties().get(l).toJSON();if(i.name)m.name=i.name;j[b._id].properties[l]=m});f.each(c,function(i){k[i]=b.properties().get(i).all("values")});h(-1,[]);return new e.Graph(j)}};
e.Node=function(a){this.nodeId=e.Node.generateId();if(a)this.val=a.value;this._properties={};this.initialize&&this.initialize(a)};e.Node.nodeCount=0;e.Node.generateId=function(){return e.Node.nodeCount+=1};f.extend(e.Node.prototype,f.Events,{identity:function(){return this.nodeId},replace:function(a,b){this._properties[a]=b},set:function(a,b,c){this._properties[a]||(this._properties[a]=new e.Hash);this._properties[a].set(b,c instanceof e.Node?c:new e.Node({value:c}));return this},get:function(a,b){if(b!==
undefined&&this._properties[a]!==undefined)return this._properties[a].get(b)},all:function(a){return this._properties[a]},first:function(a){return(a=this._properties[a])?a.first():null},value:function(a){return this.values(a).first()},values:function(a){if(!this.all(a))return new e.Hash;return this.all(a).map(function(b){return b.val})}});e.Adapter=function(a){this.config=a};e.Adapters={};e.Property=f.inherits(e.Node,{constructor:function(a,b,c){e.Node.call(this);this._id=this.key=b;this.type=a;this.unique=
c.unique;this.name=c.name;this.meta=c.meta||{};this.validator=c.validator;this.required=c.required;this["default"]=c["default"];this.expectedTypes=f.isArray(c.type)?c.type:[c.type];this.replace("values",new e.Hash)},isValueType:function(){return e.isValueType(this.expectedTypes[0])},isObjectType:function(){return!this.isValueType()},registerValues:function(a,b){var c=this,d=new e.Hash;f.each(a,function(g){if(g){var h;if(b.all(c.key))h=b.all(c.key).get(g);if(!h){h=c.get("values",g);if(!h){if(c.isObjectType()){if(typeof g===
"object")g=c.type.g.set(null,g)._id;h=c.type.g.get("objects",g);if(!h){h=new e.Object(c.type.g,g);c.type.g.set("objects",g,h)}}else{h=new e.Node({value:g});h.referencedObjects=new e.Hash}c.set("values",g,h)}h.referencedObjects.set(b._id,b)}d.set(g,h)}});b.all(c.key)&&this.unregisterValues(b.all(c.key).difference(d),b);return d},unregisterValues:function(a,b){var c=this;a.each(function(d,g){d.referencedObjects.length>1?d.referencedObjects.del(b._id):c.all("values").del(g)})},aggregate:function(a){return a(this.values("values"))},
toJSON:function(){return{name:this.name,type:this.expectedTypes,unique:this.unique,meta:this.meta,validator:this.validator,required:this.required,"default":this["default"]}}});e.Type=f.inherits(e.Node,{constructor:function(a,b,c){var d=this;e.Node.call(this);this.g=a;this._id=this.key=b;this._rev=c._rev;this._conflicted=c._conflicted;this.type=c.type;this.name=c.name;this.meta=c.meta||{};this.indexes=c.indexes;f.each(c.properties,function(g,h){d.set("properties",h,new e.Property(d,h,g))})},properties:function(){return this.all("properties")},
objects:function(){return this.all("objects")},toJSON:function(){var a={_id:this._id,type:"/type/type",name:this.name,properties:{}};if(this._rev)a._rev=this._rev;if(this.meta&&f.keys(this.meta).length>0)a.meta=this.meta;if(this.indexes&&f.keys(this.indexes).length>0)a.indexes=this.indexes;this.all("properties").each(function(b){var c=a.properties[b.key]={name:b.name,unique:b.unique,type:b.expectedTypes,required:b.required?true:false};if(b["default"])c["default"]=b["default"];if(b.validator)c.validator=
b.validator;if(b.meta&&f.keys(b.meta).length>0)c.meta=b.meta});return a}});e.Object=f.inherits(e.Node,{constructor:function(a,b,c){e.Node.call(this);this.g=a;this._id=this.key=b;this.html_id=b.replace(/\//g,"_");this.dirty=true;this.errors=[];this._types=new e.Hash;this.referencedObjects=new e.Hash;if(c)this.data=c},types:function(){return this._types},toString:function(){return this.get("name")||this.val||this._id},properties:function(){var a=new e.Hash;this._types.each(function(b){b.all("properties").each(function(c){a.set(c.key,
c)})});return a},build:function(){var a=this,b=f.isArray(this.data.type)?this.data.type:[this.data.type];if(!this.data)throw Error("Object has no data, and cannot be built");delete this.data._id;this._rev=this.data._rev;this._conflicted=this.data._conflicted;this._deleted=this.data._deleted;this.type=this.g.get("objects",f.last(b));f.each(b,function(c){a._types.set(c,a.g.get("objects",c));a._types.get(c).all("properties").each(function(d,g){function h(j){j=f.isArray(j)?j:[j];a.replace(d.key,d.registerValues(j,
a))}if(a.data[g]!==undefined)h(a.data[g]);else d["default"]&&h(d["default"])})});this.dirty&&this.g.trigger("dirty")},validate:function(){if(this.type.key==="/type/type")return true;var a=this;this.errors=[];this.properties().each(function(b,c){if(a.get(c)===undefined||a.get(c)===null||a.get(c)==="")b.required&&a.errors.push({property:c,message:'Property "'+b.name+'" is required'});else{var d=b.expectedTypes,g=function(h,j){if(f.include(j,typeof h))return true;if(!h.data)return true;if(h instanceof
e.Object&&f.intersect(j,h.types().keys()).length>0)return true;if(typeof h==="object"&&f.include(j,h.constructor.name.toLowerCase()))return true;return false};b.unique&&!g(a.get(c),d)&&a.errors.push({property:c,message:'Invalid type for property "'+b.name+'"'});!b.unique&&!f.all(a.get(c).values(),function(h){return g(h,d)})&&a.errors.push({property:c,message:'Invalid value type for property "'+b.name+'"'})}if(b.validator)RegExp(b.validator).test(a.get(c))||a.errors.push({property:c,message:'Invalid value for property "'+
b.name+'"'})});return this.errors.length===0},get:function(a,b){if(!this.data)return null;var c=this.properties().get(a);if(!c)return null;return arguments.length===1?c.isObjectType()?c.unique?this.first(a):this.all(a):c.unique?this.value(a):this.values(a):e.Node.prototype.get.call(this,a,b)},set:function(a){var b=this;if(arguments.length===1)f.each(a,function(c,d){var g=b.properties().get(d);if(g){b.replace(g.key,g.registerValues(f.isArray(c)?c:[c],b));b.dirty=true;b.g.trigger("dirty")}});else return e.Node.prototype.set.call(this,
arguments[0],arguments[1],arguments[2])},toJSON:function(){var a=this;result={};f.each(this._properties,function(b,c){var d=a.properties().get(c);result[c]=d.isObjectType()?d.unique?a.all(c).keys()[0]:a.all(c).keys():d.unique?a.value(c):a.values(c).values()});result.type=this.types().keys();result._id=this._id;if(this._rev!==undefined)result._rev=this._rev;if(this._deleted)result._deleted=this._deleted;return result}});f.extend(e.Object.prototype,f.Events);e.Graph=f.inherits(e.Node,{constructor:function(a,
b){e.Node.call(this);this.watchers={};this.replace("objects",new e.Hash);a&&this.merge(a,b)},connect:function(a,b){if(typeof exports!=="undefined")this.adapter=new (require(__dirname+"/adapters/"+a+"_adapter"))(this,b);else{if(!e.Adapters[a])throw Error('Adapter "'+a+'" not found');this.adapter=new e.Adapters[a](this,b)}return this},connected:function(a){if(this.adapter.realtime)this.connectedCallback=a;else a()},serve:function(a){require(__dirname+"/server").initialize(a,this)},watch:function(a,
b,c){this.watchers[a]=c;this.adapter.watch(a,b,function(){})},unwatch:function(a){delete this.watchers[a];this.adapter.unwatch(a,function(){})},merge:function(a,b){var c=this;f.select(a,function(d,g){if(d.type==="/type/type"||d.type==="type"){if(!c.get("objects",g)){c.set("objects",g,new e.Type(c,g,d));c.get(g).dirty=b}return true}return false});f.select(a,function(d,g){if(d.type!=="/type/type"&&d.type!=="type"){var h=c.get("objects",g),j=f.isArray(d.type)?d.type:[d.type];if(h)h.data=d;else{h=new e.Object(c,
g,d);c.set("objects",g,h)}f.each(j,function(k){if(!c.get("objects",k))throw Error("Type '"+k+"' not found for "+g+"...");c.get("objects",k).set("objects",g,h)});c.get(g).dirty=b;return true}return false});this.objects().each(function(d){d.data&&d.build()});return this},set:function(a,b){var c=f.isArray(b.type)?b.type:[b.type];if(arguments.length===2){a=a?a:e.uuid("/"+f.last(f.last(c).split("/"))+"/");c=this.get(a)?this.get(a):new e.Object(this,a,b,true);c.data=b;c.dirty=true;c.build();this.set("objects",
a,c);return this.get("objects",a)}else return e.Node.prototype.set.call(this,arguments[0],arguments[1],arguments[2])},get:function(a){return arguments.length===1?this.get("objects",a):e.Node.prototype.get.call(this,arguments[0],arguments[1])},del:function(a){var b=this.get(a);if(b){b._deleted=true;b.dirty=true;b.properties().each(function(c,d){var g=b.all(d);g&&c.unregisterValues(g,b)});this.trigger("dirty")}},find:function(a){return this.objects().select(function(b){return e.matches(b.toJSON(),a)})},
fetch:function(a,b,c){var d=this,g=new e.Hash;if(typeof b==="function"&&typeof c==="undefined"){c=b;b={}}this.adapter.read(a,b,function(h,j){if(j){d.merge(j,false);f.each(j,function(k,i){g.set(i,d.get(i))})}h?c(h):c(null,g)})},sync:function(a){a=a||function(){};var b=this,c=b.dirtyNodes(),d=new e.Hash,g=c.select(function(h,j){if(!h.validate||h.validate&&h.validate()){d.set(j,h);return false}else return true});this.adapter.write(d.toJSON(),function(h,j){if(h)a(h);else{b.merge(j,false);d.each(function(k,
i){if(j[i]){k.dirty=false;k._rejected=false}else k._rejected=true});b.conflictedNodes().length>0&&b.trigger("conflicted");b.rejectedNodes().length>0&&b.trigger("rejected");a(g.length>0?"Some invalid nodes":null,g)}})},group:function(a,b,c){var d=new e.Collection;d.g=e.Transformers.group(this,a,b,c);return d},types:function(){return this.all("objects").select(function(a){return a.type==="/type/type"||a.type==="type"})},objects:function(){return this.all("objects").select(function(a){return a.type!==
"/type/type"&&a.type!=="type"&&a.data&&!a._deleted})},dirtyNodes:function(){return this.all("objects").select(function(a){return a.dirty&&(a.data||a instanceof e.Type)})},invalidNodes:function(){return this.all("objects").select(function(a){return a.errors&&a.errors.length>0})},conflictedNodes:function(){return this.all("objects").select(function(a){return a._conflicted})},rejectedNodes:function(){return this.all("objects").select(function(a){return a._rejected})},toJSON:function(){var a={};this.all("objects").each(function(b,
c){if(b.data||b instanceof e.Type)a[c]=b.toJSON()});return a}});f.extend(e.Graph.prototype,f.Events);e.Collection=function(a){var b=this,c={"/type/item":{type:"/type/type",properties:{}}};if(a){f.each(a.properties,function(d,g){c["/type/item"].properties[g]=d});this.g=new e.Graph(c);f.each(a.items,function(d,g){b.set(g,d)})}else this.g=new e.Graph};f.extend(e.Collection.prototype,{get:function(){return this.g.get.apply(this.g,arguments)},set:function(a,b){this.g.set(a,f.extend(b,{type:"/type/item"}))},
find:function(a){return this.g.find(a)},filter:function(a){return new e.Collection({properties:this.properties().toJSON(),items:this.find(a).toJSON()})},group:function(a,b){var c=new e.Collection;c.g=e.Transformers.group(this.g,"/type/item",a,b);return c},properties:function(){return this.g.get("objects","/type/item").all("properties")},items:function(){return this.g.objects()},toJSON:function(){return{properties:this.g.toJSON()["/type/item"].properties,items:this.g.objects().toJSON()}}})})();
(function(){var e;e=typeof exports!=="undefined"?exports:this.Data={};e.VERSION="0.4.0";var g=this._;if(!g&&typeof require!=="undefined")g=require("underscore");e.VALUE_TYPES=["string","object","number","boolean","date"];e.isValueType=function(a){return g.include(e.VALUE_TYPES,a)};e.matches=function(a,b){b=g.isArray(b)?b:[b];var c=false;g.each(b,function(d){if(!c){var f=false;g.each(d,function(h,i){if(!f){var k,l=i.match(/^([a-z_]{1,30})(=|==|!=|>|>=|<|<=|\|=|&=)?$/),j=l[1];l=l[2]||(j=="type"||g.isArray(h)?
"|=":"=");if(l==="|="){l=g.isArray(h)?h:[h];var m=g.isArray(a[j])?a[j]:[a[j]];k=false;g.each(l,function(o){if(g.include(m,o))k=true})}else if(l==="&="){l=g.isArray(h)?h:[h];m=g.isArray(a[j])?a[j]:[a[j]];k=g.intersect(m,l).length===l.length}else switch(l){case "!=":k=!g.isEqual(a[j],h);break;case ">":k=a[j]>h;break;case ">=":k=a[j]>=h;break;case "<":k=a[j]<h;break;case "<=":k=a[j]<=h;break;default:k=g.isEqual(a[j],h);break}if(!k)return f=true}});if(!f)return c=true}});return c};e.uuid=function(a){for(var b=
"0123456789abcdefghijklmnopqrstuvwxyz".split(""),c=[],d=0;d<32;d++)c[d]=b[0|Math.random()*16];return(a?a:"")+c.join("")};g.Events={bind:function(a,b){this._callbacks||(this._callbacks={});(this._callbacks[a]||(this._callbacks[a]=[])).push(b);return this},unbind:function(a,b){var c;if(a){if(c=this._callbacks)if(b){c=c[a];if(!c)return this;for(var d=0,f=c.length;d<f;d++)if(b===c[d]){c.splice(d,1);break}}else c[a]=[]}else this._callbacks={};return this},trigger:function(a){var b,c,d,f;if(!(c=this._callbacks))return this;
if(b=c[a]){d=0;for(f=b.length;d<f;d++)b[d].apply(this,Array.prototype.slice.call(arguments,1))}if(b=c.all){d=0;for(f=b.length;d<f;d++)b[d].apply(this,arguments)}return this}};var q=function(){};g.inherits=function(a,b,c){var d;d=b&&b.hasOwnProperty("constructor")?b.constructor:function(){return a.apply(this,arguments)};q.prototype=a.prototype;d.prototype=new q;b&&g.extend(d.prototype,b);c&&g.extend(d,c);d.prototype.constructor=d;d.__super__=a.prototype;return d};e.Hash=function(a){var b=this;this.data=
{};this.keyOrder=[];this.length=0;if(a instanceof Array)g.each(a,function(c,d){b.set(d,c)});else a instanceof Object&&g.each(a,function(c,d){b.set(d,c)});this.initialize&&this.initialize(attributes,options)};g.extend(e.Hash.prototype,g.Events,{clone:function(){var a=new e.Hash;a.length=this.length;g.each(this.data,function(b,c){a.data[c]=b});a.keyOrder=this.keyOrder.slice(0,this.keyOrder.length);return a},set:function(a,b,c){var d;if(a===undefined)return this;if(this.data[a])d=this.index(a);else{if(c!==
undefined){d=this.select(function(h,i,k){return k<c});var f=this.select(function(h,i,k){return k>=c});this.keyOrder=[].concat(d.keyOrder);this.keyOrder.push(a);this.keyOrder=this.keyOrder.concat(f.keyOrder)}else this.keyOrder.push(a);d=this.length;this.length+=1}this.data[a]=b;this[d]=this.data[a];this.trigger("set",a);return this},del:function(a){if(this.data[a]){var b=this.length,c=this.index(a);delete this.data[a];this.keyOrder.splice(c,1);Array.prototype.splice.call(this,c,1);this.length=b-1;
this.trigger("del",a)}return this},get:function(a){return this.data.hasOwnProperty(a)?this.data[a]:undefined},at:function(a){return this.data[this.keyOrder[a]]},first:function(){return this.at(0)},range:function(a,b){for(var c=new e.Hash,d=a;d<=b;d++)c.set(this.key(d),this.at(d));return c},rest:function(a){return this.range(a,this.length-1)},last:function(){return this.at(this.length-1)},key:function(a){return this.keyOrder[a]},index:function(a){return this.keyOrder.indexOf(a)},each:function(a){var b=
this;g.each(this.keyOrder,function(c,d){a.call(b,b.data[c],c,d)});return this},values:function(){var a=[];this.each(function(b){a.push(b)});return a},keys:function(){return g.clone(this.keyOrder)},toArray:function(){var a=[];this.each(function(b,c){a.push({key:c,value:b})});return a},toJSON:function(){var a={};this.each(function(b,c){a[c]=b.toJSON?b.toJSON():b});return a},map:function(a){var b=this.clone(),c=this;b.each(function(d,f,h){b.data[c.key(h)]=a.call(b,d)});return b},select:function(a){var b=
new e.Hash,c=this;this.each(function(d,f,h){a.call(c,d,f,h)&&b.set(f,d)});return b},sort:function(a){var b=this.clone();sortedKeys=b.toArray().sort(a);b.keyOrder=g.map(sortedKeys,function(c){return c.key});return b},intersect:function(a){var b=this,c=new e.Hash;if(a.length<b.length){b=a;a=this}b.each(function(d,f){a.get(f)&&c.set(f,d)});return c},union:function(a){var b=new e.Hash;this.each(function(c,d){b.set(d,c)});a.each(function(c,d){b.get(d)||b.set(d,c)});return b},difference:function(a){result=
new e.Hash;this.each(function(b,c){a.get(c)||result.set(c,b)});return result}});e.Comparators={};e.Comparators.ASC=function(a,b){return a.value===b.value?0:a.value<b.value?-1:1};e.Comparators.DESC=function(a,b){return a.value===b.value?0:a.value>b.value?-1:1};e.Aggregators={};e.Aggregators.SUM=function(a){var b=0;a.each(function(c){if(g.isNumber(c))b+=c});return b};e.Aggregators.MIN=function(a){var b=Infinity;a.each(function(c){if(g.isNumber(c)&&c<b)b=c});return b};e.Aggregators.MAX=function(a){var b=
-Infinity;a.each(function(c){if(g.isNumber(c)&&c>b)b=c});return b};e.Aggregators.AVG=function(a){var b=0,c=0;a.each(function(d){if(g.isNumber(d)){b+=d;c+=1}});return c===0?0:b/c};e.Aggregators.COUNT=function(a){return a.length};e.Modifiers={};e.Modifiers.DEFAULT=function(a){return a};e.Modifiers.MONTH=function(a){return a.getMonth()};e.Modifiers.QUARTER=function(a){return Math.floor(a.getMonth()/3)+1};e.Transformers={group:function(a,b,c,d){function f(j){var m=new e.Hash;g.each(c,function(r,n){var p=
k[c[n]].get(j[n]).referencedObjects;m=n===0?m.union(p):m.intersect(p)});if(j.length===0)m=a.objects();if(m.length===0)return null;var o={type:b._id};g.each(i[b._id].properties,function(r,n){if(g.include(c,n))o[n]=j[g.indexOf(c,n)];else{var p=m.map(function(s){return s.get(d[n].property||n)});o[n]=(d[n].aggregator||e.Aggregators.SUM)(p)}});return o}function h(j,m){if(j===c.length-1){var o=f(m);o&&l.set(m.join("::"),o)}else{j+=1;k[c[j]].each(function(r,n){h(j,m.concat([n]))})}}var i={};b=a.get(b);var k=
{};i[b._id]={type:"/type/type",properties:{},indexes:b.indexes};g.each(c,function(j){i[b._id].properties[j]=b.properties().get(j).toJSON()});g.each(d,function(j,m){var o=b.properties().get(j.property||m).toJSON();if(j.name)o.name=j.name;i[b._id].properties[m]=o});var l=new e.Graph(i);g.each(c,function(j){k[j]=b.properties().get(j).all("values")});h(-1,[]);return l}};e.Node=function(a){this.nodeId=e.Node.generateId();if(a)this.val=a.value;this._properties={};this.initialize&&this.initialize(a)};e.Node.nodeCount=
0;e.Node.generateId=function(){return e.Node.nodeCount+=1};g.extend(e.Node.prototype,g.Events,{identity:function(){return this.nodeId},replace:function(a,b){this._properties[a]=b},set:function(a,b,c){this._properties[a]||(this._properties[a]=new e.Hash);this._properties[a].set(b,c instanceof e.Node?c:new e.Node({value:c}));return this},get:function(a,b){if(b!==undefined&&this._properties[a]!==undefined)return this._properties[a].get(b)},all:function(a){return this._properties[a]},first:function(a){return(a=
this._properties[a])?a.first():null},value:function(a){return this.values(a).first()},values:function(a){if(!this.all(a))return new e.Hash;return this.all(a).map(function(b){return b.val})}});e.Adapter=function(a){this.config=a};e.Adapters={};e.Property=g.inherits(e.Node,{constructor:function(a,b,c){e.Node.call(this);this._id=this.key=b;this.type=a;this.unique=c.unique;this.name=c.name;this.meta=c.meta||{};this.validator=c.validator;this.required=c.required;this["default"]=c["default"];this.expectedTypes=
g.isArray(c.type)?c.type:[c.type];this.replace("values",new e.Hash)},isValueType:function(){return e.isValueType(this.expectedTypes[0])},isObjectType:function(){return!this.isValueType()},registerValues:function(a,b){var c=this,d=new e.Hash;g.each(a,function(f,h){if(f!==undefined){var i;if(c.isValueType()&&c.expectedTypes[0]==="object"){i=new e.Node({value:f});d.set(h,i)}else{if(b.all(c.key))i=b.all(c.key).get(f);if(!i){i=c.get("values",f);if(!i){if(c.isObjectType()){if(typeof f==="object")f=c.type.g.set(null,
f)._id;i=c.type.g.get("nodes",f);if(!i){i=new e.Object(c.type.g,f);c.type.g.set("nodes",f,i)}}else{i=new e.Node({value:f});i.referencedObjects=new e.Hash}c.set("values",f,i)}i.referencedObjects.set(b._id,b)}d.set(f,i)}}});b.all(c.key)&&this.unregisterValues(b.all(c.key).difference(d),b);return d},unregisterValues:function(a,b){var c=this;a.each(function(d,f){d.referencedObjects&&d.referencedObjects.length>1?d.referencedObjects.del(b._id):c.all("values").del(f)})},aggregate:function(a){return a(this.values("values"))},
toJSON:function(){return{name:this.name,type:this.expectedTypes,unique:this.unique,meta:this.meta,validator:this.validator,required:this.required,"default":this["default"]}}});e.Type=g.inherits(e.Node,{constructor:function(a,b,c){var d=this;e.Node.call(this);this.g=a;this._id=this.key=b;this._rev=c._rev;this._conflicted=c._conflicted;this.type=c.type;this.name=c.name;this.meta=c.meta||{};this.indexes=c.indexes;d.replace("properties",new e.Hash);g.each(c.properties,function(f,h){d.set("properties",
h,new e.Property(d,h,f))})},properties:function(){return this.all("properties")},objects:function(){return this.all("nodes")},toJSON:function(){var a={_id:this._id,type:"/type/type",name:this.name,properties:{}};if(this._rev)a._rev=this._rev;if(this.meta&&g.keys(this.meta).length>0)a.meta=this.meta;if(this.indexes&&g.keys(this.indexes).length>0)a.indexes=this.indexes;this.all("properties").each(function(b){var c=a.properties[b.key]={name:b.name,unique:b.unique,type:b.expectedTypes,required:b.required?
true:false};if(b["default"])c["default"]=b["default"];if(b.validator)c.validator=b.validator;if(b.meta&&g.keys(b.meta).length>0)c.meta=b.meta});return a}});e.Object=g.inherits(e.Node,{constructor:function(a,b,c){e.Node.call(this);this.g=a;this._id=this.key=b;this.html_id=b.replace(/\//g,"_");this._dirty=true;this.errors=[];this._types=new e.Hash;this.referencedObjects=new e.Hash;if(c)this.data=c},types:function(){return this._types},toString:function(){return this.get("name")||this.val||this._id},
properties:function(){var a=new e.Hash;this._types.each(function(b){b.all("properties").each(function(c){a.set(c.key,c)})});return a},build:function(){var a=this,b=g.isArray(this.data.type)?this.data.type:[this.data.type];if(!this.data)throw Error("Object has no data, and cannot be built");this._rev=this.data._rev;this._conflicted=this.data._conflicted;this._deleted=this.data._deleted;this.type=this.g.get("nodes",g.last(b));g.each(b,function(c){a._types.set(c,a.g.get("nodes",c));a._types.get(c).all("properties").each(function(d,
f){function h(i){i=g.isArray(i)?i:[i];a.replace(d.key,d.registerValues(i,a))}if(a.data[f]!==undefined)h(a.data[f]);else d["default"]&&h(d["default"])})});this._dirty&&this.g.trigger("dirty")},validate:function(){if(this.type.key==="/type/type")return true;var a=this;this.errors=[];this.properties().each(function(b,c){if(a.get(c)===undefined||a.get(c)===null||a.get(c)==="")b.required&&a.errors.push({property:c,message:'Property "'+b.name+'" is required'});else{var d=b.expectedTypes,f=function(h,i){if(g.include(i,
typeof h))return true;if(!h.data)return true;if(h instanceof e.Object&&g.intersect(i,h.types().keys()).length>0)return true;if(typeof h==="object"&&g.include(i,h.constructor.name.toLowerCase()))return true;return false};b.unique&&!f(a.get(c),d)&&a.errors.push({property:c,message:'Invalid type for property "'+b.name+'"'});!b.unique&&!g.all(a.get(c).values(),function(h){return f(h,d)})&&a.errors.push({property:c,message:'Invalid value type for property "'+b.name+'"'})}if(b.validator)RegExp(b.validator).test(a.get(c))||
a.errors.push({property:c,message:'Invalid value for property "'+b.name+'"'})});return this.errors.length===0},get:function(a,b){if(!this.data)return null;var c=this.properties().get(a);if(!c)return null;return arguments.length===1?c.isObjectType()?c.unique?this.first(a):this.all(a):c.unique?this.value(a):this.values(a):e.Node.prototype.get.call(this,a,b)},set:function(a){var b=this;if(arguments.length===1)g.each(a,function(c,d){var f=b.properties().get(d);if(f){b.replace(f.key,f.registerValues(g.isArray(c)?
c:[c],b));b._dirty=true;b.g.trigger("dirty")}});else return e.Node.prototype.set.call(this,arguments[0],arguments[1],arguments[2])},toJSON:function(){var a=this;result={};g.each(this._properties,function(b,c){var d=a.properties().get(c);result[c]=d.isObjectType()?d.unique?a.all(c).keys()[0]:a.all(c).keys():d.unique?a.value(c):a.values(c).values()});result.type=this.types().keys();result._id=this._id;if(this._rev!==undefined)result._rev=this._rev;if(this._deleted)result._deleted=this._deleted;return result}});
g.extend(e.Object.prototype,g.Events);e.Graph=g.inherits(e.Node,{constructor:function(a,b){e.Node.call(this);this.watchers={};this.replace("nodes",new e.Hash);a&&this.merge(a,b)},connect:function(a,b){if(typeof exports!=="undefined")this.adapter=new (require(__dirname+"/adapters/"+a+"_adapter"))(this,b);else{if(!e.Adapters[a])throw Error('Adapter "'+a+'" not found');this.adapter=new e.Adapters[a](this,b)}return this},connected:function(a){if(this.adapter.realtime)this.connectedCallback=a;else a()},
serve:function(a){require(__dirname+"/server").initialize(a,this)},watch:function(a,b,c){this.watchers[a]=c;this.adapter.watch(a,b,function(){})},unwatch:function(a){delete this.watchers[a];this.adapter.unwatch(a,function(){})},empty:function(){var a=this;g.each(this.objects().keys(),function(b){a.del(b);a.all("nodes").del(b)})},merge:function(a,b){var c=this;g.select(a,function(f,h){if(f.type==="/type/type"||f.type==="type"){if(!c.get("nodes",h)){c.set("nodes",h,new e.Type(c,h,f));c.get(h)._dirty=
b}return true}return false});var d=g.select(a,function(f,h){if(f.type!=="/type/type"&&f.type!=="type"){var i=c.get("nodes",h),k=g.isArray(f.type)?f.type:[f.type];if(i)i.data=f;else{i=new e.Object(c,h,f);c.set("nodes",h,i)}g.each(k,function(l){if(!c.get("nodes",l))throw Error("Type '"+l+"' not found for "+h+"...");c.get("nodes",l).set("nodes",h,i)});c.get(h)._dirty=b;if(!f._id)f._id=h;return true}return false});g.each(d,function(f){f=c.get(f._id);f.data&&f.build()});return this},set:function(a){if(arguments.length===
2)a=g.extend(arguments[1],{_id:arguments[0]});var b=g.isArray(a.type)?a.type:[a.type];if(arguments.length<=2){a._id=a._id?a._id:e.uuid("/"+g.last(g.last(b).split("/"))+"/");b=this.get(a._id)?this.get(a._id):new e.Object(this,a._id,g.clone(a),true);b.data=a;b._dirty=true;b.build();this.set("nodes",a._id,b);return b}else return e.Node.prototype.set.call(this,arguments[0],arguments[1],arguments[2])},get:function(a){return arguments.length===1?this.get("nodes",a):e.Node.prototype.get.call(this,arguments[0],
arguments[1])},del:function(a){var b=this.get(a);if(b){b._deleted=true;b._dirty=true;b.properties().each(function(c,d){var f=b.all(d);f&&c.unregisterValues(f,b)});this.trigger("dirty")}},find:function(a){return this.objects().select(function(b){return e.matches(b.toJSON(),a)})},fetch:function(a,b,c){var d=this,f=new e.Hash;if(typeof b==="function"&&typeof c==="undefined"){c=b;b={}}this.adapter.read(a,b,function(h,i){if(i){d.merge(i,false);g.each(i,function(k,l){f.set(l,d.get(l))})}h?c(h):c(null,f)})},
sync:function(a){a=a||function(){};var b=this,c=b.dirtyNodes(),d=new e.Hash;c.select(function(f,h){if(!f.validate||f.validate&&f.validate())d.set(h,f)});this.adapter.write(d.toJSON(),function(f,h){if(f)return a(f);b.merge(h,false);d.each(function(k,l){if(h[l]){k._dirty=false;k._rejected=false}else k._rejected=true});b.invalidNodes().length>0&&b.trigger("invalid");b.conflictedNodes().length>0&&b.trigger("conflicted");b.rejectedNodes().length>0&&b.trigger("rejected");var i=b.invalidNodes().union(b.conflictedNodes()).union(b.rejectedNodes()).length;
a(i>0?i+" unsaved nodes":null)})},group:function(a,b,c){var d=new e.Collection;d.g=e.Transformers.group(this,a,b,c);return d},types:function(){return this.all("nodes").select(function(a){return a.type==="/type/type"||a.type==="type"})},objects:function(){return this.all("nodes").select(function(a){return a.type!=="/type/type"&&a.type!=="type"&&a.data&&!a._deleted})},dirtyNodes:function(){return this.all("nodes").select(function(a){return a._dirty&&(a.data||a instanceof e.Type)})},invalidNodes:function(){return this.all("nodes").select(function(a){return a.errors&&
a.errors.length>0})},conflictedNodes:function(){return this.all("nodes").select(function(a){return a._conflicted})},rejectedNodes:function(){return this.all("nodes").select(function(a){return a._rejected})},toJSON:function(){var a={};this.all("nodes").each(function(b,c){if(b.data||b instanceof e.Type)a[c]=b.toJSON()});return a}});g.extend(e.Graph.prototype,g.Events);e.Collection=function(a){var b=this,c={"/type/item":{type:"/type/type",properties:{}}};if(a)c["/type/item"].indexes=a.indexes||{};if(a){g.each(a.properties,
function(d,f){c["/type/item"].properties[f]=d});this.g=new e.Graph(c);g.each(a.items,function(d,f){b.set(f,d)})}else this.g=new e.Graph};g.extend(e.Collection.prototype,{get:function(){return this.g.get.apply(this.g,arguments)},set:function(a,b){this.g.set(a,g.extend(b,{type:"/type/item"}))},find:function(a){a["type|="]="/type/item";return this.g.find(a)},filter:function(a){return new e.Collection({properties:this.properties().toJSON(),items:this.find(a).toJSON()})},group:function(a,b){var c=new e.Collection;
c.g=e.Transformers.group(this.g,"/type/item",a,b);return c},properties:function(){return this.g.get("nodes","/type/item").all("properties")},items:function(){return this.g.objects()},indexes:function(){return this.g.get("/type/item").indexes},toJSON:function(){return{properties:this.g.toJSON()["/type/item"].properties,items:this.g.objects().toJSON()}}})})();

@@ -10,8 +10,4 @@ var fs = require('fs');

var graph = new Data.Graph(seed, true);
var graph = new Data.Graph(seed, true).connect('couch', { url: config.couchdb_url });
// Setup Data.Adapter
graph.setAdapter('couch', { url: config.couchdb_url });
if (process.argv[2] == "--flush") {

@@ -18,0 +14,0 @@ graph.adapter.flush(function(err) {

@@ -11,3 +11,3 @@ {

"main" : "index",
"version" : "0.3.0"
"version" : "0.4.0"
}

@@ -25,3 +25,4 @@ var _ = require('underscore');

query = JSON.parse(req.query.qry),
options = JSON.parse(req.query.options)
options = JSON.parse(req.query.options);
graph.adapter.read(JSON.parse(req.query.qry), JSON.parse(req.query.options), function(err, g) {

@@ -28,0 +29,0 @@ err ? res.send(callback+"({\"error\": "+JSON.stringify(err)+"});")

@@ -154,2 +154,13 @@ // Data.js — A utility belt for data manipulation

test("Data.Hash#range", function() {
items.set("ch", "Switzerland");
items.set("uk", "United Kingdom");
var range = items.range(0,1);
ok(range.length == 2);
ok(range.at(0) === "Austria");
ok(range.at(1) === "Germany");
});
test("Data.Hash#sort", function() {

@@ -258,2 +269,13 @@ items.set("ch", "Switzerland");

test("Only consider own properties", function() {
var hsh = new Data.Hash();
ok(hsh.get('toString') === undefined);
ok(hsh.get('toLocaleString') === undefined);
ok(hsh.get('watch') === undefined);
ok(hsh.get('hasOwnProperty') === undefined);
});
test("Data.Hash Events", function() {

@@ -405,3 +427,2 @@ persons = new Data.Hash();

module("Data.Graph", {

@@ -429,3 +450,3 @@ setup: function() {

documentType = graph.get('objects', '/type/document');
ok(documentType.all('properties').length === 4);
ok(documentType.all('properties').length === 5);
ok(documentType.key === '/type/document');

@@ -533,4 +554,4 @@ ok(documentType.name === 'Document');

test("Set new nodes on the graph", function() {
var substance = graph.set('/document/substance', {
var substance = graph.set({
"_id": "/document/substance",
"type": "/type/document",

@@ -548,3 +569,2 @@ "title": "Substance Introduction",

test("Set value properties of existing nodes", function() {

@@ -663,11 +683,20 @@ // Value properties

test("grouping", function() {
var languages = c.group(["official_language"], {
'area': { aggregator: Data.Aggregators.SUM, name: "Total Area" },
'area_total': { aggregator: Data.Aggregators.SUM, name: "Total Area", property: "area" },
'area_avg': {aggregator: Data.Aggregators.AVG, name: "Average Area", property: "area" },
'population': { aggregator: Data.Aggregators.AVG, name: "Average Population" }
});
ok(languages.items().get('German Language').get('population') === 45209450);
ok(languages.items().get('English Language').get('area') === 10071495);
ok(languages.items().get('English Language').get('area_total') === 10071495);
// Deal with empty group key
var onegroup = c.group([], {
'area_total': { aggregator: Data.Aggregators.SUM, name: "Total Area", property: "area" },
'area_avg': {aggregator: Data.Aggregators.AVG, name: "Average Area", property: "area" },
'population': { aggregator: Data.Aggregators.MIN, name: "Smallest Population" }
});
ok(onegroup.items().first().get('population') === 8356700)
});

@@ -674,0 +703,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc