Skip to content

Commit

Permalink
Add support for keyForRelationship
Browse files Browse the repository at this point in the history
  • Loading branch information
steven-ferguson committed Feb 24, 2016
1 parent b2bbd4f commit a302b06
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 19 deletions.
9 changes: 6 additions & 3 deletions addon/adapters/firebase.js
Original file line number Diff line number Diff line change
Expand Up @@ -415,13 +415,15 @@ export default DS.Adapter.extend(Waitable, {
var serializedRecord = snapshot.serialize({
includeId: (lastPiece !== snapshot.id) // record has no firebase `key` in path
});
const serializer = store.serializerFor(typeClass.modelName);

return new Promise((resolve, reject) => {
var relationshipsToSave = [];
// first we remove all relationships data from the serialized record, we backup the
// removed data so that we can save it at a later stage.
snapshot.record.eachRelationship((key, relationship) => {
const data = serializedRecord[key];
const relationshipKey = serializer.keyForRelationship(key);
const data = serializedRecord[relationshipKey];
const isEmbedded = this.isRelationshipEmbedded(store, typeClass.modelName, relationship);
const hasMany = relationship.kind === 'hasMany';
if (hasMany || isEmbedded) {
Expand All @@ -433,7 +435,7 @@ export default DS.Adapter.extend(Waitable, {
hasMany:hasMany
});
}
delete serializedRecord[key];
delete serializedRecord[relationshipKey];
}
});
var reportError = (errors) => {
Expand Down Expand Up @@ -544,7 +546,8 @@ export default DS.Adapter.extend(Waitable, {
* version of the record
*/
_saveHasManyRecord(store, typeClass, relationship, parentRef, id) {
var ref = this._getRelationshipRef(parentRef, relationship.key, id);
const serializer = store.serializerFor(typeClass.modelName);
var ref = this._getRelationshipRef(parentRef, serializer.keyForRelationship(relationship.key), id);
var record = store.peekRecord(relationship.type, id);
var isEmbedded = this.isRelationshipEmbedded(store, typeClass.modelName, relationship);
if (isEmbedded) {
Expand Down
32 changes: 17 additions & 15 deletions addon/serializers/firebase.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ export default DS.JSONSerializer.extend(DS.EmbeddedRecordsMixin, {
*/
extractRelationships(modelClass, payload) {
this.normalizeRelationships(modelClass, payload);

return this._super(modelClass, payload);
},

Expand Down Expand Up @@ -93,48 +92,51 @@ export default DS.JSONSerializer.extend(DS.EmbeddedRecordsMixin, {
*/
normalizeRelationships(modelClass, payload) {
modelClass.eachRelationship((key, meta) => {
if (meta.kind === 'hasMany') {
if (payload.hasOwnProperty(key)) {
let relationshipKey = this.keyForRelationship(key, meta.kind, 'deserialize');

if (meta.kind === 'hasMany') {
if (payload.hasOwnProperty(relationshipKey)) {
let relationshipPayload = payload[relationshipKey];
// embedded
if (this.hasDeserializeRecordsOption(key)) {
if (typeof payload[key] === 'object' && !Ember.isArray(payload[key])) {
payload[key] = Object.keys(payload[key]).map((id) => {
return assign({ id: id }, payload[key][id]);
if (typeof relationshipPayload === 'object' && !Ember.isArray(relationshipPayload)) {
relationshipPayload = Object.keys(relationshipPayload).map((id) => {
return assign({ id: id }, relationshipPayload[id]);
});
} else if (Ember.isArray(payload[key])) {
payload[key] = this._addNumericIdsToEmbeddedArray(payload[key]);
} else if (Ember.isArray(relationshipPayload)) {
relationshipPayload = this._addNumericIdsToEmbeddedArray(relationshipPayload);
} else {
throw new Error(`${modelClass.toString()} relationship ${meta.kind}('${meta.type}') must contain embedded records with an \`id\`. Example: { "${key}": { "${meta.type}_1": { "id": "${meta.type}_1" } } } instead got: ${JSON.stringify(payload[key])}`);
}
}

// normalized
else {
if (typeof payload[key] === 'object' && !Ember.isArray(payload[key])) {
payload[key] = Object.keys(payload[key]);
} else if (Ember.isArray(payload[key])) {
payload[key] = this._convertBooleanArrayToIds(payload[key]);
if (typeof relationshipPayload === 'object' && !Ember.isArray(relationshipPayload)) {
relationshipPayload = Object.keys(relationshipPayload);
} else if (Ember.isArray(relationshipPayload)) {
relationshipPayload = this._convertBooleanArrayToIds(relationshipPayload);
} else {
throw new Error(`${modelClass.toString()} relationship ${meta.kind}('${meta.type}') must be a key/value map. Example: { "${key}": { "${meta.type}_1": true } } instead got: ${JSON.stringify(payload[key])}`);
}
}

payload[relationshipKey] = relationshipPayload;
}

// hasMany property is not present
// server will not send a property which has no content
// (i.e. it will never send `comments: null`) so we need to
// force the empty relationship
else {
payload[key] = [];
payload[relationshipKey] = [];
}
}

if (meta.kind === 'belongsTo') {
if (!payload.hasOwnProperty(key)) {
if (!payload.hasOwnProperty(relationshipKey)) {
// server wont send property if it was made null elsewhere
payload[key] = null;
payload[relationshipKey] = null;
}
}
});
Expand Down
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fixed - EmberFire now respects the serializer's `keyForRelationship` method.
58 changes: 57 additions & 1 deletion tests/integration/updating-records-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,6 @@ describe('Integration: FirebaseAdapter - Updating records', function() {
parentId = parentRecord.get('id');
embeddedId = embeddedRecord.get('id');
parentRecord.get('children').addObject(embeddedRecord);
// debugger;
parentRecord.save().then(function() {
reference.once('value', function(snapshot) {
parentData = snapshot.val().treeNodes[parentId];
Expand Down Expand Up @@ -515,6 +514,63 @@ describe('Integration: FirebaseAdapter - Updating records', function() {

}); // embedded belongsTo records

it('respects keyForRelationship on belongsTo', function(done) {
const reference = firebaseTestRef.child('nonStandardKeys');
adapter._ref = reference;
store.serializerFor('application').keyForRelationship = function(key) {
return Ember.String.capitalize(key);
};

Ember.run(function() {
let user = store.createRecord('user', {
firstName: 'John'
});

let newPost = store.createRecord('post', {
title: 'New Post',
user: user
});

newPost.save().then(() => {
reference.once('value', fbSnapshot => {
const postData = fbSnapshot.val().posts[newPost.get('id')];
expect(postData.User).to.equal(user.get('id'));
done();
});
});
});
});

it('respects keyForRelationship on hasMany', function(done) {
const reference = firebaseTestRef.child('nonStandardKeys');
adapter._ref = reference;
store.serializerFor('application').keyForRelationship = function(key) {
return Ember.String.capitalize(key);
};

Ember.run(function() {
let post = store.createRecord('post', {
title: 'New Post'
});

let comment = store.createRecord('comment', {
body: 'A comment'
});

post.save().then(() => {
return comment.save();
}).then(() => {
post.set('comments', [comment]);
return post.save();
}).then(() => {
reference.once('value', fbSnapshot => {
const postData = fbSnapshot.val().posts[post.get('id')];
expect(postData.Comments).to.have.all.keys([comment.get('id')]);
done();
});
});
});
});
});

});
42 changes: 42 additions & 0 deletions tests/unit/serializers/firebase-test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* jshint expr:true */
import Ember from 'ember';
import { expect } from 'chai';
import {
describeModule,
Expand Down Expand Up @@ -251,6 +252,47 @@ describeModule(
});
});

it('respects keyForRelationship in belongsTo', function() {
let serializer = this.subject();
serializer.keyForRelationship = function(key) {
return Ember.String.capitalize(key);
};

let { data } = serializer.normalize(Post, {
id: 'post_1',
published: 1395162147646,
User: 'aputinski'
});

expect(data.relationships.user).to.deep.equal({
data: { type: 'user', id: 'aputinski' }
});
});

it('respects keyForRelationship in hasMany', function() {
let serializer = this.subject();
serializer.keyForRelationship = function(key) {
return Ember.String.capitalize(key);
};

let { data } = serializer.normalize(Post, {
id: 'post_1',
published: 1395162147646,
body: 'This is the first FireBlog post!',
title: 'Post 1',
Comments: {
comment_1: true,
comment_2: true
},
});

expect(data.relationships.comments).to.deep.equal({
data: [
{ type: 'comment', id: 'comment_1' },
{ type: 'comment', id: 'comment_2' }
]
});
});
}); // normalized relationships

describe('invalid data', function () {
Expand Down

0 comments on commit a302b06

Please sign in to comment.