o2o-site-AEO/solution/backend/crud/local_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

106 lines
4.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 local_contents
from common.enums import ErrorType, LocalContentType
from common.utils.gtime import GTime
class LocalContentCRUD:
async def list(self, db, status: int | None = None, region_code: str | None = None):
"""축제·관광지·맛집·날씨 전 종류. ★ 예전엔 FESTIVAL 로 고정돼 있어 sync_region 이 받은
관광지·맛집이 이 목록에 영영 안 보였다(admin 화면이 축제만 검수/발행하는 줄 알게 됨)."""
conds = [local_contents.deleted == False] # noqa: E712
if status is not None:
conds.append(local_contents.status == status)
if region_code:
conds.append(local_contents.region_code == region_code)
return await DB_SESSION_MNG.execute(
db, select(local_contents).where(and_(*conds)).order_by(local_contents.collected_at.desc())
)
async def insert(self, db, row):
return await DB_SESSION_MNG.insert(db, row)
async def publish(self, db, ids: list, user_id):
return await DB_SESSION_MNG.add_with_rowcount(
db,
update(local_contents).where(
local_contents.local_content_id.in_(ids), local_contents.deleted == False # noqa: E712
).values(status=2, published_at=GTime.UTC(), published_by=user_id, updated_at=GTime.UTC()),
)
async def update(self, db, content_id, data: dict):
return await DB_SESSION_MNG.add_with_rowcount(
db,
update(local_contents).where(
local_contents.local_content_id == content_id, local_contents.deleted == False # noqa: E712
).values(**data, updated_at=GTime.UTC()),
)
async def end(self, db, content_id):
return await self.update(db, content_id, {"status": 3})
async def list_keyed(self, db, region_code: str, content_type: int):
"""지역 × 종류의 외부 ID 있는 행 전부(축제·관광지·맛집). 동기화가 기존값과 비교할 때 쓴다."""
return await DB_SESSION_MNG.execute(
db,
select(local_contents).where(
local_contents.region_code == region_code,
local_contents.content_type == content_type,
local_contents.external_id.isnot(None),
local_contents.deleted == False, # noqa: E712
),
)
async def upsert_keyed(self, db, values: dict):
"""외부 ID 로 식별되는 행(축제·관광지·맛집)의 삽입/갱신.
★ uq_local_contents_keyed 부분 유니크 인덱스에 태운다 — 같은 지역을 두 번 동기화해도
중복 행이 생기지 않고 기존 값만 갱신된다."""
stmt = pg_insert(local_contents).values(**values)
stmt = stmt.on_conflict_do_update(
index_elements=[local_contents.region_code, local_contents.content_type, local_contents.external_id],
index_where=and_(local_contents.deleted == False, local_contents.external_id.isnot(None)), # noqa: E712
set_={
"title": stmt.excluded.title,
"body": stmt.excluded.body,
"source": stmt.excluded.source,
"status": stmt.excluded.status,
"collected_at": stmt.excluded.collected_at,
"display_end_at": stmt.excluded.display_end_at,
"published_at": stmt.excluded.published_at,
"updated_at": GTime.UTC(),
},
)
return await DB_SESSION_MNG.add(db, stmt)
async def get_weather(self, db, region_code: str):
err, rows = await DB_SESSION_MNG.execute(
db,
select(local_contents).where(
local_contents.region_code == region_code,
local_contents.content_type == LocalContentType.WEATHER.value,
local_contents.external_id.is_(None),
local_contents.deleted == False, # noqa: E712
).limit(1),
)
return err, rows[0] if rows else None
async def upsert_weather(self, db, values: dict):
stmt = pg_insert(local_contents).values(**values)
stmt = stmt.on_conflict_do_update(
index_elements=[local_contents.region_code, local_contents.content_type],
index_where=and_(local_contents.deleted == False, local_contents.external_id.is_(None)), # noqa: E712
set_={
"source": stmt.excluded.source,
"body": stmt.excluded.body,
"status": stmt.excluded.status,
"collected_at": stmt.excluded.collected_at,
"expires_at": stmt.excluded.expires_at,
"updated_at": stmt.excluded.updated_at,
},
)
return await DB_SESSION_MNG.add(db, stmt)