correct indents on model.js with gg=G

This commit is contained in:
James Casbon
2012-01-29 16:20:51 +00:00
parent 9eeb4ab97a
commit b3a71e82cc
2 changed files with 736 additions and 736 deletions

View File

@@ -3,420 +3,420 @@ this.recline = this.recline || {};
// Models module following classic module pattern // Models module following classic module pattern
recline.Model = function($) { recline.Model = function($) {
var my = {}; var my = {};
// A Dataset model. // A Dataset model.
// //
// Other than standard list of Backbone attributes it has two important attributes: // Other than standard list of Backbone attributes it has two important attributes:
// //
// * currentDocuments: a DocumentList containing the Documents we have currently loaded for viewing (you update currentDocuments by calling getRows) // * currentDocuments: a DocumentList containing the Documents we have currently loaded for viewing (you update currentDocuments by calling getRows)
// * docCount: total number of documents in this dataset (obtained on a fetch for this Dataset) // * docCount: total number of documents in this dataset (obtained on a fetch for this Dataset)
my.Dataset = Backbone.Model.extend({ my.Dataset = Backbone.Model.extend({
__type__: 'Dataset', __type__: 'Dataset',
initialize: function() { initialize: function() {
this.currentDocuments = new my.DocumentList(); this.currentDocuments = new my.DocumentList();
this.docCount = null; this.docCount = null;
}, },
// AJAX method with promise API to get rows (documents) from the backend. // AJAX method with promise API to get rows (documents) from the backend.
// //
// Resulting DocumentList are used to reset this.currentDocuments and are // Resulting DocumentList are used to reset this.currentDocuments and are
// also returned. // also returned.
// //
// :param numRows: passed onto backend getDocuments. // :param numRows: passed onto backend getDocuments.
// :param start: passed onto backend getDocuments. // :param start: passed onto backend getDocuments.
// //
// this does not fit very well with Backbone setup. Backbone really expects you to know the ids of objects your are fetching (which you do in classic RESTful ajax-y world). But this paradigm does not fill well with data set up we have here. // this does not fit very well with Backbone setup. Backbone really expects you to know the ids of objects your are fetching (which you do in classic RESTful ajax-y world). But this paradigm does not fill well with data set up we have here.
// This also illustrates the limitations of separating the Dataset and the Backend // This also illustrates the limitations of separating the Dataset and the Backend
getDocuments: function(numRows, start) { getDocuments: function(numRows, start) {
var self = this; var self = this;
var dfd = $.Deferred(); var dfd = $.Deferred();
this.backend.getDocuments(this.id, numRows, start).then(function(rows) { this.backend.getDocuments(this.id, numRows, start).then(function(rows) {
var docs = _.map(rows, function(row) { var docs = _.map(rows, function(row) {
return new my.Document(row); return new my.Document(row);
});
self.currentDocuments.reset(docs);
dfd.resolve(self.currentDocuments);
}); });
self.currentDocuments.reset(docs);
dfd.resolve(self.currentDocuments);
});
return dfd.promise();
},
toTemplateJSON: function() {
var data = this.toJSON();
data.docCount = this.docCount;
return data;
}
});
my.Document = Backbone.Model.extend({
__type__: 'Document'
});
my.DocumentList = Backbone.Collection.extend({
__type__: 'DocumentList',
// webStore: new WebStore(this.url),
model: my.Document
});
// Backends section
// ================
my.setBackend = function(backend) {
Backbone.sync = backend.sync;
};
// Backend which just caches in memory
//
// Does not need to be a backbone model but provides some conveniences
my.BackendMemory = Backbone.Model.extend({
// Initialize a Backend with a local in-memory dataset.
//
// NB: We can handle one and only one dataset at a time.
//
// :param dataset: the data for a dataset on which operations will be
// performed. Its form should be a hash with metadata and data
// attributes.
//
// - metadata: hash of key/value attributes of any kind (but usually with title attribute)
// - data: hash with 2 keys:
// - headers: list of header names/labels
// - rows: list of hashes, each hash being one row. A row *must* have an id attribute which is unique.
//
// Example of data:
//
// {
// headers: ['x', 'y', 'z']
// , rows: [
// {id: 0, x: 1, y: 2, z: 3}
// , {id: 1, x: 2, y: 4, z: 6}
// ]
// };
initialize: function(dataset) {
// deep copy
this._datasetAsData = $.extend(true, {}, dataset);
_.bindAll(this, 'sync');
},
getDataset: function() {
var dataset = new my.Dataset({
id: this._datasetAsData.metadata.id
});
// this is a bit weird but problem is in sync this is set to parent model object so need to give dataset a reference to backend explicitly
dataset.backend = this;
return dataset;
},
sync: function(method, model, options) {
var self = this;
if (method === "read") {
var dfd = $.Deferred();
// this switching on object type is rather horrible
// think may make more sense to do work in individual objects rather than in central Backbone.sync
if (model.__type__ == 'Dataset') {
var dataset = model;
var rawDataset = this._datasetAsData;
dataset.set(rawDataset.metadata);
dataset.set({
headers: rawDataset.data.headers
});
dataset.docCount = rawDataset.data.rows.length;
dfd.resolve(dataset);
}
return dfd.promise(); return dfd.promise();
} else if (method === 'update') { },
var dfd = $.Deferred();
if (model.__type__ == 'Document') { toTemplateJSON: function() {
_.each(this._datasetAsData.data.rows, function(row, idx) { var data = this.toJSON();
if(row.id === model.id) { data.docCount = this.docCount;
self._datasetAsData.data.rows[idx] = model.toJSON(); return data;
}
});
my.Document = Backbone.Model.extend({
__type__: 'Document'
});
my.DocumentList = Backbone.Collection.extend({
__type__: 'DocumentList',
// webStore: new WebStore(this.url),
model: my.Document
});
// Backends section
// ================
my.setBackend = function(backend) {
Backbone.sync = backend.sync;
};
// Backend which just caches in memory
//
// Does not need to be a backbone model but provides some conveniences
my.BackendMemory = Backbone.Model.extend({
// Initialize a Backend with a local in-memory dataset.
//
// NB: We can handle one and only one dataset at a time.
//
// :param dataset: the data for a dataset on which operations will be
// performed. Its form should be a hash with metadata and data
// attributes.
//
// - metadata: hash of key/value attributes of any kind (but usually with title attribute)
// - data: hash with 2 keys:
// - headers: list of header names/labels
// - rows: list of hashes, each hash being one row. A row *must* have an id attribute which is unique.
//
// Example of data:
//
// {
// headers: ['x', 'y', 'z']
// , rows: [
// {id: 0, x: 1, y: 2, z: 3}
// , {id: 1, x: 2, y: 4, z: 6}
// ]
// };
initialize: function(dataset) {
// deep copy
this._datasetAsData = $.extend(true, {}, dataset);
_.bindAll(this, 'sync');
},
getDataset: function() {
var dataset = new my.Dataset({
id: this._datasetAsData.metadata.id
});
// this is a bit weird but problem is in sync this is set to parent model object so need to give dataset a reference to backend explicitly
dataset.backend = this;
return dataset;
},
sync: function(method, model, options) {
var self = this;
if (method === "read") {
var dfd = $.Deferred();
// this switching on object type is rather horrible
// think may make more sense to do work in individual objects rather than in central Backbone.sync
if (model.__type__ == 'Dataset') {
var dataset = model;
var rawDataset = this._datasetAsData;
dataset.set(rawDataset.metadata);
dataset.set({
headers: rawDataset.data.headers
});
dataset.docCount = rawDataset.data.rows.length;
dfd.resolve(dataset);
} }
}); return dfd.promise();
dfd.resolve(model); } else if (method === 'update') {
} var dfd = $.Deferred();
return dfd.promise(); if (model.__type__ == 'Document') {
} else if (method === 'delete') { _.each(this._datasetAsData.data.rows, function(row, idx) {
var dfd = $.Deferred(); if(row.id === model.id) {
if (model.__type__ == 'Document') { self._datasetAsData.data.rows[idx] = model.toJSON();
this._datasetAsData.data.rows = _.reject(this._datasetAsData.data.rows, function(row) { }
return (row.id === model.id); });
}); dfd.resolve(model);
dfd.resolve(model); }
} return dfd.promise();
return dfd.promise(); } else if (method === 'delete') {
} else { var dfd = $.Deferred();
alert('Not supported: sync on BackendMemory with method ' + method + ' and model ' + model); if (model.__type__ == 'Document') {
} this._datasetAsData.data.rows = _.reject(this._datasetAsData.data.rows, function(row) {
}, return (row.id === model.id);
getDocuments: function(datasetId, numRows, start) { });
if (start === undefined) { dfd.resolve(model);
start = 0; }
} return dfd.promise();
if (numRows === undefined) { } else {
numRows = 10; alert('Not supported: sync on BackendMemory with method ' + method + ' and model ' + model);
} }
var dfd = $.Deferred(); },
rows = this._datasetAsData.data.rows; getDocuments: function(datasetId, numRows, start) {
var results = rows.slice(start, start+numRows); if (start === undefined) {
dfd.resolve(results); start = 0;
return dfd.promise(); }
} if (numRows === undefined) {
}); numRows = 10;
}
// Webstore Backend for connecting to the Webstore
//
// Initializing model argument must contain a url attribute pointing to
// relevant Webstore table.
//
// Designed to only attach to one dataset and one dataset only ...
// Could generalize to support attaching to different datasets
my.BackendWebstore = Backbone.Model.extend({
getDataset: function(id) {
var dataset = new my.Dataset({
id: id
});
dataset.backend = this;
return dataset;
},
sync: function(method, model, options) {
if (method === "read") {
// this switching on object type is rather horrible
// think may make more sense to do work in individual objects rather than in central Backbone.sync
if (this.__type__ == 'Dataset') {
var dataset = this;
// get the schema and return
var base = this.backend.get('url');
var schemaUrl = base + '/schema.json';
var jqxhr = $.ajax({
url: schemaUrl,
dataType: 'jsonp',
jsonp: '_callback'
});
var dfd = $.Deferred(); var dfd = $.Deferred();
jqxhr.then(function(schema) { rows = this._datasetAsData.data.rows;
headers = _.map(schema.data, function(item) { var results = rows.slice(start, start+numRows);
return item.name; dfd.resolve(results);
});
dataset.set({
headers: headers
});
dataset.docCount = schema.count;
dfd.resolve(dataset, jqxhr);
});
return dfd.promise(); return dfd.promise();
} }
} });
},
getDocuments: function(datasetId, numRows, start) {
if (start === undefined) {
start = 0;
}
if (numRows === undefined) {
numRows = 10;
}
var base = this.get('url');
var jqxhr = $.ajax({
url: base + '.json?_limit=' + numRows,
dataType: 'jsonp',
jsonp: '_callback',
cache: true
});
var dfd = $.Deferred();
jqxhr.then(function(results) {
dfd.resolve(results.data);
});
return dfd.promise();
}
});
// DataProxy Backend for connecting to the DataProxy // Webstore Backend for connecting to the Webstore
// //
// Example initialization: // Initializing model argument must contain a url attribute pointing to
// // relevant Webstore table.
// BackendDataProxy({ //
// model: { // Designed to only attach to one dataset and one dataset only ...
// url: {url-of-data-to-proxy}, // Could generalize to support attaching to different datasets
// type: xls || csv, my.BackendWebstore = Backbone.Model.extend({
// format: json || jsonp # return format (defaults to jsonp) getDataset: function(id) {
// dataproxy: {url-to-proxy} # defaults to http://jsonpdataproxy.appspot.com var dataset = new my.Dataset({
// } id: id
// }) });
my.BackendDataProxy = Backbone.Model.extend({ dataset.backend = this;
defaults: { return dataset;
dataproxy: 'http://jsonpdataproxy.appspot.com' },
sync: function(method, model, options) {
if (method === "read") {
// this switching on object type is rather horrible
// think may make more sense to do work in individual objects rather than in central Backbone.sync
if (this.__type__ == 'Dataset') {
var dataset = this;
// get the schema and return
var base = this.backend.get('url');
var schemaUrl = base + '/schema.json';
var jqxhr = $.ajax({
url: schemaUrl,
dataType: 'jsonp',
jsonp: '_callback'
});
var dfd = $.Deferred();
jqxhr.then(function(schema) {
headers = _.map(schema.data, function(item) {
return item.name;
});
dataset.set({
headers: headers
});
dataset.docCount = schema.count;
dfd.resolve(dataset, jqxhr);
});
return dfd.promise();
}
}
},
getDocuments: function(datasetId, numRows, start) {
if (start === undefined) {
start = 0;
}
if (numRows === undefined) {
numRows = 10;
}
var base = this.get('url');
var jqxhr = $.ajax({
url: base + '.json?_limit=' + numRows,
dataType: 'jsonp',
jsonp: '_callback',
cache: true
});
var dfd = $.Deferred();
jqxhr.then(function(results) {
dfd.resolve(results.data);
});
return dfd.promise();
}
});
// DataProxy Backend for connecting to the DataProxy
//
// Example initialization:
//
// BackendDataProxy({
// model: {
// url: {url-of-data-to-proxy},
// type: xls || csv,
// format: json || jsonp # return format (defaults to jsonp)
// dataproxy: {url-to-proxy} # defaults to http://jsonpdataproxy.appspot.com
// }
// })
my.BackendDataProxy = Backbone.Model.extend({
defaults: {
dataproxy: 'http://jsonpdataproxy.appspot.com'
, type: 'csv' , type: 'csv'
, format: 'jsonp' , format: 'jsonp'
}, },
getDataset: function(id) { getDataset: function(id) {
var dataset = new my.Dataset({ var dataset = new my.Dataset({
id: id id: id
}); });
dataset.backend = this; dataset.backend = this;
return dataset; return dataset;
}, },
sync: function(method, model, options) { sync: function(method, model, options) {
if (method === "read") { if (method === "read") {
// this switching on object type is rather horrible // this switching on object type is rather horrible
// think may make more sense to do work in individual objects rather than in central Backbone.sync // think may make more sense to do work in individual objects rather than in central Backbone.sync
if (this.__type__ == 'Dataset') { if (this.__type__ == 'Dataset') {
var dataset = this; var dataset = this;
// get the schema and return // get the schema and return
var base = this.backend.get('dataproxy'); var base = this.backend.get('dataproxy');
var data = this.backend.toJSON(); var data = this.backend.toJSON();
delete data['dataproxy']; delete data['dataproxy'];
// TODO: should we cache for extra efficiency // TODO: should we cache for extra efficiency
data['max-results'] = 1; data['max-results'] = 1;
var jqxhr = $.ajax({ var jqxhr = $.ajax({
url: base url: base
, data: data , data: data
, dataType: 'jsonp' , dataType: 'jsonp'
});
var dfd = $.Deferred();
jqxhr.then(function(results) {
dataset.set({
headers: results.fields
}); });
dfd.resolve(dataset, jqxhr); var dfd = $.Deferred();
}); jqxhr.then(function(results) {
return dfd.promise(); dataset.set({
headers: results.fields
});
dfd.resolve(dataset, jqxhr);
});
return dfd.promise();
}
} else {
alert('This backend only supports read operations');
} }
} else { },
alert('This backend only supports read operations'); getDocuments: function(datasetId, numRows, start) {
} if (start === undefined) {
}, start = 0;
getDocuments: function(datasetId, numRows, start) { }
if (start === undefined) { if (numRows === undefined) {
start = 0; numRows = 10;
} }
if (numRows === undefined) { var base = this.get('dataproxy');
numRows = 10; var data = this.toJSON();
} delete data['dataproxy'];
var base = this.get('dataproxy'); data['max-results'] = numRows;
var data = this.toJSON(); var jqxhr = $.ajax({
delete data['dataproxy']; url: base
data['max-results'] = numRows; , data: data
var jqxhr = $.ajax({ , dataType: 'jsonp'
url: base // , cache: true
, data: data
, dataType: 'jsonp'
// , cache: true
}); });
var dfd = $.Deferred(); var dfd = $.Deferred();
jqxhr.then(function(results) { jqxhr.then(function(results) {
var _out = _.map(results.data, function(row) { var _out = _.map(results.data, function(row) {
var tmp = {}; var tmp = {};
_.each(results.fields, function(key, idx) { _.each(results.fields, function(key, idx) {
tmp[key] = row[idx]; tmp[key] = row[idx];
});
return tmp;
}); });
return tmp; dfd.resolve(_out);
}); });
dfd.resolve(_out); return dfd.promise();
}); }
return dfd.promise(); });
}
});
// Google spreadsheet backend // Google spreadsheet backend
my.BackendGDoc = Backbone.Model.extend({ my.BackendGDoc = Backbone.Model.extend({
getDataset: function(id) { getDataset: function(id) {
var dataset = new my.Dataset({ var dataset = new my.Dataset({
id: id id: id
}); });
dataset.backend = this; dataset.backend = this;
return dataset; return dataset;
}, },
sync: function(method, model, options) { sync: function(method, model, options) {
if (method === "read") { if (method === "read") {
console.log('fetching data from url', model.backend.get('url')); console.log('fetching data from url', model.backend.get('url'));
var dfd = $.Deferred(); var dfd = $.Deferred();
var dataset = this; var dataset = this;
$.getJSON(model.backend.get('url'), function(d) { $.getJSON(model.backend.get('url'), function(d) {
result = model.backend.gdocsToJavascript(d); result = model.backend.gdocsToJavascript(d);
model.set({'headers': result.header}); model.set({'headers': result.header});
model.backend.set({'data': result.data, 'headers': result.header}); model.backend.set({'data': result.data, 'headers': result.header});
dfd.resolve(model); dfd.resolve(model);
}) })
return dfd.promise(); } return dfd.promise(); }
},
getDocuments: function(datasetId, start, numRows) {
var dfd = $.Deferred();
var fields = this.get('headers');
// zip the field headers with the data rows to produce js objs
// TODO: factor this out as a common method with other backends
var objs = _.map(this.get('data'), function (d) {
var obj = {};
_.each(_.zip(fields, d), function (x) { obj[x[0]] = x[1]; })
return obj;
});
dfd.resolve(objs);
return dfd;
}, },
gdocsToJavascript: function(gdocsSpreadsheet) {
/*
:options: (optional) optional argument dictionary:
columnsToUse: list of columns to use (specified by header names)
colTypes: dictionary (with column names as keys) specifying types (e.g. range, percent for use in conversion).
:return: tabular data object (hash with keys: header and data).
Issues: seems google docs return columns in rows in random order and not even sure whether consistent across rows. getDocuments: function(datasetId, start, numRows) {
*/ var dfd = $.Deferred();
var options = {}; var fields = this.get('headers');
if (arguments.length > 1) {
options = arguments[1]; // zip the field headers with the data rows to produce js objs
} // TODO: factor this out as a common method with other backends
var results = { var objs = _.map(this.get('data'), function (d) {
'header': [], var obj = {};
'data': [] _.each(_.zip(fields, d), function (x) { obj[x[0]] = x[1]; })
}; return obj;
// default is no special info on type of columns });
var colTypes = {}; dfd.resolve(objs);
if (options.colTypes) { return dfd;
colTypes = options.colTypes; },
} gdocsToJavascript: function(gdocsSpreadsheet) {
// either extract column headings from spreadsheet directly, or used supplied ones /*
if (options.columnsToUse) { :options: (optional) optional argument dictionary:
// columns set to subset supplied columnsToUse: list of columns to use (specified by header names)
results.header = options.columnsToUse; colTypes: dictionary (with column names as keys) specifying types (e.g. range, percent for use in conversion).
} else { :return: tabular data object (hash with keys: header and data).
// set columns to use to be all available
if (gdocsSpreadsheet.feed.entry.length > 0) { Issues: seems google docs return columns in rows in random order and not even sure whether consistent across rows.
for (var k in gdocsSpreadsheet.feed.entry[0]) { */
if (k.substr(0, 3) == 'gsx') { var options = {};
var col = k.substr(4) if (arguments.length > 1) {
results.header.push(col); options = arguments[1];
}
var results = {
'header': [],
'data': []
};
// default is no special info on type of columns
var colTypes = {};
if (options.colTypes) {
colTypes = options.colTypes;
}
// either extract column headings from spreadsheet directly, or used supplied ones
if (options.columnsToUse) {
// columns set to subset supplied
results.header = options.columnsToUse;
} else {
// set columns to use to be all available
if (gdocsSpreadsheet.feed.entry.length > 0) {
for (var k in gdocsSpreadsheet.feed.entry[0]) {
if (k.substr(0, 3) == 'gsx') {
var col = k.substr(4)
results.header.push(col);
}
}
} }
} }
}
}
// converts non numberical values that should be numerical (22.3%[string] -> 0.223[float]) // converts non numberical values that should be numerical (22.3%[string] -> 0.223[float])
var rep = /^([\d\.\-]+)\%$/; var rep = /^([\d\.\-]+)\%$/;
$.each(gdocsSpreadsheet.feed.entry, function (i, entry) { $.each(gdocsSpreadsheet.feed.entry, function (i, entry) {
var row = []; var row = [];
for (var k in results.header) { for (var k in results.header) {
var col = results.header[k]; var col = results.header[k];
var _keyname = 'gsx$' + col; var _keyname = 'gsx$' + col;
var value = entry[_keyname]['$t']; var value = entry[_keyname]['$t'];
// if labelled as % and value contains %, convert // if labelled as % and value contains %, convert
if (colTypes[col] == 'percent') { if (colTypes[col] == 'percent') {
if (rep.test(value)) { if (rep.test(value)) {
var value2 = rep.exec(value); var value2 = rep.exec(value);
var value3 = parseFloat(value2); var value3 = parseFloat(value2);
value = value3 / 100; value = value3 / 100;
}
}
row.push(value);
} }
} results.data.push(row);
row.push(value); });
return results;
} }
results.data.push(row);
}); });
return results;
}
}); return my;
return my;
}(jQuery); }(jQuery);

