mirror of
https://github.com/d3vyce/fastapi-toolsets.git
synced 2026-03-01 17:00:48 +01:00
fix: cast to String non-text columns for crud search
This commit is contained in:
@@ -129,11 +129,12 @@ def build_search_filters(
|
|||||||
else:
|
else:
|
||||||
column = field
|
column = field
|
||||||
|
|
||||||
# Build the filter
|
# Build the filter (cast to String for non-text columns)
|
||||||
|
column_as_string = column.cast(String)
|
||||||
if config.case_sensitive:
|
if config.case_sensitive:
|
||||||
filters.append(column.like(f"%{query}%"))
|
filters.append(column_as_string.like(f"%{query}%"))
|
||||||
else:
|
else:
|
||||||
filters.append(column.ilike(f"%{query}%"))
|
filters.append(column_as_string.ilike(f"%{query}%"))
|
||||||
|
|
||||||
if not filters:
|
if not filters:
|
||||||
return [], []
|
return [], []
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
"""Tests for CRUD search functionality."""
|
"""Tests for CRUD search functionality."""
|
||||||
|
|
||||||
import pytest
|
import uuid
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
|
||||||
|
|
||||||
from fastapi_toolsets.crud import SearchConfig, get_searchable_fields
|
import pytest
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from sqlalchemy import String
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
from sqlalchemy.orm import Mapped, mapped_column
|
||||||
|
|
||||||
|
from fastapi_toolsets.crud import CrudFactory, SearchConfig, get_searchable_fields
|
||||||
|
|
||||||
from .conftest import (
|
from .conftest import (
|
||||||
|
Base,
|
||||||
Role,
|
Role,
|
||||||
RoleCreate,
|
RoleCreate,
|
||||||
RoleCrud,
|
RoleCrud,
|
||||||
@@ -272,6 +278,41 @@ class TestPaginateSearch:
|
|||||||
usernames = [u.username for u in result["data"]]
|
usernames = [u.username for u in result["data"]]
|
||||||
assert usernames == ["alice", "bob", "charlie"]
|
assert usernames == ["alice", "bob", "charlie"]
|
||||||
|
|
||||||
|
@pytest.mark.anyio
|
||||||
|
async def test_search_non_string_column(self, db_session: AsyncSession):
|
||||||
|
"""Search on non-string columns (e.g., UUID) works via cast."""
|
||||||
|
|
||||||
|
class Account(Base):
|
||||||
|
__tablename__ = "accounts"
|
||||||
|
id: Mapped[uuid.UUID] = mapped_column(primary_key=True, default=uuid.uuid4)
|
||||||
|
name: Mapped[str] = mapped_column(String(100))
|
||||||
|
|
||||||
|
class AccountCreate(BaseModel):
|
||||||
|
id: uuid.UUID | None = None
|
||||||
|
name: str
|
||||||
|
|
||||||
|
AccountCrud = CrudFactory(Account)
|
||||||
|
|
||||||
|
# Create table for this test
|
||||||
|
async with db_session.get_bind().begin() as conn:
|
||||||
|
await conn.run_sync(Base.metadata.create_all)
|
||||||
|
|
||||||
|
account_id = uuid.UUID("12345678-1234-5678-1234-567812345678")
|
||||||
|
await AccountCrud.create(
|
||||||
|
db_session, AccountCreate(id=account_id, name="Test Account")
|
||||||
|
)
|
||||||
|
await AccountCrud.create(db_session, AccountCreate(name="Other Account"))
|
||||||
|
|
||||||
|
# Search by UUID (partial match)
|
||||||
|
result = await AccountCrud.paginate(
|
||||||
|
db_session,
|
||||||
|
search="12345678",
|
||||||
|
search_fields=[Account.id, Account.name],
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["pagination"]["total_count"] == 1
|
||||||
|
assert result["data"][0].id == account_id
|
||||||
|
|
||||||
|
|
||||||
class TestSearchConfig:
|
class TestSearchConfig:
|
||||||
"""Tests for SearchConfig options."""
|
"""Tests for SearchConfig options."""
|
||||||
|
|||||||
Reference in New Issue
Block a user