# /opt/docker/dev/service_finder/backend/app/api/v1/endpoints/search.py from fastapi import APIRouter, Depends from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select, func, or_ from sqlalchemy.orm import selectinload from app.db.session import get_db from app.api.deps import get_current_user from app.models.marketplace.organization import Organization, Branch from geoalchemy2 import WKTElement from typing import Optional router = APIRouter() @router.get("/match") async def match_service( lat: Optional[float] = None, lng: Optional[float] = None, radius_km: float = 20.0, sort_by: str = "distance", db: AsyncSession = Depends(get_db), current_user = Depends(get_current_user) ): """ Geofencing keresőmotor PostGIS segítségével. Ha nincs megadva lat/lng, akkor nem alkalmazunk távolságszűrést. """ # Alap lekérdezés: aktív szervezetek és telephelyek query = select( Organization.id, Organization.name, Branch.city, Branch.branch_rating, Branch.location ).join( Branch, Organization.id == Branch.organization_id ).where( Organization.is_active == True, Branch.is_deleted == False ) # Távolság számítás és szűrés, ha van koordináta if lat is not None and lng is not None: # WKT pont létrehozása a felhasználó helyéhez user_location = WKTElement(f'POINT({lng} {lat})', srid=4326) # Távolság kiszámítása méterben (ST_DistanceSphere) distance_col = func.ST_DistanceSphere(Branch.location, user_location).label("distance_meters") query = query.add_columns(distance_col) # Szűrés a sugárra (ST_DWithin) - a távolság méterben, radius_km * 1000 query = query.where( func.ST_DWithin(Branch.location, user_location, radius_km * 1000) ) else: # Ha nincs koordináta, ne legyen distance oszlop distance_col = None # Rendezés a sort_by paraméter alapján if sort_by == "distance" and lat is not None and lng is not None: query = query.order_by(distance_col.asc()) elif sort_by == "rating": query = query.order_by(Branch.branch_rating.desc()) elif sort_by == "price": # Jelenleg nincs ár információ, ezért rendezés alapértelmezettként (pl. név) query = query.order_by(Organization.name.asc()) else: # Alapértelmezett rendezés: távolság, ha van, különben név if distance_col is not None: query = query.order_by(distance_col.asc()) else: query = query.order_by(Organization.name.asc()) # Lekérdezés végrehajtása result = await db.execute(query) rows = result.fetchall() # Eredmények formázása results = [] for row in rows: row_dict = { "id": row.id, "name": row.name, "city": row.city, "rating": row.branch_rating, } if lat is not None and lng is not None: row_dict["distance_km"] = round(row.distance_meters / 1000, 2) if row.distance_meters else None results.append(row_dict) return {"results": results}