Skip to content

Commit 50e7a4c

Browse files
authored
fix(postgrest): send rpc list args as array literals on GET and HEAD (#1752)
1 parent 2a291e3 commit 50e7a4c

5 files changed

Lines changed: 39 additions & 2 deletions

File tree

‎src/postgrest/src/postgrest/_async/client.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
DEFAULT_POSTGREST_CLIENT_TIMEOUT,
1616
)
1717
from ..types import CountMethod
18+
from ..utils import rpc_query_param
1819
from ..version import __version__
1920
from .request_builder import (
2021
AsyncRequestBuilder,
@@ -181,7 +182,7 @@ def rpc(
181182
headers.update(self.headers)
182183
# the params here are params to be sent to the RPC and not the queryparams!
183184
json, http_params = (
184-
({}, QueryParams(params))
185+
({}, QueryParams({k: rpc_query_param(v) for k, v in params.items()}))
185186
if method in ("HEAD", "GET")
186187
else (params, QueryParams())
187188
)

‎src/postgrest/src/postgrest/_sync/client.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
DEFAULT_POSTGREST_CLIENT_TIMEOUT,
1616
)
1717
from ..types import CountMethod
18+
from ..utils import rpc_query_param
1819
from ..version import __version__
1920
from .request_builder import (
2021
RequestConfig,
@@ -181,7 +182,7 @@ def rpc(
181182
headers.update(self.headers)
182183
# the params here are params to be sent to the RPC and not the queryparams!
183184
json, http_params = (
184-
({}, QueryParams(params))
185+
({}, QueryParams({k: rpc_query_param(v) for k, v in params.items()}))
185186
if method in ("HEAD", "GET")
186187
else (params, QueryParams())
187188
)

‎src/postgrest/src/postgrest/utils.py‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,17 @@ def sanitize_pattern_param(pattern: str) -> str:
7171
return sanitize_param(pattern.replace("%", "*"))
7272

7373

74+
def rpc_query_param(value: Any) -> Any:
75+
"""Format an RPC argument sent in the query string, as in GET or HEAD calls.
76+
77+
Lists and tuples become PostgreSQL array literals, since PostgREST keeps only
78+
one value when a non-variadic argument is repeated.
79+
"""
80+
if isinstance(value, (list, tuple)):
81+
return f"{{{','.join(str(v) for v in value)}}}"
82+
return value
83+
84+
7485
def is_http_url(url: URL) -> bool:
7586
return url.scheme in {"https", "http"}
7687

‎src/postgrest/tests/_async/test_client.py‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import re
2+
from typing import Any
23
from unittest.mock import patch
34

45
import pytest
@@ -176,3 +177,14 @@ async def test_response_client_invalid_response_but_valid_json(
176177
assert isinstance(exc_response.get("message"), str)
177178
assert exc_response.get("message") == "JSON could not be generated"
178179
assert "code" in exc_response and int(exc_response["code"]) == 502
180+
181+
182+
@pytest.mark.parametrize("head", [False, True])
183+
def test_rpc_query_params_send_lists_as_array_literals(
184+
postgrest_client: AsyncPostgrestClient, head: bool
185+
):
186+
params: Any = {"ids": [1, 2, 3], "name": "x"}
187+
builder = postgrest_client.rpc("sum_ids", params, head=head, get=not head)
188+
189+
assert builder.request.params.get_list("ids") == ["{1,2,3}"]
190+
assert builder.request.params["name"] == "x"

‎src/postgrest/tests/_sync/test_client.py‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import re
2+
from typing import Any
23
from unittest.mock import patch
34

45
import pytest
@@ -174,3 +175,14 @@ def test_response_client_invalid_response_but_valid_json(
174175
assert isinstance(exc_response.get("message"), str)
175176
assert exc_response.get("message") == "JSON could not be generated"
176177
assert "code" in exc_response and int(exc_response["code"]) == 502
178+
179+
180+
@pytest.mark.parametrize("head", [False, True])
181+
def test_rpc_query_params_send_lists_as_array_literals(
182+
postgrest_client: SyncPostgrestClient, head: bool
183+
):
184+
params: Any = {"ids": [1, 2, 3], "name": "x"}
185+
builder = postgrest_client.rpc("sum_ids", params, head=head, get=not head)
186+
187+
assert builder.request.params.get_list("ids") == ["{1,2,3}"]
188+
assert builder.request.params["name"] == "x"

0 commit comments

Comments
 (0)