Skip to content

create_filter_dependencies: IN filters never applied to queries #405

@cofin

Description

@cofin

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&currentPage=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 (...) clause

Expected Behavior

  1. create_filter_dependencies with in_fields should produce working filter providers that parse query parameters and return InCollectionFilter instances
  2. select_with_total (and select) should apply InCollectionFilter and SearchFilter to QueryBuilder statements, generating appropriate WHERE ... IN (...) and WHERE ... 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions