覆盖所有模块: - api 层:17 个路由文件,每个接口标注用途、参数、返回值、权限 - services 层:18 个服务文件,每个方法标注作用、参数、返回值、调用方 - repositories 层:13 个仓储文件,每个方法标注查询逻辑和被调用方 - schemas 层:11 个请求/响应体文件,每个字段标注业务含义 - core 层:config、security、exceptions、responses、error_codes - models 层:19 个 ORM 模型类,每个表标注业务含义和关联关系 - scripts:bootstrap_data、smoke_check - migrations:env.py 和版本迁移文件 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
159 lines
6.5 KiB
Python
159 lines
6.5 KiB
Python
"""
|
||
产品与产品分类数据访问层。
|
||
|
||
负责封装产品(Product)和产品分类(ProductCategory)模型的数据库查询操作,
|
||
提供分类和产品的增删改查、条件筛选、唯一性校验等方法。
|
||
被 ProductService 调用。
|
||
"""
|
||
|
||
from sqlalchemy import select
|
||
from sqlalchemy.orm import Session
|
||
|
||
from backend.app.models.business import Product, ProductCategory
|
||
|
||
|
||
class ProductRepository:
|
||
"""产品与产品分类数据访问层,封装产品相关表的数据库操作。
|
||
|
||
被 ProductService 调用。
|
||
"""
|
||
|
||
def list_categories(self, session: Session, filters: dict) -> list[ProductCategory]:
|
||
"""根据筛选条件查询产品分类列表,支持分类名模糊匹配和状态精确匹配。
|
||
|
||
:param session: 数据库会话
|
||
:param filters: 筛选条件字典,可包含 category_name(模糊)、status(精确)键
|
||
:return: 符合条件的分类列表,按 sort_no 升序、id 升序排列
|
||
被 ProductService.list_categories 调用。
|
||
"""
|
||
stmt = select(ProductCategory).where(ProductCategory.deleted == 0)
|
||
|
||
if filters.get("category_name"):
|
||
stmt = stmt.where(ProductCategory.category_name.contains(filters["category_name"]))
|
||
if filters.get("status") is not None:
|
||
stmt = stmt.where(ProductCategory.status == filters["status"])
|
||
|
||
stmt = stmt.order_by(ProductCategory.sort_no.asc(), ProductCategory.id.asc())
|
||
return list(session.execute(stmt).scalars())
|
||
|
||
def get_category(self, session: Session, category_id: int) -> ProductCategory | None:
|
||
"""根据 ID 获取单个产品分类详情。
|
||
|
||
:param session: 数据库会话
|
||
:param category_id: 分类主键 ID
|
||
:return: 分类对象,不存在则返回 None
|
||
被 ProductService.get_category 调用。
|
||
"""
|
||
stmt = select(ProductCategory).where(ProductCategory.id == category_id, ProductCategory.deleted == 0)
|
||
return session.execute(stmt).scalar_one_or_none()
|
||
|
||
def get_category_by_code(self, session: Session, category_code: str) -> ProductCategory | None:
|
||
"""根据分类编码查找分类(用于创建时的唯一性校验)。
|
||
|
||
:param session: 数据库会话
|
||
:param category_code: 分类编码
|
||
:return: 匹配的分类对象,不存在则返回 None
|
||
被 ProductService.create_category 调用,用于校验分类编码是否重复。
|
||
"""
|
||
stmt = select(ProductCategory).where(
|
||
ProductCategory.category_code == category_code,
|
||
ProductCategory.deleted == 0,
|
||
)
|
||
return session.execute(stmt).scalar_one_or_none()
|
||
|
||
def create_category(self, session: Session, payload: dict) -> ProductCategory:
|
||
"""创建新的产品分类记录。
|
||
|
||
:param session: 数据库会话
|
||
:param payload: 分类字段字典
|
||
:return: 新创建的分类对象(含自增 ID)
|
||
被 ProductService.create_category 调用。
|
||
"""
|
||
category = ProductCategory(**payload)
|
||
session.add(category)
|
||
session.flush()
|
||
return category
|
||
|
||
def update_category(self, session: Session, category: ProductCategory, payload: dict) -> ProductCategory:
|
||
"""更新已有产品分类的字段信息。
|
||
|
||
:param session: 数据库会话
|
||
:param category: 待更新的分类对象
|
||
:param payload: 更新字段字典
|
||
:return: 更新后的分类对象
|
||
被 ProductService.update_category 调用。
|
||
"""
|
||
for key, value in payload.items():
|
||
setattr(category, key, value)
|
||
session.add(category)
|
||
session.flush()
|
||
return category
|
||
|
||
def list_products(self, session: Session, filters: dict) -> list[Product]:
|
||
"""根据筛选条件查询产品列表,支持产品名、规格模糊匹配,分类和状态精确匹配。
|
||
|
||
:param session: 数据库会话
|
||
:param filters: 筛选条件字典,可包含 product_name、specification、
|
||
category_id、status 等键
|
||
:return: 符合条件的产品列表,按 id 降序排列
|
||
被 ProductService.list_products 调用。
|
||
"""
|
||
stmt = select(Product).where(Product.deleted == 0)
|
||
|
||
if filters.get("product_name"):
|
||
stmt = stmt.where(Product.product_name.contains(filters["product_name"]))
|
||
if filters.get("specification"):
|
||
stmt = stmt.where(Product.specification.contains(filters["specification"]))
|
||
if filters.get("category_id") is not None:
|
||
stmt = stmt.where(Product.category_id == filters["category_id"])
|
||
if filters.get("status") is not None:
|
||
stmt = stmt.where(Product.status == filters["status"])
|
||
|
||
stmt = stmt.order_by(Product.id.desc())
|
||
return list(session.execute(stmt).scalars())
|
||
|
||
def get_product(self, session: Session, product_id: int) -> Product | None:
|
||
"""根据 ID 获取单个产品详情。
|
||
|
||
:param session: 数据库会话
|
||
:param product_id: 产品主键 ID
|
||
:return: 产品对象,不存在则返回 None
|
||
被 ProductService.get_product 调用。
|
||
"""
|
||
stmt = select(Product).where(Product.id == product_id, Product.deleted == 0)
|
||
return session.execute(stmt).scalar_one_or_none()
|
||
|
||
def get_product_by_name_and_specification(
|
||
self,
|
||
session: Session,
|
||
product_name: str,
|
||
specification: str,
|
||
) -> Product | None:
|
||
"""根据产品名称和规格精确查找产品(用于创建时的唯一性校验)。
|
||
|
||
:param session: 数据库会话
|
||
:param product_name: 产品名称
|
||
:param specification: 产品规格
|
||
:return: 匹配的产品对象,不存在则返回 None
|
||
被 ProductService.create_product 调用,用于校验产品名称+规格是否重复。
|
||
"""
|
||
stmt = select(Product).where(
|
||
Product.product_name == product_name,
|
||
Product.specification == specification,
|
||
Product.deleted == 0,
|
||
)
|
||
return session.execute(stmt).scalar_one_or_none()
|
||
|
||
def create_product(self, session: Session, payload: dict) -> Product:
|
||
"""创建新的产品记录。
|
||
|
||
:param session: 数据库会话
|
||
:param payload: 产品字段字典
|
||
:return: 新创建的产品对象(含自增 ID)
|
||
被 ProductService.create_product 调用。
|
||
"""
|
||
product = Product(**payload)
|
||
session.add(product)
|
||
session.flush()
|
||
return product
|