Load incomplete records when trying to get unknown attribute

In order to minimize ajax requests, I implemented isComplete property,
which can be used to check if record is fetched from the API or if it
was just partially loaded (for example by pusher event). This is nice in
terms of requests reduction, but caries risk of showing incomplete data.

This commit fixes this situation by saving which attributes were
provided on "incomplete" load and triggering refresh when any unknown
attribute is tried to be fetched.

The implementation is really simple and will probably need refactoring,
but I would like to test it in the wild before putting much more time
into it.
This commit is contained in:
Piotr Sarnacki 2012-10-16 02:42:51 +02:00
parent 393ef62eae
commit c05ce673bf
9 changed files with 1706 additions and 1611 deletions

View File

@ -23,7 +23,7 @@ input assets.scripts do
safe_concat assets.vendor_order, 'vendor.js' safe_concat assets.vendor_order, 'vendor.js'
end end
match 'spec/*.js' do match '{spec,spec/unit}/*.js' do
concat 'spec/specs.js' concat 'spec/specs.js'
end end

View File

@ -43,7 +43,7 @@ GIT
GIT GIT
remote: git://github.com/travis-ci/travis-api.git remote: git://github.com/travis-ci/travis-api.git
revision: 816ebc66c8b65c44d6144e721b1b4f048e86d7df revision: 558847f6555202adb7da4f7d31a7b2b80ab4bac2
specs: specs:
travis-api (0.0.1) travis-api (0.0.1)
backports (~> 2.5) backports (~> 2.5)
@ -61,7 +61,7 @@ GIT
GIT GIT
remote: git://github.com/travis-ci/travis-core.git remote: git://github.com/travis-ci/travis-core.git
revision: 56ca16046cba99cc0b4cd0c520c6bb13ace9932a revision: abac97114a36f3a6715e118cc1f90c05a08004f6
branch: sf-travis-api branch: sf-travis-api
specs: specs:
travis-core (0.0.1) travis-core (0.0.1)

View File

@ -76,18 +76,21 @@ Travis.Store = DS.Store.extend
# if we need sideload becasue we have side records with other events it needs to # if we need sideload becasue we have side records with other events it needs to
# be revised # be revised
if type == Travis.Build && json.repository if type == Travis.Build && json.repository
result = @_loadIncomplete(Travis.Repo, 'repository', json.repository) result = @loadIncomplete(Travis.Repo, json.repository)
@_loadIncomplete(type, root, json[root]) @loadIncomplete(type, json[root])
_loadIncomplete: (type, root, hash) -> loadIncomplete: (type, hash) ->
result = @merge(type, hash) result = @merge(type, hash)
if result && result.clientId if result && result.clientId
record = @findByClientId(type, result.clientId) record = @findByClientId(type, result.clientId)
unless record.get('complete') unless record.get('complete')
record.set 'incomplete', true record.set 'incomplete', true
record.loadedAttributes = Object.keys hash
@_updateAssociations(type, root, hash) @_updateAssociations(type, type.singularName(), hash)
record
_loadMany: (store, type, json) -> _loadMany: (store, type, json) ->
root = type.pluralName() root = type.pluralName()

View File

@ -2,6 +2,12 @@
primaryKey: 'id' primaryKey: 'id'
id: DS.attr('number') id: DS.attr('number')
get: (name) ->
if @constructor.isAttribute(name) && @get('incomplete') && !@isAttributeLoaded(name)
@loadTheRest()
@_super.apply this, arguments
refresh: -> refresh: ->
if id = @get('id') if id = @get('id')
store = @get('store') store = @get('store')
@ -12,6 +18,9 @@
@set(key, value) unless key is 'id' @set(key, value) unless key is 'id'
this this
isAttributeLoaded: (name) ->
@loadedAttributes.contains(name)
isComplete: (-> isComplete: (->
if @get 'incomplete' if @get 'incomplete'
@loadTheRest() @loadTheRest()
@ -63,3 +72,16 @@
pluralName: -> pluralName: ->
Travis.app.store.adapter.pluralize(@singularName()) Travis.app.store.adapter.pluralize(@singularName())
isAttribute: (name) ->
unless @attributesSaved
@_saveAttributes()
@cachedAttributes.contains(name)
_saveAttributes: ->
@attributesSaved = true
cachedAttributes = []
@eachComputedProperty (name, meta) ->
cachedAttributes.pushObject name if meta.isAttribute
@cachedAttributes = cachedAttributes

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -8865,3 +8865,73 @@ return sinon;}.call(typeof window != 'undefined' && window || {}));
this.Date.UTC = _Date.UTC; this.Date.UTC = _Date.UTC;
}).call(this); }).call(this);
(function() {
var record, store;
Travis.Foo = Travis.Model.extend({
name: DS.attr('string'),
description: DS.attr('string')
});
record = null;
store = null;
$.mockjax({
url: '/foos/1',
responseTime: 10,
responseText: {
foo: {
id: 1,
name: 'foo',
description: 'bar'
}
}
});
describe('Travis.Model', function() {
return describe('with incomplete record', function() {
beforeEach(function() {
var attrs;
store = Travis.Store.create();
attrs = {
id: 1,
name: 'foo'
};
return record = store.loadIncomplete(Travis.Foo, attrs);
});
it('shows if attribute is loaded', function() {
expect(record.isAttributeLoaded('name')).toBeTruthy();
return expect(record.isAttributeLoaded('description')).toBeFalsy();
});
it('does not trigger a request when getting known attribute', function() {
expect(record.get('name')).toEqual('foo');
waits(50);
return runs(function() {
return expect(record.get('complete')).toBeFalsy();
});
});
it('loads missing data on try to get it', function() {
expect(record.get('name')).toEqual('foo');
expect(record.get('description')).toBeNull();
waits(50);
return runs(function() {
expect(record.get('description')).toEqual('bar');
expect(record.get('complete')).toBeTruthy();
return expect(record.get('isComplete')).toBeTruthy();
});
});
return it('does not set incomplete on the record twice', function() {
record.get('description');
waits(50);
return runs(function() {
store.loadIncomplete(Travis.Foo, {
id: 1
});
return expect(record.get('incomplete')).toBeFalsy();
});
});
});
});
}).call(this);

File diff suppressed because it is too large Load Diff

View File

@ -1 +1 @@
4b27d9a7 e090359a