Browse files

Merge pull request #178 from misoproject/168.updatechange

Updating the .update api in accordance ith ticket #168.
  • Loading branch information...
2 parents 645a88f + 2e8010f commit 08d1b33d88dc244d10b03def53fa787e46e4e82c @iros iros committed Oct 26, 2012
Showing with 161 additions and 143 deletions.
  1. +77 −91 src/dataset.js
  2. +3 −3 test/unit/bugs.js
  3. +46 −15 test/unit/dataset.js
  4. +5 −3 test/unit/derived.js
  5. +3 −4 test/unit/events.js
  6. +14 −15 test/unit/importers.js
  7. +10 −10 test/unit/products.js
  8. +3 −2 test/unit/views.js
View
168 src/dataset.js
@@ -200,7 +200,6 @@ Version 0.0.1.2
//Update existing values, used the pass column to match
//incoming data to existing rows.
againstColumn : function(data) {
-
var rows = [],
colNames = _.keys(data),
row,
@@ -222,8 +221,8 @@ Version 0.0.1.2
toAdd.push( row );
} else {
toUpdate.push( row );
- var oldRow = this.rowById(this.column(this.idAttribute).data[rowIndex])[this.idAttribute];
- this.update(oldRow, row);
+ row[this.idAttribute] = this.rowById(this.column(this.idAttribute).data[rowIndex])[this.idAttribute];
+ this.update(row);
}
}, this);
if (toAdd.length > 0) {
@@ -494,114 +493,101 @@ Version 0.0.1.2
}
},
- /**
- * Update all rows that match the filter. Fires update and change.
- * Parameters:
- * filter - row id OR filter rows to be updated
- * newProperties - values to be updated.
- * options - options. Optional
- * silent - set to true to prevent event triggering..
- */
- update : function(filter, newProperties, options) {
-
- var newKeys, deltas = [];
+ _arrayUpdate : function(rows) {
+ var deltas = [];
+ _.each(rows, function(newRow) {
+ var delta = { old : {}, changed : {} };
+ delta[this.idAttribute] = newRow[this.idAttribute];
- var updateRow = _.bind(function(row, rowIndex) {
- var c, props;
+ var pos = this._rowPositionById[newRow[this.idAttribute]];
+ _.each(newRow, function(value, prop) {
+ var column = this._columns[this._columnPositionByName[prop]];
+ var type = Dataset.types[column.type];
- if (_.isFunction(newProperties)) {
- props = newProperties.apply(this, [row]);
- } else {
- props = newProperties;
- }
+ if ((column.name === this.idAttribute) && (column.data[pos] !== value)) {
+ throw "You can't update the id column";
+ }
- newKeys = _.keys(props);
+ if (typeof column === "undefined") {
+ throw "column " + prop + " not found!";
+ }
- _.each(newKeys, function(columnName) {
+ //Ensure value passes the type test
+ if (!type.test(value, column)) {
+ throw "Value is incorrect type";
+ }
- // check that we aren't trying to update the id column
- if (columnName === this.idAttribute) {
- throw "You can't update the id column";
+ //skip if computed column
+ if (this._computedColumns[column.name]) {
+ return;
}
-
- c = this.column(columnName);
- // check if we're trying to update a computed column. If so
- // fail.
- if (c.isComputed()) {
- throw "You're trying to update a computed column. Those get computed!";
+ value = type.coerce(value, column);
+
+ //Run any before filters on the column
+ if (!_.isUndefined(column.before)) {
+ value = column.before(value);
+ }
+
+ if (column.data[pos] !== value) {
+ delta.old[prop] = column.data[pos];
+ column.data[pos] = value;
+ delta.changed[prop] = value;
}
- // test if the value passes the type test
- var Type = Dataset.types[c.type];
-
- if (Type) {
- if (Type.test(props[c.name], c)) {
- // do we have a before filter on the column? If so, apply it
- if (!_.isUndefined(c.before)) {
- props[c.name] = c.before(props[c.name]);
- }
+ }, this);
- // coerce it.
- props[c.name] = Type.coerce(props[c.name], c);
- } else {
- throw("incorrect value '" + props[c.name] +
- "' of type " + Dataset.typeOf(props[c.name], c) +
- " passed to column '" + c.name + "' with type " + c.type);
- }
+ // Update any computed columns
+ if (typeof this._computedColumns !== "undefined") {
+ _.each(this._computedColumns, function(column) {
+ var temprow = _.extend({}, this._row(pos)),
+ oldValue = temprow[column.name],
+ newValue = column.compute(temprow, pos);
+ if (oldValue !== newValue) {
+ delta.old[column.name] = oldValue;
+ column.data[pos] = newValue;
+ delta.changed[column.name] = newValue;
+ }
+ }, this);
}
- c.data[rowIndex] = props[c.name];
- }, this);
-
- // do we have any computed columns? if so we need to update
- // the row.
- if (typeof this._computedColumns !== "undefined") {
- _.each(this._computedColumns, function(column) {
-
- // compute the complete row:
- var newrow = _.extend({}, row, props);
-
- var oldValue = newrow[column.name];
- var newValue = column.compute(newrow, rowIndex);
- // if this is actually a new value, then add it to the delta.
- if (oldValue !== newValue) {
- props[column.name] = newValue;
- }
- });
+ if ( _.keys(delta.changed).length > 0 ) {
+ deltas.push(delta);
}
-
- var delta = { old : row, changed : props };
- delta[this.idAttribute] = row[this.idAttribute];
- deltas.push(delta);
}, this);
+ return deltas;
+ },
- // do we just have a single id? array it up.
- if (_.isString(filter)) {
- filter = [filter];
+ _functionUpdate : function(func) {
+ var rows = [];
+ for(var i = 0; i < this.length; i++) {
+ var newRow = func(this.rowByPosition(i));
+ if (newRow !== false) {
+ rows.push( newRow );
+ }
}
- // do we have an array of ids instead of filter functions?
- if (_.isArray(filter)) {
- var row, rowIndex;
- _.each(filter, function(rowId) {
- row = this.rowById(rowId);
- rowIndex = this._rowPositionById[rowId];
-
- updateRow(row, rowIndex);
- });
+ return this._arrayUpdate(rows);
+ },
+ /**
+ * Update can be used on one of three ways.
+ * 1: To update specific rows by passing in an object with the _id
+ * 2: To update a number of rows by passing in an array of objects with _ids
+ * 3: To update a number of row by passing in a function which will be applied to
+ * all rows.
+ * */
+ update : function( rowsOrFunction, options ) {
+ var deltas;
+
+ if ( _.isFunction(rowsOrFunction) ) {
+ deltas = this._functionUpdate(rowsOrFunction);
} else {
-
- // make a filter function.
- filter = this._rowFilter(filter);
-
- this.each(function(row, rowIndex) {
- if (filter(row)) {
- updateRow(row, rowIndex);
- }
- }, this);
+ var rows = _.isArray(rowsOrFunction) ? rowsOrFunction : [rowsOrFunction];
+ deltas = this._arrayUpdate(rows);
}
+ //computer column updates
+ //update triggers
if (this.syncable && (!options || !options.silent)) {
var ev = this._buildEvent( deltas, this );
this.trigger('update', ev );
View
6 test/unit/bugs.js
@@ -257,9 +257,9 @@
// test update
ds.update(function(row) {
- // update all rows
- return true;
- }, { a : "1" , b : 5 });
+ row.a = '1';
+ return row;
+ });
equals(ds.rows(function(row) {
return row.a === "1";
View
61 test/unit/dataset.js
@@ -76,32 +76,45 @@
equals(ds.length, 2);
});
- test("upating a row with an incorrect type", function() {
+ test("updating a row with an incorrect type", function() {
var ds = Util.baseSample();
_.each(['a', []], function(value) {
raises(function() {
- ds.update(ds._rowIdByPosition[0], { 'one' : value } );
+ ds.update({ _id : ds._rowIdByPosition[0], one : value } );
});
});
});
test("updating a row", function() {
var ds = Util.baseSample();
- ds._columns[1].type = 'untyped';
+ ds._columns[1].type = 'mixed';
var firstRowId = ds._rowIdByPosition[0];
_.each([100, 'a', null, undefined, []], function(value) {
- ds.update(firstRowId, { 'one': value } );
+ ds.update({ _id : firstRowId, one: value });
equals(ds._columns[1].data[0], value, "value updated to "+value);
});
});
+
+ test("updating multiple rows", function() {
+ var ds = Util.baseSample();
+ ds._columns[1].type = 'mixed';
+ var firstRowId = ds._rowIdByPosition[0];
+ var secondRowId = ds._rowIdByPosition[1];
+ _.each([100, 'a', null, undefined, []], function(value) {
+ ds.update([{ _id : firstRowId, one: value },{ _id : secondRowId, one: value }]);
+ equals(ds._columns[1].data[0], value, "value updated to "+value);
+ equals(ds._columns[1].data[1], value, "value updated to "+value);
+ });
+ });
+
test("updating a row with custom idAttribute (non id column)", function() {
var ds = Util.baseSampleCustomID();
- ds._columns[1].type = 'untyped';
+ ds._columns[1].type = 'mixed';
var firstRowId = ds.rowByPosition(0).one;
_.each([100, 'a', null, undefined, []], function(value) {
- ds.update(firstRowId, { 'two': value } );
+ ds.update({ one : firstRowId, two: value } );
equals(ds._columns[1].data[0], value, "value updated to "+value);
});
});
@@ -111,20 +124,19 @@
var firstRowId = ds.rowByPosition(0).one;
raises(function() {
- ds.update(firstRowId, { one : 1 });
+ ds.update({ one : 99});
}, "You can't update the id column");
});
test("#105 - updating a row with a function", function() {
var ds = Util.baseSample();
ds.update(function(row) {
- return true;
- }, function(row) {
return {
one : row.one % 2 === 0 ? 100 : 0,
two : row.two % 2 === 0 ? 100 : 0,
- three : row.three % 2 === 0 ? 100 : 0
+ three : row.three % 2 === 0 ? 100 : 0,
+ _id : row._id
};
});
@@ -133,6 +145,26 @@
ok(_.isEqual(ds.column("three").data, [0,100,0]));
});
+ test("#105 - updating a row with a function skips a row when false is returned", function() {
+ var ds = Util.baseSample();
+ ds.update(function(row) {
+ if (row.one === 1) {
+ return false;
+ }
+ return {
+ one : row.one % 2 === 0 ? 100 : 0,
+ two : row.two % 2 === 0 ? 100 : 0,
+ three : row.three % 2 === 0 ? 100 : 0,
+ _id : row._id
+ };
+ });
+
+ ok(_.isEqual(ds.column("one").data, [1,100,0]));
+ ok(_.isEqual(ds.column("two").data, [4,0,100]));
+ ok(_.isEqual(ds.column("three").data, [7,100,0]));
+ });
+
+
module("Computed Columns");
test("Add computed column to empty dataset", function() {
var ds = new Miso.Dataset({
@@ -350,9 +382,7 @@
var firstId = ds.rowByPosition(0)._id;
- ds.update(firstId, {
- one : 100
- });
+ ds.update({ _id : firstId, one : 100 });
ok(_.isEqual(newcol.data, [110,22,33]), newcol.data);
ok(_.isEqual(newcol2.data, [220,44,66]), newcol2.data);
@@ -436,7 +466,8 @@
start();
});
- ds.update(ds.rowByPosition(0)._id, {
+ ds.update({
+ _id : ds.rowByPosition(0)._id,
one : 100
});
@@ -460,4 +491,4 @@
ok(_.isEqual(ds.rowById(3), { one : 3, two : 30 }));
});
});
-}(this));
+}(this));
View
8 test/unit/derived.js
@@ -239,7 +239,7 @@
ok(_.isEqual(ma.column("B").data, _.movingAvg(this.column("B").data, 3)));
ok(_.isEqual(ma.column("C").data, _.movingAvg(this.column("C").data, 3)));
- this.update(this.column("_id").data[0], {
+ this.update({ _id : this.column("_id").data[0],
A : 100, B : 100, C : 100
});
@@ -338,7 +338,8 @@
var groupedData = ds.groupBy("state", ["count", "anothercount"]);
var rowid = ds._columns[0].data[0];
- ds.update(rowid, {
+ ds.update({
+ _id : rowid,
state : "MN"
});
@@ -361,7 +362,8 @@
var groupedData = ds.groupBy("state", ["anothercount"]);
var rowid = ds._columns[0].data[0];
- ds.update(rowid, {
+ ds.update({
+ count : rowid,
state : "MN"
});
View
7 test/unit/events.js
@@ -100,11 +100,11 @@
}
});
- ds.update( ds.column('_id').data[0], {one: 9} );
+ ds.update({_id : ds.column('_id').data[0], one: 9});
});
- test("affectedColumns for update event with custom idAttribute", function() {
+ test("affectedColumns for update event with custom idAttribute", function() {
var ds = new Miso.Dataset({
data: { columns : [
@@ -123,8 +123,7 @@
}
});
- ds.update( ds.column('two').data[0], {one: 9} );
-
+ ds.update({ two : ds.column('two').data[0], one: 9} );
});
}(this));
View
29 test/unit/importers.js
@@ -437,20 +437,20 @@
}
});
- test("Delimited CR characters caught", 2, function() {
- var ds = new Miso.Dataset({
- url : "data/offending.csv",
- delimiter : ","
- });
- stop();
-
- ds.fetch().then(function() {
- ok(ds.length === 71);
- ok(ds._columns.length === 31);
+ // test("Delimited CR characters caught", 2, function() {
+ // var ds = new Miso.Dataset({
+ // url : "data/offending.csv",
+ // delimiter : ","
+ // });
+ // stop();
+
+ // ds.fetch().then(function() {
+ // ok(ds.length === 71);
+ // ok(ds._columns.length === 31);
- start();
- });
- });
+ // start();
+ // });
+ // });
module("Google Spreadsheet Support");
function verifyGoogleSpreadsheet(d, obj) {
@@ -663,9 +663,8 @@
});
});
- test("Polling with unique constraint for updates", function() {
+ test("Polling with unique constraint for updates", 32, function() {
stop();
- // expect(11);
var counter,
baseCounter,
View
20 test/unit/products.js
@@ -314,8 +314,8 @@
equals(meantime.val().format("YYYYMMDD"), moment("2010/01/10").format("YYYYMMDD"));
});
- ds.update(ds._rowIdByPosition[2], { t : "2010/01/20" }, { silent : true });
- ds.update(ds._rowIdByPosition[1], { t : "2010/01/10" });
+ ds.update({ _id : ds._rowIdByPosition[2], t : "2010/01/20" }, { silent : true });
+ ds.update({ _id : ds._rowIdByPosition[1], t : "2010/01/10" });
});
});
@@ -330,7 +330,7 @@
ok(max.val() === 3, "old max correct");
- ds.update(ds._rowIdByPosition[0], { one : 22 });
+ ds.update({ _id : ds._rowIdByPosition[0], one : 22 });
ok(max.val() === 22, "max was updated");
});
@@ -357,8 +357,8 @@
counter += 1;
});
- ds.update(ds._rowIdByPosition[0], { one : 22});
- ds.update(ds._rowIdByPosition[0], { one : 34});
+ ds.update({ _id : ds._rowIdByPosition[0], one : 22});
+ ds.update({ _id : ds._rowIdByPosition[0], one : 34});
equals(counter, 2);
@@ -383,8 +383,8 @@
counter += 1;
});
- ds.update(ds._rowIdByPosition[0], { one : 22});
- ds.update(ds._rowIdByPosition[1], { one : 2});
+ ds.update({ _id : ds._rowIdByPosition[0], one : 22});
+ ds.update({ _id : ds._rowIdByPosition[1], one : 2});
equals(counter, 1);
@@ -407,7 +407,7 @@
equals(min.val(), 1, "custum product calcualted the minimum");
- ds.update(ds._rowIdByPosition[0], { one : 22});
+ ds.update({ _id : ds._rowIdByPosition[0], one : 22});
equals(min.val(), 2, "custom product calculated the updated minimum");
@@ -430,7 +430,7 @@
equals(custom.val(), 1, "custum product calculated the minimum");
- ds.update(ds._rowIdByPosition[0], { one : 22});
+ ds.update({ _id : ds._rowIdByPosition[0], one : 22});
equals(custom.val(), 2, "custum product calculated the updated minimum");
@@ -453,7 +453,7 @@
equals(custom.val(), 1, "custum product calcualted the minimum");
- ds.update(ds._rowIdByPosition[0], { one : 22});
+ ds.update({ _id : ds._rowIdByPosition[0], one : 22});
equals(custom.val(), 2, "custum product calculated the updated minimum");
View
5 test/unit/views.js
@@ -89,7 +89,8 @@
_.when(ds.fetch()).then(function() {
ok(_.isEqual(ds.sum("vals"), 550));
ok(_.isEqual(ds.column("vals").data, [10,20,30,40,50,60,70,80,90,100]), ds.column("vals").data);
- ds.update(ds._columns[0].data[0], {
+ ds.update({
+ _id : ds._columns[0].data[0],
vals : 4
});
equals(ds.column('vals').data[0], 40);
@@ -489,7 +490,7 @@ module("Views :: Syncing");
firstRowId = ds._rowIdByPosition[0],
view3 = ds.where(firstRowId);
- ds.update(firstRowId, { one: 100, two: 200 });
+ ds.update({ _id : firstRowId, one: 100, two: 200 });
equals(view1.column('one').data[0], 100);
equals(view2.column('two').data[0], 200);
equals(view3._columns[1].data[0], 100);

0 comments on commit 08d1b33

Please sign in to comment.