Implementing filter and sort in back

This commit is contained in:
2025-04-01 18:40:45 +02:00
parent 59cc709ed5
commit 56ca5156c4
8 changed files with 53 additions and 91 deletions

View File

@@ -46,10 +46,21 @@ class Filter(BaseFilterModel):
```
"""
def sort(self, query):
def sort(self):
if not self.ordering_values:
return query
return query.sort(*self.ordering_values)
return None
sort = {}
for column in self.ordering_values:
direction = 1
if column[0] in ["+", "-"]:
if column[0] == "-":
direction = -1
column = column[1:]
sort[column] = direction
return sort
@field_validator("*", mode="before")
@classmethod
@@ -112,5 +123,13 @@ class Filter(BaseFilterModel):
def filter(self, query):
data = self._get_filter_conditions()
for filter_condition, filter_kwargs in data:
query = query.find(filter_condition, **filter_kwargs)
for field_name, value in filter_condition.items():
if field_name in query:
query[field_name] = query[field_name] | value
else:
query[field_name] = value
return query
class FilterSchema(Filter):
label__ilike: Optional[str] = None
order_by: Optional[list[str]] = None

View File

@@ -2,6 +2,7 @@ from datetime import datetime, UTC
from typing import Optional
from beanie import PydanticObjectId
from motor.motor_asyncio import AsyncIOMotorCollection
from pydantic import BaseModel, Field, computed_field
@@ -31,7 +32,7 @@ class CrudDocument(BaseModel):
return cls.__name__
@classmethod
def _get_collection(cls, db):
def _get_collection(cls, db) -> AsyncIOMotorCollection:
return db.get_collection(cls._collection_name())
@classmethod
@@ -42,10 +43,16 @@ class CrudDocument(BaseModel):
return await cls.get(db, result.inserted_id)
@classmethod
def list(cls, db, filters):
query = filters.filter(cls._get_collection(db))
query = filters.sort(query)
return query
def find(cls, db, filters):
return {
"collection": cls._get_collection(db),
"query_filter": filters.filter({}),
"sort": filters.sort(),
}
@classmethod
def list(cls, db):
return cls._get_collection(db).find({})
@classmethod
async def get(cls, db, model_id):

View File

@@ -12,55 +12,6 @@ from .schemas import Writer, Reader
from ..db import get_db_client
def parse_sort(sort_by):
if not sort_by:
return []
fields = []
for field in sort_by.split(','):
direction, column = field.split('(')
fields.append((column[:-1], 1 if direction == 'asc' else -1))
return fields
def Or(filters):
return {'$or': filters}
def parse_query(query: str, model):
if query is None:
return {}
and_array = []
for criterion in query.split(' AND '):
[column, operator, value] = criterion.split(' ', 2)
column = column.lower()
operand = None
if column == 'fulltext':
if not model.Settings.fulltext_search:
continue
or_array = []
for field in model.Settings.fulltext_search:
words_and_array = []
for word in value.split(' '):
words_and_array.append(RegEx(field, word, 'i'))
or_array.append(And(*words_and_array) if len(words_and_array) > 1 else words_and_array[0])
operand = Or(or_array) if len(or_array) > 1 else or_array[0]
elif operator == 'eq':
operand = Eq(column, value)
elif operator == 'in':
operand = In(column, value.split(','))
if operand:
and_array.append(operand)
if and_array:
return And(*and_array) if len(and_array) > 1 else and_array[0]
else:
return {}
#instance: str="westside", firm: str="cht",
def get_tenant_db_cursor(db_client=Depends(get_db_client)):
instance = "westside"
@@ -80,7 +31,7 @@ def get_crud_router(model: CrudDocument, model_create: Writer, model_read: Reade
@router.get("/", response_model=Page[model_read], response_description=f"{model_name} records retrieved")
async def read_list(filters: model_filter=FilterDepends(model_filter), db=Depends(get_logged_tenant_db_cursor)) -> Page[model_read]:
return await paginate(model.list(db, filters))
return await paginate(**model.find(db, filters))
@router.post("/", response_description=f"{model_name} added to the database")
async def create(schema: model_create, db=Depends(get_logged_tenant_db_cursor)) -> model_read: