o2o-site-AEO/solution/backend/crud/place_content_crud.py
김성경 01824a7a91 [feat] solution,admin,postgres-init: 주변정보를 업장 좌표 기준으로 — 시군구 캐시는 "가까운 곳"을 못 준다
지역 정보(맛집·관광지·축제)는 행정구역 코드(local_contents.region_code) 단위로 캐시돼
"그 시군구에 있는 것"을 줬다. 양양군 업장 옆 5km 속초 관광지는 빠지고 같은 군 반대편
30km 맛집이 붙는 구조라, 캔버스의 지역 정보 섹션은 늘 "준비 중"이었다. 업장 좌표로
TourAPI 를 직접 물어 업장 단위(place_contents)에 담고, 캔버스는 스크린샷으로 받은
형식(도보 시간 필터 + 카드 캐러셀)으로 통일했다.
2026-09-08 11:46:03 +09:00

64 lines
3.0 KiB
Python

from sqlalchemy import and_, select, update
from sqlalchemy.dialects.postgresql import insert as pg_insert
from common.database.db_session_manager import DB_SESSION_MNG
from common.database.model.models import place_contents
from common.utils.gtime import GTime
class PlaceContentCRUD:
"""업장 반경 주변정보(place_contents). 키는 place_id 다."""
async def list_by_place(self, db, place_id, *, include_hidden: bool = True):
conds = [place_contents.place_id == place_id, place_contents.deleted == False] # noqa: E712
if not include_hidden:
conds.append(place_contents.hidden == False) # noqa: E712
return await DB_SESSION_MNG.execute(
db,
select(place_contents).where(and_(*conds))
.order_by(place_contents.content_type.asc(), place_contents.has_image.desc(), place_contents.distance_m.asc()),
)
async def upsert(self, db, values: dict):
"""(place_id, content_type, external_id) 로 삽입/갱신. ★ hidden 은 건드리지 않는다 —
운영자가 숨긴 것을 재수집이 되살리면 안 된다."""
stmt = pg_insert(place_contents).values(**values)
stmt = stmt.on_conflict_do_update(
index_elements=[place_contents.place_id, place_contents.content_type, place_contents.external_id],
index_where=(place_contents.deleted == False), # noqa: E712
set_={
"title": stmt.excluded.title,
"body": stmt.excluded.body,
"distance_m": stmt.excluded.distance_m,
"has_image": stmt.excluded.has_image,
"display_end_at": stmt.excluded.display_end_at,
"collected_at": stmt.excluded.collected_at,
"updated_at": GTime.UTC(),
},
)
return await DB_SESSION_MNG.add(db, stmt)
async def soft_delete_missing(self, db, place_id, keep: set[tuple[int, str]]):
"""이번 응답에 없는 행을 소프트 삭제. keep = {(content_type, external_id)}."""
err, rows = await DB_SESSION_MNG.execute(
db,
select(place_contents.place_content_id, place_contents.content_type, place_contents.external_id)
.where(place_contents.place_id == place_id, place_contents.deleted == False), # noqa: E712
)
gone = [r.place_content_id for r in (rows or []) if (int(r.content_type), r.external_id) not in keep]
if not gone:
return err, 0
return await DB_SESSION_MNG.add_with_rowcount(
db,
update(place_contents).where(place_contents.place_content_id.in_(gone))
.values(deleted=True, updated_at=GTime.UTC()),
)
async def set_hidden(self, db, place_content_id, hidden: bool):
return await DB_SESSION_MNG.add_with_rowcount(
db,
update(place_contents).where(
place_contents.place_content_id == place_content_id, place_contents.deleted == False # noqa: E712
).values(hidden=hidden, updated_at=GTime.UTC()),
)