Skip to content

Commit e08b0c3

Browse files
Fix empty parameter list [] being converted to None
The truthiness check `if parameters` converts an empty list to None, since `bool([])` is False. Use `if parameters is not None` instead. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 96d7295 commit e08b0c3

3 files changed

Lines changed: 69 additions & 2 deletions

File tree

src/dqlitedbapi/aio/cursor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ async def execute(
5959
self._check_closed()
6060

6161
conn = await self._connection._ensure_connection()
62-
params = list(parameters) if parameters else None
62+
params = list(parameters) if parameters is not None else None
6363

6464
# Determine if this is a query that returns rows
6565
normalized = operation.strip().upper()

src/dqlitedbapi/cursor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def execute(self, operation: str, parameters: Sequence[Any] | None = None) -> "C
7171
async def _execute_async(self, operation: str, parameters: Sequence[Any] | None = None) -> None:
7272
"""Async implementation of execute."""
7373
conn = await self._connection._get_async_connection()
74-
params = list(parameters) if parameters else None
74+
params = list(parameters) if parameters is not None else None
7575

7676
# Determine if this is a query that returns rows
7777
normalized = operation.strip().upper()

tests/test_param_conversion.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
"""Tests for parameter conversion in cursor execute."""
2+
3+
import asyncio
4+
from unittest.mock import AsyncMock, MagicMock
5+
6+
from dqlitedbapi.cursor import Cursor
7+
8+
9+
def _make_mock_connection() -> MagicMock:
10+
"""Create a mock Connection with a fake async connection."""
11+
mock_protocol = AsyncMock()
12+
mock_protocol.exec_sql = AsyncMock(return_value=(0, 0))
13+
mock_protocol.query_sql = AsyncMock(return_value=(["id"], [[1]]))
14+
15+
mock_async_conn = AsyncMock()
16+
mock_async_conn._protocol = mock_protocol
17+
mock_async_conn._db_id = 0
18+
19+
mock_conn = MagicMock()
20+
21+
async def get_async_conn() -> AsyncMock:
22+
return mock_async_conn
23+
24+
mock_conn._get_async_connection = get_async_conn
25+
26+
# Make _run_sync execute the coroutine in a new event loop
27+
def run_sync(coro: object) -> object:
28+
return asyncio.get_event_loop_policy().new_event_loop().run_until_complete(coro)
29+
30+
mock_conn._run_sync = run_sync
31+
32+
return mock_conn, mock_protocol
33+
34+
35+
class TestParameterConversion:
36+
def test_empty_list_not_converted_to_none(self) -> None:
37+
"""Passing parameters=[] should not convert to None."""
38+
mock_conn, mock_protocol = _make_mock_connection()
39+
cursor = Cursor(mock_conn)
40+
41+
cursor.execute("INSERT INTO t VALUES (?)", [])
42+
43+
mock_protocol.exec_sql.assert_called_once()
44+
call_args = mock_protocol.exec_sql.call_args[0]
45+
assert call_args[2] == [], f"Expected [], got {call_args[2]!r}"
46+
47+
def test_none_params_stays_none(self) -> None:
48+
"""Passing parameters=None should stay None."""
49+
mock_conn, mock_protocol = _make_mock_connection()
50+
cursor = Cursor(mock_conn)
51+
52+
cursor.execute("INSERT INTO t VALUES (1)")
53+
54+
mock_protocol.exec_sql.assert_called_once()
55+
call_args = mock_protocol.exec_sql.call_args[0]
56+
assert call_args[2] is None, f"Expected None, got {call_args[2]!r}"
57+
58+
def test_nonempty_params_converted_to_list(self) -> None:
59+
"""Passing parameters=(1, 2) should convert to [1, 2]."""
60+
mock_conn, mock_protocol = _make_mock_connection()
61+
cursor = Cursor(mock_conn)
62+
63+
cursor.execute("INSERT INTO t VALUES (?, ?)", (1, 2))
64+
65+
mock_protocol.exec_sql.assert_called_once()
66+
call_args = mock_protocol.exec_sql.call_args[0]
67+
assert call_args[2] == [1, 2], f"Expected [1, 2], got {call_args[2]!r}"

0 commit comments

Comments
 (0)