48 lines
1.4 KiB
Python
48 lines
1.4 KiB
Python
|
|
"""Fallback name/address search over our own `places` dataset.
|
||
|
|
|
||
|
|
Used when the user denies location permission and types a place of interest,
|
||
|
|
or when 2GIS's own geocoding API isn't wired into a given client flow yet.
|
||
|
|
"""
|
||
|
|
|
||
|
|
from geoalchemy2 import Geometry
|
||
|
|
from sqlalchemy import and_, cast, func, select
|
||
|
|
from sqlalchemy.orm import Session
|
||
|
|
|
||
|
|
from app.models.city import City
|
||
|
|
from app.models.enums import ContentLanguage, ContentLength
|
||
|
|
from app.models.place import Place
|
||
|
|
from app.models.place_content import PlaceContent
|
||
|
|
|
||
|
|
|
||
|
|
def search_places(
|
||
|
|
db: Session,
|
||
|
|
*,
|
||
|
|
q: str,
|
||
|
|
language: ContentLanguage,
|
||
|
|
city_slug: str | None = None,
|
||
|
|
limit: int = 20,
|
||
|
|
):
|
||
|
|
stmt = (
|
||
|
|
select(
|
||
|
|
Place,
|
||
|
|
PlaceContent,
|
||
|
|
func.ST_X(cast(Place.location, Geometry)).label("lon"),
|
||
|
|
func.ST_Y(cast(Place.location, Geometry)).label("lat"),
|
||
|
|
)
|
||
|
|
.join(
|
||
|
|
PlaceContent,
|
||
|
|
and_(
|
||
|
|
PlaceContent.place_id == Place.id,
|
||
|
|
PlaceContent.language == language,
|
||
|
|
PlaceContent.length == ContentLength.short,
|
||
|
|
),
|
||
|
|
)
|
||
|
|
.where(Place.is_active.is_(True))
|
||
|
|
.where(PlaceContent.title.ilike(f"%{q}%"))
|
||
|
|
.limit(limit)
|
||
|
|
)
|
||
|
|
if city_slug is not None:
|
||
|
|
stmt = stmt.join(City, City.id == Place.city_id).where(City.slug == city_slug)
|
||
|
|
|
||
|
|
return db.execute(stmt).all()
|