-
Notifications
You must be signed in to change notification settings - Fork 263
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
relation ships are now saved after the record itself #365
relation ships are now saved after the record itself #365
Conversation
…to be applied while creating records
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). 📝 Please visit https://cla.developers.google.com/ to sign. Once you've signed, please reply here (e.g.
|
I signed it! |
CLAs look good, thanks! |
not copy pasting code is always a good idea.
Seems like the last commit did not trigger a rebuild :(, @tstirrat any chance you can help or should I just push a dummy commit ? I also found why I needed to reload some records after saving it happens when you create a record with relationship belongsTo -> hasMany relationship, and save the belongsTo ( parent ) first. Ember data has some bad code that check if the relationship element is "new" and is so push it again in the "hasMany" relationship. I have filled a bug at ember data, but you can fix it by saving the child before the parent ( in some case it it is not possible ). |
for reference: emberjs/data#4149 |
I tried to kick off the build again but it runs on the second to last commit, sorry |
Submitted à pullrequest to ember data for the fix as well as test for repro & proof of fix |
Then I'm going to submit a dummy |
reject(error); | ||
} else { | ||
resolve(); | ||
recordPromise.then( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can combine this with the prior line this._updateRecord().then()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dont think I can, since recordPromise is used later in the callback
On Thu, Feb 11, 2016 at 8:09 PM, Tim Stirrat [email protected]
wrote:
In addon/adapters/firebase.js
#365 (comment):var recordPromise = this._updateRecord(recordRef, serializedRecord);
Ember.RSVP.hashSettled({relationships: relationshipsPromise, record: recordPromise}).then((promises) => {
var rejected = Ember.A(promises.relationships.value).filterBy('state', 'rejected');
if (promises.record.state === 'rejected') {
rejected.push(promises.record);
}
// Throw an error if any of the relationships failed to save
if (rejected.length !== 0) {
var error = new Error(`Some errors were encountered while saving ${typeClass} ${snapshot.id}`);
error.errors = Ember.A(rejected).mapBy('reason');
reject(error);
} else {
resolve();
recordPromise.then(
you can combine this with the prior line this._updateRecord().then()
—
Reply to this email directly or view it on GitHub
https://github.com/firebase/emberfire/pull/365/files#r52650315.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
recordPromise.state
should not be rejected
after the promise resolved, it would be inside the rejected (.catch()
)
Also, we would not need to rollback inside the then
block. The good thing about your new approach, due to promise chaining, is that when Firebase returns an error, we will not attempt to save the relationships.
@tstirrat any more comment ? |
resolve(); | ||
recordPromise.then( | ||
() => { | ||
if (recordPromise.state === 'rejected') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this check should not be here, it should be in the .catch()
handler
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, but what about if the attributes are saving OK, but the relations are
failing ?
On Thu, Feb 11, 2016 at 8:20 PM, Tim Stirrat [email protected]
wrote:
In addon/adapters/firebase.js
#365 (comment):
Ember.RSVP.hashSettled({relationships: relationshipsPromise, record: recordPromise}).then((promises) => {
var rejected = Ember.A(promises.relationships.value).filterBy('state', 'rejected');
if (promises.record.state === 'rejected') {
rejected.push(promises.record);
}
// Throw an error if any of the relationships failed to save
if (rejected.length !== 0) {
var error = new Error(`Some errors were encountered while saving ${typeClass} ${snapshot.id}`);
error.errors = Ember.A(rejected).mapBy('reason');
reject(error);
} else {
resolve();
recordPromise.then(
() => {
if (recordPromise.state === 'rejected') {
this check should not be here, it should be in the .catch() handler
—
Reply to this email directly or view it on GitHub
https://github.com/firebase/emberfire/pull/365/files#r52651996.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this would probably be related to security rules. its a good question.
If we want to support this, we'd need a backup of previous attributes. This could be grabbed from ember-data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, test are passing, but I did not try yet on my application ( waiting
for it to build ).
On Thu, Feb 11, 2016 at 8:28 PM, Tim Stirrat [email protected]
wrote:
In addon/adapters/firebase.js
#365 (comment):
Ember.RSVP.hashSettled({relationships: relationshipsPromise, record: recordPromise}).then((promises) => {
var rejected = Ember.A(promises.relationships.value).filterBy('state', 'rejected');
if (promises.record.state === 'rejected') {
rejected.push(promises.record);
}
// Throw an error if any of the relationships failed to save
if (rejected.length !== 0) {
var error = new Error(`Some errors were encountered while saving ${typeClass} ${snapshot.id}`);
error.errors = Ember.A(rejected).mapBy('reason');
reject(error);
} else {
resolve();
recordPromise.then(
() => {
if (recordPromise.state === 'rejected') {
this would probably be related to security rules. its a good question.
If we want to support this, we'd need a backup of previous attributes.
This could be grabbed from ember-data.—
Reply to this email directly or view it on GitHub
https://github.com/firebase/emberfire/pull/365/files#r52653256.
Thanks for this PR, btw. I appreciate all the help I can get! One final nitpick: arrow functions blocks should be on the same line: method.then(() => {
// ...
}); |
no problem, I just dont like to wait for things to happen :). If my PR is validated for ember-data, that would be cool for emberfire as well ( and probably other adapter/serializer ). |
} | ||
}); | ||
).then( | ||
(results) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
still a lambda here on new line
so. we could reduce the number of saves to exactly 2 by using a multi-path update for the relationships writing something like this: rootReference.child('posts').child(postId).update({
// ignore unchanged comment links
'comments/comment_5': null, // deleted
'comments/comment_6': true, // added
'comments/comment_7': true, // added
}); |
yes I think it should be easily feasible, the code is pretty much already On Thu, Feb 11, 2016 at 8:47 PM, Tim Stirrat [email protected]
|
Actually, we could probably reduce it to 1, with an update like this: rootReference.child('posts').update({
// model attributes:
'post_1/title': 'Title',
'post_1/body': 'Body here',
// relationships:
// ignore unchanged comment links
'post_1/comments/comment_5': null, // deleted
'post_1/comments/comment_6': true, // added
'post_1/comments/comment_7': true, // added
}); |
yep that make sense ( trying to figure out if something is wrong with either my app or the change I commited ) |
if you find out its an edge case, or a slight bug.. please write a test that exposes it |
it was working before the change I have made ( catch, etc. ) so I'm On Thu, Feb 11, 2016 at 8:55 PM, Tim Stirrat [email protected]
|
The more I think about this, the more I wonder if we can take the other atomic save branch, take the serialized json hash, convert it to a multi-path update with only changed attributes.. and we solve both problems. e.g. if the serializer returns only changed attributes: {
title: 'New title',
comments: {
comment_1: null, // deleted
comment_5: true, // added
}
} we can convert this to a multi-path update: {
'post_1/title': 'New title',
'post_1/comment_1': null, // deleted
'post_1/comment_5': true, // added
} |
Well that would definitly solve the problem :) can you try ? On Thu, Feb 11, 2016 at 9:04 PM, Tim Stirrat [email protected]
|
However this will cause problems with validation rules where say, "post must have a body". So, an adapted version of this is that we could save all model attributes, and only the changed relationships.. |
yes, attributes are fine to overrides normally On Thu, Feb 11, 2016 at 9:05 PM, Tim Stirrat [email protected]
|
I'll get better time to work on this over the weekend. Sadly wont get a chance today/tomorrow. |
I can try to do it then, as I think it would be a very cool way of doing :) On Thu, Feb 11, 2016 at 9:11 PM, Tim Stirrat [email protected]
|
Got a first version that works, but does not handle embedded record, going On Thu, Feb 11, 2016 at 9:11 PM, Olivier Chatry [email protected]
|
For some odd reason, I cannot update your branch to my fork without getting On Thu, Feb 11, 2016 at 10:54 PM, Olivier Chatry [email protected]
|
ah, sorry. I rebased it, so your history and the remote one are out of sync. delete the branch locally and then check it out again
|
Nop, not working, I always endup with conflict one way or the other. I will On Thu, Feb 11, 2016 at 11:24 PM, Tim Stirrat [email protected]
|
I think, if you think this branch is OK ( it looks and works OK at least in my software ), we should merge it and release a version before the multipath update is working. |
aa8dc67
to
cc8f9e6
Compare
squashed everything together. |
rejected.push(promises.record); | ||
} | ||
// Throw an error if any of the relationships failed to save | ||
recordPromise.then(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need recordPromise separated into a named variable anymore. We can just use this._updateRecord().then()
now.
Otherwise, we're good to go on this PR.
done :) if you have time, take a look at #366 :) |
relation ships are now saved after the record itself
solve #327, save record and then save relationships, which allows for rules to be applied ( generally rules are using record data, not relationship data).