ssfinder-matching / db_connector.py
asefasdfcv's picture
Update db_connector.py
47601ee verified
"""
MySQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ๋ฐ ์Šต๋“๋ฌผ ๋ฐ์ดํ„ฐ ์กฐํšŒ ๋ชจ๋“ˆ
"""
import os
import logging
import traceback
import pymysql
from pymysql.cursors import DictCursor
from contextlib import contextmanager
# ๋กœ๊น… ์„ค์ •
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ์„ค์ •
DB_CONFIG = {
'host': os.getenv('DB_HOST', 'localhost'),
'port': int(os.getenv('DB_PORT', 3306)),
'user': os.getenv('DB_USER', 'username'),
'password': os.getenv('DB_PASSWORD', 'password'),
'db': os.getenv('DB_NAME', 'foundlost'),
'charset': 'utf8mb4',
'cursorclass': DictCursor
}
@contextmanager
def get_db_connection():
"""
๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ์„ ์ œ๊ณตํ•˜๋Š” ์ปจํ…์ŠคํŠธ ๋งค๋‹ˆ์ €
Yields:
pymysql.connections.Connection: ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ๊ฐ์ฒด
"""
connection = None
try:
connection = pymysql.connect(**DB_CONFIG)
logger.info("๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ์„ฑ๊ณต")
yield connection
except Exception as e:
logger.error(f"๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ์˜ค๋ฅ˜: {str(e)}")
logger.error(traceback.format_exc())
raise
finally:
if connection:
connection.close()
logger.debug("๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ์ข…๋ฃŒ")
async def fetch_found_items(limit=100, offset=0):
"""
MySQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์Šต๋“๋ฌผ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒ
Args:
limit (int): ์กฐํšŒํ•  ์ตœ๋Œ€ ํ•ญ๋ชฉ ์ˆ˜ (๊ธฐ๋ณธ๊ฐ’: 100)
offset (int): ์กฐํšŒ ์‹œ์ž‘ ์œ„์น˜ (๊ธฐ๋ณธ๊ฐ’: 0)
Returns:
list: ์Šต๋“๋ฌผ ๋ฐ์ดํ„ฐ ๋ชฉ๋ก
"""
found_items = []
try:
with get_db_connection() as connection:
with connection.cursor() as cursor:
query = """
SELECT f.id, f.user_id, f.item_category_id, f.name as title, f.color,
f.detail as content, f.location, f.image, f.status, f.found_at as lost_at,
f.created_at, f.management_id, f.stored_at,
ic.name as category_name,
ic.level as majorCategory, # major_category ๋Œ€์‹  level ์‚ฌ์šฉ
ic.name as minorCategory
FROM found_item f
LEFT JOIN item_category ic ON f.item_category_id = ic.id
WHERE f.status IN ('STORED', 'RECEIVED', 'TRANSFERRED')
ORDER BY f.created_at DESC
LIMIT %s OFFSET %s
"""
cursor.execute(query, (limit, offset))
rows = cursor.fetchall()
# ์กฐํšŒ ๊ฒฐ๊ณผ๋ฅผ API ์‘๋‹ต ํ˜•์‹์— ๋งž๊ฒŒ ๋ณ€ํ™˜
for row in rows:
found_item = {
"id": row["id"],
"user_id": row["user_id"],
"item_category_id": row["item_category_id"],
"title": row["title"], # name ์ปฌ๋Ÿผ์„ title๋กœ ๋งคํ•‘
"color": row["color"],
"content": row["content"], # detail ์ปฌ๋Ÿผ์„ content๋กœ ๋งคํ•‘
"location": row["location"],
"image": row["image"],
"status": row["status"],
"lost_at": row["lost_at"],
"stored_at": row["stored_at"],
"management_id": row["management_id"],
"category": row["category_name"], # ์นดํ…Œ๊ณ ๋ฆฌ๋ช… ์ถ”๊ฐ€
"majorCategory": row["majorCategory"],
"minorCategory": row["minorCategory"]
}
found_items.append(found_item)
logger.info(f"{len(found_items)}๊ฐœ์˜ ์Šต๋“๋ฌผ ๋ฐ์ดํ„ฐ ์กฐํšŒ ์™„๋ฃŒ")
except Exception as e:
logger.error(f"์Šต๋“๋ฌผ ๋ฐ์ดํ„ฐ ์กฐํšŒ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}")
logger.error(traceback.format_exc())
return found_items
# ์Šต๋“๋ฌผ ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜ ์กฐํšŒ ํ•จ์ˆ˜
async def count_found_items():
"""
MySQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์Šต๋“๋ฌผ ๋ฐ์ดํ„ฐ์˜ ์ด ๊ฐœ์ˆ˜๋ฅผ ์กฐํšŒ
Returns:
int: ์Šต๋“๋ฌผ ๋ฐ์ดํ„ฐ ์ด ๊ฐœ์ˆ˜
"""
try:
with get_db_connection() as connection:
with connection.cursor() as cursor:
# status๊ฐ€ 'STORED'์ธ ํ•ญ๋ชฉ๋งŒ ์กฐํšŒ
query = "SELECT COUNT(*) as total FROM found_item WHERE status IN ('STORED', 'RECEIVED', 'TRANSFERRED')"
cursor.execute(query)
result = cursor.fetchone()
total_count = result["total"]
logger.info(f"์ด ์Šต๋“๋ฌผ ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜: {total_count}")
return total_count
except Exception as e:
logger.error(f"์Šต๋“๋ฌผ ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜ ์กฐํšŒ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}")
logger.error(traceback.format_exc())
return 0
# ๋ถ„์‹ค๋ฌผ ๋ชฉ๋ก์„ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜
async def fetch_lost_items(limit=100, offset=0):
"""
๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๋ถ„์‹ค๋ฌผ ๋ชฉ๋ก์„ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜
Args:
limit (int): ์กฐํšŒํ•  ์ตœ๋Œ€ ํ•ญ๋ชฉ ์ˆ˜ (๊ธฐ๋ณธ๊ฐ’: 100)
offset (int): ์กฐํšŒ ์‹œ์ž‘ ์œ„์น˜ (๊ธฐ๋ณธ๊ฐ’: 0)
Returns:
list: ๋ถ„์‹ค๋ฌผ ๋ฐ์ดํ„ฐ ๋ชฉ๋ก
"""
try:
# ํ™˜๊ฒฝ๋ณ€์ˆ˜ ํ™•์ธ - ํ…Œ์ŠคํŠธ ๋ชจ๋“œ์ธ ๊ฒฝ์šฐ ์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ ๋ฐ˜ํ™˜
if os.getenv('APP_ENV') == 'test':
logger.info("ํ…Œ์ŠคํŠธ ๋ชจ๋“œ: ์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ ์‚ฌ์šฉ")
# ์˜ˆ์‹œ ๋ฐ์ดํ„ฐ - ํ…Œ์ŠคํŠธ์šฉ
sample_lost_items = [
{
"id": 1,
"item_category_id": 1,
"title": "๊ฒ€์ • ๊ฐ€์ฃฝ ์ง€๊ฐ‘",
"color": "๊ฒ€์ •์ƒ‰",
"content": "๊ฐ•๋‚จ์—ญ ๊ทผ์ฒ˜์—์„œ ๊ฒ€์ •์ƒ‰ ๊ฐ€์ฃฝ ์ง€๊ฐ‘์„ ์žƒ์–ด๋ฒ„๋ ธ์Šต๋‹ˆ๋‹ค.",
"location": "๊ฐ•๋‚จ์—ญ",
"image": None,
"category": "์ง€๊ฐ‘"
},
{
"id": 2,
"item_category_id": 1,
"title": "๊ฐˆ์ƒ‰ ๊ฐ€์ฃฝ ์ง€๊ฐ‘",
"color": "๊ฐˆ์ƒ‰",
"content": "์„œ์šธ๋Œ€์ž…๊ตฌ์—ญ ๊ทผ์ฒ˜์—์„œ ๊ฐˆ์ƒ‰ ๊ฐ€์ฃฝ ์ง€๊ฐ‘์„ ์žƒ์–ด๋ฒ„๋ ธ์Šต๋‹ˆ๋‹ค.",
"location": "์„œ์šธ๋Œ€์ž…๊ตฌ์—ญ",
"image": None,
"category": "์ง€๊ฐ‘"
}
]
return sample_lost_items
# ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๋ฐ์ดํ„ฐ ์กฐํšŒ
logger.info(f"๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๋ถ„์‹ค๋ฌผ ๋ฐ์ดํ„ฐ ์กฐํšŒ ์ค‘ (limit: {limit}, offset: {offset})...")
with get_db_connection() as connection:
with connection.cursor() as cursor:
# lost_item ํ…Œ์ด๋ธ”์—์„œ ๋ถ„์‹ค๋ฌผ ๋ฐ์ดํ„ฐ ์กฐํšŒ (l.stored_at ์ปฌ๋Ÿผ ์ œ๊ฑฐ)
query = """
SELECT l.id, l.user_id, l.item_category_id, l.title, l.color,
l.lost_at, l.location, l.detail as content, l.image,
l.status,
ic.level as majorCategory,
ic.name as minorCategory
FROM lost_item l
LEFT JOIN item_category ic ON l.item_category_id = ic.id
WHERE l.status = 'LOST'
ORDER BY l.id DESC
LIMIT %s OFFSET %s
"""
cursor.execute(query, (limit, offset))
result = cursor.fetchall() # DictCursor๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ๋”•์…”๋„ˆ๋ฆฌ๋กœ ๋ฐ˜ํ™˜๋จ
logger.info(f"๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ {len(result)}๊ฐœ์˜ ๋ถ„์‹ค๋ฌผ ๋ฐ์ดํ„ฐ ์กฐํšŒ ์™„๋ฃŒ")
return result
except Exception as e:
logger.error(f"๋ถ„์‹ค๋ฌผ ๋ฐ์ดํ„ฐ ์กฐํšŒ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}")
logger.error(traceback.format_exc())
# ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ ๋นˆ ๋ชฉ๋ก ๋ฐ˜ํ™˜
return []
# ๋ถ„์‹ค๋ฌผ ์ด ๊ฐœ์ˆ˜๋ฅผ ์กฐํšŒํ•˜๋Š” ํ•จ์ˆ˜
async def count_lost_items():
"""
๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๋ถ„์‹ค๋ฌผ ์ด ๊ฐœ์ˆ˜๋ฅผ ์กฐํšŒํ•˜๋Š” ํ•จ์ˆ˜
Returns:
int: ์ด ๋ถ„์‹ค๋ฌผ ์ˆ˜
"""
try:
# ํ…Œ์ŠคํŠธ ๋ชจ๋“œ์ธ ๊ฒฝ์šฐ ์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜ ๋ฐ˜ํ™˜
if os.getenv('APP_ENV') == 'test':
return 2 # ์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜
# ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜ ์กฐํšŒ
with get_db_connection() as connection:
with connection.cursor() as cursor:
query = "SELECT COUNT(*) as total FROM lost_item WHERE status = 'LOST'"
cursor.execute(query)
result = cursor.fetchone()
# DictCursor๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ๋”•์…”๋„ˆ๋ฆฌ๋กœ ๋ฐ˜ํ™˜๋จ
count = result["total"]
return count
except Exception as e:
logger.error(f"๋ถ„์‹ค๋ฌผ ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜ ์กฐํšŒ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}")
logger.error(traceback.format_exc())
# ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ 0 ๋ฐ˜ํ™˜
return 0
# ํŠน์ • ID์˜ ์Šต๋“๋ฌผ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜ - ์ƒˆ๋กœ ์ถ”๊ฐ€
async def get_found_item_info(found_item_id):
"""
ํŠน์ • ์Šต๋“๋ฌผ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜
"""
try:
if os.getenv('APP_ENV') == 'test':
return {
"id": found_item_id,
"item_category_id": 1,
"name": "๊ฒ€์ • ๊ฐ€์ฃฝ ์ง€๊ฐ‘",
"color": "๊ฒ€์ •์ƒ‰",
"detail": "๊ฐ•๋‚จ์—ญ ๊ทผ์ฒ˜์—์„œ ๊ฒ€์ •์ƒ‰ ๊ฐ€์ฃฝ ์ง€๊ฐ‘์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค.",
"location": "๊ฐ•๋‚จ์—ญ"
}
with get_db_connection() as connection:
with connection.cursor() as cursor:
query = """
SELECT f.id, f.user_id, f.item_category_id, f.name, f.color,
f.found_at, f.location, f.detail, f.image,
f.status, f.stored_at, f.management_id,
ic.major_category AS majorCategory,
ic.name AS minorCategory
FROM found_item f
LEFT JOIN item_category ic ON f.item_category_id = ic.id
WHERE f.id = %s
"""
cursor.execute(query, (found_item_id,))
return cursor.fetchone()
except Exception as e:
logger.error(f"์Šต๋“๋ฌผ ์ •๋ณด ์กฐํšŒ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}")
logger.error(traceback.format_exc())
return None
# ํŠน์ • ID์˜ ๋ถ„์‹ค๋ฌผ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜ - ์ƒˆ๋กœ ์ถ”๊ฐ€
async def get_lost_item_info(lost_item_id):
"""
ํŠน์ • ๋ถ„์‹ค๋ฌผ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜
"""
try:
if os.getenv('APP_ENV') == 'test':
return {
"id": lost_item_id,
"item_category_id": 1,
"title": "๊ฒ€์ • ๊ฐ€์ฃฝ ์ง€๊ฐ‘",
"color": "๊ฒ€์ •์ƒ‰",
"detail": "๊ฐ•๋‚จ์—ญ ๊ทผ์ฒ˜์—์„œ ๊ฒ€์ •์ƒ‰ ๊ฐ€์ฃฝ ์ง€๊ฐ‘์„ ์žƒ์–ด๋ฒ„๋ ธ์Šต๋‹ˆ๋‹ค.",
"location": "๊ฐ•๋‚จ์—ญ"
}
with get_db_connection() as connection:
with connection.cursor() as cursor:
query = """
SELECT l.id, l.user_id, l.item_category_id, l.title, l.color,
l.lost_at, l.location, l.detail, l.image,
l.status,
ic.major_category AS majorCategory,
ic.name AS minorCategory
FROM lost_item l
LEFT JOIN item_category ic ON l.item_category_id = ic.id
WHERE l.id = %s
"""
cursor.execute(query, (lost_item_id,))
return cursor.fetchone()
except Exception as e:
logger.error(f"๋ถ„์‹ค๋ฌผ ์ •๋ณด ์กฐํšŒ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}")
logger.error(traceback.format_exc())
return None
# ํŠน์ • ID์˜ ์Šต๋“๋ฌผ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜ - ์ˆ˜์ •
async def fetch_found_item_by_id(found_item_id):
"""
๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ํŠน์ • ID์˜ ์Šต๋“๋ฌผ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜
Args:
found_item_id (int): ์กฐํšŒํ•  ์Šต๋“๋ฌผ ID
Returns:
dict: ์Šต๋“๋ฌผ ๋ฐ์ดํ„ฐ (์—†์œผ๋ฉด None)
"""
try:
# ํ…Œ์ŠคํŠธ ๋ชจ๋“œ์ธ ๊ฒฝ์šฐ ์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ ๋ฐ˜ํ™˜
if os.getenv('APP_ENV') == 'test':
# ID์— ํ•ด๋‹นํ•˜๋Š” ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ ๋ฐ˜ํ™˜
if found_item_id == 1:
return {
"id": 1,
"item_category_id": 1,
"title": "๊ฒ€์ • ๊ฐ€์ฃฝ ์ง€๊ฐ‘",
"color": "๊ฒ€์ •์ƒ‰",
"content": "๊ฐ•๋‚จ์—ญ ๊ทผ์ฒ˜์—์„œ ๊ฒ€์ •์ƒ‰ ๊ฐ€์ฃฝ ์ง€๊ฐ‘์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค.",
"location": "๊ฐ•๋‚จ์—ญ",
"image": None,
"category": "์ง€๊ฐ‘"
}
return None
# ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๋ฐ์ดํ„ฐ ์กฐํšŒ
logger.info(f"๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์Šต๋“๋ฌผ ID {found_item_id} ์กฐํšŒ ์ค‘...")
with get_db_connection() as connection:
with connection.cursor() as cursor:
query = """
SELECT f.id, f.user_id, f.item_category_id, f.name as title, f.color,
f.found_at, f.location, f.detail as content, f.image,
f.status, f.stored_at, f.management_id,
ic.major_category as majorCategory,
ic.name as minorCategory
FROM found_item f
LEFT JOIN item_category ic ON f.item_category_id = ic.id
WHERE f.id = %s
"""
cursor.execute(query, (found_item_id,))
item = cursor.fetchone()
if item:
logger.info(f"์Šต๋“๋ฌผ ID {found_item_id} ์กฐํšŒ ์™„๋ฃŒ")
return item
else:
logger.warning(f"์Šต๋“๋ฌผ ID {found_item_id}๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Œ")
return None
except Exception as e:
logger.error(f"์Šต๋“๋ฌผ ์กฐํšŒ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}")
logger.error(traceback.format_exc())
# ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ None ๋ฐ˜ํ™˜
return None
# ํŠน์ • ID์˜ ๋ถ„์‹ค๋ฌผ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜ - ์ˆ˜์ •
async def fetch_lost_item_by_id(lost_item_id):
"""
๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ํŠน์ • ID์˜ ๋ถ„์‹ค๋ฌผ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜
Args:
lost_item_id (int): ์กฐํšŒํ•  ๋ถ„์‹ค๋ฌผ ID
Returns:
dict: ๋ถ„์‹ค๋ฌผ ๋ฐ์ดํ„ฐ (์—†์œผ๋ฉด None)
"""
try:
# ํ…Œ์ŠคํŠธ ๋ชจ๋“œ์ธ ๊ฒฝ์šฐ ์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ ๋ฐ˜ํ™˜
if os.getenv('APP_ENV') == 'test':
# ID์— ํ•ด๋‹นํ•˜๋Š” ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ ๋ฐ˜ํ™˜
if lost_item_id == 1:
return {
"id": 1,
"item_category_id": 1,
"title": "๊ฒ€์ • ๊ฐ€์ฃฝ ์ง€๊ฐ‘",
"color": "๊ฒ€์ •์ƒ‰",
"content": "๊ฐ•๋‚จ์—ญ ๊ทผ์ฒ˜์—์„œ ๊ฒ€์ •์ƒ‰ ๊ฐ€์ฃฝ ์ง€๊ฐ‘์„ ์žƒ์–ด๋ฒ„๋ ธ์Šต๋‹ˆ๋‹ค.",
"location": "๊ฐ•๋‚จ์—ญ",
"image": None,
"category": "์ง€๊ฐ‘"
}
return None
# ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๋ฐ์ดํ„ฐ ์กฐํšŒ
logger.info(f"๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๋ถ„์‹ค๋ฌผ ID {lost_item_id} ์กฐํšŒ ์ค‘...")
with get_db_connection() as connection:
with connection.cursor() as cursor:
# stored_at ์ปฌ๋Ÿผ ์ œ๊ฑฐ
query = """
SELECT l.id, l.user_id, l.item_category_id, l.title, l.color,
l.lost_at, l.location, l.detail as content, l.image,
l.status,
ic.major_category as majorCategory,
ic.name as minorCategory
FROM lost_item l
LEFT JOIN item_category ic ON l.item_category_id = ic.id
WHERE l.id = %s
"""
cursor.execute(query, (lost_item_id,))
item = cursor.fetchone()
if item:
logger.info(f"๋ถ„์‹ค๋ฌผ ID {lost_item_id} ์กฐํšŒ ์™„๋ฃŒ")
return item
else:
logger.warning(f"๋ถ„์‹ค๋ฌผ ID {lost_item_id}๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Œ")
return None
except Exception as e:
logger.error(f"๋ถ„์‹ค๋ฌผ ์กฐํšŒ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}")
logger.error(traceback.format_exc())
# ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ None ๋ฐ˜ํ™˜
return None