nilbus/Backbone.dualStorage — pull request #103 by reubano (2014-03-28 12:09:38+00:00)
Title: Add support for setting collection with a promise

Some APIs (flickr) require you to call multiple endpoints before returning useful data. In these cases, you need to return a promise for the data in parseBeforeLocalSave that gets resolved once all the API calls are complete. This change adds support so that the promise is handled properly.

Usage

`models/photos.coffee`
```coffeescript
Collection = require 'models/base/collection'
Model = require require 'models/base/model'
config = require 'config'

module.exports = class Photos extends Collection
_.extend @prototype, Chaplin.SyncMachine

base_url = "https://api.flickr.com/services/rest/"
base_data =
api_key: config.flickr.api_token
format: 'json'
nojsoncallback: 1

url_data =
method: 'flickr.urls.lookupUser'
url: "https://www.flickr.com/photos/#{config.flickr.user}/"

model: Model
url: "#{base_url}?#{$.param _.extend url_data, base_data}"
storeName: 'Photos'
local: -> localStorage.getItem "synced"

getCollection: (response) =>
data =
method: 'flickr.collections.getTree'
collection_id: config.flickr.collection_id
user_id: response.user.id

$.get base_url, _.extend data, base_data

getSets: (response) =>
deferreds = []

for id in (s.id for s in response.collections.collection[0].set)
data =
method: 'flickr.photosets.getPhotos'
photoset_id: id

deferreds.push $.get base_url, _.extend data, base_data

deferreds

applySets: (deferreds) => $.when.apply($, deferreds)

getData: (results...) => _.union (r[0].photoset.photo for r in results)

parseBeforeLocalSave: (resp) =>
return if @disposed
@getCollection(resp).then(@getSets).then(@applySets).then(@getData)

wrapError: (model, options) =>
error = options.error
options.error = (resp) =>
error model, resp, options if error
@unSync

_fetch: (options) =>
@beginSync()
options = if options then _.clone(options) else {}
success = options.success

options.success = (resp) =>
method = if options.reset then 'reset' else 'set'
resp.done (data) =>
@[method] data, options
success @, data, options if success
@finishSync()

@wrapError @, options
@sync 'read', @, options

fetch: =>
$.Deferred((deferred) => @_fetch
success: deferred.resolve
error: deferred.reject).promise()
```

Then elsewhere

```coffeescript
Photos = require 'models/photos'
photos = new Photos()
photos.fetch().done -> localStorage.setItem "#{config.title}:Photos:synced", true
```