Skip to content

Commit

Permalink
Merge pull request FirebaseExtended#373 from steven-ferguson/custom-k…
Browse files Browse the repository at this point in the history
…eys-embedded

Respect keyForRelationship for embedded records
  • Loading branch information
tstirrat committed Apr 12, 2016
2 parents f417915 + e290243 commit 1a33473
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 52 deletions.
25 changes: 14 additions & 11 deletions addon/adapters/firebase.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export default DS.Adapter.extend(Waitable, {

return this._fetch(ref, log).then((snapshot) => {
var payload = this._assignIdToPayload(snapshot);
this._updateRecordCacheForType(typeClass, payload);
this._updateRecordCacheForType(typeClass, payload, store);
if (payload === null) {
var error = new Error(`no record was found at ${ref.toString()}`);
error.recordId = id;
Expand Down Expand Up @@ -174,7 +174,7 @@ export default DS.Adapter.extend(Waitable, {
var inverseKey = record.inverseFor(relationship.key);
if (inverseKey && parentRecord.get('id')) {
var parentRef = this._getCollectionRef(inverseKey.type, parentRecord.get('id'));
this._removeHasManyRecord(store, parentRef, inverseKey.name, record.id);
this._removeHasManyRecord(store, parentRef, inverseKey.name, record.constructor, record.id);
}
}
});
Expand Down Expand Up @@ -231,7 +231,7 @@ export default DS.Adapter.extend(Waitable, {
var results = [];
snapshot.forEach((childSnapshot) => {
var payload = this._assignIdToPayload(childSnapshot);
this._updateRecordCacheForType(typeClass, payload);
this._updateRecordCacheForType(typeClass, payload, store);
results.push(payload);
});

Expand All @@ -252,7 +252,7 @@ export default DS.Adapter.extend(Waitable, {
if (!record || !record.__listening) {
var payload = this._assignIdToPayload(snapshot);
var normalizedData = store.normalize(typeClass.modelName, payload);
this._updateRecordCacheForType(typeClass, payload);
this._updateRecordCacheForType(typeClass, payload, store);
record = store.push(normalizedData);
}

Expand Down Expand Up @@ -289,7 +289,7 @@ export default DS.Adapter.extend(Waitable, {
var results = [];
snapshot.forEach((childSnapshot) => {
var payload = this._assignIdToPayload(childSnapshot);
this._updateRecordCacheForType(typeClass, payload);
this._updateRecordCacheForType(typeClass, payload, store);
results.push(payload);
});
return results;
Expand Down Expand Up @@ -516,7 +516,7 @@ export default DS.Adapter.extend(Waitable, {
});

removedRecords = map(removedRecords, (id) => {
return this._removeHasManyRecord(store, recordRef, relationship.key, id);
return this._removeHasManyRecord(store, recordRef, relationship.key, typeClass, id);
});
// Combine all the saved records
var savedRecords = dirtyRecords.concat(removedRecords);
Expand Down Expand Up @@ -589,8 +589,9 @@ export default DS.Adapter.extend(Waitable, {
/**
* Remove a relationship
*/
_removeHasManyRecord(store, parentRef, key, id) {
var ref = this._getRelationshipRef(parentRef, key, id);
_removeHasManyRecord(store, parentRef, key, typeClass, id) {
const relationshipKey = store.serializerFor(typeClass.modelName).keyForRelationship(key);
var ref = this._getRelationshipRef(parentRef, relationshipKey, id);
return toPromise(ref.remove, ref, [], ref.toString());
},

Expand Down Expand Up @@ -658,7 +659,8 @@ export default DS.Adapter.extend(Waitable, {

if (embeddingParent) {
var { record: parent, relationship } = embeddingParent;
var recordRef = this._getAbsoluteRef(parent).child(relationship.key);
const embeddedKey = parent.store.serializerFor(parent.modelName).keyForRelationship(relationship.key);
var recordRef = this._getAbsoluteRef(parent).child(embeddedKey);

if (relationship.kind === 'hasMany') {
recordRef = recordRef.child(record.id);
Expand Down Expand Up @@ -760,14 +762,15 @@ export default DS.Adapter.extend(Waitable, {
/**
* _updateHasManyCacheForType
*/
_updateRecordCacheForType(typeClass, payload) {
_updateRecordCacheForType(typeClass, payload, store) {
if (!payload) { return; }
var id = payload.id;
var cache = this._getRecordCache(typeClass, id);
const serializer = store.serializerFor(typeClass.modelName);
// Only cache relationships for now
typeClass.eachRelationship((key, relationship) => {
if (relationship.kind === 'hasMany') {
var ids = payload[key];
var ids = payload[serializer.keyForRelationship(key)];
cache[key] = !Ember.isNone(ids) ? Ember.A(Object.keys(ids)) : Ember.A();
}
});
Expand Down
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fixed - `keyForRelationship` now works for embedded records.
218 changes: 177 additions & 41 deletions tests/integration/updating-records-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -514,63 +514,199 @@ 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'
describe('when keyForRelationship is overwritten in serializer', function() {
it('adds belongsTo', function(done) {
const reference = firebaseTestRef.child('CapitalizedRelations');
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();
});
});
});
});

let newPost = store.createRecord('post', {
title: 'New Post',
user: user
it('adds hasMany', function(done) {
const reference = firebaseTestRef.child('CapitalizedRelations');
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();
});
});
});
});

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('removes hasMany', function(done) {
const reference = firebaseTestRef.child('CapitalizedRelations');
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 commentA = store.createRecord('comment', {
body: 'A comment'
});

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

post.save().then(() => {
return Ember.RSVP.all([
commentA.save(),
commentB.save()
]);
}).then(() => {
post.set('comments', [commentA, commentB]);
return post.save();
}).then(() => {
post.set('comments', [commentA]);
return post.save();
}).then(() => {
reference.once('value', fbSnapshot => {
const postData = fbSnapshot.val().posts[post.get('id')];
expect(postData.Comments).to.not.have.all.keys([commentB.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);
};
it('saves embedded hasMany', function(done) {
const reference = firebaseTestRef.child('CapitalizedRelations');
adapter._ref = reference;
store.serializerFor('tree-node').keyForRelationship = function(key) {
return Ember.String.capitalize(key);
};

Ember.run(function() {
let parentRecord = store.createRecord('tree-node', {
label: 'Parent Node'
});
let embeddedRecord = store.createRecord('tree-node', {
label: 'Child Node'
});

Ember.run(function() {
let post = store.createRecord('post', {
title: 'New Post'
const parentId = parentRecord.get('id');
const embeddedId = embeddedRecord.get('id');
parentRecord.get('children').addObject(embeddedRecord);
parentRecord.save().then(function() {
reference.once('value', function(snapshot) {
const parentData = snapshot.val().treeNodes[parentId];
expect(parentData.Children).to.have.all.keys(embeddedId);
done();
});
});
});
});

it('removes embedded hasMany', function(done) {
const reference = firebaseTestRef.child('CapitalizedRelations');
adapter._ref = reference;
store.serializerFor('tree-node').keyForRelationship = function(key) {
return Ember.String.capitalize(key);
};

Ember.run(function() {
let parentRecord = store.createRecord('tree-node', {
label: 'Parent Node'
});

let embeddedRecordA = store.createRecord('tree-node', {
label: 'Child Node'
});

let embeddedRecordB = store.createRecord('tree-node', {
label: 'Another Child Node'
});

let comment = store.createRecord('comment', {
body: 'A comment'
const parentId = parentRecord.get('id');
const embeddedId = embeddedRecordB.get('id');
parentRecord.get('children').addObjects([embeddedRecordA, embeddedRecordB]);
parentRecord.save().then(() => {
embeddedRecordB.destroyRecord();
return parentRecord.save();
}).then(function() {
reference.once('value', function(snapshot) {
const parentData = snapshot.val().treeNodes[parentId];
expect(parentData.Children).to.not.have.all.keys(embeddedId);
done();
});
});
});
});

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();
it('saves embedded belongsTo', function(done) {
const reference = firebaseTestRef.child('CapitalizedRelations');
adapter._ref = reference;
store.serializerFor('tree-node').keyForRelationship = function(key) {
return Ember.String.capitalize(key);
};

Ember.run(function() {
let parentRecord = store.createRecord('tree-node', {
label: 'Parent'
});
let embeddedRecord = store.createRecord('tree-node-config', {
sync: true
});
const parentId = parentRecord.get('id');
const embeddedId = embeddedRecord.get('id');
parentRecord.set('config', embeddedRecord);
parentRecord.save().then(function() {
reference.once('value', function(data) {
const parentData = data.val().treeNodes[parentId];
expect(parentData.Config).to.deep.equal({
id: embeddedId,
sync: true
});
done();
});
});
});
});
});
});

});

0 comments on commit 1a33473

Please sign in to comment.