diff --git a/CHANGELOG.md b/CHANGELOG.md index a6f644c..6292762 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ All notable changes to this project will be documented in this file. ### Added +* Support named and positional query bind values through `QueryRequest.params`. * Add an optional Ibis backend with native Parquet results through `Client.query_parquet`. * Surface errors received during NDJSON query streaming as `QueryError`. * Add `Client.upload` with typed upload modes and support for file streams. diff --git a/README.md b/README.md index 7df9b34..6a0c3de 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,10 @@ client = Client(username="your_username", password="your_password", verify=False from altertable_lakehouse.models import QueryRequest # Stream rows (good for large datasets) -req = QueryRequest(statement="SELECT * FROM my_table") +req = QueryRequest( + statement="SELECT * FROM my_table WHERE age >= $min_age", + params={"min_age": 25}, +) metadata, columns, row_iterator = client.query(req) print(metadata.values) print(columns) diff --git a/src/altertable_lakehouse/models.py b/src/altertable_lakehouse/models.py index 65c8deb..aefc03f 100644 --- a/src/altertable_lakehouse/models.py +++ b/src/altertable_lakehouse/models.py @@ -58,6 +58,7 @@ class QueryRequest(BaseModel): sanitize: Optional[bool] = None limit: Optional[int] = None offset: Optional[int] = None + params: Optional[Union[Dict[str, Union[str, int, float, bool, None]], List[Union[str, int, float, bool, None]]]] = None timezone: Optional[str] = None ephemeral: Optional[bool] = None visible: Optional[bool] = None diff --git a/tests/test_client.py b/tests/test_client.py index 6ba0549..d34387f 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -46,6 +46,14 @@ def test_query_all(client): assert isinstance(res.columns, list) assert isinstance(res.rows, list) + +def test_query_request_serializes_named_and_positional_bind_values(): + named = models.QueryRequest(statement="SELECT $min_age", params={"min_age": 25}) + positional = models.QueryRequest(statement="SELECT $1", params=[25]) + + assert named.model_dump(exclude_none=True)["params"] == {"min_age": 25} + assert positional.model_dump(exclude_none=True)["params"] == [25] + def test_upsert_sends_primary_key_without_unsupported_mode(client): captured = {}