Skip to content

Commit

Permalink
Proper value unregistration of nodes being deleted.
Browse files Browse the repository at this point in the history
  • Loading branch information
michael committed Apr 25, 2011
1 parent 96aaf0a commit 241ff64
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 94 deletions.
55 changes: 23 additions & 32 deletions data.js
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,6 @@
val = new Data.Node({value: v});
val.referencedObjects = new Data.Hash();
}

// Register value on the property
that.set('values', v, val);
}
Expand All @@ -814,15 +813,24 @@
res.set(v, val);
});

// Deregister values that are no longer used on the object
// Unregister values that are no longer used on the object
if (obj.all(that.key)) {
var removedValues = obj.all(that.key).difference(res);
removedValues.each(function(val, key) {
if (val.referencedObjects.length<=1) that.all('values').del(key);
});
this.unregisterValues(obj.all(that.key).difference(res), obj);
}
return res;
},

// Unregister values from a certain object
unregisterValues: function(values, obj) {
var that = this;
values.each(function(val, key) {
if (val.referencedObjects.length>1) {
val.referencedObjects.del(obj._id);
} else {
that.all('values').del(key);
}
});
},

// Aggregates the property's values
aggregate: function (fn) {
Expand Down Expand Up @@ -985,11 +993,8 @@
that._types.get(type).all('properties').each(function(property, key) {
function applyValue(value) {
var values = _.isArray(value) ? value : [value];

// Initialize Property
var vals = property.registerValues(values, that);
// Replace the old ones
that.replace(property.key, vals);
// Apply property values
that.replace(property.key, property.registerValues(values, that));
}

if (that.data[key] !== undefined) {
Expand Down Expand Up @@ -1021,7 +1026,6 @@

function validType(value, types) {
if (_.include(types, typeof value)) return true;

// FIXME: assumes that unloaded objects are valid properties
if (!value.data) return true;
if (value instanceof Data.Object && _.intersect(types, value.types().keys()).length>0) return true;
Expand Down Expand Up @@ -1109,7 +1113,6 @@
toJSON: function() {
var that = this;
result = {};

_.each(this._properties, function(value, key) {
var p = that.properties().get(key);
if (p.isObjectType()) {
Expand All @@ -1118,7 +1121,6 @@
result[key] = p.unique ? that.value(key) : that.values(key).values();
}
});

result['type'] = this.types().keys();
result['_id'] = this._id;
if (this._rev !== undefined) result['_rev'] = this._rev;
Expand Down Expand Up @@ -1209,35 +1211,28 @@
if (node.type !== '/type/type' && node.type !== 'type') {
var res = that.get('objects', key);
var types = _.isArray(node.type) ? node.type : [node.type];

if (!res) {
res = new Data.Object(that, key, node);
that.set('objects', key, res);
} else {
// Populate existing node with data in order to be rebuilt
res.data = node;
}

// Check for type existence
_.each(types, function(type) {
if (!that.get('objects', type)) {
throw new Error("Type '"+type+"' not found for "+key+"...");
}
that.get('objects', type).set('objects', key, res);
});

that.get(key).dirty = dirty;

return true;
}
return false;
});

// Now that all objects are registered we can build them
this.objects().each(function(r, key, index) {
if (r.data) {
r.build();
}
if (r.data) r.build();
});
return this;
},
Expand All @@ -1246,19 +1241,15 @@
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('/')) + '/');

// 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;
res.build();

this.set('objects', id, res);
return this.get('objects', id);

} else { // Delegate to Data.Node#set
return Data.Node.prototype.set.call(this, arguments[0], arguments[1], arguments[2]);
}
Expand All @@ -1281,6 +1272,10 @@
if (!node) return;
node._deleted = true;
node.dirty = true;
// Remove registered values
node.properties().each(function(p, key) {
p.unregisterValues(node.all(key), node);
});
this.trigger('dirty');
},

Expand Down Expand Up @@ -1322,7 +1317,6 @@
nodes = that.dirtyNodes();

