167 lines
5.2 KiB
Python
167 lines
5.2 KiB
Python
"""CRUD基础类"""
|
|
from typing import TypeVar, Generic, Type, Optional, List, Any
|
|
from sqlalchemy.orm import Session
|
|
from sqlalchemy import and_, or_
|
|
import re
|
|
|
|
from app.core.utils import generate_id
|
|
from app.core.database import Base
|
|
from sqlalchemy import func
|
|
|
|
ModelType = TypeVar("ModelType", bound=Base)
|
|
|
|
|
|
def camel_to_snake(name: str) -> str:
|
|
"""驼峰命名转蛇形命名"""
|
|
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
|
|
return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
|
|
|
|
|
|
def get_model_attr(obj, key: str):
|
|
"""获取模型的属性名,支持驼峰转蛇形"""
|
|
# 先尝试直接匹配
|
|
if hasattr(obj, key):
|
|
return key
|
|
# 尝试驼峰转蛇形
|
|
snake_key = camel_to_snake(key)
|
|
if hasattr(obj, snake_key):
|
|
return snake_key
|
|
# 如果都没有,返回None
|
|
return None
|
|
|
|
|
|
class CRUDBase(Generic[ModelType]):
|
|
"""CRUD基类"""
|
|
|
|
def __init__(self, model: Type[ModelType]):
|
|
self.model = model
|
|
|
|
def get(self, db: Session, id: str) -> Optional[ModelType]:
|
|
"""根据ID获取单条记录"""
|
|
return db.query(self.model).filter(self.model.id == id).first()
|
|
|
|
def get_multi(
|
|
self,
|
|
db: Session,
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
filters: List[Any] = None,
|
|
order_by: str = None,
|
|
order_type: str = "desc"
|
|
) -> List[ModelType]:
|
|
"""获取多条记录"""
|
|
query = db.query(self.model)
|
|
if filters:
|
|
query = query.filter(*filters)
|
|
if order_by:
|
|
order_column = getattr(self.model, order_by, None)
|
|
if order_column:
|
|
if order_type == "asc":
|
|
query = query.order_by(order_column.asc())
|
|
else:
|
|
query = query.order_by(order_column.desc())
|
|
else:
|
|
query = query.order_by(self.model.create_at.desc())
|
|
return query.offset(skip).limit(limit).all()
|
|
|
|
def get_all(self, db: Session, filters: List[Any] = None) -> List[ModelType]:
|
|
"""获取所有记录"""
|
|
query = db.query(self.model)
|
|
if filters:
|
|
query = query.filter(*filters)
|
|
return query.all()
|
|
|
|
def create(self, db: Session, obj_in: dict, creator: dict = None) -> ModelType:
|
|
"""创建记录"""
|
|
obj = self.model()
|
|
for key, value in obj_in.items():
|
|
attr_name = get_model_attr(obj, key)
|
|
if attr_name:
|
|
setattr(obj, attr_name, value)
|
|
# 设置ID
|
|
if not obj.id:
|
|
obj.id = generate_id()
|
|
# 设置创建人信息
|
|
if creator:
|
|
if not obj.create_by and "user_id" in creator:
|
|
obj.create_by = creator["user_id"]
|
|
if not obj.create_name and "real_name" in creator:
|
|
obj.create_name = creator["real_name"]
|
|
db.add(obj)
|
|
db.commit()
|
|
db.refresh(obj)
|
|
return obj
|
|
|
|
def update(self, db: Session, id: str, obj_in: dict, updater: dict = None) -> Optional[ModelType]:
|
|
"""更新记录"""
|
|
obj = self.get(db, id)
|
|
if obj:
|
|
for key, value in obj_in.items():
|
|
attr_name = get_model_attr(obj, key)
|
|
if attr_name and key not in ["id", "create_at", "create_by", "create_name"]:
|
|
setattr(obj, attr_name, value)
|
|
# 设置更新人信息
|
|
if updater:
|
|
if "user_id" in updater:
|
|
obj.update_by = updater["user_id"]
|
|
if "real_name" in updater:
|
|
obj.update_name = updater.get("real_name", obj.create_name)
|
|
obj.update_at = func.now()
|
|
db.commit()
|
|
db.refresh(obj)
|
|
return obj
|
|
|
|
def delete(self, db: Session, id: str) -> bool:
|
|
"""删除记录(软删除)"""
|
|
obj = self.get(db, id)
|
|
if obj:
|
|
if hasattr(obj, "is_del"):
|
|
obj.is_del = 1
|
|
else:
|
|
db.delete(obj)
|
|
db.commit()
|
|
return True
|
|
return False
|
|
|
|
def hard_delete(self, db: Session, id: str) -> bool:
|
|
"""物理删除"""
|
|
obj = self.get(db, id)
|
|
if obj:
|
|
db.delete(obj)
|
|
db.commit()
|
|
return True
|
|
return False
|
|
|
|
def count(self, db: Session, filters: List[Any] = None) -> int:
|
|
"""统计数量"""
|
|
query = db.query(self.model)
|
|
if filters:
|
|
query = query.filter(*filters)
|
|
return query.count()
|
|
|
|
def exists(self, db: Session, filters: List[Any] = None) -> bool:
|
|
"""检查记录是否存在"""
|
|
query = db.query(self.model)
|
|
if filters:
|
|
query = query.filter(*filters)
|
|
return query.first() is not None
|
|
|
|
|
|
class HistoryCRUD(CRUDBase[ModelType]):
|
|
"""历史表CRUD类"""
|
|
|
|
def create_history(self, db: Session, original_data: dict) -> ModelType:
|
|
"""创建历史记录"""
|
|
obj = self.model()
|
|
# 复制原始数据到历史表
|
|
for key, value in original_data.items():
|
|
if hasattr(obj, key):
|
|
setattr(obj, key, value)
|
|
# 设置历史记录创建时间
|
|
if hasattr(obj, "his_create_at"):
|
|
obj.his_create_at = func.now()
|
|
db.add(obj)
|
|
db.commit()
|
|
db.refresh(obj)
|
|
return obj
|