Skip to content

Commit

Permalink
Implement Adapter#shouldReloadRecord and Adapter#shouldBackgroundRelo…
Browse files Browse the repository at this point in the history
…adRecord

Implement Adapter#shouldReloadAll and Adapter#shouldBackgroundReloadAll
  • Loading branch information
bmac committed Jun 15, 2015
1 parent e9b8450 commit c6f9908
Show file tree
Hide file tree
Showing 6 changed files with 524 additions and 36 deletions.
79 changes: 79 additions & 0 deletions packages/ember-data/lib/system/adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,85 @@ var Adapter = Ember.Object.extend({
*/
groupRecordsForFindMany: function(store, snapshots) {
return [snapshots];
},


/**
This method is used by the store to determine if the store should
reload a record from the adapter when a record is requested by
`store.findRecord`.
If this method returns true the store will re fetch a record form
the adapter. If is method returns false the store will resolve
immediately using the cached record.
@method shouldReloadRecord
@param {DS.Store} store
@param {DS.Snapshot} snapshot
@return {Boolean}
*/
shouldReloadRecord: function(store, snapshot) {
return false;
},

/**
This method is used by the store to determine if the store should
reload all records from the adapter when records are requested by
`store.findAll`.
If this method returns true the store will re fetch all records form
the adapter. If is method returns false the store will resolve
immediately using the cached record.
@method shouldReloadRecord
@param {DS.Store} store
@param {DS.SnapshotRecordArray} snapshotRecordArray
@return {Boolean}
*/
shouldReloadAll: function(store, snapshotRecordArray) {
Ember.deprecate('The default behavior of `shouldBackgroundReloadAll` will change in Ember Data 2.0 to always return false. If you would like to preserve the current behavior please override `shouldReloadAll` in you adapter:application and return true.');
return true;
},

/**
This method is used by the store to determine if the store should
reload a record after the `store.findRecord` method resolves a
chached record.
This method is *only* checked by the store when the store is
returning a cached record.
If this method returns true the store will re-fetch a record form
the adapter.
@method shouldBackgroundReloadRecord
@param {DS.Store} store
@param {DS.Snapshot} snapshot
@return {Boolean}
*/
shouldBackgroundReloadRecord: function(store, snapshot) {
Ember.deprecate('The default behavior of `shouldBackgroundReloadRecord` will change in Ember Data 2.0 to always return true. If you would like to preserve the current behavior please override `shouldBackgroundReloadRecord` in you adapter:application and return false.');
return false;
},

/**
This method is used by the store to determine if the store should
reload a record array after the `store.findAll` method resolves
with a chached record array.
This method is *only* checked by the store when the store is
returning a cached record array.
If this method returns true the store will re-fetch all records
form the adapter.
@method shouldBackgroundReloadAll
@param {DS.Store} store
@param {DS.SnapshotRecordArray} snapshotRecordArray
@return {Boolean}
*/
shouldBackgroundReloadAll: function(store, snapshotRecordArray) {
return true;
}
});

Expand Down
8 changes: 8 additions & 0 deletions packages/ember-data/lib/system/record-arrays/record-array.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
*/

import { PromiseArray } from "ember-data/system/promise-proxies";
import SnapshotRecordArray from "ember-data/system/snapshot-record-array";

var get = Ember.get;
var set = Ember.set;

Expand Down Expand Up @@ -198,5 +200,11 @@ export default Ember.ArrayProxy.extend(Ember.Evented, {
this._dissociateFromOwnRecords();
set(this, 'content', undefined);
this._super.apply(this, arguments);
},

createSnapshot(options) {
var adapterOptions = options && options.adapterOptions;
var meta = this.get('meta');
return new SnapshotRecordArray(this, meta, adapterOptions);
}
});
13 changes: 0 additions & 13 deletions packages/ember-data/lib/system/snapshot-record-array.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,6 @@ function SnapshotRecordArray(recordArray, meta, adapterOptions) {
this.adapterOptions = adapterOptions;
}

/**
@method fromRecordArray
@private
@static
@param {DS.RecordArray} recordArray
@param {Object} adapterOptions
@return SnapshotRecordArray
*/
SnapshotRecordArray.fromRecordArray = function(recordArray, adapterOptions) {
var meta = recordArray.get('meta');
return new SnapshotRecordArray(recordArray, meta, adapterOptions);
};

