Skip to content
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

optimize merge defaults strategy #516

Conversation

alexzurbonsen
Copy link
Contributor

@alexzurbonsen alexzurbonsen commented Mar 9, 2024

Types of changes

  • Enhancement (project structure, spelling, grammar, formatting)
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

A description of the changes proposed in the Pull Request

I wrote a test suite that explains my understanding of what the function should do. The current mergeObject function fails this suite. E.g. it overrides an input if its value is false and the default is true. It does not deep merge objects.

Changed the implementation to pass the tests.

@alexzurbonsen alexzurbonsen force-pushed the fix-mergeObjects-function branch 2 times, most recently from 4dff3f6 to b1d0318 Compare March 9, 2024 09:08
@@ -21,7 +21,7 @@ const mergeDefaults = (
) => {
if (inputs) {
const response = defaults
? inputs.map(input => mergeObjects(input, defaults))
? inputs.map(input => mergeObjects({...defaults}, input))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @alexzurbonsen , thanks for your contribution.
Just wandering if there is specific reason for using object destructuring on defaults?

Copy link
Contributor Author

@alexzurbonsen alexzurbonsen Mar 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @MariamKhalatova, that is because the function uses lodash's mergeWith function. And that writes input into defaults.

Not sure how much more detail the explanation should contain, but just in case, here is the rest: Because objects are passed by reference in JS we need to deep copy the top level of defaults here. And that is what the spread operator does for us.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docs: mergeWith and merge

Copy link
Contributor Author

@alexzurbonsen alexzurbonsen Mar 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a test, that might help understand the issue. If you replace {...defaults} with defaults and run the test, you can see how the object reference kicks in.

I had to export mergeDefaults to make this testable. But I guess its worth it.

Currently the mergeObject function has a couple of problems.
E.g. it overrides an input if its value is false and the default
is true. It does not deep merge objects.

Added a test suite that the current function would not pass.
And fixed it.

Signed-off-by: alexzurbonsen <[email protected]>
@alexzurbonsen alexzurbonsen force-pushed the fix-mergeObjects-function branch from b1d0318 to f000d2d Compare March 20, 2024 20:49
@alexzurbonsen
Copy link
Contributor Author

Thank you for your comments. I adressed them.

@narekhovhannisyan
Copy link
Member

Hi @alexzurbonsen, we have gone through this PR on our weekly triage. Everything seems good and we are keen to merge your PR if it can be rewritten without lodash library since the code uses only one function from it.

@alexzurbonsen
Copy link
Contributor Author

Hi @narekhovhannisyan, to be honest I am not a fan of this approach in this case. Writing this kind of code is fairly complex or at least complex enough that you easily make mistakes or overlook edge cases. In this kind of situation I would prefer to use a library. The function we are fixing in this PR is a good example, why it isn't a good idea to write this stuff yourself.

Thus, I won't invest time to rewrite a lodash function that works better than any code I will be writing myself.

@alexzurbonsen
Copy link
Contributor Author

But of course, you can take over the PR if you like.

@narekhovhannisyan
Copy link
Member

@alexzurbonsen we decided to not merge arrays and nested objects to keep everything straightforward. Will push changes for tests and the implementation accordingly.

Comment on lines 23 to 36
export const mergeObjects = (defaults: any, input: any) => {
const merged: Record<string, any> = {...input};

for (const key in defaults) {
if (Array.isArray(defaults[key])) {
merged[key] = input[key] !== undefined ? input[key] : defaults[key];
}
return;
};

return mergeWith(destination, source, handleArrays);
if (!(key in input)) {
merged[key] = defaults[key];
}
}

return merged;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just use {...defaults, ...inputs} now?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it won't do the trick since null values won't be overridden

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and that behavior should be covered by tests too, the current implementation doesn't satisfy that either

@alexzurbonsen
Copy link
Contributor Author

@alexzurbonsen we decided to not merge arrays and nested objects to keep everything straightforward. Will push changes for tests and the implementation accordingly.

I guess it might be helpful if this behaviour is documented somewhere?

@narekhovhannisyan narekhovhannisyan changed the title fix(util): fix mergeObject function optimize merge defaults strategy Mar 31, 2024
@MariamKhalatova MariamKhalatova merged commit f482eb0 into Green-Software-Foundation:main Mar 31, 2024
1 check passed
This was referenced May 17, 2024
@github-actions github-actions bot mentioned this pull request Jun 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants