From b9a9e9efd4646ed19c470561707b9ece324dac32 Mon Sep 17 00:00:00 2001 From: Rufus Pollock Date: Thu, 16 Feb 2012 19:34:44 +0000 Subject: [PATCH 1/6] [test][xs]: include new view files in test index.html (fixes brokenness). --- test/index.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/index.html b/test/index.html index 3302dceb..219e2b3d 100644 --- a/test/index.html +++ b/test/index.html @@ -20,6 +20,9 @@ + + + From 57effa02aa5d25a9dcc4927dfcccbb5fc3f38953 Mon Sep 17 00:00:00 2001 From: Rufus Pollock Date: Thu, 16 Feb 2012 19:51:05 +0000 Subject: [PATCH 2/6] [whitespace][xs]: correct indentation issues introduced in b3a71e82cca77bfe24c93290dd321174c85ab3b7. --- src/backend.js | 98 ++--- src/model.js | 1 + test/model.test.js | 890 ++++++++++++++++++++++----------------------- 3 files changed, 491 insertions(+), 498 deletions(-) diff --git a/src/backend.js b/src/backend.js index ae32508e..b2676694 100644 --- a/src/backend.js +++ b/src/backend.js @@ -69,59 +69,59 @@ this.recline.Model = this.recline.Model || {}; // }; // my.BackendMemory = Backbone.Model.extend({ - sync: function(method, model, options) { - var self = this; - if (method === "read") { - var dfd = $.Deferred(); - if (model.__type__ == 'Dataset') { - var dataset = model; - dataset.set({ - headers: dataset.backendConfig.data.headers - }); - dataset.docCount = dataset.backendConfig.data.rows.length; - dfd.resolve(dataset); - } - return dfd.promise(); - } else if (method === 'update') { - var dfd = $.Deferred(); - if (model.__type__ == 'Document') { - _.each(model.backendConfig.data.rows, function(row, idx) { - if(row.id === model.id) { - model.backendConfig.data.rows[idx] = model.toJSON(); - } - }); - dfd.resolve(model); - } - return dfd.promise(); - } else if (method === 'delete') { - var dfd = $.Deferred(); - if (model.__type__ == 'Document') { - model.backendConfig.data.rows = _.reject(model.backendConfig.data.rows, function(row) { - return (row.id === model.id); - }); - dfd.resolve(model); - } - return dfd.promise(); - } else { - alert('Not supported: sync on BackendMemory with method ' + method + ' and model ' + model); - } - }, - query: function(model, queryObj) { - var numRows = queryObj.size; - var start = queryObj.offset; + sync: function(method, model, options) { + var self = this; + if (method === "read") { var dfd = $.Deferred(); - results = model.backendConfig.data.rows; - // not complete sorting! - _.each(queryObj.sort, function(item) { - results = _.sortBy(results, function(row) { - var _out = row[item[0]]; - return (item[1] == 'asc') ? _out : -1*_out; + if (model.__type__ == 'Dataset') { + var dataset = model; + dataset.set({ + headers: dataset.backendConfig.data.headers }); - }); - var results = results.slice(start, start+numRows); - dfd.resolve(results); + dataset.docCount = dataset.backendConfig.data.rows.length; + dfd.resolve(dataset); + } return dfd.promise(); + } else if (method === 'update') { + var dfd = $.Deferred(); + if (model.__type__ == 'Document') { + _.each(model.backendConfig.data.rows, function(row, idx) { + if(row.id === model.id) { + model.backendConfig.data.rows[idx] = model.toJSON(); + } + }); + dfd.resolve(model); + } + return dfd.promise(); + } else if (method === 'delete') { + var dfd = $.Deferred(); + if (model.__type__ == 'Document') { + model.backendConfig.data.rows = _.reject(model.backendConfig.data.rows, function(row) { + return (row.id === model.id); + }); + dfd.resolve(model); + } + return dfd.promise(); + } else { + alert('Not supported: sync on BackendMemory with method ' + method + ' and model ' + model); } + }, + query: function(model, queryObj) { + var numRows = queryObj.size; + var start = queryObj.offset; + var dfd = $.Deferred(); + results = model.backendConfig.data.rows; + // not complete sorting! + _.each(queryObj.sort, function(item) { + results = _.sortBy(results, function(row) { + var _out = row[item[0]]; + return (item[1] == 'asc') ? _out : -1*_out; + }); + }); + var results = results.slice(start, start+numRows); + dfd.resolve(results); + return dfd.promise(); + } }); my.backends['memory'] = new my.BackendMemory(); diff --git a/src/model.js b/src/model.js index 36d6da5e..1f5c0b8e 100644 --- a/src/model.js +++ b/src/model.js @@ -12,6 +12,7 @@ this.recline.Model = this.recline.Model || {}; my.Dataset = Backbone.Model.extend({ __type__: 'Dataset', initialize: function(options) { + console.log(options); this.currentDocuments = new my.DocumentList(); this.docCount = null; this.backend = null; diff --git a/test/model.test.js b/test/model.test.js index 1149802f..21b2c52d 100644 --- a/test/model.test.js +++ b/test/model.test.js @@ -1,16 +1,15 @@ (function ($) { +module("Dataset"); - module("Dataset"); - - test('new Dataset', function () { - var datasetId = 'test-dataset'; - var metadata = { - title: 'My Test Dataset' +test('new Dataset', function () { + var datasetId = 'test-dataset'; + var metadata = { + title: 'My Test Dataset' , name: '1-my-test-dataset' , id: datasetId - }; - var indata = { - headers: ['x', 'y', 'z'] + }; + var indata = { + headers: ['x', 'y', 'z'] , rows: [ {id: 0, x: 1, y: 2, z: 3} , {id: 1, x: 2, y: 4, z: 6} @@ -19,476 +18,469 @@ , {id: 4, x: 5, y: 10, z: 15} , {id: 5, x: 6, y: 12, z: 18} ] - }; - var dataset = new recline.Model.Dataset(metadata); - dataset.backendConfig = { - type: 'memory' - // deep copy so we do not touch original data ... - , data: $.extend(true, {}, indata) - }; - expect(10); - dataset.fetch().then(function(dataset) { - equal(dataset.get('name'), metadata.name); - deepEqual(dataset.get('headers'), indata.headers); - equal(dataset.docCount, 6); - var queryObj = { - size: 4 - , offset: 2 - }; - dataset.query(queryObj).then(function(documentList) { - deepEqual(indata.rows[2], documentList.models[0].toJSON()); - }); - var queryObj = { - sort: [ - ['y', 'desc'] - ] - }; - dataset.query(queryObj).then(function(docs) { - var doc0 = dataset.currentDocuments.models[0].toJSON(); - equal(doc0.x, 6); - }); - dataset.query().then(function(docList) { - equal(docList.length, Math.min(100, indata.rows.length)); - var doc1 = docList.models[0]; - deepEqual(doc1.toJSON(), indata.rows[0]); - - // Test UPDATE - var newVal = 10; - doc1.set({x: newVal}); - doc1.save().then(function() { - equal(dataset.backendConfig.data.rows[0].x, newVal); - }) - - // Test Delete - doc1.destroy().then(function() { - equal(dataset.backendConfig.data.rows.length, 5); - equal(dataset.backendConfig.data.rows[0].x, indata.rows[1].x); - }); - }); - }); - }); - - // TODO: move to fixtures - var webstoreSchema = { - "count": 3, - "data": [ - { - "name": "__id__", - "type": "integer", - "values_url": "/rufuspollock/demo/data/distinct/__id__" - }, - { - "name": "date", - "type": "text", - "values_url": "/rufuspollock/demo/data/distinct/date" - }, - { - "name": "geometry", - "type": "text", - "values_url": "/rufuspollock/demo/data/distinct/geometry" - }, - { - "name": "amount", - "type": "text", - "values_url": "/rufuspollock/demo/data/distinct/amount" - } - ], - "fields": [ - { - "name": "type" - }, - { - "name": "name" - }, - { - "name": "values_url" - } - ] }; - - webstoreData = { - "count": null, - "data": [ - { - "__id__": 1, - "amount": "100", - "date": "2009-01-01", - "geometry": null - }, - { - "__id__": 2, - "amount": "200", - "date": "2010-01-01", - "geometry": null - }, - { - "__id__": 3, - "amount": "300", - "date": "2011-01-01", - "geometry": null - } - ], - "fields": [ - { - "name": "__id__" - }, - { - "name": "date" - }, - { - "name": "geometry" - }, - { - "name": "amount" - } - ] + var dataset = new recline.Model.Dataset(metadata); + dataset.backendConfig = { + type: 'memory' + // deep copy so we do not touch original data ... + , data: $.extend(true, {}, indata) }; - - test('Webstore Backend', function() { - var dataset = new recline.Model.Dataset(); - dataset.backendConfig = { - type: 'webstore', - url: 'http://webstore.test.ckan.org/rufuspollock/demo/data' + expect(10); + dataset.fetch().then(function(dataset) { + equal(dataset.get('name'), metadata.name); + deepEqual(dataset.get('headers'), indata.headers); + equal(dataset.docCount, 6); + var queryObj = { + size: 4 + , offset: 2 }; - - var stub = sinon.stub($, 'ajax', function(options) { - if (options.url.indexOf('schema.json') != -1) { - return { - done: function(callback) { - callback(webstoreSchema); - return this; - }, - fail: function() { - return this; - } - } - } else { - return { - done: function(callback) { - callback(webstoreData); - }, - fail: function() { - } - } - } + dataset.query(queryObj).then(function(documentList) { + deepEqual(indata.rows[2], documentList.models[0].toJSON()); }); - - dataset.fetch().done(function(dataset) { - deepEqual(['__id__', 'date', 'geometry', 'amount'], dataset.get('headers')); - equal(3, dataset.docCount) - // dataset.query().done(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", - "1950-02", - "34.73" - ], - [ - "3", - "1950-03", - "34.73" - ], - [ - "4", - "1950-04", - "34.73" - ], - [ - "5", - "1950-05", - "34.73" - ], - [ - "6", - "1950-06", - "34.73" - ], - [ - "7", - "1950-07", - "34.73" - ], - [ - "8", - "1950-08", - "34.73" - ], - [ - "9", - "1950-09", - "34.73" - ], - [ - "10", - "1950-10", - "34.73" + var queryObj = { + sort: [ + ['y', 'desc'] ] - ], + }; + dataset.query(queryObj).then(function(docs) { + var doc0 = dataset.currentDocuments.models[0].toJSON(); + equal(doc0.x, 6); + }); + dataset.query().then(function(docList) { + equal(docList.length, Math.min(100, indata.rows.length)); + var doc1 = docList.models[0]; + deepEqual(doc1.toJSON(), indata.rows[0]); + + // Test UPDATE + var newVal = 10; + doc1.set({x: newVal}); + doc1.save().then(function() { + equal(dataset.backendConfig.data.rows[0].x, newVal); + }) + + // Test Delete + doc1.destroy().then(function() { + equal(dataset.backendConfig.data.rows.length, 5); + equal(dataset.backendConfig.data.rows[0].x, indata.rows[1].x); + }); + }); + }); +}); + +// TODO: move to fixtures +var webstoreSchema = { + "count": 3, + "data": [ + { + "name": "__id__", + "type": "integer", + "values_url": "/rufuspollock/demo/data/distinct/__id__" + }, + { + "name": "date", + "type": "text", + "values_url": "/rufuspollock/demo/data/distinct/date" + }, + { + "name": "geometry", + "type": "text", + "values_url": "/rufuspollock/demo/data/distinct/geometry" + }, + { + "name": "amount", + "type": "text", + "values_url": "/rufuspollock/demo/data/distinct/amount" + } + ], "fields": [ - "__id__", - "date", - "price" - ], - "length": null, - "max_results": 10, - "url": "http://webstore.thedatahub.org/rufuspollock/gold_prices/data.csv" + { + "name": "type" + }, + { + "name": "name" + }, + { + "name": "values_url" + } + ] +}; + +webstoreData = { + "count": null, + "data": [ + { + "__id__": 1, + "amount": "100", + "date": "2009-01-01", + "geometry": null + }, + { + "__id__": 2, + "amount": "200", + "date": "2010-01-01", + "geometry": null + }, + { + "__id__": 3, + "amount": "300", + "date": "2011-01-01", + "geometry": null + } + ], + "fields": [ + { + "name": "__id__" + }, + { + "name": "date" + }, + { + "name": "geometry" + }, + { + "name": "amount" + } + ] +}; + +test('Webstore Backend', function() { + var dataset = new recline.Model.Dataset(); + dataset.backendConfig = { + type: 'webstore', + url: 'http://webstore.test.ckan.org/rufuspollock/demo/data' }; - test('DataProxy Backend', function() { - // needed only if not stubbing - // stop(); - var dataset = new recline.Model.Dataset(); - dataset.backendConfig = { - type: 'dataproxy', - url: 'http://webstore.thedatahub.org/rufuspollock/gold_prices/data.csv' - }; - - var stub = sinon.stub($, 'ajax', function(options) { - var partialUrl = 'jsonpdataproxy.appspot.com'; - if (options.url.indexOf(partialUrl) != -1) { - return { - done: function(callback) { - callback(dataProxyData); - return this; - }, - fail: function() { - return this; - } + var stub = sinon.stub($, 'ajax', function(options) { + if (options.url.indexOf('schema.json') != -1) { + return { + done: function(callback) { + callback(webstoreSchema); + return this; + }, + fail: function() { + return this; } } - }); - - dataset.fetch().done(function(dataset) { - deepEqual(['__id__', 'date', 'price'], dataset.get('headers')); - equal(null, dataset.docCount) - dataset.query().done(function(docList) { - equal(10, docList.length) - equal("1950-01", docList.models[0].get('date')); - // needed only if not stubbing - start(); - }); - }); - $.ajax.restore(); + } else { + return { + done: function(callback) { + callback(webstoreData); + }, + fail: function() { + } + } + } }); + dataset.fetch().done(function(dataset) { + deepEqual(['__id__', 'date', 'geometry', 'amount'], dataset.get('headers')); + equal(3, dataset.docCount) + // dataset.query().done(function(docList) { + // equal(3, docList.length) + // equal("2009-01-01", docList.models[0].get('date')); + // }); + }); + $.ajax.restore(); +}); - var sample_gdocs_spreadsheet_data = { - "feed": { - "category": [ + +var dataProxyData = { + "data": [ + [ + "1", + "1950-01", + "34.73" + ], + [ + "2", + "1950-02", + "34.73" + ], + [ + "3", + "1950-03", + "34.73" + ], + [ + "4", + "1950-04", + "34.73" + ], + [ + "5", + "1950-05", + "34.73" + ], + [ + "6", + "1950-06", + "34.73" + ], + [ + "7", + "1950-07", + "34.73" + ], + [ + "8", + "1950-08", + "34.73" + ], + [ + "9", + "1950-09", + "34.73" + ], + [ + "10", + "1950-10", + "34.73" + ] + ], + "fields": [ + "__id__", + "date", + "price" + ], + "length": null, + "max_results": 10, + "url": "http://webstore.thedatahub.org/rufuspollock/gold_prices/data.csv" +}; + +test('DataProxy Backend', function() { + // needed only if not stubbing + // stop(); + var dataset = new recline.Model.Dataset(); + dataset.backendConfig = { + type: 'dataproxy', + url: 'http://webstore.thedatahub.org/rufuspollock/gold_prices/data.csv' + }; + + var stub = sinon.stub($, 'ajax', function(options) { + var partialUrl = 'jsonpdataproxy.appspot.com'; + if (options.url.indexOf(partialUrl) != -1) { + return { + done: function(callback) { + callback(dataProxyData); + return this; + }, + fail: function() { + return this; + } + } + } + }); + + dataset.fetch().done(function(dataset) { + deepEqual(['__id__', 'date', 'price'], dataset.get('headers')); + equal(null, dataset.docCount) + dataset.query().done(function(docList) { + equal(10, docList.length) + equal("1950-01", docList.models[0].get('date')); + // needed only if not stubbing + start(); + }); + }); + $.ajax.restore(); +}); + + +var sample_gdocs_spreadsheet_data = { + "feed": { + "category": [ + { + "term": "http://schemas.google.com/spreadsheets/2006#list", + "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": [ { - "term": "http://schemas.google.com/spreadsheets/2006#list", - "scheme": "http://schemas.google.com/spreadsheets/2006" + "name": { + "$t": "okfn.rufus.pollock" + }, + "email": { + "$t": "okfn.rufus.pollock@gmail.com" + } } - ], - "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": [ + ], + "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": [ { - "name": { - "$t": "okfn.rufus.pollock" + "term": "http://schemas.google.com/spreadsheets/2006#list", + "scheme": "http://schemas.google.com/spreadsheets/2006" + } + ], + "updated": { + "$t": "2010-07-12T18:32:16.200Z" }, - "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": [ + "gsx$column-2": { + "$t": "1" + }, + "gsx$column-1": { + "$t": "A" + }, + "title": { + "$t": "A", + "type": "text" + }, + "content": { + "$t": "column-2: 1", + "type": "text" + }, + "link": [ { - "term": "http://schemas.google.com/spreadsheets/2006#list", - "scheme": "http://schemas.google.com/spreadsheets/2006" + "href": "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values/cokwr", + "type": "application/atom+xml", + "rel": "self" } - ], - "updated": { - "$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" - } - }, + ], + "id": { + "$t": "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values/cokwr" + } + }, + { + "category": [ { - "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": "2" + }, + "gsx$column-1": { + "$t": "b" + }, + "title": { + "$t": "b", + "type": "text" + }, + "content": { + "$t": "column-2: 2", + "type": "text" + }, + "link": [ { - "term": "http://schemas.google.com/spreadsheets/2006#list", - "scheme": "http://schemas.google.com/spreadsheets/2006" + "href": "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values/cpzh4", + "type": "application/atom+xml", + "rel": "self" } - ], - "updated": { - "$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" - } - }, + ], + "id": { + "$t": "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values/cpzh4" + } + }, + { + "category": [ { - "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": [ { - "term": "http://schemas.google.com/spreadsheets/2006#list", - "scheme": "http://schemas.google.com/spreadsheets/2006" + "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" } - ], - "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" - }, - "id": { - "$t": "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values" - } - }, - "version": "1.0", - "encoding": "UTF-8" - } - - - - - test("GDoc Backend", function() { - var dataset = new recline.Model.Dataset(); - dataset.backendConfig = { - type: 'gdocs', - url: 'https://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values?alt=json' - }; - - 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) - } - }); + ], + "openSearch$totalResults": { + "$t": "3" + }, + "id": { + "$t": "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values" + } + }, + "version": "1.0", + "encoding": "UTF-8" +} - 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.query().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(); +test("GDoc Backend", function() { + var dataset = new recline.Model.Dataset(); + dataset.backendConfig = { + type: 'gdocs', + url: 'https://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values?alt=json' + }; + 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.query().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(); +}); })(this.jQuery); From 2d4e6a2eccc48fe548dc6e815b6efea8e69f1575 Mon Sep 17 00:00:00 2001 From: Rufus Pollock Date: Fri, 17 Feb 2012 08:53:36 +0000 Subject: [PATCH 3/6] [#43,model][m]: refactor Dataset and BackendMemory to the new setup approach. * NB: other model tests broken as a result. --- src/backend.js | 93 ++++++++++++++++++++++++---------------------- src/model.js | 21 +++++++---- test/model.test.js | 50 ++++++++++++------------- 3 files changed, 87 insertions(+), 77 deletions(-) diff --git a/src/backend.js b/src/backend.js index b2676694..5fe33501 100644 --- a/src/backend.js +++ b/src/backend.js @@ -9,13 +9,11 @@ this.recline = this.recline || {}; this.recline.Model = this.recline.Model || {}; (function($, my) { - my.backends = {}; - // ## Backbone.sync // // Override Backbone.sync to hand off to sync function in relevant backend Backbone.sync = function(method, model, options) { - return my.backends[model.backendConfig.type].sync(method, model, options); + return model.backend.sync(method, model, options); } // ## wrapInTimeout @@ -45,49 +43,59 @@ this.recline.Model = this.recline.Model || {}; // ## BackendMemory - uses in-memory data // - // To use you should: + // This is very artificial and is really only designed for testing + // purposes. + // + // To use it you should provide in your constructor data: // - // A. provide metadata as model data to the Dataset + // * metadata (including headers array) + // * documents: list of hashes, each hash being one doc. A doc *must* have an id attribute which is unique. // - // B. Set backendConfig on your dataset with attributes: - // - // - type: 'memory' - // - 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: + // Example: // //
-  //        {
-  //            headers: ['x', 'y', 'z']
-  //          , rows: [
-  //              {id: 0, x: 1, y: 2, z: 3}
-  //            , {id: 1, x: 2, y: 4, z: 6}
-  //          ]
-  //        };
+  //  // Backend setup
+  //  var backend = Backend();
+  //  backend.addDataset({
+  //    metadata: {
+  //      id: 'my-id',
+  //      title: 'My Title',
+  //      headers: ['x', 'y', 'z'],
+  //    },
+  //    documents: [
+  //        {id: 0, x: 1, y: 2, z: 3},
+  //        {id: 1, x: 2, y: 4, z: 6}
+  //      ]
+  //  });
+  //  // later ...
+  //  var dataset = Dataset({id: 'my-id'});
+  //  dataset.fetch();
+  //  etc ...
   //  
