From ab4495ce65798721172639c01ba848b3840a3c92 Mon Sep 17 00:00:00 2001 From: Wu Clan Date: Tue, 24 Sep 2024 13:50:02 +0800 Subject: [PATCH] Optimize and normalize the code generator (#430) --- backend/app/generator/api/v1/gen.py | 8 +- backend/app/generator/crud/crud_gen.py | 12 +- backend/app/generator/crud/crud_gen_model.py | 7 +- backend/app/generator/schema/gen_model.py | 3 +- .../generator/service/gen_model_service.py | 7 + backend/app/generator/service/gen_service.py | 15 +- backend/common/enums.py | 195 +++++++++++++----- backend/sql/init_test_data.sql | 80 ++++--- backend/templates/py/api.jinja | 4 +- backend/templates/py/model.jinja | 11 +- backend/utils/type_conversion.py | 83 +------- 11 files changed, 231 insertions(+), 194 deletions(-) diff --git a/backend/app/generator/api/v1/gen.py b/backend/app/generator/api/v1/gen.py index 0c21399f..d3830bea 100644 --- a/backend/app/generator/api/v1/gen.py +++ b/backend/app/generator/api/v1/gen.py @@ -33,7 +33,7 @@ async def get_all_businesses() -> ResponseModel: @router.get('/businesses/{pk}', summary='获取代码生成业务详情', dependencies=[DependsJwtAuth]) async def get_business(pk: Annotated[int, Path(...)]) -> ResponseModel: - business = await gen_service.get_business_with_model(pk=pk) + business = await gen_business_service.get(pk=pk) data = GetGenBusinessListDetails(**select_as_dict(business)) return response_base.success(data=data) @@ -89,6 +89,12 @@ async def delete_business(pk: Annotated[int, Path(...)]) -> ResponseModel: return response_base.fail() +@router.get('/models/types', summary='获取代码生成模型列类型', dependencies=[DependsJwtAuth]) +async def get_model_types() -> ResponseModel: + model_types = await gen_model_service.get_types() + return response_base.success(data=model_types) + + @router.get('/models/{pk}', summary='获取代码生成模型详情', dependencies=[DependsJwtAuth]) async def get_model(pk: Annotated[int, Path(...)]) -> ResponseModel: model = await gen_model_service.get(pk=pk) diff --git a/backend/app/generator/crud/crud_gen.py b/backend/app/generator/crud/crud_gen.py index 88321865..a449c916 100644 --- a/backend/app/generator/crud/crud_gen.py +++ b/backend/app/generator/crud/crud_gen.py @@ -2,21 +2,11 @@ # -*- coding: utf-8 -*- from typing import Sequence -from sqlalchemy import Row, select, text +from sqlalchemy import Row, text from sqlalchemy.ext.asyncio import AsyncSession -from sqlalchemy.orm import selectinload - -from backend.app.generator.model import GenBusiness class CRUDGen: - @staticmethod - async def get_business_with_model(db: AsyncSession, business_id: int) -> GenBusiness: - stmt = select(GenBusiness).options(selectinload(GenBusiness.gen_model)).where(GenBusiness.id == business_id) - result = await db.execute(stmt) - data = result.scalars().first() - return data - @staticmethod async def get_all_tables(db: AsyncSession, table_schema: str) -> Sequence[str]: stmt = text( diff --git a/backend/app/generator/crud/crud_gen_model.py b/backend/app/generator/crud/crud_gen_model.py index 15971ac5..c12e0c8b 100644 --- a/backend/app/generator/crud/crud_gen_model.py +++ b/backend/app/generator/crud/crud_gen_model.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- from typing import Sequence +from sqlalchemy import update from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy_crud_plus import CRUDPlus @@ -34,6 +35,7 @@ async def create(self, db: AsyncSession, obj_in: CreateGenModelParam, pd_type: s :param db: :param obj_in: + :param pd_type: :return: """ await self.create_model(db, obj_in, pd_type=pd_type) @@ -45,9 +47,12 @@ async def update(self, db: AsyncSession, pk: int, obj_in: UpdateGenModelParam, p :param db: :param pk: :param obj_in: + :param pd_type: :return: """ - return await self.update_model_by_column(db, obj_in, id=pk, pd_type=pd_type) + stmt = update(self.model).where(self.model.id == pk).values(**obj_in.model_dump(), pd_type=pd_type) + result = await db.execute(stmt) + return result.rowcount async def delete(self, db: AsyncSession, pk: int) -> int: """ diff --git a/backend/app/generator/schema/gen_model.py b/backend/app/generator/schema/gen_model.py index e29bd06b..d75bd9de 100644 --- a/backend/app/generator/schema/gen_model.py +++ b/backend/app/generator/schema/gen_model.py @@ -2,7 +2,6 @@ # -*- coding: utf-8 -*- from pydantic import ConfigDict, Field, field_validator -from backend.common.enums import GenModelColumnType from backend.common.schema import SchemaBase from backend.utils.type_conversion import sql_type_to_sqlalchemy @@ -10,7 +9,7 @@ class GenModelSchemaBase(SchemaBase): name: str comment: str | None = None - type: GenModelColumnType = Field(GenModelColumnType.VARCHAR) + type: str default: str | None = None sort: int length: int diff --git a/backend/app/generator/service/gen_model_service.py b/backend/app/generator/service/gen_model_service.py index feb04e32..551f2c20 100644 --- a/backend/app/generator/service/gen_model_service.py +++ b/backend/app/generator/service/gen_model_service.py @@ -5,6 +5,7 @@ from backend.app.generator.crud.crud_gen_model import gen_model_dao from backend.app.generator.model import GenModel from backend.app.generator.schema.gen_model import CreateGenModelParam, UpdateGenModelParam +from backend.common.enums import GenModelMySQLColumnType from backend.common.exception import errors from backend.database.db_mysql import async_db_session from backend.utils.type_conversion import sql_type_to_pydantic @@ -17,6 +18,12 @@ async def get(*, pk: int) -> GenModel: gen_model = await gen_model_dao.get(db, pk) return gen_model + @staticmethod + async def get_types() -> list[str]: + types = GenModelMySQLColumnType.get_member_keys() + types.sort() + return types + @staticmethod async def get_by_business(*, business_id: int) -> Sequence[GenModel]: async with async_db_session() as db: diff --git a/backend/app/generator/service/gen_service.py b/backend/app/generator/service/gen_service.py index 3a3f5e7f..1809132e 100644 --- a/backend/app/generator/service/gen_service.py +++ b/backend/app/generator/service/gen_service.py @@ -18,20 +18,14 @@ from backend.app.generator.schema.gen_business import CreateGenBusinessParam from backend.app.generator.schema.gen_model import CreateGenModelParam from backend.app.generator.service.gen_model_service import gen_model_service -from backend.common.enums import GenModelColumnType from backend.common.exception import errors from backend.core.path_conf import BasePath from backend.database.db_mysql import async_db_session from backend.utils.gen_template import gen_template +from backend.utils.type_conversion import sql_type_to_pydantic class GenService: - @staticmethod - async def get_business_with_model(*, pk: int) -> GenBusiness: - async with async_db_session() as db: - business = await gen_dao.get_business_with_model(db, pk) - return business - @staticmethod async def get_tables(*, table_schema: str) -> Sequence[str]: async with async_db_session() as db: @@ -60,19 +54,18 @@ async def import_business_and_model(*, app: str, table_schema: str, table_name: column_info = await gen_dao.get_all_columns(db, table_schema, table_name) for column in column_info: column_type = column[-1].split('(')[0].upper() + pd_type = sql_type_to_pydantic(column_type) model_data = { 'name': column[0], 'comment': column[-2], 'type': column_type, 'sort': column[-3], - 'length': column[-1].split('(')[1][:-1] - if column_type == GenModelColumnType.CHAR or column_type == GenModelColumnType.VARCHAR - else 0, + 'length': column[-1].split('(')[1][:-1] if pd_type == 'str' and '(' in column[-1] else 0, 'is_pk': column[1], 'is_nullable': column[2], 'gen_business_id': new_business.id, } - await gen_model_dao.create(db, CreateGenModelParam(**model_data)) + await gen_model_dao.create(db, CreateGenModelParam(**model_data), pd_type=pd_type) @staticmethod async def render_tpl_code(*, business: GenBusiness) -> dict: diff --git a/backend/common/enums.py b/backend/common/enums.py index 79ed5c21..e60fca30 100644 --- a/backend/common/enums.py +++ b/backend/common/enums.py @@ -90,50 +90,151 @@ class UserSocialType(StrEnum): linuxdo = 'LinuxDo' -class GenModelColumnType(StrEnum): - """代码生成模型列类型""" - - BIGINT = 'BIGINT' - BINARY = 'BINARY' - BIT = 'BIT' - BLOB = 'BLOB' - BOOL = 'BOOL' - BOOLEAN = 'BOOLEAN' - CHAR = 'CHAR' - DATE = 'DATE' - DATETIME = 'DATETIME' - DECIMAL = 'DECIMAL' - DOUBLE = 'DOUBLE' - DOUBLE_PRECISION = 'DOUBLE PRECISION' - ENUM = 'ENUM' - FLOAT = 'FLOAT' - GEOMETRY = 'GEOMETRY' - GEOMETRYCOLLECTION = 'GEOMETRYCOLLECTION' - INT = 'INT' - INTEGER = 'INTEGER' - JSON = 'JSON' - LINESTRING = 'LINESTRING' - LONGBLOB = 'LONGBLOB' - LONGTEXT = 'LONGTEXT' - MEDIUMBLOB = 'MEDIUMBLOB' - MEDIUMINT = 'MEDIUMINT' - MEDIUMTEXT = 'MEDIUMTEXT' - MULTILINESTRING = 'MULTILINESTRING' - MULTIPOINT = 'MULTIPOINT' - MULTIPOLYGON = 'MULTIPOLYGON' - NUMERIC = 'NUMERIC' - POINT = 'POINT' - POLYGON = 'POLYGON' - REAL = 'REAL' - SERIAL = 'SERIAL' - SET = 'SET' - SMALLINT = 'SMALLINT' - TEXT = 'TEXT' - TIME = 'TIME' - TIMESTAMP = 'TIMESTAMP' - TINYBLOB = 'TINYBLOB' - TINYINT = 'TINYINT' - TINYTEXT = 'TINYTEXT' - VARBINARY = 'VARBINARY' - VARCHAR = 'VARCHAR' - YEAR = 'YEAR' +class GenModelMySQLColumnType(StrEnum): + """代码生成模型列类型(MySQL)""" + + # Python 类型映射 + BIGINT = 'int' + BigInteger = 'int' # BIGINT + BINARY = 'bytes' + BLOB = 'bytes' + BOOLEAN = 'bool' # BOOL + Boolean = 'bool' # BOOL + CHAR = 'str' + CLOB = 'str' + DATE = 'date' + Date = 'date' # DATE + DATETIME = 'datetime' + DateTime = 'datetime' # DATETIME + DECIMAL = 'Decimal' + DOUBLE = 'float' + Double = 'float' # DOUBLE + DOUBLE_PRECISION = 'float' + Enum = 'Enum' # Enum() + FLOAT = 'float' + Float = 'float' # FLOAT + INT = 'int' # INTEGER + INTEGER = 'int' + Integer = 'int' # INTEGER + Interval = 'timedelta' # DATETIME + JSON = 'dict' + LargeBinary = 'bytes' # BLOB + NCHAR = 'str' + NUMERIC = 'Decimal' + Numeric = 'Decimal' # NUMERIC + NVARCHAR = 'str' # String + PickleType = 'bytes' # BLOB + REAL = 'float' + SMALLINT = 'int' + SmallInteger = 'int' # SMALLINT + String = 'str' # String + TEXT = 'str' + Text = 'str' # TEXT + TIME = 'time' + Time = 'time' # TIME + TIMESTAMP = 'datetime' + Unicode = 'str' # String + UnicodeText = 'str' # TEXT + UUID = 'str | UUID' + Uuid = 'str' # CHAR(32) + VARBINARY = 'bytes' + VARCHAR = 'str' # String + + # sa.dialects.mysql 导入 + BIT = 'bool' + ENUM = 'Enum' + LONGBLOB = 'bytes' + LONGTEXT = 'str' + MEDIUMBLOB = 'bytes' + MEDIUMINT = 'int' + MEDIUMTEXT = 'str' + SET = 'list[str]' + TINYBLOB = 'bytes' + TINYINT = 'int' + TINYTEXT = 'str' + YEAR = 'int' + + +class GenModelPostgreSQLColumnType(StrEnum): + """代码生成模型列类型(PostgreSQL),仅作为数据保留,并未实施""" + + # Python 类型映射 + BIGINT = 'int' + BigInteger = 'int' # BIGINT + BINARY = 'bytes' + BLOB = 'bytes' + BOOLEAN = 'bool' + Boolean = 'bool' # BOOLEAN + CHAR = 'str' + CLOB = 'str' + DATE = 'date' + Date = 'date' # DATE + DATETIME = 'datetime' + DateTime = 'datetime' # TIMESTAMP WITHOUT TIME ZONE + DECIMAL = 'Decimal' + DOUBLE = 'float' + Double = 'float' # DOUBLE PRECISION + DOUBLE_PRECISION = 'float' # DOUBLE PRECISION + Enum = 'Enum' # Enum(name='enum') + FLOAT = 'float' + Float = 'float' # FLOAT + INT = 'int' # INTEGER + INTEGER = 'int' + Integer = 'int' # INTEGER + Interval = 'timedelta' # INTERVAL + JSON = 'dict' + LargeBinary = 'bytes' # BYTEA + NCHAR = 'str' + NUMERIC = 'Decimal' + Numeric = 'Decimal' # NUMERIC + NVARCHAR = 'str' # String + PickleType = 'bytes' # BYTEA + REAL = 'float' + SMALLINT = 'int' + SmallInteger = 'int' # SMALLINT + String = 'str' # String + TEXT = 'str' + Text = 'str' # TEXT + TIME = 'time' # TIME WITHOUT TIME ZONE + Time = 'time' # TIME WITHOUT TIME ZONE + TIMESTAMP = 'datetime' # TIMESTAMP WITHOUT TIME ZONE + Unicode = 'str' # String + UnicodeText = 'str' # TEXT + UUID = 'str | UUID' + Uuid = 'str' + VARBINARY = 'bytes' + VARCHAR = 'str' # String + + # sa.dialects.postgresql 导入 + ARRAY = 'list' + BIT = 'bool' + BYTEA = 'bytes' + CIDR = 'str' + CITEXT = 'str' + DATEMULTIRANGE = 'list[date]' + DATERANGE = 'tuple[date, date]' + DOMAIN = 'str' + ENUM = 'Enum' + HSTORE = 'dict' + INET = 'str' + INT4MULTIRANGE = 'list[int]' + INT4RANGE = 'tuple[int, int]' + INT8MULTIRANGE = 'list[int]' + INT8RANGE = 'tuple[int, int]' + INTERVAL = 'timedelta' + JSONB = 'dict' + JSONPATH = 'str' + MACADDR = 'str' + MACADDR8 = 'str' + MONEY = 'Decimal' + NUMMULTIRANGE = 'list[Decimal]' + NUMRANGE = 'tuple[Decimal, Decimal]' + OID = 'int' + REGCLASS = 'str' + REGCONFIG = 'str' + TSMULTIRANGE = 'list[datetime]' + TSQUERY = 'str' + TSRANGE = 'tuple[datetime, datetime]' + TSTZMULTIRANGE = 'list[datetime]' + TSTZRANGE = 'tuple[datetime, datetime]' + TSVECTOR = 'str' diff --git a/backend/sql/init_test_data.sql b/backend/sql/init_test_data.sql index c3392ac8..1ec68213 100644 --- a/backend/sql/init_test_data.sql +++ b/backend/sql/init_test_data.sql @@ -5,47 +5,45 @@ INSERT INTO fba.sys_menu (id, title, name, level, sort, icon, path, menu_type, c VALUES (1, '测试', 'test', 0, 0, '', null, 0, null, null, 0, 0, 1, null, null, '2023-07-27 19:14:10', null), (2, '仪表盘', 'dashboard', 0, 0, 'IconDashboard', 'dashboard', 0, null, null, 1, 1, 1, null, null, '2023-07-27 19:15:45', null), (3, '工作台', 'Workplace', 0, 0, null, 'workplace', 1, '/dashboard/workplace/index.vue', null, 1, 1, 1, null, 2, '2023-07-27 19:17:59', null), - (4, 'arco官网', 'arcoWebsite', 0, 888, 'IconLink', 'https://arco.design', 1, null, null, 1, 1, 1, null, null, '2023-07-27 19:19:23', null), - (5, '日志', 'log', 0, 66, 'IconBug', 'log', 0, null, null, 1, 1, 1, null, null, '2023-07-27 19:19:59', null), - (6, '登录日志', 'Login', 0, 0, null, 'login', 1, '/log/login/index.vue', null, 1, 1, 1, null, 5, '2023-07-27 19:20:56', null), - (7, '操作日志', 'Opera', 0, 0, null, 'opera', 1, '/log/opera/index.vue', null, 1, 1, 1, null, 5, '2023-07-27 19:21:28', null), - (8, '常见问题', 'faq', 0, 999, 'IconQuestion', 'https://arco.design/vue/docs/pro/faq', 1, null, null, 1, 1, 1, null, null, '2023-07-27 19:22:24', null), - (9, '系统管理', 'admin', 0, 6, 'IconSettings', 'admin', 0, null, null, 1, 1, 1, null, null, '2023-07-27 19:23:00', null), - (10, '部门管理', 'SysDept', 0, 0, null, 'sys-dept', 1, '/admin/dept/index.vue', null, 1, 1, 1, null, 9, '2023-07-27 19:23:42', null), - (11, '新增', '', 0, 0, null, null, 2, null, 'sys:dept:add', 1, 1, 1, null, 10, '2024-01-07 11:37:00', null), - (12, '编辑', '', 0, 0, null, null, 2, null, 'sys:dept:edit', 1, 1, 1, null, 10, '2024-01-07 11:37:29', null), - (13, '删除', '', 0, 0, null, null, 2, null, 'sys:dept:del', 1, 1, 1, null, 10, '2024-01-07 11:37:44', null), - (14, 'API管理', 'SysApi', 0, 1, null, 'sys-api', 1, '/admin/api/index.vue', null, 1, 1, 1, null, 9, '2023-07-27 19:24:12', null), - (15, '新增', '', 0, 0, null, null, 2, null, 'sys:api:add', 1, 1, 1, null, 14, '2024-01-07 11:57:09', null), - (16, '编辑', '', 0, 0, null, null, 2, null, 'sys:api:edit', 1, 1, 1, null, 14, '2024-01-07 11:57:44', null), - (17, '删除', '', 0, 0, null, null, 2, null, 'sys:api:del', 1, 1, 1, null, 14, '2024-01-07 11:57:56', null), - (18, '用户管理', 'SysUser', 0, 0, null, 'sys-user', 1, '/admin/user/index.vue', null, 1, 1, 1, null, 9, '2023-07-27 19:25:13', null), - (19, '编辑用户角色', '', 0, 0, null, null, 2, null, 'sys:user:role:edit', 1, 1, 1, null, 18, '2024-01-07 12:04:20', null), - (20, '注销', '', 0, 0, null, null, 2, null, 'sys:user:del', 1, 1, 1, '用户注销 != 用户登出,注销之后用户将从数据库删除', 18, '2024-01-07 02:28:09', null), - (21, '角色管理', 'SysRole', 0, 2, null, 'sys-role', 1, '/admin/role/index.vue', null, 1, 1, 1, null, 9, '2023-07-27 19:25:45', null), - (22, '新增', '', 0, 0, null, null, 2, null, 'sys:role:add', 1, 1, 1, null, 21, '2024-01-07 11:58:37', null), - (23, '编辑', '', 0, 0, null, null, 2, null, 'sys:role:edit', 1, 1, 1, null, 21, '2024-01-07 11:58:52', null), - (24, '删除', '', 0, 0, null, null, 2, null, 'sys:role:del', 1, 1, 1, null, 21, '2024-01-07 11:59:07', null), - (25, '编辑角色菜单', '', 0, 0, null, null, 2, null, 'sys:role:menu:edit', 1, 1, 1, null, 21, '2024-01-07 01:59:39', null), - (26, '菜单管理', 'SysMenu', 0, 2, null, 'sys-menu', 1, '/admin/menu/index.vue', null, 1, 1, 1, null, 9, '2023-07-27 19:45:29', null), - (27, '新增', '', 0, 0, null, null, 2, null, 'sys:menu:add', 1, 1, 1, null, 26, '2024-01-07 12:01:24', null), - (28, '编辑', '', 0, 0, null, null, 2, null, 'sys:menu:edit', 1, 1, 1, null, 26, '2024-01-07 12:01:34', null), - (29, '删除', '', 0, 0, null, null, 2, null, 'sys:menu:del', 1, 1, 1, null, 26, '2024-01-07 12:01:48', null), - (30, '系统监控', 'monitor', 0, 88, 'IconComputer', 'monitor', 0, null, null, 1, 1, 1, null, null, '2023-07-27 19:27:08', null), - (31, 'Redis监控', 'Redis', 0, 0, null, 'redis', 1, '/monitor/redis/index.vue', 'sys:monitor:redis', 1, 1, 1, null, 30, '2023-07-27 19:28:03', null), - (32, '服务器监控', 'Server', 0, 0, null, 'server', 1, '/monitor/server/index.vue', 'sys:monitor:server', 1, 1, 1, null, 30, '2023-07-27 19:28:29', null), - (33, '系统自动化', 'automation', 0, 777, 'IconCodeSquare', 'automation', 0, null, null, 1, 1, 1, null, null, '2024-07-27 02:06:20', '2024-07-27 02:18:52'), - (34, '代码生成', 'CodeGenerator', 0, 0, null, 'code-generator', 1, '/automation/generator/index.vue', null, 1, 1, 1, null, 33, '2024-07-27 12:24:54', null), - (35, '导入', '', 0, 0, null, null, 2, null, 'gen:code:import', 1, 1, 1, null, 34, '2024-08-04 12:49:58', null), - (36, '新增业务', '', 0, 0, null, null, 2, null, 'gen:code:business:add', 1, 1, 1, null, 34, '2024-08-04 12:51:29', null), - (37, '编辑业务', '', 0, 0, null, null, 2, null, 'gen:code:business:edit', 1, 1, 1, null, 34, '2024-08-04 12:51:45', null), - (48, '删除业务', '', 0, 0, null, null, 2, null, 'gen:code:business:del', 1, 1, 1, null, 34, '2024-08-04 12:52:05', null), - (49, '新增模型', '', 0, 0, null, null, 2, null, 'gen:code:model:add', 1, 1, 1, null, 34, '2024-08-04 12:52:28', null), - (50, '编辑模型', '', 0, 0, null, null, 2, null, 'gen:code:model:edit', 1, 1, 1, null, 34, '2024-08-04 12:52:45', null), - (51, '删除模型', '', 0, 0, null, null, 2, null, 'gen:code:model:del', 1, 1, 1, null, 34, '2024-08-04 12:52:59', null), - (52, '生成', '', 0, 0, null, null, 2, null, 'gen:code:generate', 1, 1, 1, null, 34, '2024-08-04 12:55:03', null), - (53, 'GitHub', 'github', 0, 8888, 'IconGithub', 'https://github.com/wu-clan', 0, null, null, 1, 1, 1, null, null, '2024-07-27 12:32:46', null), - (54, '赞助', 'sponsor', 0, 9999, 'IconFire', 'https://wu-clan.github.io/sponsor/', 0, null, null, 1, 1, 1, null, null, '2024-07-27 12:39:57', null); + (4, '日志', 'log', 0, 66, 'IconBug', 'log', 0, null, null, 1, 1, 1, null, null, '2023-07-27 19:19:59', null), + (5, '登录日志', 'Login', 0, 0, null, 'login', 1, '/log/login/index.vue', null, 1, 1, 1, null, 4, '2023-07-27 19:20:56', null), + (6, '操作日志', 'Opera', 0, 0, null, 'opera', 1, '/log/opera/index.vue', null, 1, 1, 1, null, 4, '2023-07-27 19:21:28', null), + (7, '系统管理', 'admin', 0, 6, 'IconSettings', 'admin', 0, null, null, 1, 1, 1, null, null, '2023-07-27 19:23:00', null), + (8, '部门管理', 'SysDept', 0, 0, null, 'sys-dept', 1, '/admin/dept/index.vue', null, 1, 1, 1, null, 7, '2023-07-27 19:23:42', null), + (9, '新增', '', 0, 0, null, null, 2, null, 'sys:dept:add', 1, 1, 1, null, 8, '2024-01-07 11:37:00', null), + (10, '编辑', '', 0, 0, null, null, 2, null, 'sys:dept:edit', 1, 1, 1, null, 8, '2024-01-07 11:37:29', null), + (11, '删除', '', 0, 0, null, null, 2, null, 'sys:dept:del', 1, 1, 1, null, 8, '2024-01-07 11:37:44', null), + (12, 'API管理', 'SysApi', 0, 1, null, 'sys-api', 1, '/admin/api/index.vue', null, 1, 1, 1, null, 7, '2023-07-27 19:24:12', null), + (13, '新增', '', 0, 0, null, null, 2, null, 'sys:api:add', 1, 1, 1, null, 12, '2024-01-07 11:57:09', null), + (14, '编辑', '', 0, 0, null, null, 2, null, 'sys:api:edit', 1, 1, 1, null, 12, '2024-01-07 11:57:44', null), + (15, '删除', '', 0, 0, null, null, 2, null, 'sys:api:del', 1, 1, 1, null, 12, '2024-01-07 11:57:56', null), + (16, '用户管理', 'SysUser', 0, 0, null, 'sys-user', 1, '/admin/user/index.vue', null, 1, 1, 1, null, 7, '2023-07-27 19:25:13', null), + (17, '编辑用户角色', '', 0, 0, null, null, 2, null, 'sys:user:role:edit', 1, 1, 1, null, 16, '2024-01-07 12:04:20', null), + (18, '注销', '', 0, 0, null, null, 2, null, 'sys:user:del', 1, 1, 1, '用户注销 != 用户登出,注销之后用户将从数据库删除', 16, '2024-01-07 02:28:09', null), + (19, '角色管理', 'SysRole', 0, 2, null, 'sys-role', 1, '/admin/role/index.vue', null, 1, 1, 1, null, 7, '2023-07-27 19:25:45', null), + (20, '新增', '', 0, 0, null, null, 2, null, 'sys:role:add', 1, 1, 1, null, 19, '2024-01-07 11:58:37', null), + (21, '编辑', '', 0, 0, null, null, 2, null, 'sys:role:edit', 1, 1, 1, null, 19, '2024-01-07 11:58:52', null), + (22, '删除', '', 0, 0, null, null, 2, null, 'sys:role:del', 1, 1, 1, null, 19, '2024-01-07 11:59:07', null), + (23, '编辑角色菜单', '', 0, 0, null, null, 2, null, 'sys:role:menu:edit', 1, 1, 1, null, 19, '2024-01-07 01:59:39', null), + (24, '菜单管理', 'SysMenu', 0, 2, null, 'sys-menu', 1, '/admin/menu/index.vue', null, 1, 1, 1, null, 7, '2023-07-27 19:45:29', null), + (25, '新增', '', 0, 0, null, null, 2, null, 'sys:menu:add', 1, 1, 1, null, 24, '2024-01-07 12:01:24', null), + (26, '编辑', '', 0, 0, null, null, 2, null, 'sys:menu:edit', 1, 1, 1, null, 24, '2024-01-07 12:01:34', null), + (27, '删除', '', 0, 0, null, null, 2, null, 'sys:menu:del', 1, 1, 1, null, 24, '2024-01-07 12:01:48', null), + (28, '系统监控', 'monitor', 0, 88, 'IconComputer', 'monitor', 0, null, null, 1, 1, 1, null, null, '2023-07-27 19:27:08', null), + (29, 'Redis监控', 'Redis', 0, 0, null, 'redis', 1, '/monitor/redis/index.vue', 'sys:monitor:redis', 1, 1, 1, null, 28, '2023-07-27 19:28:03', null), + (30, '服务器监控', 'Server', 0, 0, null, 'server', 1, '/monitor/server/index.vue', 'sys:monitor:server', 1, 1, 1, null, 28, '2023-07-27 19:28:29', null), + (31, '系统自动化', 'automation', 0, 777, 'IconCodeSquare', 'automation', 0, null, null, 1, 1, 1, null, null, '2024-07-27 02:06:20', '2024-07-27 02:18:52'), + (32, '代码生成', 'CodeGenerator', 0, 0, null, 'code-generator', 1, '/automation/generator/index.vue', null, 1, 1, 1, null, 31, '2024-07-27 12:24:54', null), + (33, '导入', '', 0, 0, null, null, 2, null, 'gen:code:import', 1, 1, 1, null, 31, '2024-08-04 12:49:58', null), + (34, '新增业务', '', 0, 0, null, null, 2, null, 'gen:code:business:add', 1, 1, 1, null, 31, '2024-08-04 12:51:29', null), + (35, '编辑业务', '', 0, 0, null, null, 2, null, 'gen:code:business:edit', 1, 1, 1, null, 31, '2024-08-04 12:51:45', null), + (36, '删除业务', '', 0, 0, null, null, 2, null, 'gen:code:business:del', 1, 1, 1, null, 31, '2024-08-04 12:52:05', null), + (37, '新增模型', '', 0, 0, null, null, 2, null, 'gen:code:model:add', 1, 1, 1, null, 31, '2024-08-04 12:52:28', null), + (38, '编辑模型', '', 0, 0, null, null, 2, null, 'gen:code:model:edit', 1, 1, 1, null, 31, '2024-08-04 12:52:45', null), + (39, '删除模型', '', 0, 0, null, null, 2, null, 'gen:code:model:del', 1, 1, 1, null, 31, '2024-08-04 12:52:59', null), + (40, '生成', '', 0, 0, null, null, 2, null, 'gen:code:generate', 1, 1, 1, null, 31, '2024-08-04 12:55:03', null), + (41, 'GitHub', 'github', 0, 8888, 'IconGithub', 'https://github.com/wu-clan', 0, null, null, 1, 1, 1, null, null, '2024-07-27 12:32:46', null), + (42, '赞助', 'sponsor', 0, 9999, 'IconFire', 'https://wu-clan.github.io/sponsor/', 0, null, null, 1, 1, 1, null, null, '2024-07-27 12:39:57', null); INSERT INTO fba.sys_role (id, name, data_scope, status, remark, created_time, updated_time) VALUES (1, 'test', 2, 1, null, '2023-06-26 17:13:45', null); diff --git a/backend/templates/py/api.jinja b/backend/templates/py/api.jinja index 7b07ff94..1cbf936f 100644 --- a/backend/templates/py/api.jinja +++ b/backend/templates/py/api.jinja @@ -60,7 +60,7 @@ async def create_{{ table_name_en }}(obj: Create{{ schema_name }}Param) -> Respo async def update_{{ table_name_en }}(pk: Annotated[int, Path(...)], obj: Update{{ schema_name }}Param) -> ResponseModel: count = await {{ table_name_en }}_service.update(pk=pk, obj=obj) if count > 0: - return await response_base.success() + return response_base.success() return response_base.fail() @@ -75,5 +75,5 @@ async def update_{{ table_name_en }}(pk: Annotated[int, Path(...)], obj: Update{ async def delete_{{ table_name_en }}(pk: Annotated[list[int], Query(...)]) -> ResponseModel: count = await {{ table_name_en }}_service.delete(pk=pk) if count > 0: - return await response_base.success() + return response_base.success() return response_base.fail() diff --git a/backend/templates/py/model.jinja b/backend/templates/py/model.jinja index da61f9d0..48d5155e 100644 --- a/backend/templates/py/model.jinja +++ b/backend/templates/py/model.jinja @@ -1,5 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- +from uuid import UUID + import sqlalchemy as sa from sqlalchemy.dialects import mysql @@ -19,10 +21,13 @@ class {{ table_name_class }}({% if have_datetime_column %}Base{% else %}MappedBa {%- if model.is_nullable %} Mapped[{{ model.pd_type }} | None] {%- else %} Mapped[{{ model.pd_type }}] {%- endif %} = mapped_column( - {%- if model.type == 'VARCHAR' -%} + {%- if model.type in ['NVARCHAR', 'String', 'Unicode', 'VARCHAR'] -%} sa.String({{ model.length }}) - {%- else -%} + {%- elif model.type in ['BIT', 'ENUM', 'LONGBLOB', 'LONGTEXT', 'MEDIUMBLOB', 'MEDIUMINT', 'MEDIUMTEXT', 'SET', + 'TINYBLOB', 'TINYINT', 'TINYTEXT', 'YEAR'] -%} mysql.{{ model.type }}() + {%- else -%} + sa.{{ model.type }}() {%- endif -%}, default= {%- if model.is_nullable and model.default == None -%} None @@ -44,7 +49,7 @@ class {{ table_name_class }}({% if have_datetime_column %}Base{% else %}MappedBa {} {%- elif model.pd_type == 'date' or model.pd_type == 'datetime' -%} timezone.now() - {%- elif model.pd_type == 'List[str]' -%} + {%- elif model.pd_type == 'list[str]' -%} () {%- else -%} '' diff --git a/backend/utils/type_conversion.py b/backend/utils/type_conversion.py index 3ac6f397..12afe4ea 100644 --- a/backend/utils/type_conversion.py +++ b/backend/utils/type_conversion.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -from backend.common.enums import GenModelColumnType +from backend.common.enums import GenModelMySQLColumnType def sql_type_to_sqlalchemy(typing: str) -> str: @@ -10,43 +10,9 @@ def sql_type_to_sqlalchemy(typing: str) -> str: :param typing: :return: """ - type_mapping = { - GenModelColumnType.BIGINT: 'BIGINT', - GenModelColumnType.BINARY: 'BINARY', - GenModelColumnType.BIT: 'BIT', - GenModelColumnType.BLOB: 'BLOG', - GenModelColumnType.BOOL: 'BOOLEAN', - GenModelColumnType.BOOLEAN: 'BOOLEAN', - GenModelColumnType.CHAR: 'CHAR', - GenModelColumnType.DATE: 'DATE', - GenModelColumnType.DATETIME: 'DATETIME', - GenModelColumnType.DECIMAL: 'DECIMAL', - GenModelColumnType.DOUBLE: 'DOUBLE', - GenModelColumnType.ENUM: 'ENUM', - GenModelColumnType.FLOAT: 'FLOAT', - GenModelColumnType.INT: 'INT', - GenModelColumnType.INTEGER: 'INTEGER', - GenModelColumnType.JSON: 'JSON', - GenModelColumnType.LONGBLOB: 'LONGBLOB', - GenModelColumnType.LONGTEXT: 'LONGTEXT', - GenModelColumnType.MEDIUMBLOB: 'MEDIUMBLOB', - GenModelColumnType.MEDIUMINT: 'MEDIUMINT', - GenModelColumnType.MEDIUMTEXT: 'MEDIUMTEXT', - GenModelColumnType.NUMERIC: 'NUMERIC', - GenModelColumnType.SET: 'SET', - GenModelColumnType.SMALLINT: 'SMALLINT', - GenModelColumnType.REAL: 'REAL', - GenModelColumnType.TEXT: 'TEXT', - GenModelColumnType.TIME: 'TIME', - GenModelColumnType.TIMESTAMP: 'TIMESTAMP', - GenModelColumnType.TINYBLOB: 'TINYBLOB', - GenModelColumnType.TINYINT: 'TINYINT', - GenModelColumnType.TINYTEXT: 'TINYTEXT', - GenModelColumnType.VARBINARY: 'VARBINARY', - GenModelColumnType.VARCHAR: 'VARCHAR', - GenModelColumnType.YEAR: 'YEAR', - } - return type_mapping.get(typing, 'VARCHAR') + if typing in GenModelMySQLColumnType.get_member_keys(): + return typing + return 'String' def sql_type_to_pydantic(typing: str) -> str: @@ -56,40 +22,7 @@ def sql_type_to_pydantic(typing: str) -> str: :param typing: :return: """ - type_mapping = { - GenModelColumnType.BIGINT: 'int', - GenModelColumnType.BINARY: 'bytes', - GenModelColumnType.BIT: 'bool', - GenModelColumnType.BLOB: 'bytes', - GenModelColumnType.BOOL: 'bool', - GenModelColumnType.BOOLEAN: 'bool', - GenModelColumnType.CHAR: 'str', - GenModelColumnType.DATE: 'date', - GenModelColumnType.DATETIME: 'datetime', - GenModelColumnType.DECIMAL: 'Decimal', - GenModelColumnType.DOUBLE: 'float', - GenModelColumnType.ENUM: 'Enum', - GenModelColumnType.FLOAT: 'float', - GenModelColumnType.INT: 'int', - GenModelColumnType.INTEGER: 'int', - GenModelColumnType.JSON: 'dict', - GenModelColumnType.LONGBLOB: 'bytes', - GenModelColumnType.LONGTEXT: 'str', - GenModelColumnType.MEDIUMBLOB: 'bytes', - GenModelColumnType.MEDIUMINT: 'int', - GenModelColumnType.MEDIUMTEXT: 'str', - GenModelColumnType.NUMERIC: 'NUMERIC', - GenModelColumnType.SET: 'List[str]', - GenModelColumnType.SMALLINT: 'int', - GenModelColumnType.REAL: 'float', - GenModelColumnType.TEXT: 'str', - GenModelColumnType.TIME: 'time', - GenModelColumnType.TIMESTAMP: 'datetime', - GenModelColumnType.TINYBLOB: 'bytes', - GenModelColumnType.TINYINT: 'int', - GenModelColumnType.TINYTEXT: 'str', - GenModelColumnType.VARBINARY: 'bytes', - GenModelColumnType.VARCHAR: 'str', - GenModelColumnType.YEAR: 'int', - } - return type_mapping.get(typing, 'str') + try: + return GenModelMySQLColumnType[typing].value + except KeyError: + return 'str'