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

[BUGFIX] enable lazy-relationship payloads to work with polymorphic relationships #5230

Merged
merged 16 commits into from
Feb 28, 2018
Merged
Show file tree
Hide file tree
Changes from 11 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
4 changes: 4 additions & 0 deletions addon/-private/system/model/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -1927,6 +1927,10 @@ if (DEBUG) {
// the computed property.
let meta = value.meta();

/*
This is buggy because if the parent has never been looked up
via `modelFor` it will not have `modelName` set.
*/
meta.parentType = proto.constructor;
}
}
Expand Down
11 changes: 2 additions & 9 deletions addon/-private/system/relationship-meta.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { singularize } from 'ember-inflector';
import normalizeModelName from './normalize-model-name';
import { DEBUG } from '@glimmer/env';

export function typeForRelationshipMeta(meta) {
let modelName;
Expand All @@ -13,19 +12,13 @@ export function typeForRelationshipMeta(meta) {
}

export function relationshipFromMeta(meta) {
let result = {
return {
key: meta.key,
kind: meta.kind,
type: typeForRelationshipMeta(meta),
options: meta.options,
options: meta.options,
name: meta.name,
parentType: meta.parentType,
isRelationship: true
};

if (DEBUG) {
result.parentType = meta.parentType;
}

return result;
}
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ export default class RelationshipPayloadsManager {
relationshipPayloads.get('user', 'hobbies') === relationshipPayloads.get('hobby', 'user');

The signature has a somewhat large arity to avoid extra work, such as
a) string maipulation & allocation with `modelName` and
a) string manipulation & allocation with `modelName` and
`relationshipName`
b) repeatedly getting `relationshipsByName` via `Ember.get`

Expand All @@ -172,7 +172,28 @@ export default class RelationshipPayloadsManager {
return this._initializeRelationshipPayloads(modelName, relationshipName, modelClass, relationshipsByName);
}

return this._cache[key];
let cache = this._cache[key];

if (cache === undefined) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add comments here as to what we are doing

let inverseMeta = modelClass.inverseFor(relationshipName, this._store);

if (inverseMeta) {
let inverseRelationshipMeta = get(inverseMeta.type, 'relationshipsByName').get(inverseMeta.name);
let baseModelName = inverseRelationshipMeta.type;

if (baseModelName !== modelName) {
let baseKey = `${baseModelName}:${relationshipName}`;
cache = this._cache[baseKey];

if (cache !== undefined) {
cache.addPolymorphicType(baseModelName, modelName);
this._cache[key] = cache;
}
}
}
}

return cache;
}

/**
Expand All @@ -184,18 +205,24 @@ export default class RelationshipPayloadsManager {
_initializeRelationshipPayloads(modelName, relationshipName, modelClass, relationshipsByName) {
let relationshipMeta = relationshipsByName.get(relationshipName);
let inverseMeta = modelClass.inverseFor(relationshipName, this._store);

let selfIsPolymorphic = relationshipMeta.options !== undefined && relationshipMeta.options.polymorphic === true;
let baseModelName = modelName;
let inverseModelName;
let inverseRelationshipName;
let inverseRelationshipMeta;
let inverseIsPolymorphic = false;
let existingPolymorphicCache;

// figure out the inverse relationship; we need two things
// a) the inverse model name
//- b) the name of the inverse relationship
// b) the name of the inverse relationship
if (inverseMeta) {
inverseRelationshipName = inverseMeta.name
inverseRelationshipName = inverseMeta.name;
inverseModelName = relationshipMeta.type;
inverseRelationshipMeta = get(inverseMeta.type, 'relationshipsByName').get(inverseRelationshipName);
inverseIsPolymorphic = inverseRelationshipMeta.options !== undefined && inverseRelationshipMeta.options.polymorphic === true;

baseModelName = inverseRelationshipMeta.type;
} else {
// relationship has no inverse
inverseModelName = inverseRelationshipName = '';
Expand All @@ -204,14 +231,29 @@ export default class RelationshipPayloadsManager {

let lhsKey = `${modelName}:${relationshipName}`;
let rhsKey = `${inverseModelName}:${inverseRelationshipName}`;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as discussed out of band, in both cases we want the key to be the model name defined by the inverse relationship, when an inverse relationship exists

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so we should always create RelationshipPayloads with the base name and then add the actual model name

let lhsBaseKey = `${baseModelName}:${relationshipName}`;

if (inverseIsPolymorphic === true) {
existingPolymorphicCache = this._cache[rhsKey];
} else if (selfIsPolymorphic) {
existingPolymorphicCache = this._cache[lhsBaseKey];
}

if (existingPolymorphicCache !== undefined) {
this._cache[lhsKey] = existingPolymorphicCache;

existingPolymorphicCache.addPolymorphicType(baseModelName, modelName);

return existingPolymorphicCache;
}

// populate the cache for both sides of the relationship, as they both use
// the same `RelationshipPayloads`.
//
// This works out better than creating a single common key, because to
// compute that key we would need to do work to look up the inverse
//
return this._cache[lhsKey] =
return this._cache[lhsBaseKey] = this._cache[lhsKey] =
this._cache[rhsKey] =
new RelationshipPayloads(
this._store,
Expand Down
Loading