bugfix PRM-04: Suchfunktion filtert zuerst, dann sortiert und dann paginiert, sonst fehlerhafte rückgaben
This commit is contained in:
parent
8c2e9d2183
commit
b04211bed4
1 changed files with 92 additions and 9 deletions
|
|
@ -1,12 +1,13 @@
|
||||||
# Copyright (c) 2025 Patrick Motsch
|
# Copyright (c) 2025 Patrick Motsch
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
from fastapi import APIRouter, HTTPException, Depends, Body, Path, Request, Query
|
from fastapi import APIRouter, HTTPException, Depends, Body, Path, Request, Query
|
||||||
from typing import List, Dict, Any, Optional
|
from typing import List, Dict, Any, Optional, Tuple
|
||||||
from fastapi import status
|
from fastapi import status
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
import logging
|
import logging
|
||||||
import json
|
import json
|
||||||
import math
|
import math
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
# Import auth module
|
# Import auth module
|
||||||
from modules.auth import limiter, getCurrentUser
|
from modules.auth import limiter, getCurrentUser
|
||||||
|
|
@ -74,6 +75,46 @@ def get_prompts(
|
||||||
paginationParams = applyViewToParams(paginationParams, viewConfig)
|
paginationParams = applyViewToParams(paginationParams, viewConfig)
|
||||||
groupByLevels = effective_group_by_levels(paginationParams, viewConfig)
|
groupByLevels = effective_group_by_levels(paginationParams, viewConfig)
|
||||||
|
|
||||||
|
def _getVisiblePromptSearchFields() -> List[str]:
|
||||||
|
"""Return Prompt fields considered visible/searchable in the table."""
|
||||||
|
fields: List[str] = []
|
||||||
|
for fieldName, fieldInfo in Prompt.model_fields.items():
|
||||||
|
if fieldName == "id":
|
||||||
|
continue
|
||||||
|
jsonExtra = fieldInfo.json_schema_extra or {}
|
||||||
|
if jsonExtra.get("frontend_visible", True) is False:
|
||||||
|
continue
|
||||||
|
if jsonExtra.get("system", False):
|
||||||
|
continue
|
||||||
|
fields.append(fieldName)
|
||||||
|
return fields
|
||||||
|
|
||||||
|
visibleSearchFields = _getVisiblePromptSearchFields()
|
||||||
|
|
||||||
|
def _applyPromptSearchOnVisibleFields(rows: List[Dict[str, Any]], searchValue: Any) -> List[Dict[str, Any]]:
|
||||||
|
"""Apply global prompt search only on visible Prompt fields."""
|
||||||
|
searchTerm = str(searchValue or "").strip().lower()
|
||||||
|
if not searchTerm:
|
||||||
|
return rows
|
||||||
|
filteredRows: List[Dict[str, Any]] = []
|
||||||
|
for row in rows:
|
||||||
|
for fieldName in visibleSearchFields:
|
||||||
|
value = row.get(fieldName)
|
||||||
|
if value is None:
|
||||||
|
continue
|
||||||
|
if searchTerm in str(value).lower():
|
||||||
|
filteredRows.append(row)
|
||||||
|
break
|
||||||
|
return filteredRows
|
||||||
|
|
||||||
|
def _extractSearchAndRemoveFromFilters(filters: Optional[Dict[str, Any]]) -> Tuple[Any, Optional[Dict[str, Any]]]:
|
||||||
|
"""Extract generic search from filters and return remaining filters."""
|
||||||
|
if not filters:
|
||||||
|
return None, None
|
||||||
|
cleanedFilters = deepcopy(filters)
|
||||||
|
searchValue = cleanedFilters.pop("search", None)
|
||||||
|
return searchValue, (cleanedFilters if cleanedFilters else None)
|
||||||
|
|
||||||
def _promptsToEnrichedDicts(promptItems):
|
def _promptsToEnrichedDicts(promptItems):
|
||||||
dicts = [r.model_dump() if hasattr(r, 'model_dump') else (dict(r) if not isinstance(r, dict) else r) for r in promptItems]
|
dicts = [r.model_dump() if hasattr(r, 'model_dump') else (dict(r) if not isinstance(r, dict) else r) for r in promptItems]
|
||||||
enrichRowsWithFkLabels(dicts, Prompt)
|
enrichRowsWithFkLabels(dicts, Prompt)
|
||||||
|
|
@ -115,21 +156,57 @@ def get_prompts(
|
||||||
|
|
||||||
if not groupByLevels:
|
if not groupByLevels:
|
||||||
# No grouping: let DB handle pagination directly
|
# No grouping: let DB handle pagination directly
|
||||||
result = managementInterface.getAllPrompts(pagination=paginationParams)
|
promptSearchValue = None
|
||||||
if paginationParams and hasattr(result, 'items'):
|
remainingFilters = paginationParams.filters if paginationParams else None
|
||||||
response: dict = {
|
if paginationParams and paginationParams.filters:
|
||||||
"items": _promptsToEnrichedDicts(result.items),
|
promptSearchValue, remainingFilters = _extractSearchAndRemoveFromFilters(paginationParams.filters)
|
||||||
|
|
||||||
|
# For prompt search, we must filter before page slicing.
|
||||||
|
if paginationParams and promptSearchValue is not None:
|
||||||
|
result = managementInterface.getAllPrompts(pagination=None)
|
||||||
|
allItems = _promptsToEnrichedDicts(result if isinstance(result, list) else (result.items if hasattr(result, 'items') else []))
|
||||||
|
allItems = _applyPromptSearchOnVisibleFields(allItems, promptSearchValue)
|
||||||
|
|
||||||
|
if remainingFilters or paginationParams.sort:
|
||||||
|
from modules.interfaces.interfaceDbManagement import ComponentObjects
|
||||||
|
comp = ComponentObjects()
|
||||||
|
comp.setUserContext(currentUser)
|
||||||
|
if remainingFilters:
|
||||||
|
allItems = comp._applyFilters(allItems, remainingFilters)
|
||||||
|
if paginationParams.sort:
|
||||||
|
allItems = comp._applySorting(allItems, paginationParams.sort)
|
||||||
|
|
||||||
|
totalItems = len(allItems)
|
||||||
|
totalPages = math.ceil(totalItems / paginationParams.pageSize) if totalItems > 0 else 0
|
||||||
|
startIdx = (paginationParams.page - 1) * paginationParams.pageSize
|
||||||
|
endIdx = startIdx + paginationParams.pageSize
|
||||||
|
response = {
|
||||||
|
"items": allItems[startIdx:endIdx],
|
||||||
"pagination": PaginationMetadata(
|
"pagination": PaginationMetadata(
|
||||||
currentPage=paginationParams.page,
|
currentPage=paginationParams.page,
|
||||||
pageSize=paginationParams.pageSize,
|
pageSize=paginationParams.pageSize,
|
||||||
totalItems=result.totalItems,
|
totalItems=totalItems,
|
||||||
totalPages=result.totalPages,
|
totalPages=totalPages,
|
||||||
sort=paginationParams.sort,
|
sort=paginationParams.sort,
|
||||||
filters=paginationParams.filters
|
filters=paginationParams.filters
|
||||||
).model_dump(),
|
).model_dump(),
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
response = {"items": _promptsToEnrichedDicts(result if isinstance(result, list) else [result]), "pagination": None}
|
result = managementInterface.getAllPrompts(pagination=paginationParams)
|
||||||
|
if paginationParams and hasattr(result, 'items'):
|
||||||
|
response = {
|
||||||
|
"items": _promptsToEnrichedDicts(result.items),
|
||||||
|
"pagination": PaginationMetadata(
|
||||||
|
currentPage=paginationParams.page,
|
||||||
|
pageSize=paginationParams.pageSize,
|
||||||
|
totalItems=result.totalItems,
|
||||||
|
totalPages=result.totalPages,
|
||||||
|
sort=paginationParams.sort,
|
||||||
|
filters=paginationParams.filters
|
||||||
|
).model_dump(),
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
response = {"items": _promptsToEnrichedDicts(result if isinstance(result, list) else [result]), "pagination": None}
|
||||||
if viewMeta:
|
if viewMeta:
|
||||||
response["appliedView"] = viewMeta.model_dump()
|
response["appliedView"] = viewMeta.model_dump()
|
||||||
return response
|
return response
|
||||||
|
|
@ -148,8 +225,14 @@ def get_prompts(
|
||||||
from modules.interfaces.interfaceDbManagement import ComponentObjects
|
from modules.interfaces.interfaceDbManagement import ComponentObjects
|
||||||
comp = ComponentObjects()
|
comp = ComponentObjects()
|
||||||
comp.setUserContext(currentUser)
|
comp.setUserContext(currentUser)
|
||||||
|
filtersForGenericApply = paginationParams.filters
|
||||||
|
promptSearchValue = None
|
||||||
if paginationParams.filters:
|
if paginationParams.filters:
|
||||||
allItems = comp._applyFilters(allItems, paginationParams.filters)
|
promptSearchValue, filtersForGenericApply = _extractSearchAndRemoveFromFilters(paginationParams.filters)
|
||||||
|
if promptSearchValue is not None:
|
||||||
|
allItems = _applyPromptSearchOnVisibleFields(allItems, promptSearchValue)
|
||||||
|
if filtersForGenericApply:
|
||||||
|
allItems = comp._applyFilters(allItems, filtersForGenericApply)
|
||||||
if paginationParams.sort:
|
if paginationParams.sort:
|
||||||
allItems = comp._applySorting(allItems, paginationParams.sort)
|
allItems = comp._applySorting(allItems, paginationParams.sort)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue