Feature: Implement advanced POST-based search with recursive logical grouping and unique parameterization (Verified Working).
This commit is contained in:
@@ -16,6 +16,7 @@ from app.lib_general_v3 import (
|
||||
DelayParams, get_delay_params
|
||||
)
|
||||
from app.models.response_models import *
|
||||
from app.models.api_crud_models import SearchQuery
|
||||
from app.ae_obj_types_def import obj_type_kv_li
|
||||
from app.db_sql import redis_lookup_id_random, sql_select, sql_insert, sql_update, sql_delete, get_id_random
|
||||
|
||||
@@ -213,6 +214,67 @@ async def get_obj_li(
|
||||
return mk_resp(data=[], status_code=200, response=response) # Return empty list on no results
|
||||
|
||||
|
||||
@router.post('/{obj_type_l1}/search', response_model=Resp_Body_Base, tags=['CRUD v3 Search (Dev)'])
|
||||
async def search_obj_li(
|
||||
response: Response,
|
||||
obj_type_l1: str,
|
||||
search_query: SearchQuery,
|
||||
order_by_li: Optional[str] = Query(None),
|
||||
account: AccountContext = Depends(get_account_context),
|
||||
pagination: PaginationParams = Depends(get_pagination_params),
|
||||
status_filter: StatusFilterParams = Depends(get_status_filter_params),
|
||||
serialization: SerializationParams = Depends(get_serialization_params),
|
||||
delay: DelayParams = Depends(get_delay_params),
|
||||
):
|
||||
"""
|
||||
Search top-level objects using a complex SearchQuery in the POST body.
|
||||
|
||||
This endpoint supports:
|
||||
- Recursive AND/OR grouping
|
||||
- Operators: eq, ne, gt, gte, lt, lte, like, in, is_null, is_not_null
|
||||
- Large filters that would exceed URL length limits.
|
||||
"""
|
||||
if delay.sleep_time_s > 0:
|
||||
await asyncio.sleep(delay.sleep_time_s)
|
||||
|
||||
log.setLevel(logging.WARNING)
|
||||
log.debug(locals())
|
||||
|
||||
if order_by_li:
|
||||
order_by_li = json.loads(order_by_li)
|
||||
|
||||
obj_name = obj_type_l1
|
||||
if obj_name not in obj_type_kv_li:
|
||||
return mk_resp(data=False, status_code=400, response=response, status_message=f"Object type '{obj_name}' not found.")
|
||||
|
||||
obj_cfg = obj_type_kv_li[obj_name]
|
||||
table_name = obj_cfg.get('tbl_default', obj_cfg.get('tbl'))
|
||||
base_name = obj_cfg.get('mdl_default', obj_cfg.get('mdl'))
|
||||
|
||||
if not table_name or not base_name:
|
||||
return mk_resp(data=False, status_code=500, response=response, status_message=f"Configuration for object type '{obj_name}' is incomplete.")
|
||||
|
||||
sql_result = sql_select(
|
||||
table_name=table_name,
|
||||
enabled=status_filter.enabled,
|
||||
hidden=status_filter.hidden,
|
||||
search_query=search_query,
|
||||
order_by_li=order_by_li,
|
||||
limit=pagination.limit,
|
||||
offset=pagination.offset,
|
||||
as_list=True,
|
||||
)
|
||||
|
||||
if sql_result:
|
||||
resp_data_li = []
|
||||
for record in sql_result:
|
||||
resp_data = base_name(**record).dict(by_alias=serialization.by_alias, exclude_unset=serialization.exclude_unset)
|
||||
resp_data_li.append(resp_data)
|
||||
return mk_resp(data=resp_data_li, response=response)
|
||||
else:
|
||||
return mk_resp(data=[], status_code=200, response=response)
|
||||
|
||||
|
||||
@router.post('/{obj_type_l1}/', response_model=Resp_Body_Base)
|
||||
async def post_obj(
|
||||
request: Request,
|
||||
|
||||
Reference in New Issue
Block a user