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

Add URI::Params#merge, #merge! and URI#update_query_params #13415

Merged
merged 11 commits into from
May 17, 2023

Conversation

skinnyjames
Copy link
Contributor

@skinnyjames skinnyjames commented Apr 29, 2023

This PR adds 3 new methods in the URI namespace.

2 utility methods on URI::Params for merging other URI::Params, destructively and non-destructively.

  • merge(other : URI::Params, *, replace : Bool) : URI::Params
  • merge!(other : URI::Params, *, replace : Bool) : URI::Params

It also adds a method on URI to mutate query_params on the URI object in place.

  • update_query_params(&) : URI::Params

Happy to speak more to it, modify, or close if needed.

closes #13399

This commit adds 2 methods for destructive and non-destructive
merging of params.  Specs are included.
This commit adds a `query_params` method on URI that yields
a URI::Params of the query and commits any modifications to it.
@straight-shoota
Copy link
Member

straight-shoota commented May 15, 2023

Just a note about the implementation: I think it would be cleaner and more efficient to iterate params.raw_params. That avoids the extra complexity for keeping track of whether a key was already assigned from params.
I figure this could be quite simple using Hash#merge!. The yielding variant would be great for replace: false.

@skinnyjames
Copy link
Contributor Author

skinnyjames commented May 15, 2023

Just a note about the implementation: I think it would be cleaner and more efficient to iterate params.raw_params. That avoids the extra complexity for keeping track of whether a key was already assigned from params. I figure this could be quite simple using Hash#merge!. The yielding variant would be great for replace: false.

Great call, I wasn't aware of block form of Hash#merge!. Thanks.

Would it be more performant for the non-destructive URI::Params#merge to just use Hash#merge as well? or is dup.merge! more concise?

Nevermind. It's been a bit since I looked at this PR, this doesn't make sense

This refactor simplifies URI::Params#merge! by using Hash#merge!
instead of #reduce
Copy link
Member

@straight-shoota straight-shoota left a comment

Choose a reason for hiding this comment

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

There's a bug in merge! where the array value needs to be duped.

I also made a couple of suggestions for improving the API docs.

src/uri/params.cr Outdated Show resolved Hide resolved
src/uri/params.cr Outdated Show resolved Hide resolved
src/uri/params.cr Show resolved Hide resolved
src/uri/params.cr Outdated Show resolved Hide resolved
src/uri/params.cr Show resolved Hide resolved
src/uri.cr Outdated Show resolved Hide resolved
else
add(key, value)
if replace
@raw_params.merge!(params.raw_params)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
@raw_params.merge!(params.raw_params)
@raw_params.merge!(params.raw_params) { |_, first, second| second.dup }

The array needs to be duped to prevent mutations on either self or params to reflect on the other.

a = URI::Params.parse("foo=bar")
b = URI::Params.parse("foo=baz")
b.merge!(a)
b.add("foo", "qux")
a.add("foo", "qax")
a # => URI::Params{"foo" => ["bar", "qux", "qax]}
b # => URI::Params{"foo" => ["bar", "qux", "qax]}

Could you add a spec for this please?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If Hash#merge! is causing state to leak, would the solve using reduce be more explicit?

I'll add these changes + spec, but I personally find it confusing to follow nested #dups

Copy link
Member

Choose a reason for hiding this comment

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

Using Hash#merge! is fine and safe. The only reason this dup is necessary is that the Array representation is an implementation detail of URI::Params and not exposed.

src/uri.cr Outdated Show resolved Hide resolved
* Updates docs
* Fixes leaky state bug when merging params
* Adds tests
src/uri/params.cr Outdated Show resolved Hide resolved
spec/std/uri_spec.cr Outdated Show resolved Hide resolved
Co-authored-by: Quinton Miller <nicetas.c@gmail.com>
@straight-shoota straight-shoota added this to the 1.9.0 milestone May 16, 2023
@straight-shoota straight-shoota changed the title Adds utility methods for merging and modifying URI#query_params Add URI::Params#merge, #merge! and URI#update_query_params May 17, 2023
@straight-shoota straight-shoota merged commit 0410331 into crystal-lang:master May 17, 2023
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

URI::Params#merge! and URI#merge_params!
4 participants