kurko / ember-sync

MIT License
282 stars 28 forks source link

Find records from offline store, then from online store only if not found #33

Open Leooo opened 9 years ago

Leooo commented 9 years ago

Small piece of code for this, use

this.emberSync.findOfflineFirst('posts');

or

this.emberSync.findOfflineFirst('post','27');

to get a promise filled with offline store results if any (without fetching the server), otherwise online store results fetched from the server. This can be useful if we want to use localStorage as a cache of user's own data, and reduce the number of requests to the server for records which can only be modified by the user (while still being able to send changes to the server):

import EmberSync from 'ember-sync';
import StoreInitMixin from "ember-sync/store-initialization-mixin";
import Persistence from "ember-sync/persistence";
import Query from 'ember-sync/query';
import Ember from 'ember';

var alreadyRun=false;

export default {
  name: 'override-ember-sync',
  before: 'store',
  initialize: function() {
    if (alreadyRun) {
      return;
    } else {
      alreadyRun=true;
    }

    EmberSync.reopen(StoreInitMixin,{
      findOfflineFirst: function(type, query) {
        var _this = this;
        var syncQuery = Query.create({
          onlineStore:  this.onlineStore,
          offlineStore: this.offlineStore,
          onError:      this.get('onError'),
          onRecordAdded:     function(record) {
            _this.onRecordAdded(record, type);
          }
        });
        return syncQuery.findOfflineFirst(type, query);
      },
    });

    Query.reopen({
      findOfflineFirst: function(type, query) {
        var _this=this;
        var offlineSearch = Ember.isNone(query) ? _this.offlineStore.findAll(type) : _this.offlineStore.find(type, query);
        return new Ember.RSVP.Promise(function(resolve, reject) {
          offlineSearch.then(function(record) {
              if (!record.toArray().length) {
                _this.findOnlineOnly(type, query).then(function(record){resolve(record);},
                                                       function(error){reject(error);});
              }
              else {
                //see https://github.com/kurko/ember-localstorage-adapter/issues/113
                record.forEach(function(rec){
                  if (record.get('id')) {
                    _this.onRecordAdded(record);
                  }
                });
                resolve(record);
              }
          },
          function(error) {
            _this.findOnlineOnly(type, query).then(function(record){resolve(record);},
                                                   function(error){reject(error);});
          });
        });
      },
      findOnlineOnly: function(type, query){
        var _this=this;
        var onlineSearch  = Ember.isNone(query) ? _this.onlineStore.findAll(type) : _this.onlineStore.find(type, query);
        return new Ember.RSVP.Promise(function(resolve, reject) {
          onlineSearch.then(function(record) {
              if (!record.toArray().length) {reject(record);}
              else{
                 record.forEach(function(rec){
                  var id = rec.get('id'),
                      persistenceState = _this.offlineStore.find(type, id);
                  var persistRecordOffline = function(onlineRecord) {
                    var persistence = Persistence.create({
                      onlineStore:  _this.onlineStore,
                      offlineStore: _this.offlineStore,
                    });
                    persistence.persistRecordOffline(type,rec);
                  };
                  persistenceState.then(persistRecordOffline, persistRecordOffline);
                  _this.onRecordAdded(rec);
                });
                resolve(record);
            }
          },function(error){
            reject(error);
          });
        });
      },
    });

  },
}
kurko commented 9 years ago

Any chance you could write this as a PR, with some tests? That way we'd be able discuss line by line :D

kurko commented 9 years ago

I think something like this.emberSync.findQuery('post', {id: '27', fetchOnline: false}); would be better because then it complies with ED Store interface.

Also, could you move this code into a PR?