View File

@@ -1,66 +1,66 @@
(function ($) { (function ($) {
module("Dataset"); module("Dataset");
test('new Dataset', function () { test('new Dataset', function () {
var datasetId = 'test-dataset'; var datasetId = 'test-dataset';
var metadata = { var metadata = {
title: 'My Test Dataset' title: 'My Test Dataset'
, name: '1-my-test-dataset' , name: '1-my-test-dataset'
, id: datasetId , id: datasetId
}; };
var indata = { var indata = {
headers: ['x', 'y', 'z'] headers: ['x', 'y', 'z']
, rows: [ , rows: [
{id: 0, x: 1, y: 2, z: 3} {id: 0, x: 1, y: 2, z: 3}
, {id: 1, x: 2, y: 4, z: 6} , {id: 1, x: 2, y: 4, z: 6}
, {id: 2, x: 3, y: 6, z: 9} , {id: 2, x: 3, y: 6, z: 9}
, {id: 3, x: 4, y: 8, z: 12} , {id: 3, x: 4, y: 8, z: 12}
, {id: 4, x: 5, y: 10, z: 15} , {id: 4, x: 5, y: 10, z: 15}
, {id: 5, x: 6, y: 12, z: 18} , {id: 5, x: 6, y: 12, z: 18}
] ]
}; };
// this is all rather artificial here but would make more sense with more complex backend // this is all rather artificial here but would make more sense with more complex backend
backend = new recline.Model.BackendMemory({ backend = new recline.Model.BackendMemory({
metadata: metadata, metadata: metadata,
data: indata data: indata
}); });
recline.Model.setBackend(backend); recline.Model.setBackend(backend);
var dataset = backend.getDataset(datasetId); var dataset = backend.getDataset(datasetId);
expect(9); expect(9);
dataset.fetch().then(function(dataset) { dataset.fetch().then(function(dataset) {
equal(dataset.get('name'), metadata.name); equal(dataset.get('name'), metadata.name);
deepEqual(dataset.get('headers'), indata.headers); deepEqual(dataset.get('headers'), indata.headers);
equal(dataset.docCount, 6); equal(dataset.docCount, 6);
dataset.getDocuments(4, 2).then(function(documentList) { dataset.getDocuments(4, 2).then(function(documentList) {
deepEqual(indata.rows[2], documentList.models[0].toJSON()); deepEqual(indata.rows[2], documentList.models[0].toJSON());
}); });
dataset.getDocuments().then(function(docList) { dataset.getDocuments().then(function(docList) {
// Test getDocuments // Test getDocuments
equal(docList.length, Math.min(10, indata.rows.length)); equal(docList.length, Math.min(10, indata.rows.length));
var doc1 = docList.models[0]; var doc1 = docList.models[0];
deepEqual(doc1.toJSON(), indata.rows[0]); deepEqual(doc1.toJSON(), indata.rows[0]);
// Test UPDATA // Test UPDATA
var newVal = 10; var newVal = 10;
doc1.set({x: newVal}); doc1.set({x: newVal});
doc1.save().then(function() { doc1.save().then(function() {
equal(backend._datasetAsData.data.rows[0].x, newVal); equal(backend._datasetAsData.data.rows[0].x, newVal);
}) })
// Test Delete // Test Delete
doc1.destroy().then(function() { doc1.destroy().then(function() {
equal(backend._datasetAsData.data.rows.length, 5); equal(backend._datasetAsData.data.rows.length, 5);
equal(backend._datasetAsData.data.rows[0].x, indata.rows[1].x); equal(backend._datasetAsData.data.rows[0].x, indata.rows[1].x);
});
}); });
}); });
}); });
});
// TODO: move to fixtures // TODO: move to fixtures
var webstoreSchema = { var webstoreSchema = {
"count": 3, "count": 3,
"data": [ "data": [
{ {
"name": "__id__", "name": "__id__",
"type": "integer", "type": "integer",
@@ -81,23 +81,23 @@ var webstoreSchema = {
"type": "text", "type": "text",
"values_url": "/rufuspollock/demo/data/distinct/amount" "values_url": "/rufuspollock/demo/data/distinct/amount"
} }
], ],
"fields": [ "fields": [
{ {
"name": "type" "name": "type"
}, },
{ {
"name": "name" "name": "name"
}, },
{ {
"name": "values_url" "name": "values_url"
} }
] ]
}; };
webstoreData = { webstoreData = {
"count": null, "count": null,
"data": [ "data": [
{ {
"__id__": 1, "__id__": 1,
"amount": "100", "amount": "100",
@@ -116,357 +116,357 @@ webstoreData = {
"date": "2011-01-01", "date": "2011-01-01",
"geometry": null "geometry": null
} }
],
"fields": [
{
"name": "__id__"
},
{
"name": "date"
},
{
"name": "geometry"
},
{
"name": "amount"
}
]
};
test('Webstore Backend', function() {
var backend = new recline.Model.BackendWebstore({
url: 'http://webstore.test.ckan.org/rufuspollock/demo/data'
});
recline.Model.setBackend(backend);
dataset = backend.getDataset();
var stub = sinon.stub($, 'ajax', function(options) {
if (options.url.indexOf('schema.json') != -1) {
return {
then: function(callback) {
callback(webstoreSchema);
}
}
} else {
return {
then: function(callback) {
callback(webstoreData);
}
}
}
});
dataset.fetch().then(function(dataset) {
deepEqual(['__id__', 'date', 'geometry', 'amount'], dataset.get('headers'));
equal(3, dataset.docCount)
dataset.getDocuments().then(function(docList) {
equal(3, docList.length)
equal("2009-01-01", docList.models[0].get('date'));
});
});
$.ajax.restore();
});
var dataProxyData = {
"data": [
[
"1",
"1950-01",
"34.73"
], ],
"fields": [
{
"name": "__id__"
},
{
"name": "date"
},
{
"name": "geometry"
},
{
"name": "amount"
}
]
};
test('Webstore Backend', function() {
var backend = new recline.Model.BackendWebstore({
url: 'http://webstore.test.ckan.org/rufuspollock/demo/data'
});
recline.Model.setBackend(backend);
dataset = backend.getDataset();
var stub = sinon.stub($, 'ajax', function(options) {
if (options.url.indexOf('schema.json') != -1) {
return {
then: function(callback) {
callback(webstoreSchema);
}
}
} else {
return {
then: function(callback) {
callback(webstoreData);
}
}
}
});
dataset.fetch().then(function(dataset) {
deepEqual(['__id__', 'date', 'geometry', 'amount'], dataset.get('headers'));
equal(3, dataset.docCount)
dataset.getDocuments().then(function(docList) {
equal(3, docList.length)
equal("2009-01-01", docList.models[0].get('date'));
});
});
$.ajax.restore();
});
var dataProxyData = {
"data": [
[
"1",
"1950-01",
"34.73"
],
[ [
"2", "2",
"1950-02", "1950-02",
"34.73" "34.73"
], ],
[ [
"3", "3",
"1950-03", "1950-03",
"34.73" "34.73"
], ],
[ [
"4", "4",
"1950-04", "1950-04",
"34.73" "34.73"
], ],
[ [
"5", "5",
"1950-05", "1950-05",
"34.73" "34.73"
], ],
[ [
"6", "6",
"1950-06", "1950-06",
"34.73" "34.73"
], ],
[ [
"7", "7",
"1950-07", "1950-07",
"34.73" "34.73"
], ],
[ [
"8", "8",
"1950-08", "1950-08",
"34.73" "34.73"
], ],
[ [
"9", "9",
"1950-09", "1950-09",
"34.73" "34.73"
], ],
[ [
"10", "10",
"1950-10", "1950-10",
"34.73" "34.73"
] ]
], ],
"fields": [ "fields": [
"__id__", "__id__",
"date", "date",
"price" "price"
], ],
"length": null, "length": null,
"max_results": 10, "max_results": 10,
"url": "http://webstore.thedatahub.org/rufuspollock/gold_prices/data.csv" "url": "http://webstore.thedatahub.org/rufuspollock/gold_prices/data.csv"
}; };
test('DataProxy Backend', function() { test('DataProxy Backend', function() {
// needed only if not stubbing // needed only if not stubbing
// stop(); // stop();
var backend = new recline.Model.BackendDataProxy({ var backend = new recline.Model.BackendDataProxy({
url: 'http://webstore.thedatahub.org/rufuspollock/gold_prices/data.csv' url: 'http://webstore.thedatahub.org/rufuspollock/gold_prices/data.csv'
}); });
recline.Model.setBackend(backend); recline.Model.setBackend(backend);
dataset = backend.getDataset(); dataset = backend.getDataset();
var stub = sinon.stub($, 'ajax', function(options) { var stub = sinon.stub($, 'ajax', function(options) {
var partialUrl = 'jsonpdataproxy.appspot.com'; var partialUrl = 'jsonpdataproxy.appspot.com';
if (options.url.indexOf(partialUrl) != -1) { if (options.url.indexOf(partialUrl) != -1) {
return { return {
then: function(callback) { then: function(callback) {
callback(dataProxyData); callback(dataProxyData);
}
} }
} }
} });
});
dataset.fetch().then(function(dataset) { dataset.fetch().then(function(dataset) {
deepEqual(['__id__', 'date', 'price'], dataset.get('headers')); deepEqual(['__id__', 'date', 'price'], dataset.get('headers'));
equal(null, dataset.docCount) equal(null, dataset.docCount)
dataset.getDocuments().then(function(docList) { dataset.getDocuments().then(function(docList) {
equal(10, docList.length) equal(10, docList.length)
equal("1950-01", docList.models[0].get('date')); equal("1950-01", docList.models[0].get('date'));
// needed only if not stubbing // needed only if not stubbing
start(); start();
});
}); });
$.ajax.restore();
}); });
$.ajax.restore();
});
var sample_gdocs_spreadsheet_data = { var sample_gdocs_spreadsheet_data = {
"feed": { "feed": {
"category": [ "category": [
{ {
"term": "http://schemas.google.com/spreadsheets/2006#list", "term": "http://schemas.google.com/spreadsheets/2006#list",
"scheme": "http://schemas.google.com/spreadsheets/2006" "scheme": "http://schemas.google.com/spreadsheets/2006"
} }
], ],
"updated": {
"$t": "2010-07-12T18:32:16.200Z"
},
"xmlns": "http://www.w3.org/2005/Atom",
"xmlns$gsx": "http://schemas.google.com/spreadsheets/2006/extended",
"title": {
"$t": "Sheet1",
"type": "text"
},
"author": [
{
"name": {
"$t": "okfn.rufus.pollock"
},
"email": {
"$t": "okfn.rufus.pollock@gmail.com"
}
}
],
"openSearch$startIndex": {
"$t": "1"
},
"link": [
{
"href": "http://spreadsheets.google.com/pub?key=0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc",
"type": "text/html",
"rel": "alternate"
},
{
"href": "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values",
"type": "application/atom+xml",
"rel": "http://schemas.google.com/g/2005#feed"
},
{
"href": "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values?alt=json-in-script",
"type": "application/atom+xml",
"rel": "self"
}
],
"xmlns$openSearch": "http://a9.com/-/spec/opensearchrss/1.0/",
"entry": [
{
"category": [
{
"term": "http://schemas.google.com/spreadsheets/2006#list",
"scheme": "http://schemas.google.com/spreadsheets/2006"
}
],
"updated": { "updated": {
"$t": "2010-07-12T18:32:16.200Z" "$t": "2010-07-12T18:32:16.200Z"
}, },
"gsx$column-2": { "xmlns": "http://www.w3.org/2005/Atom",
"xmlns$gsx": "http://schemas.google.com/spreadsheets/2006/extended",
"title": {
"$t": "Sheet1",
"type": "text"
},
"author": [
{
"name": {
"$t": "okfn.rufus.pollock"
},
"email": {
"$t": "okfn.rufus.pollock@gmail.com"
}
}
],
"openSearch$startIndex": {
"$t": "1" "$t": "1"
}, },
"gsx$column-1": {
"$t": "A"
},
"title": {
"$t": "A",
"type": "text"
},
"content": {
"$t": "column-2: 1",
"type": "text"
},
"link": [ "link": [
{ {
"href": "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values/cokwr", "href": "http://spreadsheets.google.com/pub?key=0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc",
"type": "application/atom+xml", "type": "text/html",
"rel": "self" "rel": "alternate"
} },
], {
"id": { "href": "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values",
"$t": "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values/cokwr" "type": "application/atom+xml",
"rel": "http://schemas.google.com/g/2005#feed"
},
{
"href": "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values?alt=json-in-script",
"type": "application/atom+xml",
"rel": "self"
} }
}, ],
{ "xmlns$openSearch": "http://a9.com/-/spec/opensearchrss/1.0/",
"category": [ "entry": [
{
"category": [
{ {
"term": "http://schemas.google.com/spreadsheets/2006#list", "term": "http://schemas.google.com/spreadsheets/2006#list",
"scheme": "http://schemas.google.com/spreadsheets/2006" "scheme": "http://schemas.google.com/spreadsheets/2006"
} }
], ],
"updated": { "updated": {
"$t": "2010-07-12T18:32:16.200Z" "$t": "2010-07-12T18:32:16.200Z"
},
"gsx$column-2": {
"$t": "1"
},
"gsx$column-1": {
"$t": "A"
},
"title": {
"$t": "A",
"type": "text"
},
"content": {
"$t": "column-2: 1",
"type": "text"
},
"link": [
{
"href": "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values/cokwr",
"type": "application/atom+xml",
"rel": "self"
}
],
"id": {
"$t": "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values/cokwr"
}
}, },
"gsx$column-2": { {
"$t": "2" "category": [
},
"gsx$column-1": {
"$t": "b"
},
"title": {
"$t": "b",
"type": "text"
},
"content": {
"$t": "column-2: 2",
"type": "text"
},
"link": [
{
"href": "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values/cpzh4",
"type": "application/atom+xml",
"rel": "self"
}
],
"id": {
"$t": "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values/cpzh4"
}
},
{
"category": [
{ {
"term": "http://schemas.google.com/spreadsheets/2006#list", "term": "http://schemas.google.com/spreadsheets/2006#list",
"scheme": "http://schemas.google.com/spreadsheets/2006" "scheme": "http://schemas.google.com/spreadsheets/2006"
} }
], ],
"updated": { "updated": {
"$t": "2010-07-12T18:32:16.200Z" "$t": "2010-07-12T18:32:16.200Z"
},
"gsx$column-2": {
"$t": "2"
},
"gsx$column-1": {
"$t": "b"
},
"title": {
"$t": "b",
"type": "text"
},
"content": {
"$t": "column-2: 2",
"type": "text"
},
"link": [
{
"href": "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values/cpzh4",
"type": "application/atom+xml",
"rel": "self"
}
],
"id": {
"$t": "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values/cpzh4"
}
}, },
"gsx$column-2": { {
"category": [
{
"term": "http://schemas.google.com/spreadsheets/2006#list",
"scheme": "http://schemas.google.com/spreadsheets/2006"
}
],
"updated": {
"$t": "2010-07-12T18:32:16.200Z"
},
"gsx$column-2": {
"$t": "3"
},
"gsx$column-1": {
"$t": "c"
},
"title": {
"$t": "c",
"type": "text"
},
"content": {
"$t": "column-2: 3",
"type": "text"
},
"link": [
{
"href": "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values/cre1l",
"type": "application/atom+xml",
"rel": "self"
}
],
"id": {
"$t": "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values/cre1l"
}
}
],
"openSearch$totalResults": {
"$t": "3" "$t": "3"
}, },
"gsx$column-1": {
"$t": "c"
},
"title": {
"$t": "c",
"type": "text"
},
"content": {
"$t": "column-2: 3",
"type": "text"
},
"link": [
{
"href": "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values/cre1l",
"type": "application/atom+xml",
"rel": "self"
}
],
"id": { "id": {
"$t": "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values/cre1l" "$t": "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values"
} }
}
],
"openSearch$totalResults": {
"$t": "3"
}, },
"id": { "version": "1.0",
"$t": "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values" "encoding": "UTF-8"
} }
},
"version": "1.0",
"encoding": "UTF-8"
}
test("GDoc Backend", function() { test("GDoc Backend", function() {
var backend = new recline.Model.BackendGDoc({url: 'https://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values?alt=json' var backend = new recline.Model.BackendGDoc({url: 'https://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values?alt=json'
});
recline.Model.setBackend(backend);
dataset = backend.getDataset();
console.log('got gdoc dataset', dataset);
var stub = sinon.stub($, 'getJSON', function(options, cb) {
console.log('options are', options, cb);
var partialUrl = 'spreadsheets.google.com';
if (options.indexOf(partialUrl) != -1) {
cb(sample_gdocs_spreadsheet_data)
}
});
dataset.fetch().then(function(dataset) {
console.log('inside dataset:', dataset, dataset.get('headers'), dataset.get('data'));
deepEqual(['column-2', 'column-1'], dataset.get('headers'));
//equal(null, dataset.docCount)
dataset.getDocuments().then(function(docList) {
equal(3, docList.length);
console.log(docList.models[0]);
equal("A", docList.models[0].get('column-1'));
// needed only if not stubbing
start();
}); });
recline.Model.setBackend(backend);
dataset = backend.getDataset();
console.log('got gdoc dataset', dataset);
var stub = sinon.stub($, 'getJSON', function(options, cb) {
console.log('options are', options, cb);
var partialUrl = 'spreadsheets.google.com';
if (options.indexOf(partialUrl) != -1) {
cb(sample_gdocs_spreadsheet_data)
}
});
dataset.fetch().then(function(dataset) {
console.log('inside dataset:', dataset, dataset.get('headers'), dataset.get('data'));
deepEqual(['column-2', 'column-1'], dataset.get('headers'));
//equal(null, dataset.docCount)
dataset.getDocuments().then(function(docList) {
equal(3, docList.length);
console.log(docList.models[0]);
equal("A", docList.models[0].get('column-1'));
// needed only if not stubbing
start();
});
});
$.getJSON.restore();
}); });
$.getJSON.restore();
});
})(this.jQuery); })(this.jQuery);