Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement adapter reload hooks from RFC #61 #3324

Merged
merged 1 commit into from
Jun 15, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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