From 7141b7aafd72496889fc2de8737ce2059c1ab101 Mon Sep 17 00:00:00 2001 From: Rufus Pollock Date: Sat, 23 Jun 2012 13:28:32 +0100 Subject: [PATCH] [#162,model,be/memory][m]: refactor started with the new API on Dataset, Record and Memory backend. * Tests are passing except for a dataproxy one. --- src/backend/memory.js | 97 +++++++++++++++++-------------------- src/model.js | 39 ++++++++++++++- test/backend/memory.test.js | 37 ++++++++------ 3 files changed, 104 insertions(+), 69 deletions(-) diff --git a/src/backend/memory.js b/src/backend/memory.js index fea90eb9..308557d1 100644 --- a/src/backend/memory.js +++ b/src/backend/memory.js @@ -3,6 +3,8 @@ this.recline.Backend = this.recline.Backend || {}; this.recline.Backend.Memory = this.recline.Backend.Memory || {}; (function($, my) { + my.__type__ = 'memory'; + // ## createDataset // // Convenience function to create a simple 'in-memory' dataset in one step. @@ -15,15 +17,52 @@ this.recline.Backend.Memory = this.recline.Backend.Memory || {}; // @param metadata: (optional) dataset metadata - see recline.Model.Dataset. // If not defined (or id not provided) id will be autogenerated. my.createDataset = function(data, fields, metadata) { - var wrapper = new my.Store(data, fields); - var backend = new my.Backbone(); - var dataset = new recline.Model.Dataset(metadata, backend); - dataset._dataCache = wrapper; + var dataset = new recline.Model.Dataset( + _.extend({}, metadata, {records: data, fields: fields}) + ); dataset.fetch(); - dataset.query(); return dataset; }; + my.fetch = function(dataset) { + var dfd = $.Deferred(); + var store = new my.Store(dataset.get('records'), dataset.get('fields')); + dataset._dataCache = store; + dataset.fields.reset(store.fields); + dataset.query(); + dfd.resolve(dataset); + return dfd.promise(); + }; + + my.save = function(dataset, changes) { + var dfd = $.Deferred(); + // TODO + // _.each(changes.creates) { ... } + _.each(changes.updates, function(record) { + dataset._dataCache.update(record); + }); + _.each(changes.deletes, function(record) { + dataset._dataCache.delete(record); + }); + dfd.resolve(dataset); + return dfd.promise(); + }, + + my.query = function(dataset, queryObj) { + var dfd = $.Deferred(); + var results = dataset._dataCache.query(queryObj); + var hits = _.map(results.records, function(row) { + return { _source: row }; + }); + var out = { + total: results.total, + hits: hits, + facets: results.facets + }; + dfd.resolve(out); + return dfd.promise(); + }; + // ## Data Wrapper // // Turn a simple array of JS objects into a mini data-store with @@ -166,53 +205,5 @@ this.recline.Backend.Memory = this.recline.Backend.Memory || {}; return facetResults; }; }; - - - // ## Backbone - // - // Backbone connector for memory store attached to a Dataset object - my.Backbone = function() { - this.__type__ = 'memory'; - this.sync = function(method, model, options) { - var self = this; - var dfd = $.Deferred(); - if (method === "read") { - if (model.__type__ == 'Dataset') { - model.fields.reset(model._dataCache.fields); - dfd.resolve(model); - } - return dfd.promise(); - } else if (method === 'update') { - if (model.__type__ == 'Record') { - model.dataset._dataCache.update(model.toJSON()); - dfd.resolve(model); - } - return dfd.promise(); - } else if (method === 'delete') { - if (model.__type__ == 'Record') { - model.dataset._dataCache.delete(model.toJSON()); - dfd.resolve(model); - } - return dfd.promise(); - } else { - alert('Not supported: sync on Memory backend with method ' + method + ' and model ' + model); - } - }; - - this.query = function(model, queryObj) { - var dfd = $.Deferred(); - var results = model._dataCache.query(queryObj); - var hits = _.map(results.records, function(row) { - return { _source: row }; - }); - var out = { - total: results.total, - hits: hits, - facets: results.facets - }; - dfd.resolve(out); - return dfd.promise(); - }; - }; }(jQuery, this.recline.Backend.Memory)); diff --git a/src/model.js b/src/model.js index ea7a9ff1..75f1ee09 100644 --- a/src/model.js +++ b/src/model.js @@ -44,11 +44,22 @@ my.Dataset = Backbone.Model.extend({ initialize: function(model, backend) { _.bindAll(this, 'query'); this.backend = backend; + if (typeof backend === 'undefined') { + // guess backend ... + if (this.get('records')) { + this.backend = recline.Backend.Memory; + } + } if (typeof(backend) === 'string') { this.backend = this._backendFromString(backend); } this.fields = new my.FieldList(); this.currentRecords = new my.RecordList(); + this._changes = { + deletes: [], + updates: [], + creates: [] + }; this.facets = new my.FacetList(); this.docCount = null; this.queryState = new my.Query(); @@ -56,6 +67,17 @@ my.Dataset = Backbone.Model.extend({ this.queryState.bind('facet:add', this.query); }, + // ### fetch + // + // Retrieve dataset and (some) records from the backend. + fetch: function() { + return this.backend.fetch(this); + }, + + save: function() { + return this.backend.save(this, this._changes); + }, + // ### query // // AJAX method with promise API to get records from the backend. @@ -76,6 +98,12 @@ my.Dataset = Backbone.Model.extend({ var _doc = new my.Record(hit._source); _doc.backend = self.backend; _doc.dataset = self; + _doc.bind('change', function(doc) { + self._changes.updates.push(doc.toJSON()); + }); + _doc.bind('destroy', function(doc) { + self._changes.deletes.push(doc.toJSON()); + }); return _doc; }); self.currentRecords.reset(docs); @@ -96,6 +124,7 @@ my.Dataset = Backbone.Model.extend({ return dfd.promise(); }, + _prepareQuery: function(newQueryObj) { if (newQueryObj) { this.queryState.set(newQueryObj); @@ -242,7 +271,15 @@ my.Record = Backbone.Model.extend({ } } return html; - } + }, + + // Override Backbone save, fetch and destroy so they do nothing + // Instead, Dataset object that created this Record should take care of + // handling these changes (discovery will occur via event notifications) + // WARNING: these will not persist *unless* you call save on Dataset + fetch: function() {}, + save: function() {}, + destroy: function() { this.trigger('destroy', this); } }); // ## A Backbone collection of Records diff --git a/test/backend/memory.test.js b/test/backend/memory.test.js index 535aeb61..ba14b0e5 100644 --- a/test/backend/memory.test.js +++ b/test/backend/memory.test.js @@ -125,7 +125,7 @@ test('update and delete', function () { (function ($) { -module("Backend Memory - Backbone"); +module("Backend Memory - Model Integration"); var memoryData = { metadata: { @@ -145,18 +145,24 @@ var memoryData = { }; function makeBackendDataset() { - var dataset = new recline.Backend.Memory.createDataset(memoryData.records, null, memoryData.metadata); + var dataset = new recline.Model.Dataset({ + id: 'test-dataset', + title: 'My Test Dataset', + name: '1-my-test-dataset', + fields: [{id: 'x'}, {id: 'y'}, {id: 'z'}, {id: 'country'}, {id: 'label'}], + records: [ + {id: 0, x: 1, y: 2, z: 3, country: 'DE', label: 'first'} + , {id: 1, x: 2, y: 4, z: 6, country: 'UK', label: 'second'} + , {id: 2, x: 3, y: 6, z: 9, country: 'US', label: 'third'} + , {id: 3, x: 4, y: 8, z: 12, country: 'UK', label: 'fourth'} + , {id: 4, x: 5, y: 10, z: 15, country: 'UK', label: 'fifth'} + , {id: 5, x: 6, y: 12, z: 18, country: 'DE', label: 'sixth'} + ] + }); + dataset.fetch(); return dataset; } -test('createDataset', function () { - var dataset = recline.Backend.Memory.createDataset(memoryData.records); - equal(dataset.fields.length, 6); - deepEqual(['id', 'x', 'y', 'z', 'country', 'label'], dataset.fields.pluck('id')); - dataset.query(); - equal(memoryData.records.length, dataset.currentRecords.length); -}); - test('basics', function () { var dataset = makeBackendDataset(); expect(3); @@ -256,12 +262,13 @@ test('update and delete', function () { // Test UPDATE var newVal = 10; doc1.set({x: newVal}); - doc1.save().then(function() { - equal(data.data[0].x, newVal); - }) + doc1.save(); + equal(dataset._changes.updates[0].x, newVal); - // Test Delete - doc1.destroy().then(function() { + doc1.destroy(); + deepEqual(dataset._changes.deletes[0], doc1.toJSON()); + + dataset.save().then(function() { equal(data.data.length, 5); equal(data.data[0].x, memoryData.records[1].x); });