Files
FastapiAdmin/backend/app/api/v1/module_generator/gencode/crud.py
T
zhangtao ba7fddc34a refactor(generator): 优化代码生成模块接口和服务实现
- 修改接口定义,增加路径参数并完善请求描述,增强参数校验和依赖注入
- 优化CRUD层数据库操作,统一异步会话使用,删除多余db参数
- 增加业务表与字段模型关系级联删除配置,优化模型关联关系声明
- 精简pydantic模型,去除冗余校验装饰器,完善字段描述和必填约束
- 服务层增加类型检查和异常抛出,规范业务逻辑流程和错误提示
- 优化代码结构,调整模块导入顺序和注释,提升代码可读性和一致性
2025-10-01 16:58:49 +08:00

308 lines
12 KiB
Python

# -*- coding:utf-8 -*-
from datetime import datetime, time
from sqlalchemy.engine.row import Row
from sqlalchemy import delete, func, select, text, update
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload
from typing import List, Optional, Sequence, Any, Dict
from .model import GenTableModel, GenTableColumnModel
from app.config.setting import settings
from app.common.request import PaginationService
from .schema import GenTableCreateSchema, GenTableUpdateSchema, GenTableOutSchema, GenTableDeleteSchema, GenTableColumnCreateSchema, GenTableColumnUpdateSchema, GenTableColumnOutSchema, GenTableColumnDeleteSchema
from .param import GenTableQueryParam
from app.core.base_crud import CRUDBase
from app.api.v1.module_system.auth.schema import AuthSchema
class GenTableCRUD(CRUDBase[GenTableModel, GenTableCreateSchema, GenTableUpdateSchema]):
"""代码生成业务表模块数据库操作层"""
def __init__(self, auth: AuthSchema) -> None:
"""初始化CRUD"""
super().__init__(model=GenTableModel, auth=auth)
async def get_gen_table_by_id(self, table_id: int) -> Optional[GenTableModel]:
"""
根据业务表id获取需要生成的业务表信息
:param db: orm对象
:param table_id: 业务表id
:return: 需要生成的业务表信息对象
"""
gen_table_info = (
(
await self.db.execute(
select(GenTableModel).options(selectinload(GenTableModel.columns)).where(GenTableModel.id == table_id)
)
)
.scalars()
.first()
)
return gen_table_info
async def get_gen_table_by_name(self, table_name: str) -> Optional[GenTableModel]:
"""
根据业务表名称获取需要生成的业务表信息
:param db: orm对象
:param table_name: 业务表名称
:return: 需要生成的业务表信息对象
"""
gen_table_info = (
(
await self.db.execute(
select(GenTableModel).options(selectinload(GenTableModel.columns)).where(GenTableModel.table_name == table_name)
)
)
.scalars()
.first()
)
return gen_table_info
async def get_gen_table_all(self) -> Sequence[GenTableModel]:
"""
获取所有业务表信息
:param db: orm对象
:return: 所有业务表信息
"""
gen_table_all = (await self.db.execute(select(GenTableModel).options(selectinload(GenTableModel.columns)))).scalars().all()
return gen_table_all
async def create_table_by_sql(self, sql_statements: List) -> None:
"""
根据sql语句创建表结构
:param db: orm对象
:param sql_statements: sql语句的ast列表
:return:
"""
for sql_statement in sql_statements:
sql = sql_statement.sql(dialect=settings.DATABASE_TYPE)
await self.db.execute(text(sql))
async def get_gen_table_list(self, query_object: GenTableQueryParam, is_page: bool = False):
"""
根据查询参数获取代码生成业务表列表信息
:param db: orm对象
:param query_object: 查询参数对象
:param is_page: 是否开启分页
:return: 代码生成业务表列表信息对象
"""
# 构建查询条件
conditions = []
# 访问table_name属性
if getattr(query_object, 'table_name', None) and query_object.table_name[1]:
conditions.append(func.lower(GenTableModel.table_name).like(f'%{str(query_object.table_name[1]).lower()}%'))
# 访问table_comment属性
if getattr(query_object, 'table_comment', None):
conditions.append(func.lower(GenTableModel.table_comment).like(f'%{str(query_object.table_comment).lower()}%'))
# 访问created_at属性而不是start_time和end_time
if hasattr(query_object, 'created_at') and query_object.created_at:
if isinstance(query_object.created_at, tuple) and query_object.created_at[0] == "between":
conditions.append(GenTableModel.created_at.between(*query_object.created_at[1]))
query = (
select(GenTableModel)
.options(selectinload(GenTableModel.columns))
.where(*conditions)
.order_by(GenTableModel.created_at.desc())
.distinct()
)
# 获取所有数据
result = await self.db.execute(query)
all_data = list(result.scalars().all())
# 使用PaginationService.paginate进行分页
# 注意:这里假设query_object有page_no和page_size属性,如果没有需要从其他地方获取
page_no = getattr(query_object, 'page_no', None)
page_size = getattr(query_object, 'page_size', None)
if is_page and page_no is not None and page_size is not None:
paginated_result = await PaginationService.paginate(
data_list=all_data,
page_no=page_no,
page_size=page_size
)
return paginated_result
else:
return {
"items": all_data,
"total": len(all_data),
"page_no": None,
"page_size": None,
"has_next": False
}
async def get_gen_db_table_list(self, db: AsyncSession, query_object: GenTableQueryParam, is_page: bool = False):
"""
根据查询参数获取数据库列表信息
:param db: orm对象
:param query_object: 查询参数对象
:param is_page: 是否开启分页
:return: 数据库列表信息对象
"""
query_sql = """
SELECT table_name as table_name,
table_comment as table_comment,
create_time as create_time,
update_time as update_time
from
information_schema.tables
where
table_schema = (select database())
and table_name not like 'apscheduler\_%'
and table_name not like 'gen\_%'
and table_name not in (select table_name from gen_table)
"""
# 根据param.py中的定义,table_name是元组形式("like", value)
if getattr(query_object, 'table_name', None) and query_object.table_name[1]:
query_sql += """and lower(table_name) like lower(concat('%', :table_name, '%'))"""
# 处理table_comment字段(如果有)
if getattr(query_object, 'table_comment', None):
query_sql += """and lower(table_comment) like lower(concat('%', :table_comment, '%'))"""
# 构建查询参数
query_params = {}
# 添加table_name查询参数
if getattr(query_object, 'table_name', None) and query_object.table_name[1]:
query_params['table_name'] = query_object.table_name[1]
# 添加table_comment查询参数
if getattr(query_object, 'table_comment', None):
query_params['table_comment'] = query_object.table_comment
query_sql += """order by create_time desc"""
query = text(query_sql).bindparams(**query_params)
# 执行查询
result = await db.execute(query)
all_data = list(result.fetchall())
# 使用PaginationService.paginate进行分页
# 注意:这里假设query_object有page_no和page_size属性,如果没有需要从其他地方获取
page_no = getattr(query_object, 'page_no', None)
page_size = getattr(query_object, 'page_size', None)
if is_page and page_no is not None and page_size is not None:
paginated_result = await PaginationService.paginate(
data_list=all_data,
page_no=page_no,
page_size=page_size
)
return paginated_result
else:
return {
"items": all_data,
"total": len(all_data),
"page_no": None,
"page_size": None,
"has_next": False
}
async def get_gen_db_table_list_by_names(self, db: AsyncSession, table_names: List[str]):
"""
根据业务表名称组获取数据库列表信息
:param db: orm对象
:param table_names: 业务表名称组
:return: 数据库列表信息对象
"""
query_sql = """
select
table_name as table_name,
table_comment as table_comment,
create_time as create_time,
update_time as update_time
from
information_schema.tables
where
table_schema = (select database())
and table_name in :table_names
"""
query = text(query_sql).bindparams(table_names=tuple(table_names))
gen_db_table_list = (await db.execute(query)).fetchall()
return gen_db_table_list
class GenTableColumnCRUD(CRUDBase[GenTableColumnModel, GenTableColumnCreateSchema, GenTableColumnUpdateSchema]):
"""代码生成业务表字段模块数据库操作层"""
def __init__(self, auth: AuthSchema) -> None:
"""初始化CRUD"""
super().__init__(model=GenTableColumnModel, auth=auth)
async def get_gen_table_column_list_by_table_id_crud(self, table_id: int) -> Sequence[GenTableColumnModel]:
"""根据业务表id获取需要生成的业务表字段列表信息"""
return await self.list(search={"table_id": table_id})
async def get_gen_table_column_list_by_table_id(self, db: AsyncSession, table_id: int) -> Sequence[GenTableColumnModel]:
"""
根据业务表id获取需要生成的业务表字段列表信息
:param db: orm对象
:param table_id: 业务表id
:return: 需要生成的业务表字段列表信息对象
"""
gen_table_column_list = (
(
await db.execute(
select(GenTableColumnModel).where(GenTableColumnModel.table_id == table_id).order_by(GenTableColumnModel.sort)
)
)
.scalars()
.all()
)
return gen_table_column_list
async def get_gen_db_table_columns_by_name(self, db: AsyncSession, table_name: str) -> Sequence[Row[Any]]:
"""
根据业务表名称获取业务表字段列表信息
:param db: orm对象
:param table_name: 业务表名称
:return: 业务表字段列表信息对象
"""
query_sql = """
select
column_name as column_name,
case
when is_nullable = 'no' and column_key != 'PRI' then '1'
else '0'
end as is_required,
case
when column_key = 'PRI' then '1'
else '0'
end as is_pk,
ordinal_position as sort,
column_comment as column_comment,
case
when extra = 'auto_increment' then '1'
else '0'
end as is_increment,
column_type as column_type
from
information_schema.columns
where
table_schema = (select database())
and table_name = :table_name
order by
ordinal_position
"""
query = text(query_sql).bindparams(table_name=table_name)
gen_db_table_columns = (await db.execute(query)).fetchall()
return gen_db_table_columns