TravelContentCreator/domain/aigc/shared/database_accessor.py

275 lines
8.5 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
数据库访问器
提供按领域组织的数据库访问接口
"""
import logging
from typing import Dict, Any, Optional, List
logger = logging.getLogger(__name__)
class ScenicSpotAccessor:
"""景区数据访问器"""
def __init__(self, db_service):
self._db = db_service
async def find_by_id(self, spot_id: int) -> Optional[Dict[str, Any]]:
"""根据 ID 查询景区"""
try:
# 调用现有的 DatabaseService
return self._db.get_scenic_spot_by_id(spot_id)
except Exception as e:
logger.error(f"查询景区失败: {e}")
return None
async def find_by_name(self, name: str) -> Optional[Dict[str, Any]]:
"""根据名称查询景区"""
try:
return self._db.get_scenic_spot_by_name(name)
except Exception as e:
logger.error(f"查询景区失败: {e}")
return None
async def find_all(self, limit: int = 100) -> List[Dict[str, Any]]:
"""查询所有景区"""
try:
return self._db.get_all_scenic_spots(limit=limit)
except Exception as e:
logger.error(f"查询景区列表失败: {e}")
return []
class ProductAccessor:
"""产品数据访问器"""
def __init__(self, db_service):
self._db = db_service
async def find_by_id(self, product_id: int) -> Optional[Dict[str, Any]]:
"""根据 ID 查询产品"""
try:
return self._db.get_product_by_id(product_id)
except Exception as e:
logger.error(f"查询产品失败: {e}")
return None
async def find_by_scenic_spot(self, spot_id: int) -> List[Dict[str, Any]]:
"""根据景区查询产品"""
try:
return self._db.get_products_by_scenic_spot(spot_id)
except Exception as e:
logger.error(f"查询产品列表失败: {e}")
return []
class StyleAccessor:
"""风格数据访问器"""
def __init__(self, db_service):
self._db = db_service
async def find_by_id(self, style_id: int) -> Optional[Dict[str, Any]]:
"""根据 ID 查询风格"""
try:
return self._db.get_style_by_id(style_id)
except Exception as e:
logger.error(f"查询风格失败: {e}")
return None
async def find_all(self) -> List[Dict[str, Any]]:
"""查询所有风格"""
try:
return self._db.get_all_styles()
except Exception as e:
logger.error(f"查询风格列表失败: {e}")
return []
class AudienceAccessor:
"""受众数据访问器"""
def __init__(self, db_service):
self._db = db_service
async def find_by_id(self, audience_id: int) -> Optional[Dict[str, Any]]:
"""根据 ID 查询受众"""
try:
return self._db.get_audience_by_id(audience_id)
except Exception as e:
logger.error(f"查询受众失败: {e}")
return None
async def find_all(self) -> List[Dict[str, Any]]:
"""查询所有受众"""
try:
return self._db.get_all_audiences()
except Exception as e:
logger.error(f"查询受众列表失败: {e}")
return []
class TemplateAccessor:
"""模板数据访问器"""
def __init__(self, db_service):
self._db = db_service
async def find_by_id(self, template_id: str) -> Optional[Dict[str, Any]]:
"""根据 ID 查询模板"""
try:
return self._db.get_poster_template_by_id(template_id)
except Exception as e:
logger.error(f"查询模板失败: {e}")
return None
async def find_active(self) -> List[Dict[str, Any]]:
"""查询所有激活的模板"""
try:
return self._db.get_active_poster_templates()
except Exception as e:
logger.error(f"查询模板列表失败: {e}")
return []
class ProductPackageAccessor:
"""ProductPackage 数据访问器 (ppid 解析)"""
def __init__(self, db_service):
self._db = db_service
async def find_by_id(self, ppid: int) -> Optional[Dict[str, Any]]:
"""根据 ppid 查询 ProductPackage"""
try:
if hasattr(self._db, 'get_product_package_by_id'):
return self._db.get_product_package_by_id(ppid)
else:
# 如果没有专门的方法,尝试通用查询
return self._db.execute_query(
"SELECT * FROM product_package WHERE id = %s AND is_delete = 0",
(ppid,)
)
except Exception as e:
logger.error(f"查询 ProductPackage 失败: {e}")
return None
async def resolve_ids(self, ppid: int) -> Optional[Dict[str, int]]:
"""
解析 ppid 为原始 ID
Args:
ppid: ProductPackage ID
Returns:
{"scenic_spot_id": ..., "product_id": ..., "ppid": ...}
"""
try:
package = await self.find_by_id(ppid)
if package:
return {
"scenic_spot_id": package.get('scenic_spot_id') or package.get('scenicSpotId'),
"product_id": package.get('product_id') or package.get('productId'),
"ppid": ppid
}
return None
except Exception as e:
logger.error(f"解析 ppid 失败: {e}")
return None
class DatabaseAccessor:
"""
数据库访问器
按领域组织数据访问:
- db.scenic_spot.find_by_id(id)
- db.product.find_by_id(id)
- db.style.find_all()
- db.audience.find_all()
- db.template.find_active()
"""
def __init__(self, db_service=None):
"""
初始化数据库访问器
Args:
db_service: 底层 DatabaseService 实例
"""
self._db_service = db_service
self._scenic_spot: Optional[ScenicSpotAccessor] = None
self._product: Optional[ProductAccessor] = None
self._style: Optional[StyleAccessor] = None
self._audience: Optional[AudienceAccessor] = None
self._template: Optional[TemplateAccessor] = None
self._product_package: Optional[ProductPackageAccessor] = None
def set_db_service(self, db_service):
"""设置底层数据库服务"""
self._db_service = db_service
# 重置访问器
self._scenic_spot = None
self._product = None
self._style = None
self._audience = None
self._template = None
self._product_package = None
@property
def scenic_spot(self) -> ScenicSpotAccessor:
"""景区数据访问器"""
if self._scenic_spot is None:
self._scenic_spot = ScenicSpotAccessor(self._db_service)
return self._scenic_spot
@property
def product(self) -> ProductAccessor:
"""产品数据访问器"""
if self._product is None:
self._product = ProductAccessor(self._db_service)
return self._product
@property
def style(self) -> StyleAccessor:
"""风格数据访问器"""
if self._style is None:
self._style = StyleAccessor(self._db_service)
return self._style
@property
def audience(self) -> AudienceAccessor:
"""受众数据访问器"""
if self._audience is None:
self._audience = AudienceAccessor(self._db_service)
return self._audience
@property
def template(self) -> TemplateAccessor:
"""模板数据访问器"""
if self._template is None:
self._template = TemplateAccessor(self._db_service)
return self._template
@property
def product_package(self) -> ProductPackageAccessor:
"""ProductPackage 数据访问器 (ppid)"""
if self._product_package is None:
self._product_package = ProductPackageAccessor(self._db_service)
return self._product_package
async def resolve_ppid(self, ppid: int) -> Optional[Dict[str, int]]:
"""
解析 ppid 为原始 ID (便捷方法)
Args:
ppid: ProductPackage ID
Returns:
{"scenic_spot_id": ..., "product_id": ..., "ppid": ...}
"""
return await self.product_package.resolve_ids(ppid)