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'
end
match 'spec/*.js' do
match '{spec,spec/unit}/*.js' do
concat 'spec/specs.js'
end

View File

@ -43,7 +43,7 @@ GIT
GIT
remote: git://github.com/travis-ci/travis-api.git
revision: 816ebc66c8b65c44d6144e721b1b4f048e86d7df
revision: 558847f6555202adb7da4f7d31a7b2b80ab4bac2
specs:
travis-api (0.0.1)
backports (~> 2.5)
@ -61,7 +61,7 @@ GIT
GIT
remote: git://github.com/travis-ci/travis-core.git
revision: 56ca16046cba99cc0b4cd0c520c6bb13ace9932a
revision: abac97114a36f3a6715e118cc1f90c05a08004f6
branch: sf-travis-api
specs:
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
# be revised
if type == Travis.Build && json.repository
result = @_loadIncomplete(Travis.Repo, 'repository', json.repository)
@_loadIncomplete(type, root, json[root])
result = @loadIncomplete(Travis.Repo, json.repository)
@loadIncomplete(type, json[root])
_loadIncomplete: (type, root, hash) ->
loadIncomplete: (type, hash) ->
result = @merge(type, hash)
if result && result.clientId
record = @findByClientId(type, result.clientId)
unless record.get('complete')
record.set 'incomplete', true
record.loadedAttributes = Object.keys hash
@_updateAssociations(type, root, hash)
@_updateAssociations(type, type.singularName(), hash)
record
_loadMany: (store, type, json) ->
root = type.pluralName()

View File

@ -2,6 +2,12 @@
primaryKey: 'id'
id: DS.attr('number')
get: (name) ->
if @constructor.isAttribute(name) && @get('incomplete') && !@isAttributeLoaded(name)
@loadTheRest()
@_super.apply this, arguments
refresh: ->
if id = @get('id')
store = @get('store')
@ -12,6 +18,9 @@
@set(key, value) unless key is 'id'
this
isAttributeLoaded: (name) ->
@loadedAttributes.contains(name)
isComplete: (->
if @get 'incomplete'
@loadTheRest()
@ -63,3 +72,16 @@
pluralName: ->
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;
}).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