feat(db): ajouter count_marches, count_unique_marches et paramètre offset à query_marches
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -135,10 +135,11 @@ def get_cursor() -> duckdb.DuckDBPyConnection:
|
|||||||
|
|
||||||
def query_marches(
|
def query_marches(
|
||||||
where_sql: str = "TRUE",
|
where_sql: str = "TRUE",
|
||||||
params: tuple = (),
|
params: tuple | list = (),
|
||||||
columns: list[str] | None = None,
|
columns: list[str] | None = None,
|
||||||
order_by: str | None = None,
|
order_by: str | None = None,
|
||||||
limit: int | None = None,
|
limit: int | None = None,
|
||||||
|
offset: int | None = None,
|
||||||
) -> pl.DataFrame:
|
) -> pl.DataFrame:
|
||||||
"""Run a parameterized SELECT against the decp table and return Polars.
|
"""Run a parameterized SELECT against the decp table and return Polars.
|
||||||
|
|
||||||
@@ -152,4 +153,20 @@ def query_marches(
|
|||||||
sql += f" ORDER BY {order_by}"
|
sql += f" ORDER BY {order_by}"
|
||||||
if limit is not None:
|
if limit is not None:
|
||||||
sql += f" LIMIT {int(limit)}"
|
sql += f" LIMIT {int(limit)}"
|
||||||
|
if offset is not None:
|
||||||
|
sql += f" OFFSET {int(offset)}"
|
||||||
return get_cursor().execute(sql, list(params)).pl()
|
return get_cursor().execute(sql, list(params)).pl()
|
||||||
|
|
||||||
|
|
||||||
|
def count_marches(where_sql: str = "TRUE", params: tuple | list = ()) -> int:
|
||||||
|
"""Retourne le nombre de lignes correspondant à where_sql."""
|
||||||
|
sql = f"SELECT COUNT(*) FROM decp WHERE {where_sql}"
|
||||||
|
result = get_cursor().execute(sql, list(params)).fetchone()
|
||||||
|
return int(result[0]) if result else 0
|
||||||
|
|
||||||
|
|
||||||
|
def count_unique_marches(where_sql: str = "TRUE", params: tuple | list = ()) -> int:
|
||||||
|
"""Retourne le nombre de uid distincts correspondant à where_sql."""
|
||||||
|
sql = f"SELECT COUNT(DISTINCT uid) FROM decp WHERE {where_sql}"
|
||||||
|
result = get_cursor().execute(sql, list(params)).fetchone()
|
||||||
|
return int(result[0]) if result else 0
|
||||||
|
|||||||
@@ -206,6 +206,38 @@ def test_query_marches_returns_polars_frame(built_db, monkeypatch):
|
|||||||
assert set(frame["uid"].to_list()) == {"1", "2"}
|
assert set(frame["uid"].to_list()) == {"1", "2"}
|
||||||
|
|
||||||
|
|
||||||
|
def test_count_marches_returns_total_without_filter():
|
||||||
|
from src.db import count_marches
|
||||||
|
|
||||||
|
n = count_marches()
|
||||||
|
assert isinstance(n, int)
|
||||||
|
assert n > 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_count_marches_with_filter():
|
||||||
|
from src.db import count_marches
|
||||||
|
|
||||||
|
n = count_marches('"uid" = ?', ["__nonexistent__"])
|
||||||
|
assert n == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_count_unique_marches_respects_distinct():
|
||||||
|
from src.db import count_unique_marches
|
||||||
|
|
||||||
|
n = count_unique_marches()
|
||||||
|
assert isinstance(n, int)
|
||||||
|
assert n > 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_query_marches_with_offset():
|
||||||
|
from src.db import query_marches
|
||||||
|
|
||||||
|
page_0 = query_marches(limit=2, offset=0)
|
||||||
|
page_1 = query_marches(limit=2, offset=2)
|
||||||
|
if page_0.height == 2 and page_1.height >= 1:
|
||||||
|
assert set(page_0["uid"].to_list()).isdisjoint(set(page_1["uid"].to_list()))
|
||||||
|
|
||||||
|
|
||||||
def test_concurrent_build_serialized(tmp_path):
|
def test_concurrent_build_serialized(tmp_path):
|
||||||
"""Multiple threads calling _ensure_database must serialize via flock.
|
"""Multiple threads calling _ensure_database must serialize via flock.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user