summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2019-01-31 18:19:37 +0100
committerGitHub <noreply@github.com>2019-01-31 18:19:37 +0100
commitfc99ddc648d994abaf839cc8b93b579d95313df7 (patch)
tree88b4169b532a5d400dfc5511489b36466dc1f35c
parentc268bfd5a24820f832106e8675c21dc584f5520d (diff)
parentec26bc472d3f9f6c3fc299da00c9b13733b114f8 (diff)
downloadNim-fc99ddc648d994abaf839cc8b93b579d95313df7.tar.gz
Merge pull request #10513 from LemonBoy/uri-encq
Add `encodeQuery` and `?` to Uri module
-rw-r--r--lib/pure/uri.nim56
1 files changed, 56 insertions, 0 deletions
diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim
index e49bfb3c6..f322718d1 100644
--- a/lib/pure/uri.nim
+++ b/lib/pure/uri.nim
@@ -119,6 +119,33 @@ proc decodeUrl*(s: string, decodePlus=true): string =
     inc(j)
   setLen(result, j)
 
+proc encodeQuery*(query: openArray[(string, string)], usePlus=true, omitEq=true): string =
+  ## Encodes a set of (key, value) parameters into a URL query string.
+  ##
+  ## Every (key, value) pair is URL-encoded and written as ``key=value``. If the
+  ## value is an empty string then the ``=`` is omitted, unless ``omitEq`` is
+  ## false.
+  ## The pairs are joined together by a ``&`` character.
+  ##
+  ## The ``usePlus`` parameter is passed down to the `encodeUrl` function that
+  ## is used for the URL encoding of the string values.
+  ##
+  ## **See also:**
+  ## * `encodeUrl proc<#encodeUrl,string>`_
+  runnableExamples:
+    assert encodeQuery({:}) == ""
+    assert encodeQuery({"a": "1", "b": "2"}) == "a=1&b=2"
+    assert encodeQuery({"a": "1", "b": ""}) == "a=1&b"
+  for elem in query:
+    # Encode the `key = value` pairs and separate them with a '&'
+    if result.len > 0: result.add('&')
+    let (key, val) = elem
+    result.add(encodeUrl(key, usePlus))
+    # Omit the '=' if the value string is empty
+    if not omitEq or val.len > 0:
+      result.add('=')
+      result.add(encodeUrl(val, usePlus))
+
 proc parseAuthority(authority: string, result: var Uri) =
   var i = 0
   var inPort = false
@@ -392,6 +419,14 @@ proc `/`*(x: Uri, path: string): Uri =
       result.path.add '/'
     result.path.add(path)
 
+proc `?`*(u: Uri, query: openArray[(string, string)]): Uri =
+  ## Concatenates the query parameters to the specified URI object.
+  runnableExamples:
+    let foo = parseUri("https://example.com") / "foo" ? {"bar": "qux"}
+    assert $foo == "https://example.com/foo?bar=qux"
+  result = u
+  result.query = encodeQuery(query)
+
 proc `$`*(u: Uri): string =
   ## Returns the string representation of the specified URI object.
   runnableExamples:
@@ -676,4 +711,25 @@ when isMainModule:
     doAssert "https://example.com/about/staff.html?".parseUri().isAbsolute == true
     doAssert "https://example.com/about/staff.html?parameters".parseUri().isAbsolute == true
 
+  # encodeQuery tests
+  block:
+    doAssert encodeQuery({:}) == ""
+    doAssert encodeQuery({"foo": "bar"}) == "foo=bar"
+    doAssert encodeQuery({"foo": "bar & baz"}) == "foo=bar+%26+baz"
+    doAssert encodeQuery({"foo": "bar & baz"}, usePlus=false) == "foo=bar%20%26%20baz"
+    doAssert encodeQuery({"foo": ""}) == "foo"
+    doAssert encodeQuery({"foo": ""}, omitEq=false) == "foo="
+    doAssert encodeQuery({"a": "1", "b": "", "c": "3"}) == "a=1&b&c=3"
+    doAssert encodeQuery({"a": "1", "b": "", "c": "3"}, omitEq=false) == "a=1&b=&c=3"
+
+    block:
+      var foo = parseUri("http://example.com") / "foo" ? {"bar": "1", "baz": "qux"}
+      var foo1 = parseUri("http://example.com/foo?bar=1&baz=qux")
+      doAssert foo == foo1
+
+    block:
+      var foo = parseUri("http://example.com") / "foo" ? {"do": "do", "bar": ""}
+      var foo1 = parseUri("http://example.com/foo?do=do&bar")
+      doAssert foo == foo1
+
   echo("All good!")