Created
March 3, 2019 04:34
-
-
Save villander/e1cb45ef7a29e9ed9059a638b4c178de to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { assertPolymorphicType } from "../../../-debug"; | |
import Model from '../model/model'; | |
import Reference from './reference'; | |
import recordDataFor from '../record-data-for'; | |
/** | |
A BelongsToReference is a low-level API that allows users and | |
addon author to perform meta-operations on a belongs-to | |
relationship. | |
@class BelongsToReference | |
@namespace DS | |
@extends DS.Reference | |
*/ | |
export default class BelongsToReference extends Reference { | |
constructor(store, parentInternalModel, belongsToRelationship, key) { | |
super(store, parentInternalModel); | |
this.key = key; | |
this.belongsToRelationship = belongsToRelationship; | |
this.type = belongsToRelationship.relationshipMeta.type; | |
this.parent = parentInternalModel.recordReference; | |
this.parentInternalModel = parentInternalModel; // TODO inverse | |
} | |
/** | |
The `id` of the record that this reference refers to. Together, the | |
`type()` and `id()` methods form a composite key for the identity | |
map. This can be used to access the id of an async relationship | |
without triggering a fetch that would normally happen if you | |
attempted to use `record.get('relationship.id')`. | |
Example | |
```javascript | |
// models/blog.js | |
export default DS.Model.extend({ | |
user: DS.belongsTo({ async: true }) | |
}); | |
let blog = store.push({ | |
data: { | |
type: 'blog', | |
id: 1, | |
relationships: { | |
user: { | |
data: { type: 'user', id: 1 } | |
} | |
} | |
} | |
}); | |
let userRef = blog.belongsTo('user'); | |
// get the identifier of the reference | |
if (userRef.remoteType() === "id") { | |
let id = userRef.id(); | |
} | |
``` | |
@method id | |
@return {String} The id of the record in this belongsTo relationship. | |
*/ | |
id() { | |
var id = null; | |
var resource = this._resource(); | |
if (resource && resource.data && resource.data.id) { | |
id = resource.data.id; | |
} | |
return id; | |
} | |
_resource() { | |
return this.recordData.getBelongsTo(this.key); | |
} | |
/** | |
`push` can be used to update the data in the relationship and Ember | |
Data will treat the new data as the conanical value of this | |
relationship on the backend. | |
Example | |
```javascript | |
// models/blog.js | |
export default DS.Model.extend({ | |
user: DS.belongsTo({ async: true }) | |
}); | |
let blog = store.push({ | |
data: { | |
type: 'blog', | |
id: 1, | |
relationships: { | |
user: { | |
data: { type: 'user', id: 1 } | |
} | |
} | |
} | |
}); | |
let userRef = blog.belongsTo('user'); | |
// provide data for reference | |
userRef.push({ | |
data: { | |
type: 'user', | |
id: 1, | |
attributes: { | |
username: "@user" | |
} | |
} | |
}).then(function(user) { | |
userRef.value() === user; | |
}); | |
``` | |
@method push | |
@param {Object|Promise} objectOrPromise a promise that resolves to a JSONAPI document object describing the new value of this relationship. | |
@return {Promise<record>} A promise that resolves with the new value in this belongs-to relationship. | |
*/ | |
push(objectOrPromise) { | |
return Ember.RSVP.resolve(objectOrPromise).then(data => { | |
var record; // TODO deprecate data as Model | |
if (data instanceof Model) { | |
record = data; | |
} else { | |
record = this.store.push(data); | |
} | |
assertPolymorphicType(this.internalModel, this.belongsToRelationship.relationshipMeta, record._internalModel, this.store); //TODO Igor cleanup, maybe move to relationship push | |
this.belongsToRelationship.setCanonicalRecordData(recordDataFor(record)); | |
return record; | |
}); | |
} | |
/** | |
`value()` synchronously returns the current value of the belongs-to | |
relationship. Unlike `record.get('relationshipName')`, calling | |
`value()` on a reference does not trigger a fetch if the async | |
relationship is not yet loaded. If the relationship is not loaded | |
it will always return `null`. | |
Example | |
```javascript | |
// models/blog.js | |
export default DS.Model.extend({ | |
user: DS.belongsTo({ async: true }) | |
}); | |
let blog = store.push({ | |
data: { | |
type: 'blog', | |
id: 1, | |
relationships: { | |
user: { | |
data: { type: 'user', id: 1 } | |
} | |
} | |
} | |
}); | |
let userRef = blog.belongsTo('user'); | |
userRef.value(); // null | |
// provide data for reference | |
userRef.push({ | |
data: { | |
type: 'user', | |
id: 1, | |
attributes: { | |
username: "@user" | |
} | |
} | |
}).then(function(user) { | |
userRef.value(); // user | |
}); | |
``` | |
@method value | |
@return {DS.Model} the record in this relationship | |
*/ | |
value() { | |
var store = this.parentInternalModel.store; | |
var resource = this._resource(); | |
if (resource && resource.data) { | |
var inverseInternalModel = store._internalModelForResource(resource.data); | |
if (inverseInternalModel && inverseInternalModel.isLoaded()) { | |
return inverseInternalModel.getRecord(); | |
} | |
} | |
return null; | |
} | |
/** | |
Loads a record in a belongs to relationship if it is not already | |
loaded. If the relationship is already loaded this method does not | |
trigger a new load. | |
Example | |
```javascript | |
// models/blog.js | |
export default DS.Model.extend({ | |
user: DS.belongsTo({ async: true }) | |
}); | |
let blog = store.push({ | |
data: { | |
type: 'blog', | |
id: 1, | |
relationships: { | |
user: { | |
data: { type: 'user', id: 1 } | |
} | |
} | |
} | |
}); | |
let userRef = blog.belongsTo('user'); | |
userRef.value(); // null | |
userRef.load().then(function(user) { | |
userRef.value() === user | |
}); | |
``` | |
You may also pass in an options object whose properties will be | |
fed forward. This enables you to pass `adapterOptions` into the | |
request given to the adapter via the reference. | |
Example | |
```javascript | |
userRef.load({ adapterOptions: { isPrivate: true } }).then(function(user) { | |
userRef.value() === user; | |
}); | |
``` | |
```app/adapters/user.js | |
export default ApplicationAdapter.extend({ | |
findRecord(store, type, id, snapshot) { | |
// In the adapter you will have access to adapterOptions. | |
let adapterOptions = snapshot.adapterOptions; | |
} | |
}); | |
``` | |
@method load | |
@param {Object} options the options to pass in. | |
@return {Promise} a promise that resolves with the record in this belongs-to relationship. | |
*/ | |
load(options) { | |
return this.parentInternalModel.getBelongsTo(this.key, options); | |
} | |
/** | |
Triggers a reload of the value in this relationship. If the | |
remoteType is `"link"` Ember Data will use the relationship link to | |
reload the relationship. Otherwise it will reload the record by its | |
id. | |
Example | |
```javascript | |
// models/blog.js | |
export default DS.Model.extend({ | |
user: DS.belongsTo({ async: true }) | |
}); | |
let blog = store.push({ | |
data: { | |
type: 'blog', | |
id: 1, | |
relationships: { | |
user: { | |
data: { type: 'user', id: 1 } | |
} | |
} | |
} | |
}); | |
let userRef = blog.belongsTo('user'); | |
userRef.reload().then(function(user) { | |
userRef.value() === user | |
}); | |
``` | |
You may also pass in an options object whose properties will be | |
fed forward. This enables you to pass `adapterOptions` into the | |
request given to the adapter via the reference. A full example | |
can be found in the `load` method. | |
Example | |
```javascript | |
userRef.reload({ adapterOptions: { isPrivate: true } }) | |
``` | |
@method reload | |
@param {Object} options the options to pass in. | |
@return {Promise} a promise that resolves with the record in this belongs-to relationship after the reload has completed. | |
*/ | |
// TODO IGOR CHECK FOR OBJECT PROXIES | |
reload(options) { | |
var resource = this._resource(); | |
if (resource && resource.links && resource.links.related) { | |
return this.store._fetchBelongsToLinkFromResource(resource, this.parentInternalModel, this.belongsToRelationship.relationshipMeta, options); | |
} | |
if (resource && resource.data) { | |
if (resource.data && (resource.data.id || resource.data.clientId)) { | |
var internalModel = this.store._internalModelForResource(resource.data); | |
if (internalModel.isLoaded()) { | |
return internalModel.reload(options).then(internalModel => { | |
if (internalModel) { | |
return internalModel.getRecord(); | |
} | |
return null; | |
}); | |
} else { | |
return this.store._findByInternalModel(internalModel, options); | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment