refactor: change search router

This commit is contained in:
2026-06-15 11:01:39 +03:00
parent 6f8206c867
commit db30feb0e2
6 changed files with 90 additions and 64 deletions

View File

@@ -6,10 +6,10 @@ from src.application.commands.create_organization import CreateOrganizationComma
from src.application.commands.create_organization_wallets import CreateOrganizationWalletsCommand
from src.application.commands.put_organization_document import PutOrganizationDocumentCommand
from src.application.commands.set_password import SetPasswordCommand
from src.application.commands.party_search_command import SearchPartiesCommand
from src.application.commands.organization_commands import (
ListOrganizationsCommand,
GetOrganizationCommand,
SearchPartiesCommand,
UpdateOrganizationCommand,
)
from src.application.commands.organization_document_commands import (

View File

@@ -4,8 +4,7 @@ from typing import Any
from src.application.abstractions import IUnitOfWork
from src.application.contracts import ILogger
from src.application.domain.entities.organization import LegalEntityEntity, PartySearchEntity
from src.application.domain.enums.account_type import AccountType
from src.application.domain.entities.organization import LegalEntityEntity
from src.infrastructure.database.decorators import transactional
@@ -31,49 +30,6 @@ class ListOrganizationsCommand:
return items, total
class SearchPartiesCommand:
def __init__(self, unit_of_work: IUnitOfWork, logger: ILogger):
self._unit_of_work = unit_of_work
self._logger = logger
@transactional
async def __call__(self, *, query: str, limit: int = 50, offset: int = 0) -> tuple[list[PartySearchEntity], int]:
query = query.strip()
if not query:
return [], 0
fetch_limit = limit + offset
legal_items = await self._unit_of_work.legal_entity_repository.list_all(
limit=fetch_limit,
offset=0,
search=query,
)
individual_items = await self._unit_of_work.user_repository.search_individuals(
query=query,
limit=fetch_limit,
offset=0,
)
legal_total = await self._unit_of_work.legal_entity_repository.count_all(search=query)
individual_total = await self._unit_of_work.user_repository.count_individuals(query=query)
items = [self._legal_to_search_entity(item) for item in legal_items] + individual_items
items.sort(key=lambda item: item.created_at.timestamp() if item.created_at else 0, reverse=True)
return items[offset:offset + limit], legal_total + individual_total
def _legal_to_search_entity(self, item: LegalEntityEntity) -> PartySearchEntity:
return PartySearchEntity(
id=item.id,
account_type=AccountType.LEGAL_ENTITY,
user_id=item.user_id,
email=None,
name=item.name,
inn=item.inn,
phone=item.contact_phone,
status=item.status,
kyc_verified=item.kyc_verified,
created_at=item.created_at,
)
class GetOrganizationCommand:
def __init__(self, unit_of_work: IUnitOfWork, logger: ILogger):
self._unit_of_work = unit_of_work

View File

@@ -0,0 +1,52 @@
from __future__ import annotations
from typing import Any
from src.application.abstractions import IUnitOfWork
from src.application.contracts import ILogger
from src.application.domain.entities.organization import LegalEntityEntity, PartySearchEntity
from src.application.domain.enums.account_type import AccountType
from src.infrastructure.database.decorators import transactional
class SearchPartiesCommand:
def __init__(self, unit_of_work: IUnitOfWork, logger: ILogger):
self._unit_of_work = unit_of_work
self._logger = logger
@transactional
async def __call__(self, *, query: str, limit: int = 50, offset: int = 0) -> tuple[list[PartySearchEntity], int]:
query = query.strip()
if not query:
return [], 0
fetch_limit = limit + offset
legal_items = await self._unit_of_work.legal_entity_repository.list_all(
limit=fetch_limit,
offset=0,
search=query,
)
individual_items = await self._unit_of_work.user_repository.search_individuals(
query=query,
limit=fetch_limit,
offset=0,
)
legal_total = await self._unit_of_work.legal_entity_repository.count_all(search=query)
individual_total = await self._unit_of_work.user_repository.count_individuals(query=query)
items = [self._legal_to_search_entity(item) for item in legal_items] + individual_items
items.sort(key=lambda item: item.created_at.timestamp() if item.created_at else 0, reverse=True)
return items[offset:offset + limit], legal_total + individual_total
def _legal_to_search_entity(self, item: LegalEntityEntity) -> PartySearchEntity:
return PartySearchEntity(
id=item.id,
account_type=AccountType.LEGAL_ENTITY,
user_id=item.user_id,
email=None,
name=item.name,
inn=item.inn,
phone=item.contact_phone,
status=item.status,
kyc_verified=item.kyc_verified,
created_at=item.created_at,
)

View File

@@ -6,6 +6,7 @@ from src.presentation.routing.jwt import jwt_router
from src.presentation.routing.organizations import organizations_router
from src.presentation.routing.purchase_requests import purchase_requests_router
from src.presentation.routing.users import users_router
from src.presentation.routing.search import search_router
v1_router = APIRouter(prefix='/v1')
v1_router.include_router(auth_router)
@@ -13,4 +14,5 @@ v1_router.include_router(jwt_router)
v1_router.include_router(organizations_router)
v1_router.include_router(documents_router)
v1_router.include_router(purchase_requests_router)
v1_router.include_router(users_router)
v1_router.include_router(users_router)
v1_router.include_router(search_router)

View File

@@ -42,8 +42,6 @@ from src.presentation.schemas.organization import (
from src.presentation.schemas.entity import (
CreateWalletsResponse,
MnemonicResponse,
PartySearchResponse,
PartySearchListResponse,
PurchaseRequestResponse,
PurchaseRequestListResponse,
SecretKeyResponse,
@@ -93,21 +91,6 @@ async def create_organization(
return organization_to_response(org)
@organizations_router.get('/search', response_model=PartySearchListResponse)
async def search_parties(
q: str = Query(min_length=1, max_length=255),
limit: int = Query(default=50, ge=1, le=200),
offset: int = Query(default=0, ge=0),
auth: AdminAuthContext = Depends(require_admin_access),
command: SearchPartiesCommand = Depends(get_search_parties_command),
):
items, total = await command(query=q, limit=limit, offset=offset)
return PartySearchListResponse(
items=[party_search_to_response(x) for x in items],
total=total,
)
@organizations_router.get('/{organization_id}', response_model=OrganizationResponse)
async def get_organization(
organization_id: str,

View File

@@ -0,0 +1,33 @@
from fastapi import APIRouter, Depends, Query, status
from src.application.commands import (
SearchPartiesCommand,
)
from src.application.domain.dto import AdminAuthContext
from src.presentation.decorators.admin_auth import require_admin_access
from src.presentation.dependencies.commands import (
get_search_parties_command,
)
from src.presentation.schemas.mappers import (
party_search_to_response,
)
from src.presentation.schemas.entity import (
PartySearchResponse,
PartySearchListResponse,
)
search_router = APIRouter(prefix='/search', tags=['search'])
@search_router.get('', response_model=PartySearchListResponse)
async def search_parties(
q: str = Query(min_length=1, max_length=255),
limit: int = Query(default=50, ge=1, le=200),
offset: int = Query(default=0, ge=0),
# auth: AdminAuthContext = Depends(require_admin_access),
command: SearchPartiesCommand = Depends(get_search_parties_command),
):
items, total = await command(query=q, limit=limit, offset=offset)
return PartySearchListResponse(
items=[party_search_to_response(x) for x in items],
total=total,
)