-
-
Notifications
You must be signed in to change notification settings - Fork 8
create_filter_dependencies: IN filters never applied to queries #405
Description
Description
create_filter_dependencies with in_fields generates filter providers that never produce InCollectionFilter instances. The provide_in_filter functions always return None, so the filters aggregator never includes them. As a result, IN filtering is completely non-functional when using declarative filters.
Additionally, even when InCollectionFilter is manually constructed and passed to select_with_total, the driver does not apply it to QueryBuilder statements — only LimitOffsetFilter is handled.
Reproduction
Issue 1: Filter providers return None
import asyncio
from litestar import Litestar, get
from litestar.params import Dependency
from litestar.testing import AsyncTestClient
from sqlspec.extensions.litestar.providers import create_filter_dependencies
deps = create_filter_dependencies({
"pagination_type": "limit_offset",
"in_fields": ["status"],
})
@get("/items", dependencies=deps)
async def list_items(filters: list = Dependency(skip_validation=True)) -> dict:
return {"filters": [type(f).__name__ for f in filters]}
app = Litestar([list_items])
async def test():
async with AsyncTestClient(app) as client:
# Pass a valid IN filter value
resp = await client.get("/items?statusIn=active&pageSize=10¤tPage=1")
print(resp.json())
# Expected: {"filters": ["LimitOffsetFilter", "InCollectionFilter"]}
# Actual: {"filters": ["LimitOffsetFilter"]}
asyncio.run(test())The InCollectionFilter for statusIn is never created. Only LimitOffsetFilter appears in the filters list. This happens for all in_fields — the provide_in_filter closure always returns None.
Issue 2: Filters not applied to QueryBuilder by driver
Even when manually constructing an InCollectionFilter and passing it to select_with_total, the driver does not apply it to the QueryBuilder:
from sqlspec import sql, InCollectionFilter, LimitOffsetFilter
query = sql.select("*").from_("items").where_eq("workspace_id", ws_id)
# InCollectionFilter is passed but never applied to the query
results, total = await driver.select_with_total(
query,
LimitOffsetFilter(limit=10, offset=0),
InCollectionFilter(field_name="status", values=["active", "archived"]),
)
# The SQL executed has no WHERE status IN (...) clauseExpected Behavior
create_filter_dependencieswithin_fieldsshould produce working filter providers that parse query parameters and returnInCollectionFilterinstancesselect_with_total(andselect) should applyInCollectionFilterandSearchFiltertoQueryBuilderstatements, generating appropriateWHERE ... IN (...)andWHERE ... LIKE/ILIKE ...clauses
Current Workaround
Declare explicit handler parameters and apply filters manually:
@get("/items", dependencies=deps)
async def list_items(
filters: list = Dependency(skip_validation=True),
status_in: list[str] | None = Parameter(query="statusIn", default=None, required=False),
) -> ...:
query = sql.select("*").from_("items")
if status_in:
query = query.where(sql.column("status").in_(status_in))
return await service.paginate(query, *filters)Environment
- sqlspec 0.42.0
- litestar 2.21.1
- Python 3.12
- asyncpg adapter