Created
April 7, 2020 19:37
-
-
Save betocantu93/a40daa515cbd829df159a97c233c8826 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 Mixin from '@ember/object/mixin'; | |
import Ember from 'ember'; | |
import { singularize } from 'ember-inflector'; | |
export default Mixin.create({ | |
// ember temporary ids | |
_tempIds: {}, | |
//************************ | |
//***REQUEST SECTION****** | |
//************************ | |
//#4 serialize a related record, example: if creating a visit this will serialize each associated report | |
//this is where the actual relationship object get built and added to the json | |
serializeRecord(obj) { | |
if (!obj) { return null;} | |
//build the instance | |
const relatedRecord = obj.serialize({__isSaveRelationshipsMixinCallback: true}); | |
if (obj.id) { | |
relatedRecord.data.id = obj.id; | |
this.get('_tempIds')[obj.id] = {}; | |
} else { | |
relatedRecord.data.id = ''; //required in jsonapi | |
if (!relatedRecord.data.attributes) { //default hash | |
relatedRecord.data.attributes = {}; | |
} | |
relatedRecord.data.attributes['emberid'] = obj.record.get('_internalModel')[Ember.GUID_KEY]; //set temporary id | |
this.get('_tempIds')[relatedRecord.data.attributes['emberid']] = {}; //store temporary in hash | |
} | |
// verify that relatedRecord does not have a relationship with a name present in _tempIds | |
// TODO this might not be necessary | |
for (let relationshipName in relatedRecord.data.relationships) { | |
if (this.get('_tempIds')[relationshipName]){ | |
alert('this is necessary'); | |
delete relatedRecord.data.relationships[relationshipName]; | |
} | |
} | |
//remove relationships key if none present | |
if (relatedRecord.data.relationships === {}){ | |
delete relatedRecord.data.relationships; | |
} | |
return relatedRecord.data; | |
}, | |
// #3 function that modifies the serialization of the snapshot to include its relationships in the json | |
serializeRelationship(snapshot, data, rel) { | |
const relKind = rel.kind; | |
const relKey = rel.key; | |
//only if serialize: true is specified in the serializer | |
if (data && this.get(`attrs.${relKey}.serialize`) === true) { | |
data.relationships = data.relationships || {}; | |
const key = this.keyForRelationship(relKey, relKind, 'serialize'); | |
const relationship = data.relationships[key] = data.relationships[key] || {}; | |
if (relKind === "belongsTo") { | |
relationship.data = this.serializeRecord(snapshot.belongsTo(relKey)); //add serialized relationship record | |
} else if (relKind === "hasMany") { | |
relationship.data = []; // provide a default empty value | |
const hasMany = snapshot.hasMany(relKey); | |
if (hasMany !== undefined) { | |
relationship.data = hasMany.map(this.serializeRecord.bind(this)); //add each serialized relationship record | |
} | |
} | |
} | |
}, | |
//#2 ember data hook for hasMany relationships (runs for every hasMany relationship in model) | |
serializeHasMany() { | |
this._super(...arguments); | |
this.serializeRelationship(...arguments); | |
}, | |
//#2 ember data hook for belongsTo relationships (runs for every belongsTo relationship in model) | |
serializeBelongsTo() { | |
this._super(...arguments); | |
this.serializeRelationship(...arguments); | |
}, | |
// #1 to run, runs only once | |
serialize (snapshot, options) { | |
if (!(options && options.__isSaveRelationshipsMixinCallback)) { | |
this.set("_tempIds", {}); | |
} | |
return this._super(...arguments); | |
}, | |
//************************ | |
//***RESPONSE SECTION***** | |
//************************ | |
// last method to run, removes uncommitted model item so it is not duplicated | |
updateRelatedRecord(json, store) { | |
if (json.attributes !== undefined && json.attributes['emberid'] !== undefined){ | |
json.type = singularize(json.type); | |
const record = store.peekAll(json.type) | |
.filterBy('currentState.stateName', "root.loaded.created.uncommitted") | |
.findBy('_internalModel.' + Ember.GUID_KEY, json.attributes['emberid']); | |
if(record) { | |
record.rollbackAttributes(); | |
} | |
} | |
return json; | |
}, | |
// #1 ember data hook used to normalize the server response | |
normalizeSaveResponse(store, primaryModelClass, payload, id, requestType) { | |
requestType; | |
const rels = payload.data.relationships || []; | |
let included = {}; //hash to store jsonapi included section | |
//convert included array into a hash {model3: {id: 3..}, model170: {id: 170...} ...} | |
if (payload.included){ | |
included = payload.included.reduce((prev, current) => { | |
prev[`${current.type}${current.id}`] = current; | |
return prev; | |
}, {}); | |
} | |
Object.keys(rels).forEach(relName => { | |
let relationshipData = rels[relName].data; | |
if (relationshipData){ | |
this.normalizeRelationship(relationshipData, store, included); | |
} | |
}); | |
// run through the included objects looking for client ids | |
if (payload.included) { | |
for(let includedItem of payload.included) { | |
this.updateRelatedRecord(includedItem, store); | |
} | |
} | |
return this._super(...arguments); | |
}, | |
//normalizeRelationshipItem and normalizeRelationship are only used to call updateRelatedRecord | |
//when the relationship data is returned in the 'relationships' section of jsonapi response | |
//instead of in the 'included' section | |
// normalize relationships for belongsTo and hasMany | |
normalizeRelationship(relationshipData, store, included) { | |
if (Array.isArray(relationshipData)) { | |
// hasMany | |
relationshipData = relationshipData.map(item => this.normalizeRelationshipItem(item, store, included)); | |
} else if (relationshipData) { | |
this.normalizeRelationshipItem(relationshipData, store, included); | |
} | |
}, | |
//adds __normalized flag and calls updateRelatedRecord if data is not in 'included' section of response | |
normalizeRelationshipItem(item, store, included) { | |
if (item.__normalized) { return; } // skip if already normalized | |
item.__normalized = true; | |
let includedData = included[`${item.type}${item.id}`]; | |
if (includedData){ | |
item = includedData; | |
} | |
let internalRelationships = item.relationships; | |
if (internalRelationships !== undefined) { //go recursive | |
Object.keys(internalRelationships).forEach(relName => { | |
let relationshipData = internalRelationships[relName].data; | |
if (relationshipData){ | |
this.normalizeRelationship(relationshipData, store, included); | |
} | |
}); | |
} | |
if (!includedData) { | |
// if it's in the included block then it will be updated at the end of normalizeSaveResponse | |
this.updateRelatedRecord(item, store); | |
} | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment