-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Pay go setup relationships #4821
Conversation
ac26ee6
to
c6a496e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've done a partial review, will do more next.
*/ | ||
_getRelationshipPayloads(modelName, relationshipName) { | ||
// TODO: lightschema this | ||
let modelClass = this._store._modelFor(modelName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this be _modelFor
over store.modelFor
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's strictly internal, so by the time we get here modelName
should already be normalized. I'm fine with normalizing here (ie calling this._store.modelFor
instead of this._store._modelFor
) for simplicity's sake.
export default class RelationshipsPayloads { | ||
constructor(store) { | ||
this._store = store; | ||
this._map = {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thoughts on renaming this to cache
with a comment of // cache for relationshipPayloads
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
*/ | ||
_getRelationshipPayloads(modelName, relationshipName) { | ||
// TODO: lightschema this | ||
let modelClass = this._store._modelFor(modelName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if _getRelationshipPayload
should take also take relationshipsByName
as an argument.
In push
and unload
the callers of this method invoke it in a loop and for each iteration of the loop modelClass
is constant, but yet each iteration must repeatedly lookup modelClass
modelClass.relationshipsByName
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@@ -463,8 +463,8 @@ testInDebug("Inverse relationships that don't exist throw a nice error for a bel | |||
}, /We found no inverse relationships by the name of 'testPost' on the 'user' model/); | |||
}); | |||
|
|||
test("inverseFor is only called when inverse is not null", function(assert) { | |||
assert.expect(2); | |||
test("inverseFor short-circuits when inverse is null", function(assert) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that we have both inverseFor
and _inverseFor
should we test both of them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking more closely, we don't need to introduce _inverseFor
; the point was just to separate the API from the work so we can test that the expensive path is not taken, but this separation already exists between inverseFor
and _findInverseFor
, so I've updated the tests to assert that inverseFor
short-circuits _findInverseFor
rather than _inverseFor
.
@@ -505,6 +505,7 @@ export default class InternalModel { | |||
assert("Cannot destroy an internalModel while its record is materialized", !this.record || this.record.get('isDestroyed') || this.record.get('isDestroying')); | |||
|
|||
this.store._removeFromIdMap(this); | |||
this.store._relationshipsPayloads.unload(this.modelName, this.id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we unify 507 and 508 into this.store._internalModelDestroyed(internalModel)
that way, we don't need to leak _removeFromIdMap
and _relationshipsPayload
private members to internalModel
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@@ -988,6 +991,8 @@ export default class InternalModel { | |||
*/ | |||
adapterDidCommit(data) { | |||
if (data) { | |||
this.store._relationshipsPayloads.push(this.modelName, this.id, data.relationships); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} | ||
} | ||
|
||
@class RelationshipsPayloads |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
likely should be marked as @private
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
*/ | ||
_inverseFor(modelName, relationshipName) { | ||
// TODO: lightschema this | ||
let modelClass = this._store._modelFor(modelName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this by modelFor
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} | ||
} | ||
|
||
_hasRecordForId(store, type, id) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this method does not appear to rely on this
, we should likely move it off the prototype and just to a module local helper function. Or, we should make it use this._store
internally.
When I see methods on this
I feel it suggests it needs access to this
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
get _lhsRelationshipIsMany() { | ||
if (this.__lhsRelatinoshipIsMany === undefined) { | ||
if (this._lhsModelName) { | ||
let modelClass = this._store.modelFor(this._lhsModelName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe both LHS and RHS modelClass's are loaded when RelationshipPayload is instantiated, should we just pass them in at construction? At that point, do we already have the relationship descriptor as well, or is that what we want lazy?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe both LHS and RHS modelClass's are loaded when RelationshipPayload is instantiated, should we just pass them in at construction? At that point, do we already have the relationship descriptor as well, or is that what we want lazy?
This is not necessarily the case. inverseFor
does not load the inverse class. Even when we check for the inverse relationship, we won't cause the inverse class to be loaded.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not necessarily the case. inverseFor does not load the inverse class. Even when we check for the inverse relationship, we won't cause the inverse class to be loaded.
Okay what I said is just wrong. I check this but obviously did not do so correctly. I'll push the classes down to RelationshipPayloads
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm just passing in the relationship meta since all we want off of it is to know whether or not this side of the relationship is a many side.
cb16735
to
c53997e
Compare
@stefanpenner i've responded to your review + done some additional perf tweaks. I've kept the changes separate, in c53997e if you want to look at only the changes |
addon/-private/system/model/model.js
Outdated
return this._inverseFor(name, store); | ||
}, | ||
|
||
_inverseFor(name, store) { | ||
let inverseMap = get(this, 'inverseMap'); | ||
if (inverseMap[name]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this also check for null
and if it is null
return null
, rather then failing this branch and looking it up again on 1315 only to find null
again?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
if (rel) { | ||
relationship = relationships[key] = createRelationshipFor(internalModel, rel, internalModel.store); | ||
} | ||
if (!rel) { return undefined; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we move this return to before line 60, that way we don't bother getting the relationshipPayload at all?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
relationship.pushFromInverse(payload); | ||
} | ||
if (relationshipPayload) { | ||
this.internalModel.store._backburner.join(function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
=>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm surprised this join
is required, whats it all about?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the thing that batches canonical flushes. In master this batching happens within _push
if (this.inverseKey) { | ||
let relationships = internalModel._relationships; | ||
let relationshipExisted = relationships.has(this.inverseKey); | ||
let relationship = relationships.get(this.inverseKey); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we move this line to 72, that way if the branch is not taken we don't lazily create the relationship at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No; this PR preserves the invariant that if a relationship is initialized, its inverse is also initialized.
We could change the invariant, but it would add complexity in the case where a relationship A gets its initial state from the payload of its inverse B, B is initialized and then mutated before A is initialized.
This is something we could do but it seems better to leave that for a separate PR
@@ -2839,6 +2839,7 @@ test("deleted records should stay deleted", function(assert) { | |||
message.destroyRecord() | |||
}); | |||
|
|||
self.halt=true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@@ -2853,7 +2854,12 @@ test("deleted records should stay deleted", function(assert) { | |||
} | |||
}] | |||
}); | |||
self.halt=false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@@ -518,6 +518,8 @@ export default class InternalModel { | |||
|
|||
setupData(data) { | |||
heimdall.increment(setupData); | |||
this.store._internalModelHasRelationshipData(this.modelName, this.id, data.relationships); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sounds like a boolean returning method, maybe something like received or process or something would be better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_internalModelDidGetGetRelationshipData
?
addon/-private/system/model/model.js
Outdated
return inverse; | ||
let relationship = get(this, 'relationshipsByName').get(name); | ||
if (!relationship) { | ||
return inverseMap[name] = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we not assign & return at the same time
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
addon/-private/system/model/model.js
Outdated
} | ||
|
||
let options = relationship.options; | ||
if (options && options.inverse === null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you leave a comment here please
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
let get = Ember.get; | ||
|
||
/** | ||
Manages relationship payloads for a given store. Acts as a single source of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you expand on this comment to say that this is only until the relationship is initialized
get(modelName, id, relationshipName) { | ||
let modelClass = this._store._modelFor(modelName); | ||
let relationshipsByName = get(modelClass, 'relationshipsByName'); | ||
let relationshipPayloads = this._getRelationshipPayloads(modelName, relationshipName, modelClass, relationshipsByName, false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you leave a comment as to why this signature is so long
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
|
||
let modelClass = this._store._modelFor(modelName); | ||
let relationshipsByName = get(modelClass, 'relationshipsByName'); | ||
for (let key in relationshipsData) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this safe to do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah yeah, i'll switch this to Object.keys().forEach
let modelClass = this._store._modelFor(modelName); | ||
let relationshipsByName = get(modelClass, 'relationshipsByName'); | ||
for (let key in relationshipsData) { | ||
let relationshipPayloads = this._getRelationshipPayloads(modelName, key, modelClass, relationshipsByName, true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe passing the relationship would simplify things?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unfortunately we'd need to also pass the inverse relationship, which we don't always need to compute
return this._cache[key]; | ||
} | ||
|
||
_initializeRelationshipPayloads(modelName, relationshipName, modelClass, relationshipsByName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method could use comments or breaking apart
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
this._rhsRelationshipMeta = inverseRelationshipMeta; | ||
|
||
this._lhsPayloads = {}; | ||
if (modelName !== inverseModelName || relationshipName !== inverseRelationshipName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain the goal behind this conditional
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added some comments in the then clause to explain, as well as expanded the comments in the else clause.
// then clause
// The common case of a non-reflexive relationship, or a reflexive
// relationship whose inverse is not itself
// else clause
// Edge case when we have a reflexive relationship to itself
// eg user hasMany friends inverse friends
//
// In this case there aren't really two sides to the relationship, but
// we set `_rhsPayloads = _lhsPayloads` to make things easier to reason
// about
this._isReflexive = true; | ||
} | ||
|
||
// either canoical on push or pending & flush |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment doesn't really tell me very much
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
get(modelName, id, relationshipName) { | ||
this._flushPending(); | ||
|
||
if (modelName === this._lhsModelName && relationshipName === this._lhsRelationshipName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you leave a comment explaining the logic behind mapping to lhs or rhs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
|
||
if (modelName === this._lhsModelName && relationshipName === this._lhsRelationshipName) { | ||
return this._lhsPayloads[id]; | ||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's add a debug check that asserts this is actually === rhsRelationshipName
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
unload(modelName, id, relationshipName) { | ||
this._flushPending(); | ||
|
||
if (modelName === this._lhsModelName && relationshipName === this._lhsRelationshipName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe extract into a method?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
_flushPending() { | ||
if (this._pendingPayloads.length === 0) { return; } | ||
|
||
let work = this._pendingPayloads.splice(0, this._pendingPayloads.length); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we rename this to payloadsToBeProcessed or something like that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure
} | ||
} | ||
|
||
if (modelName === this._lhsModelName && relationshipName === this._lhsRelationshipName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you leave a comment explaining the intent behind this blob
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
} | ||
} | ||
|
||
_inverseLoaded(payload) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems bad that the invariant from unloading where graphs are either unloaded together or not at all, is changed here
} | ||
} | ||
|
||
_populateInverse(relationshipData, inversePayload, inversePayloads, inverseIsMany) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When we rename the classes, can we rename this arguments as well please
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
k i've renamed inversePayloads
to inverseIdToPayloads
here and elsewhere
e42e839
to
dd55489
Compare
} | ||
} | ||
|
||
function hasRecordForId(store, type, id) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In case this sticks around can we verify this is needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's gone
@@ -36,6 +36,18 @@ export default class BelongsToRelationship extends Relationship { | |||
this.flushCanonicalLater(); | |||
} | |||
|
|||
setInitialCanonicalRecord(record) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we move this to a separate PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved to a separate commit within this PR in case we want to revert separately
relationship = relationships[key] = createRelationshipFor(internalModel, rel, internalModel.store); | ||
|
||
if (relationshipPayload) { | ||
this.internalModel.store._backburner.join(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check if this is needed
} | ||
this.flushCanonicalLater(); | ||
this.setHasData(true); | ||
} | ||
|
||
setupInverseRelationship(internalModel, initial) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need initial
here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
let relationships = internalModel._relationships; | ||
let relationshipExisted = relationships.has(this.inverseKey); | ||
let relationship = relationships.get(this.inverseKey); | ||
if (relationshipExisted || this.isPolymorphic) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you leave comments explaining
- The laziness
- why we are not lazy in the polymorphic case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
} else { | ||
let relationships = internalModel._implicitRelationships; | ||
let relationship = relationships[this.inverseKeyForImplicit]; | ||
if (!relationship) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The semantics here have not changed at all:
data/addon/-private/system/relationships/state/relationship.js
Lines 160 to 165 in 2edaf16
} else { | |
if (!record._implicitRelationships[this.inverseKeyForImplicit]) { | |
record._implicitRelationships[this.inverseKeyForImplicit] = new Relationship(this.store, record, this.key, { options: {} }); | |
} | |
record._implicitRelationships[this.inverseKeyForImplicit].addCanonicalRecord(this.record); | |
} |
addon/-private/system/store.js
Outdated
@@ -2403,14 +2412,15 @@ Store = Service.extend({ | |||
heimdall.increment(_setupRelationships); | |||
let setupToken = heimdall.start('store._setupRelationships'); | |||
let pushed = this._pushedInternalModels; | |||
let modelNameToInverseMap = Object.create(null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets see if there are perf benefits to caching this across runs
addon/-private/system/store.js
Outdated
@@ -2403,14 +2412,15 @@ Store = Service.extend({ | |||
heimdall.increment(_setupRelationships); | |||
let setupToken = heimdall.start('store._setupRelationships'); | |||
let pushed = this._pushedInternalModels; | |||
let modelNameToInverseMap = Object.create(null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you leave a comment as to why we do this
addon/-private/system/store.js
Outdated
@@ -2787,19 +2797,82 @@ function _commit(adapter, store, operation, snapshot) { | |||
}, label); | |||
} | |||
|
|||
function setupRelationships(store, internalModel, data) { | |||
function inverseRelationshipInitialized(store, internalModel, data, key, modelNameToInverseMap) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets rename this to isInverseRelationshipInitialized
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
addon/-private/system/store.js
Outdated
inverseMap = modelNameToInverseMap[internalModel.modelName] = get(internalModel.type, 'inverseMap'); | ||
} | ||
let inverseData = inverseMap[key]; | ||
if (inverseData === undefined) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets rename this to something like inverseRelationshipMetadata
/something not containing the word Data
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
addon/-private/system/store.js
Outdated
let relationship = internalModel._relationships.get(key); | ||
relationship.push(data.relationships[key]); | ||
}); | ||
for (let key in data.relationships) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets try switching this back to eachRelationship
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep this seems good; also with the setInitial work the backburner.join run in relationships/store/create seems unnecessary
bf5db27
to
97dd39d
Compare
@igorT @stefanpenner this is ready to merge. |
addon/-private/system/store.js
Outdated
if (relationshipRequiresNotification) { | ||
let relationshipData = data.relationships[relationshipName]; | ||
relationships.get(relationshipName).push(relationshipData); | ||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We were gonna remove this else right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah you're right, LMK push this fix
- add option for expanding relationships - make eager materialize materialize included as well
The goal here is to do as little work as we can with relationship payloads until the relationship is actually accessed. In an extreme case, where many relationship payloads are pushed, but no relationships are accessed, all we want to do is stash the payload.
We don't need to go through `computeChanges`, `flushCqnonical` &c. when initializing relationships. Treating initial payloads the same as updated payloads is costly.
97dd39d
to
f8304b2
Compare
Looks like this has broken for JSONAPI payloads which contain When accessing a relationship in a template I now get the following error, going to before this PR was merged works fine:
Looks like Tried to make a Twiddle, but the example Twiddle appears to be broken at the moment. |
@rlivsey can you open a new issue so this isn't lost? (also ideally a failing test suite will make this much more actionable) |
@stefanpenner yup, was trying to make a repro first but will open an issue once I get the kids to bed! |
The goal here is to do as little work as we can with relationship payloads until the relationship is actually accessed. In an extreme case, where many relationship payloads are pushed, but no relationships are accessed, all we want to do is stash the payload.
So what we want is
Testing on my early 2015 13" macbook pro I get a substantial improvement on pushing relationships that aren't accessed.
For my test case of 2800 models and 4800 relationships lazy relationships is about 2.2x as fast when no relationship is accessed.
master
pr
For my test case of 2800 models and 4800 relationships lazy relationships costs about as much as master
master
pr