From 0a4bec62c16db6981bc83ec4560dd045698030b0 Mon Sep 17 00:00:00 2001 From: Gentile G Date: Mon, 20 Jan 2025 16:08:42 +0100 Subject: [PATCH] Adding filter capacities to api client and server --- api/app/account/routes.py | 6 ++-- api/app/category/models.py | 13 +++++++-- api/app/category/routes.py | 11 +++++--- api/app/requirements.txt | 1 + .../common/crud/widgets/crud-text-widget.tsx | 4 +-- .../src/common/crud/widgets/foreign-key.tsx | 28 +++++-------------- gui/app/src/providers/data-provider.tsx | 5 ++-- 7 files changed, 32 insertions(+), 36 deletions(-) diff --git a/api/app/account/routes.py b/api/app/account/routes.py index d19c0b5..f26b9b4 100644 --- a/api/app/account/routes.py +++ b/api/app/account/routes.py @@ -1,12 +1,10 @@ from uuid import UUID - -from fastapi import APIRouter, HTTPException, Depends, Query -from sqlmodel import Field, Session, SQLModel, create_engine, select +from fastapi import APIRouter, HTTPException, Depends from fastapi_pagination import Page from fastapi_pagination.ext.sqlmodel import paginate -from .models import Account, AccountCreate, AccountRead, AccountUpdate +from account.models import Account, AccountCreate, AccountRead, AccountUpdate from db import SessionDep from user.manager import get_current_user diff --git a/api/app/category/models.py b/api/app/category/models.py index d46f165..7a8edaa 100644 --- a/api/app/category/models.py +++ b/api/app/category/models.py @@ -1,6 +1,8 @@ from uuid import UUID, uuid4 from enum import Enum +from typing import Optional +from fastapi_filter.contrib.sqlalchemy import Filter from sqlmodel import Field, SQLModel, select class CategoryBase(SQLModel): @@ -21,8 +23,8 @@ class Category(CategoryRead, table=True): return category_db @classmethod - def list(cls): - return select(Category) + def list(cls, filters): + return filters.filter(select(cls)) @classmethod def get(cls, session, category_id): @@ -49,3 +51,10 @@ class CategoryCreate(CategoryWrite): class CategoryUpdate(CategoryWrite): pass + +class CategoryFilters(Filter): + name__like: Optional[str] = None + + class Constants(Filter.Constants): + model = Category + search_model_fields = ["name"] diff --git a/api/app/category/routes.py b/api/app/category/routes.py index be52781..e5aff90 100644 --- a/api/app/category/routes.py +++ b/api/app/category/routes.py @@ -1,11 +1,12 @@ from uuid import UUID - from fastapi import APIRouter, HTTPException, Depends +from fastapi_filter import FilterDepends from fastapi_pagination import Page from fastapi_pagination.ext.sqlmodel import paginate +from pydantic import BaseModel -from category.models import Category, CategoryCreate, CategoryRead, CategoryUpdate +from category.models import Category, CategoryCreate, CategoryRead, CategoryUpdate, CategoryFilters from db import SessionDep from user.manager import get_current_user @@ -17,8 +18,10 @@ def create_category(category: CategoryCreate, session: SessionDep, current_user= return category @router.get("") -def read_categories(session: SessionDep, current_user=Depends(get_current_user)) -> Page[CategoryRead]: - return paginate(session, Category.list()) +def read_categories(session: SessionDep, + filters: CategoryFilters = FilterDepends(CategoryFilters), + current_user=Depends(get_current_user)) -> Page[CategoryRead]: + return paginate(session, Category.list(filters)) @router.get("/{category_id}") def read_category(category_id: UUID, session: SessionDep, current_user=Depends(get_current_user)) -> CategoryRead: diff --git a/api/app/requirements.txt b/api/app/requirements.txt index 7b42cc8..4ed1615 100644 --- a/api/app/requirements.txt +++ b/api/app/requirements.txt @@ -5,3 +5,4 @@ fastapi fastapi-pagination fastapi-users[sqlmodel] fastapi-users-db-sqlmodel +fastapi-filter[sqlalchemy] diff --git a/gui/app/src/common/crud/widgets/crud-text-widget.tsx b/gui/app/src/common/crud/widgets/crud-text-widget.tsx index 094ce65..1aaaf4c 100644 --- a/gui/app/src/common/crud/widgets/crud-text-widget.tsx +++ b/gui/app/src/common/crud/widgets/crud-text-widget.tsx @@ -10,6 +10,6 @@ export default function CrudTextWidget); }else { - return (); + return (); } -} \ No newline at end of file +} diff --git a/gui/app/src/common/crud/widgets/foreign-key.tsx b/gui/app/src/common/crud/widgets/foreign-key.tsx index 756ebc3..7da4c3e 100644 --- a/gui/app/src/common/crud/widgets/foreign-key.tsx +++ b/gui/app/src/common/crud/widgets/foreign-key.tsx @@ -11,38 +11,24 @@ import {useList} from "@refinedev/core"; export const ForeignKeyWidget = (props: WidgetProps) => { const [inputValue, setInputValue] = useState(""); const [selectedValue, setSelectedValue] = useState(null); + const [debouncedInputValue, setDebouncedInputValue] = useState(inputValue); const resource = props.schema.foreign_key.reference.resource + useEffect(() => { + const handler = setTimeout(() => setDebouncedInputValue(inputValue), 300); // Adjust debounce delay as needed + return () => clearTimeout(handler); + }, [inputValue]); + const { data, isLoading } = useList({ resource: resource, pagination: { current: 1, pageSize: 10 }, + filters: [{ field: "name", operator: "contains", value: debouncedInputValue }], sorters: [{ field: "name", order: "asc" }], - filters: [{ field: "name", operator: "contains", value: "input" }], }); const options = data?.data || []; - // const fetchOptions = async (input: string) => { - // try { - // - // } catch (error) { - // console.error("Error fetching options:", error); - // } - // }; - - // // Debounced version of the fetch function - // const debouncedFetch = useCallback(debounce(fetchOptions, 300), []); - // // Trigger fetch whenever the inputValue changes - // useEffect(() => { - // if (inputValue) { - // debouncedFetch(inputValue); - // } else { - // setOptions([]); // Clear options when input is empty - // } - // }, [inputValue, debouncedFetch]); - - return ( 0) { filters.forEach((filter) => { - if ("field" in filter && filter.operator === "eq") { - // Our fake API supports "eq" operator by simply appending the field name and value to the query string. - params.append(filter.field, filter.value); + if ("field" in filter && filter.value.length > 0 && filter.operator === "contains") { + params.append(filter.field + "__like", "%" + filter.value + "%"); } }); }