my.BackendMemory = Backbone.Model.extend({ + initialize: function() { + this.datasets = {}; + }, + addDataset: function(data) { + this.datasets[data.metadata.id] = $.extend(true, {}, data); + }, sync: function(method, model, options) { var self = this; if (method === "read") { var dfd = $.Deferred(); if (model.__type__ == 'Dataset') { - var dataset = model; - dataset.set({ - headers: dataset.backendConfig.data.headers - }); - dataset.docCount = dataset.backendConfig.data.rows.length; - dfd.resolve(dataset); + var rawDataset = this.datasets[model.id]; + model.set(rawDataset.metadata); + model.docCount = rawDataset.documents.length; + dfd.resolve(model); } return dfd.promise(); } else if (method === 'update') { var dfd = $.Deferred(); if (model.__type__ == 'Document') { - _.each(model.backendConfig.data.rows, function(row, idx) { - if(row.id === model.id) { - model.backendConfig.data.rows[idx] = model.toJSON(); + _.each(self.datasets[model.dataset.id].documents, function(doc, idx) { + if(doc.id === model.id) { + self.datasets[model.dataset.id].documents[idx] = model.toJSON(); } }); dfd.resolve(model); @@ -96,9 +104,11 @@ this.recline.Model = this.recline.Model || {}; } else if (method === 'delete') { var dfd = $.Deferred(); if (model.__type__ == 'Document') { - model.backendConfig.data.rows = _.reject(model.backendConfig.data.rows, function(row) { - return (row.id === model.id); + var rawDataset = self.datasets[model.dataset.id]; + var newdocs = _.reject(rawDataset.documents, function(doc) { + return (doc.id === model.id); }); + rawDataset.documents = newdocs; dfd.resolve(model); } return dfd.promise(); @@ -110,11 +120,11 @@ this.recline.Model = this.recline.Model || {}; var numRows = queryObj.size; var start = queryObj.offset; var dfd = $.Deferred(); - results = model.backendConfig.data.rows; + results = this.datasets[model.id].documents; // not complete sorting! _.each(queryObj.sort, function(item) { - results = _.sortBy(results, function(row) { - var _out = row[item[0]]; + results = _.sortBy(results, function(doc) { + var _out = doc[item[0]]; return (item[1] == 'asc') ? _out : -1*_out; }); }); @@ -129,14 +139,7 @@ this.recline.Model = this.recline.Model || {}; // // Connecting to [Webstores](http://github.com/okfn/webstore) // - // To use this backend set backendConfig on your Dataset as: - // - //
-  // {
-  //   'type': 'webstore',
-  //   'url': url to relevant Webstore table
-  // }
-  // 
+ // To use this backend ensure your Dataset has a webstore_url in its attributes. my.BackendWebstore = Backbone.Model.extend({ sync: function(method, model, options) { if (method === "read") { @@ -256,10 +259,10 @@ this.recline.Model = this.recline.Model || {}; }); var dfd = $.Deferred(); jqxhr.done(function(results) { - var _out = _.map(results.data, function(row) { + var _out = _.map(results.data, function(doc) { var tmp = {}; _.each(results.fields, function(key, idx) { - tmp[key] = row[idx]; + tmp[key] = doc[idx]; }); return tmp; }); diff --git a/src/model.js b/src/model.js index 1f5c0b8e..034b196a 100644 --- a/src/model.js +++ b/src/model.js @@ -11,11 +11,13 @@ this.recline.Model = this.recline.Model || {}; // * docCount: total number of documents in this dataset (obtained on a fetch for this Dataset) my.Dataset = Backbone.Model.extend({ __type__: 'Dataset', - initialize: function(options) { - console.log(options); + initialize: function(model, backend) { + this.backend = backend; + if (backend && backend.constructor == String) { + this.backend = my.backends[backend]; + } this.currentDocuments = new my.DocumentList(); this.docCount = null; - this.backend = null; this.defaultQuery = { size: 100 , offset: 0 @@ -37,15 +39,14 @@ this.recline.Model = this.recline.Model || {}; // This also illustrates the limitations of separating the Dataset and the Backend query: function(queryObj) { var self = this; - var backend = my.backends[this.backendConfig.type]; this.queryState = queryObj || this.defaultQuery; this.queryState = _.extend({size: 100, offset: 0}, this.queryState); var dfd = $.Deferred(); - backend.query(this, this.queryState).done(function(rows) { + this.backend.query(this, this.queryState).done(function(rows) { var docs = _.map(rows, function(row) { var _doc = new my.Document(row); - _doc.backendConfig = self.backendConfig; - _doc.backend = backend; + _doc.backend = self.backend; + _doc.dataset = self; return _doc; }); self.currentDocuments.reset(docs); @@ -76,5 +77,11 @@ this.recline.Model = this.recline.Model || {}; __type__: 'DocumentList', model: my.Document }); + + // ## Backend registry + // + // Backends will register themselves by id into this registry + my.backends = {}; + }(jQuery, this.recline.Model)); diff --git a/test/model.test.js b/test/model.test.js index 21b2c52d..3e07d46e 100644 --- a/test/model.test.js +++ b/test/model.test.js @@ -1,41 +1,41 @@ (function ($) { module("Dataset"); -test('new Dataset', function () { +test('Memory Backend', function () { var datasetId = 'test-dataset'; - var metadata = { - title: 'My Test Dataset' - , name: '1-my-test-dataset' - , id: datasetId - }; - var indata = { - headers: ['x', 'y', 'z'] - , rows: [ + var inData = { + metadata: { + title: 'My Test Dataset' + , name: '1-my-test-dataset' + , id: datasetId + , headers: ['x', 'y', 'z'] + }, + documents: [ {id: 0, x: 1, y: 2, z: 3} , {id: 1, x: 2, y: 4, z: 6} , {id: 2, x: 3, y: 6, z: 9} , {id: 3, x: 4, y: 8, z: 12} , {id: 4, x: 5, y: 10, z: 15} , {id: 5, x: 6, y: 12, z: 18} - ] - }; - var dataset = new recline.Model.Dataset(metadata); - dataset.backendConfig = { - type: 'memory' - // deep copy so we do not touch original data ... - , data: $.extend(true, {}, indata) + ] }; + var backend = new recline.Model.BackendMemory(); + backend.addDataset(inData); + var dataset = new recline.Model.Dataset({id: datasetId}, backend); + // ### Start testing expect(10); - dataset.fetch().then(function(dataset) { - equal(dataset.get('name'), metadata.name); - deepEqual(dataset.get('headers'), indata.headers); + // convenience for tests + var data = backend.datasets[datasetId]; + dataset.fetch().then(function(datasetAgain) { + equal(dataset.get('name'), data.metadata.name); + deepEqual(dataset.get('headers'), data.metadata.headers); equal(dataset.docCount, 6); var queryObj = { size: 4 , offset: 2 }; dataset.query(queryObj).then(function(documentList) { - deepEqual(indata.rows[2], documentList.models[0].toJSON()); + deepEqual(data.documents[2], documentList.models[0].toJSON()); }); var queryObj = { sort: [ @@ -47,21 +47,21 @@ test('new Dataset', function () { equal(doc0.x, 6); }); dataset.query().then(function(docList) { - equal(docList.length, Math.min(100, indata.rows.length)); + equal(docList.length, Math.min(100, data.documents.length)); var doc1 = docList.models[0]; - deepEqual(doc1.toJSON(), indata.rows[0]); + deepEqual(doc1.toJSON(), data.documents[0]); // Test UPDATE var newVal = 10; doc1.set({x: newVal}); doc1.save().then(function() { - equal(dataset.backendConfig.data.rows[0].x, newVal); + equal(data.documents[0].x, newVal); }) // Test Delete doc1.destroy().then(function() { - equal(dataset.backendConfig.data.rows.length, 5); - equal(dataset.backendConfig.data.rows[0].x, indata.rows[1].x); + equal(data.documents.length, 5); + equal(data.documents[0].x, inData.documents[1].x); }); }); }); From 7f923d3ccfa27afaa72192d649549f2c638cc404 Mon Sep 17 00:00:00 2001 From: Rufus Pollock Date: Fri, 17 Feb 2012 09:10:24 +0000 Subject: [PATCH 4/6] [backend][s]: Webstore and DataProxy now passing tests again. --- src/backend.js | 44 ++++++++++++++++++++------------------------ test/model.test.js | 30 +++++++++++++++--------------- 2 files changed, 35 insertions(+), 39 deletions(-) diff --git a/src/backend.js b/src/backend.js index 5fe33501..94435c16 100644 --- a/src/backend.js +++ b/src/backend.js @@ -144,8 +144,7 @@ this.recline.Model = this.recline.Model || {}; sync: function(method, model, options) { if (method === "read") { if (model.__type__ == 'Dataset') { - var dataset = model; - var base = dataset.backendConfig.url; + var base = model.get('webstore_url'); var schemaUrl = base + '/schema.json'; var jqxhr = $.ajax({ url: schemaUrl, @@ -157,11 +156,11 @@ this.recline.Model = this.recline.Model || {}; headers = _.map(schema.data, function(item) { return item.name; }); - dataset.set({ + model.set({ headers: headers }); - dataset.docCount = schema.count; - dfd.resolve(dataset, jqxhr); + model.docCount = schema.count; + dfd.resolve(model, jqxhr); }) .fail(function(arguments) { dfd.reject(arguments); @@ -171,7 +170,7 @@ this.recline.Model = this.recline.Model || {}; } }, query: function(model, queryObj) { - var base = model.backendConfig.url; + var base = model.get('webstore_url'); var data = { _limit: queryObj.size , _offset: queryObj.offset @@ -196,33 +195,30 @@ this.recline.Model = this.recline.Model || {}; // // For connecting to [DataProxy-s](http://github.com/okfn/dataproxy). // - // Set a Dataset to use this backend: - // - // dataset.backendConfig = { - // // required - // url: {url-of-data-to-proxy}, - // format: csv | xls, - // } - // // When initializing the DataProxy backend you can set the following attributes: // // * dataproxy: {url-to-proxy} (optional). Defaults to http://jsonpdataproxy.appspot.com // + // Datasets using using this backend should set the following attributes: + // + // * url: (required) url-of-data-to-proxy + // * format: (optional) csv | xls (defaults to csv if not specified) + // // Note that this is a **read-only** backend. my.BackendDataProxy = Backbone.Model.extend({ defaults: { - dataproxy: 'http://jsonpdataproxy.appspot.com' + dataproxy_url: 'http://jsonpdataproxy.appspot.com' }, sync: function(method, model, options) { + var self = this; if (method === "read") { if (model.__type__ == 'Dataset') { - var dataset = model; - var base = my.backends['dataproxy'].get('dataproxy'); + var base = self.get('dataproxy_url'); // TODO: should we cache for extra efficiency var data = { - url: dataset.backendConfig.url + url: model.get('url') , 'max-results': 1 - , type: dataset.backendConfig.format + , type: model.get('format') || 'csv' }; var jqxhr = $.ajax({ url: base @@ -231,10 +227,10 @@ this.recline.Model = this.recline.Model || {}; }); var dfd = $.Deferred(); wrapInTimeout(jqxhr).done(function(results) { - dataset.set({ + model.set({ headers: results.fields }); - dfd.resolve(dataset, jqxhr); + dfd.resolve(model, jqxhr); }) .fail(function(arguments) { dfd.reject(arguments); @@ -246,11 +242,11 @@ this.recline.Model = this.recline.Model || {}; } }, query: function(dataset, queryObj) { - var base = my.backends['dataproxy'].get('dataproxy'); + var base = this.get('dataproxy_url'); var data = { - url: dataset.backendConfig.url + url: dataset.get('url') , 'max-results': queryObj.size - , type: dataset.backendConfig.format + , type: dataset.get('format') }; var jqxhr = $.ajax({ url: base diff --git a/test/model.test.js b/test/model.test.js index 3e07d46e..706fd08c 100644 --- a/test/model.test.js +++ b/test/model.test.js @@ -144,12 +144,12 @@ webstoreData = { }; test('Webstore Backend', function() { - var dataset = new recline.Model.Dataset(); - dataset.backendConfig = { - type: 'webstore', - url: 'http://webstore.test.ckan.org/rufuspollock/demo/data' - }; - + var dataset = new recline.Model.Dataset({ + id: 'my-id', + webstore_url: 'http://webstore.test.ckan.org/rufuspollock/demo/data' + }, + 'webstore' + ); var stub = sinon.stub($, 'ajax', function(options) { if (options.url.indexOf('schema.json') != -1) { return { @@ -175,10 +175,10 @@ test('Webstore Backend', function() { dataset.fetch().done(function(dataset) { deepEqual(['__id__', 'date', 'geometry', 'amount'], dataset.get('headers')); equal(3, dataset.docCount) - // dataset.query().done(function(docList) { - // equal(3, docList.length) - // equal("2009-01-01", docList.models[0].get('date')); - // }); + dataset.query().done(function(docList) { + equal(3, docList.length) + equal("2009-01-01", docList.models[0].get('date')); + }); }); $.ajax.restore(); }); @@ -250,11 +250,11 @@ var dataProxyData = { test('DataProxy Backend', function() { // needed only if not stubbing // stop(); - var dataset = new recline.Model.Dataset(); - dataset.backendConfig = { - type: 'dataproxy', - url: 'http://webstore.thedatahub.org/rufuspollock/gold_prices/data.csv' - }; + var dataset = new recline.Model.Dataset({ + url: 'http://webstore.thedatahub.org/rufuspollock/gold_prices/data.csv' + }, + 'dataproxy' + ); var stub = sinon.stub($, 'ajax', function(options) { var partialUrl = 'jsonpdataproxy.appspot.com'; From 87fa7529089a42c478484c3258c5012941fcfc90 Mon Sep 17 00:00:00 2001 From: Rufus Pollock Date: Fri, 17 Feb 2012 09:16:02 +0000 Subject: [PATCH 5/6] [#43,backend][s]: GDocs backend working (and has improved docs). --- src/backend.js | 18 +++++++++++++++--- test/model.test.js | 12 +++++------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/backend.js b/src/backend.js index 94435c16..98dff9da 100644 --- a/src/backend.js +++ b/src/backend.js @@ -272,15 +272,27 @@ this.recline.Model = this.recline.Model || {}; // ## Google spreadsheet backend // - // Connect to Google Docs spreadsheet. For write operations + // Connect to Google Docs spreadsheet. + // + // Dataset must have a url attribute pointing to the Gdocs + // spreadsheet's JSON feed e.g. + // + //
+  // var dataset = new recline.Model.Dataset({
+  //     url: 'https://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values?alt=json'
+  //   },
+  //   'gdocs'
+  // );
+  // 
my.BackendGDoc = Backbone.Model.extend({ sync: function(method, model, options) { + var self = this; if (method === "read") { var dfd = $.Deferred(); var dataset = model; - $.getJSON(model.backendConfig.url, function(d) { - result = my.backends['gdocs'].gdocsToJavascript(d); + $.getJSON(model.get('url'), function(d) { + result = self.gdocsToJavascript(d); model.set({'headers': result.header}); // cache data onto dataset (we have loaded whole gdoc it seems!) model._dataCache = result.data; diff --git a/test/model.test.js b/test/model.test.js index 706fd08c..d44ff330 100644 --- a/test/model.test.js +++ b/test/model.test.js @@ -452,13 +452,11 @@ var sample_gdocs_spreadsheet_data = { } test("GDoc Backend", function() { - var dataset = new recline.Model.Dataset(); - dataset.backendConfig = { - type: 'gdocs', - url: 'https://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values?alt=json' - }; - - console.log('got gdoc dataset', dataset); + var dataset = new recline.Model.Dataset({ + url: 'https://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values?alt=json' + }, + 'gdocs' + ); var stub = sinon.stub($, 'getJSON', function(options, cb) { console.log('options are', options, cb); From b179ab50cfc7939c7efe0f16c4bd6412a411578a Mon Sep 17 00:00:00 2001 From: Rufus Pollock Date: Fri, 17 Feb 2012 09:20:19 +0000 Subject: [PATCH 6/6] [#43,demo][s]: fix up demo to use new form for creating datasets and backends. --- demo/js/app.js | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/demo/js/app.js b/demo/js/app.js index d0c54337..cbfeddc2 100755 --- a/demo/js/app.js +++ b/demo/js/app.js @@ -29,15 +29,15 @@ $(function() { function demoDataset() { var datasetId = 'test-dataset'; - var metadata = { - title: 'My Test Dataset' - , name: '1-my-test-dataset' - , id: datasetId - }; - var indata = { - headers: ['x', 'y', 'z'] - , rows: [ - {id: 0, x: 1, y: 2, z: 3} + var inData = { + metadata: { + title: 'My Test Dataset' + , name: '1-my-test-dataset' + , id: datasetId + , headers: ['x', 'y', 'z'] + }, + documents: [ + {id: 0, x: 1, y: 2, z: 3} , {id: 1, x: 2, y: 4, z: 6} , {id: 2, x: 3, y: 6, z: 9} , {id: 3, x: 4, y: 8, z: 12} @@ -45,12 +45,9 @@ function demoDataset() { , {id: 5, x: 6, y: 12, z: 18} ] }; - var dataset = new recline.Model.Dataset(metadata); - dataset.backendConfig = { - type: 'memory' - // deep copy so we do not touch original data ... - , data: $.extend(true, {}, indata) - }; + var backend = new recline.Model.BackendMemory(); + backend.addDataset(inData); + var dataset = new recline.Model.Dataset({id: datasetId}, backend); return dataset; } @@ -62,11 +59,12 @@ function setupLoadFromWebstore(callback) { e.preventDefault(); var $form = $(e.target); var source = $form.find('input[name="source"]').val(); - var dataset = new recline.Model.Dataset(); - dataset.backendConfig = { - type: 'webstore', - url: source - }; + var dataset = new recline.Model.Dataset({ + id: 'gold-prices', + webstore_url: source + }, + 'webstore' + ); callback(dataset); }); }