feat: auto-include primary key in CrudFactory searchable_fields (#130)

This commit is contained in:
d3vyce
2026-03-12 20:21:32 +01:00
committed by GitHub
parent dde5183e68
commit 26d649791f
3 changed files with 24 additions and 4 deletions

View File

@@ -212,6 +212,9 @@ Two search strategies are available, both compatible with [`offset_paginate`](..
### Full-text search ### Full-text search
!!! info "Added in `v2.2.1`"
The model's primary key is always included in `searchable_fields` automatically, so searching by ID works out of the box without any configuration. When no `searchable_fields` are declared, only the primary key is searched.
Declare `searchable_fields` on the CRUD class. Relationship traversal is supported via tuples: Declare `searchable_fields` on the CRUD class. Relationship traversal is supported via tuples:
```python ```python

View File

@@ -1211,12 +1211,26 @@ def CrudFactory(
) )
``` ```
""" """
pk_key = model.__mapper__.primary_key[0].key
assert pk_key is not None
pk_col = getattr(model, pk_key)
if searchable_fields is None:
effective_searchable = [pk_col]
else:
existing_keys = {f.key for f in searchable_fields if not isinstance(f, tuple)}
effective_searchable = (
[pk_col, *searchable_fields]
if pk_key not in existing_keys
else list(searchable_fields)
)
cls = type( cls = type(
f"Async{model.__name__}Crud", f"Async{model.__name__}Crud",
(AsyncCrud,), (AsyncCrud,),
{ {
"model": model, "model": model,
"searchable_fields": searchable_fields, "searchable_fields": effective_searchable,
"facet_fields": facet_fields, "facet_fields": facet_fields,
"order_fields": order_fields, "order_fields": order_fields,
"m2m_fields": m2m_fields, "m2m_fields": m2m_fields,

View File

@@ -211,14 +211,17 @@ class TestPaginateSearch:
assert result.data[0].username == "active_john" assert result.data[0].username == "active_john"
@pytest.mark.anyio @pytest.mark.anyio
async def test_search_auto_detect_fields(self, db_session: AsyncSession): async def test_search_explicit_fields(self, db_session: AsyncSession):
"""Auto-detect searchable fields when not specified.""" """Search works when search_fields are passed per call."""
await UserCrud.create( await UserCrud.create(
db_session, UserCreate(username="findme", email="other@test.com") db_session, UserCreate(username="findme", email="other@test.com")
) )
result = await UserCrud.offset_paginate( result = await UserCrud.offset_paginate(
db_session, search="findme", schema=UserRead db_session,
search="findme",
search_fields=[User.username],
schema=UserRead,
) )
assert isinstance(result.pagination, OffsetPagination) assert isinstance(result.pagination, OffsetPagination)