Skip to content

Commit 9424361

Browse files
feat(dbapi): validate max_total_rows at Connection boundary
Forward validation to the client-layer helper so both sync and async DBAPI Connection constructors reject zero/negative/non-int values up front. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 18b70a1 commit 9424361

File tree

3 files changed

+50
-2
lines changed

3 files changed

+50
-2
lines changed

src/dqlitedbapi/aio/connection.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import dqliteclient.exceptions as _client_exc
99
from dqliteclient import DqliteConnection
10+
from dqliteclient.protocol import _validate_max_total_rows
1011
from dqlitedbapi.aio.cursor import AsyncCursor
1112
from dqlitedbapi.exceptions import InterfaceError, OperationalError, ProgrammingError
1213

@@ -37,7 +38,7 @@ def __init__(
3738
self._address = address
3839
self._database = database
3940
self._timeout = timeout
40-
self._max_total_rows = max_total_rows
41+
self._max_total_rows = _validate_max_total_rows(max_total_rows)
4142
self._async_conn: DqliteConnection | None = None
4243
self._closed = False
4344
# asyncio primitives MUST be created inside the loop they will

src/dqlitedbapi/connection.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
import dqliteclient.exceptions as _client_exc
1212
from dqliteclient import DqliteConnection
13+
from dqliteclient.protocol import _validate_max_total_rows
1314
from dqlitedbapi.cursor import Cursor
1415
from dqlitedbapi.exceptions import InterfaceError, OperationalError, ProgrammingError
1516

@@ -82,7 +83,7 @@ def __init__(
8283
self._address = address
8384
self._database = database
8485
self._timeout = timeout
85-
self._max_total_rows = max_total_rows
86+
self._max_total_rows = _validate_max_total_rows(max_total_rows)
8687
self._async_conn: DqliteConnection | None = None
8788
self._closed = False
8889
self._loop: asyncio.AbstractEventLoop | None = None
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"""Validation of the ``max_total_rows`` constructor parameter (DB-API)."""
2+
3+
import pytest
4+
5+
from dqlitedbapi import Connection
6+
from dqlitedbapi.aio import AsyncConnection
7+
8+
9+
class TestConnectionValidation:
10+
def test_zero_rejected(self) -> None:
11+
with pytest.raises(ValueError):
12+
Connection("localhost:19001", max_total_rows=0)
13+
14+
def test_negative_rejected(self) -> None:
15+
with pytest.raises(ValueError):
16+
Connection("localhost:19001", max_total_rows=-10)
17+
18+
def test_bool_rejected(self) -> None:
19+
with pytest.raises(TypeError):
20+
Connection("localhost:19001", max_total_rows=True) # type: ignore[arg-type]
21+
22+
def test_string_rejected(self) -> None:
23+
with pytest.raises(TypeError):
24+
Connection("localhost:19001", max_total_rows="100") # type: ignore[arg-type]
25+
26+
def test_none_allowed(self) -> None:
27+
conn = Connection("localhost:19001", max_total_rows=None)
28+
assert conn._max_total_rows is None
29+
30+
31+
class TestAsyncConnectionValidation:
32+
def test_zero_rejected(self) -> None:
33+
with pytest.raises(ValueError):
34+
AsyncConnection("localhost:19001", max_total_rows=0)
35+
36+
def test_negative_rejected(self) -> None:
37+
with pytest.raises(ValueError):
38+
AsyncConnection("localhost:19001", max_total_rows=-10)
39+
40+
def test_bool_rejected(self) -> None:
41+
with pytest.raises(TypeError):
42+
AsyncConnection("localhost:19001", max_total_rows=True) # type: ignore[arg-type]
43+
44+
def test_none_allowed(self) -> None:
45+
conn = AsyncConnection("localhost:19001", max_total_rows=None)
46+
assert conn._max_total_rows is None

0 commit comments

Comments
 (0)