var validNodes = new Data.Hash();
// Validate nodes
var invalidNodes = nodes.select(function(node, key) {
if (!node.validate || (node.validate && node.validate())) {
validNodes.set(key, node);
Expand Down Expand Up @@ -1431,13 +1425,10 @@
_.each(spec.properties, function(property, key) {
gspec["/type/item"].properties[key] = property;
});

this.g = new Data.Graph(gspec);
_.each(spec.items, function(item, key) {
gspec[key] = item;
gspec[key].type = "/type/item";
that.set(key, item);
});

this.g = new Data.Graph(gspec);
} else {
this.g = new Data.Graph();
}
Expand Down
69 changes: 7 additions & 62 deletions test/testsuite.js
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,7 @@ test("Set object properties of existing nodes", function() {
entities: ['/location/toronto'],
authors: 'Michael Aufreiter'
});

ok(protovis.get('entities').first() === graph.get('/location/toronto'));
ok(protovis.type.get('properties', 'entities').get('values', '/location/toronto'));
});
Expand Down Expand Up @@ -602,6 +602,12 @@ test("Proper value registration / deregistration", function() {
});

ok(values.keys().length === valueCount);

// Proper value unregistration of nodes being deleted
graph.del("/doc/unveil_introduction");
var type = graph.get('/type/document');
ok(!type.properties().get("title").all('values').get("Unveil.js Introduction"));
ok(!type.properties().get("authors").all('values').get("Lindsay Kay"));
});


Expand Down Expand Up @@ -643,8 +649,6 @@ test("grouping", function() {
'area': { aggregator: Data.Aggregators.SUM, name: "Total Area" },
'population': { aggregator: Data.Aggregators.AVG, name: "Average Population" }
});

console.log(languages.items().get('German Language').get('population'));

ok(languages.items().get('German Language').get('population') === 45209450);
ok(languages.items().get('English Language').get('area') === 10071495);
Expand Down Expand Up @@ -706,63 +710,4 @@ test("allow aggregation of property values", function() {
var population = c.properties().get("population");
ok(population.aggregate(Data.Aggregators.MIN) === 8356700);
ok(population.aggregate(Data.Aggregators.MAX) === 306108000);
});


// Data.Criterion
//-------------

// DEPRECATED. Use graph.find() instead.

module('Criterion');

var graph;
module("Data.Graph", {
setup: function() {
graph = new Data.Graph(documents_fixture);
},
teardown: function() {
delete graph;
}
});

test('Data.Criterion.operators.CONTAINS', function() {
// For value type properties
var matchedItems = Data.Criterion.operators.CONTAINS(graph, '/type/document', 'page_count', 8);

ok(matchedItems.length === 2);
ok(matchedItems.at(0).value('page_count') === 8);
ok(matchedItems.at(1).value('page_count') === 8);

var matchedItems = Data.Criterion.operators.CONTAINS(graph, '/type/document', 'title', 'Unveil.js');
ok(matchedItems.length === 1);
ok(matchedItems.at(0).value('title') === 'Unveil.js');

// For object type properties
var matchedItems = Data.Criterion.operators.CONTAINS(graph, '/type/document', 'entities', '/location/new_york');
ok(matchedItems.length === 1);
ok(matchedItems.at(0).get('entities', '/location/new_york') instanceof Data.Object);
});

test('Data.Criterion.operators.GT', function() {
// For value type properties
var matchedItems = Data.Criterion.operators.GT(graph, '/type/document', 'page_count', 10);
ok(matchedItems.length === 1);
ok(matchedItems.at(0).value('page_count') > 10);
});

test("nested criteria", function() {
// the root criterion takes it all
var criteria = new Data.Criterion('AND', '/type/document'),
filteredGraph;

var titleprop = graph.get('/type/document').get('properties', 'title');

criteria.add(new Data.Criterion('GT', '/type/document', 'page_count', 5));
criteria.add(new Data.Criterion('OR', '/type/document')
.add(new Data.Criterion('CONTAINS', '/type/document', 'title', 'Unveil.js'))
.add(new Data.Criterion('CONTAINS', '/type/document', 'title', 'Processing.js')));

filteredGraph = graph.filter(criteria);
ok(filteredGraph.find({"type|=": "/type/document"}).length === 2);
});

0 comments on commit 241ff64

Please sign in to comment.