From 25f3aa3915305b3a6b978eed535cf30d105514d6 Mon Sep 17 00:00:00 2001 From: Aleksei Rybnikov <14005836+a-rybnikov@users.noreply.github.com> Date: Mon, 8 Jun 2026 15:58:44 -0500 Subject: [PATCH] fix(uri): `?` operator now appends to existing query string (#25831) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Fixes #19782. The `?` operator in `std/uri` was silently overwriting any query string already present in the URI. This PR makes it append instead — which matches the docstring ("Concatenates the query parameters") and the natural expectation when chaining operations. **Before:** ```nim let u = parseUri("https://example.com/foo?existing=1") ? {"bar": "qux"} echo $u # https://example.com/foo?bar=qux (existing=1 lost) ``` **After:** ```nim let u = parseUri("https://example.com/foo?existing=1") ? {"bar": "qux"} echo $u # https://example.com/foo?existing=1&bar=qux ``` ## Changes - `lib/pure/uri.nim`: fix `?` to append with `&` when a query string already exists; add example to `runnableExamples` - `tests/stdlib/turi.nim`: two new test cases (append to existing query, empty params preserve existing) - `changelog.md`: entry under Standard library changes ## Notes I work with Claude as a co-processor. I'm 56, came to programming late, and this is genuinely how I learn and contribute. I understand what I'm submitting, but I didn't write it alone. If your project prefers human-only contributions, just say so and I'll close without friction. --------- Co-authored-by: Claude Sonnet 4.6 Co-authored-by: n0madgang <14005836+n0madgang@users.noreply.github.com> (cherry picked from commit b6842c144d28d82d335dab5515a2fe75f969d84d) --- changelog.md | 2 ++ lib/pure/uri.nim | 9 ++++++++- tests/stdlib/turi.nim | 9 +++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 7b8a90d13d..79ee034696 100644 --- a/changelog.md +++ b/changelog.md @@ -82,6 +82,8 @@ parameter and result types, not just their source-level shape. Use - `std/pegs` now correctly lexes UTF-8 bytes inside bare identifier-style terminals, so case-insensitive matching of non-ASCII terms (e.g. ``\i café``) works without single-quoting. +- `std/uri`: The `?` operator now appends query parameters to an existing query + string instead of replacing it. Fixes [#19782](https://github.com/nim-lang/Nim/issues/19782). ## Language changes diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index e57587ba47..c20049de12 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -487,11 +487,18 @@ func `/`*(x: Uri, path: string): Uri = func `?`*(u: Uri, query: openArray[(string, string)]): Uri = ## Concatenates the query parameters to the specified URI object. + ## If the URI already has a query string, the new parameters are appended. runnableExamples: let foo = parseUri("https://example.com") / "foo" ? {"bar": "qux"} assert $foo == "https://example.com/foo?bar=qux" + let bar = parseUri("https://example.com/foo?existing=1") ? {"bar": "qux"} + assert $bar == "https://example.com/foo?existing=1&bar=qux" result = u - result.query = encodeQuery(query) + let newQuery = encodeQuery(query) + if newQuery.len > 0: + if result.query.len > 0: + result.query.add('&') + result.query.add(newQuery) func `$`*(u: Uri): string = ## Returns the string representation of the specified URI object. diff --git a/tests/stdlib/turi.nim b/tests/stdlib/turi.nim index 9c717c5b15..71aea6af14 100644 --- a/tests/stdlib/turi.nim +++ b/tests/stdlib/turi.nim @@ -289,6 +289,15 @@ template main() = var foo = parseUri("http://example.com") / "foo" ? {"do": "do", "bar": ""} var foo1 = parseUri("http://example.com/foo?do=do&bar") doAssert foo == foo1 + block: # issue #19782: appends to existing query string + var foo = parseUri("http://example.com/foo?existing=1") ? {"bar": "qux"} + doAssert $foo == "http://example.com/foo?existing=1&bar=qux" + block: # issue #19782: empty params list preserves existing query + var foo = parseUri("http://example.com/foo?existing=1") ? {:} + doAssert $foo == "http://example.com/foo?existing=1" + block: # issue #19782: empty params on uri without query is a no-op + var foo = parseUri("http://example.com/foo") ? {:} + doAssert $foo == "http://example.com/foo" block: # getDataUri, dataUriBase64 doAssert getDataUri("", "text/plain") == "data:text/plain;charset=utf-8;base64,"