-
Notifications
You must be signed in to change notification settings - Fork 4
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
Add diff for many associations without primary keys #144
base: master
Are you sure you want to change the base?
Add diff for many associations without primary keys #144
Conversation
Hello, @ddidwyll! This is your first Pull Request that will be reviewed by SourceLevel, an automatic Code Review service. It will leave comments on this diff with potential issues and style violations found in the code as you push new commits. You can also see all the issues found on this Pull Request on its review page. Please check our documentation for more information. |
Hello! Thank you for the PR! 🎉 It would be fantastic if you could include a test for this feature. Is that possible? |
Yes, of course, I'll write tests a little later. |
I wrote a small test that shows how this feature can work. |
Hello! Sorry about the delay in getting back to you. Too many GitHub notifications. I'll take a look at these changes shortly! |
prev_child = Map.get(previous_map, key) | ||
current_child = Map.get(current_map, key) | ||
if primary_key_fields == [] do | ||
from = max(length(previous), length(current)) - 1 | ||
|
||
do_diff(prev_child, current_child) | ||
end) | ||
|> Enum.reject(&no_changes?/1) | ||
from | ||
|> Range.new(0) | ||
|> Enum.map(fn i -> | ||
prev_child = Enum.at(previous, i) | ||
current_child = Enum.at(current, i) | ||
|
||
if diffs == [] do | ||
acc | ||
else | ||
[{field, diffs} | acc] | ||
do_diff(prev_child, current_child) | ||
end) |
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.
The performance of this isn't great, because Enum.at
traverses the whole list each time. It would be better to zip the two lists together first and traverse the zipped list instead. The problem of course is that Enum.zip
stops at the shortest list. Here's a simple implementation of a zip that zips all the way to the longest list, defaulting missing elements to nil
: https://gist.github.com/nathan-cruz77/586092fa2487da2bdd5603934e7db4ad
I would recommend adding this util function somewhere and using it here.
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.
Thanks, good idea
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.
Looks good, and thank you for the contribution.
I'd like to support doughsay's suggestion and make a couple comments for how to update your PR with the changes he recommended.
from = max(length(previous), length(current)) - 1 | ||
|
||
do_diff(prev_child, current_child) | ||
end) | ||
|> Enum.reject(&no_changes?/1) | ||
from | ||
|> Range.new(0) | ||
|> Enum.map(fn i -> | ||
prev_child = Enum.at(previous, i) | ||
current_child = Enum.at(current, i) | ||
|
||
if diffs == [] do | ||
acc | ||
else | ||
[{field, diffs} | acc] | ||
do_diff(prev_child, current_child) | ||
end) |
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.
Along with doughsay's suggestion, once you bring in that zip_longest
function, this implementation becomes:
zip_longest(previous, current)
|> Enum.map(&do_diff(&1, &2))
end) | ||
|
||
keys | ||
|> Enum.reverse() |
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.
However, once you make the above change, you'll need to pull this reverse back out to the end of this whole function body, in the pipeline after Enum.reject/2
.
Hi, I actively use ecto_diff in my projects, and sometimes I miss the ability to diff on embeds_many associations without a primary key.
I propose a patch to add this feature.