SnapshotRecordArray.prototype.snapshots = function() {
if (this._snapshots) {
return this._snapshots;
Expand Down
71 changes: 52 additions & 19 deletions packages/ember-data/lib/system/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,7 @@ if (!Backburner.prototype.join) {
//an internal model and return it in a promiseObject. Useful for returning
//from find methods
function promiseRecord(internalModel, label) {
//TODO cleanup
var toReturn = internalModel;
if (!internalModel.then) {
toReturn = internalModel.getRecord();
} else {
toReturn = internalModel.then((model) => model.getRecord());
}
var toReturn = internalModel.then((model) => model.getRecord());
return promiseObject(toReturn, label);
}

Expand Down Expand Up @@ -612,29 +606,53 @@ Store = Service.extend({
var internalModel = this._internalModelForId(modelName, id);
options = options || {};

if (options.reload && this.hasRecordForId(modelName, id)) {
return this.peekRecord(modelName, id).reload();
}
return this._findByInternalModel(internalModel, options);
},

_findByInternalModel: function(internalModel, options) {
var fetchedInternalModel;
options = options || {};


if (options.preload) {
internalModel._preloadData(options.preload);
}

var fetchedInternalModel = this._fetchOrResolveInternalModel(internalModel, options);

return promiseRecord(fetchedInternalModel, "DS: Store#findRecord " + internalModel.typeKey + " with id: " + get(internalModel, 'id'));
},

_fetchOrResolveInternalModel: function(internalModel, options) {
var typeClass = internalModel.type;
var adapter = this.adapterFor(typeClass.modelName);
// Always fetch the model if it is not loaded
if (internalModel.isEmpty()) {
fetchedInternalModel = this.scheduleFetch(internalModel, options);
//TODO double check about reloading
} else if (internalModel.isLoading()) {
fetchedInternalModel = internalModel._loadingPromise;
return this.scheduleFetch(internalModel, options);
}

//TODO double check about reloading
if (internalModel.isLoading()) {
return internalModel._loadingPromise;
}

return promiseRecord(fetchedInternalModel || internalModel, "DS: Store#findRecord " + internalModel.typeKey + " with id: " + get(internalModel, 'id'));
// Refetch if the reload option is passed
if (options.reload) {
return this.scheduleFetch(internalModel, options);
}

// Refetch the record if the adapter thinks the record is stale
var snapshot = internalModel.createSnapshot();
snapshot.adapterOptions = options && options.adapterOptions;
if (adapter.shouldReloadRecord(this, snapshot)) {
return this.scheduleFetch(internalModel, options);
}

// Trigger the background refetch if all the previous checks fail
if (adapter.shouldBackgroundReloadRecord(this, snapshot)) {
this.scheduleFetch(internalModel, options);
}

// Return the cached record
return Promise.resolve(internalModel);
},
/**
This method makes a series of requests to the adapter's `find` method
Expand Down Expand Up @@ -1128,15 +1146,30 @@ Store = Service.extend({
@return {Promise} promise
*/
_fetchAll: function(typeClass, array, options) {
options = options || {};
var adapter = this.adapterFor(typeClass.modelName);
var sinceToken = this.typeMapFor(typeClass).metadata.since;

set(array, 'isUpdating', true);

Ember.assert("You tried to load all records but you have no adapter (for " + typeClass + ")", adapter);
Ember.assert("You tried to load all records but your adapter does not implement `findAll`", typeof adapter.findAll === 'function');

return promiseArray(_findAll(adapter, this, typeClass, sinceToken, options));
if (!get(array, '__isLoaded')) {
var arrayPromise = promiseArray(_findAll(adapter, this, typeClass, sinceToken, options));
arrayPromise.then(() => set(array, '__isLoaded', true));
return arrayPromise;
}
if (options.reload) {
return promiseArray(_findAll(adapter, this, typeClass, sinceToken, options));
}
var snapshotArray = array.createSnapshot(options);
if (adapter.shouldReloadAll(this, snapshotArray)) {
return promiseArray(_findAll(adapter, this, typeClass, sinceToken, options));
}
if (adapter.shouldBackgroundReloadAll(this, snapshotArray)) {
promiseArray(_findAll(adapter, this, typeClass, sinceToken, options));
}
return promiseArray(Promise.resolve(array));
},

/**
Expand Down
6 changes: 2 additions & 4 deletions packages/ember-data/lib/system/store/finders.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ import {
serializerForAdapter
} from "ember-data/system/store/serializers";

import SnapshotRecordArray from "ember-data/system/snapshot-record-array";

var Promise = Ember.RSVP.Promise;
var map = Ember.EnumerableUtils.map;

Expand Down Expand Up @@ -121,9 +119,9 @@ export function _findBelongsTo(adapter, store, internalModel, link, relationship
}

export function _findAll(adapter, store, typeClass, sinceToken, options) {
var adapterOptions = options && options.adapterOptions;
var modelName = typeClass.modelName;
var snapshotArray = SnapshotRecordArray.fromRecordArray(store.peekAll(modelName), adapterOptions);
var recordArray = store.peekAll(modelName);
var snapshotArray = recordArray.createSnapshot(options);
var promise = adapter.findAll(store, typeClass, sinceToken, snapshotArray);
var serializer = serializerForAdapter(store, adapter, modelName);
var label = "DS: Handle Adapter#findAll of " + typeClass;
Expand Down
Loading

0 comments on commit c6f9908

Please sign in to comment.