Skip to content

Commit

Permalink
!22 RuoYi-Vue-FastAPI v1.6.1
Browse files Browse the repository at this point in the history
Merge pull request !22 from insistence/develop
  • Loading branch information
insistence authored and gitee-org committed Mar 3, 2025
2 parents 4e8a84a + 47c49ad commit 6527e42
Show file tree
Hide file tree
Showing 11 changed files with 61 additions and 27 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<p align="center">
<img alt="logo" src="https://oscimg.oschina.net/oscnet/up-d3d0a9303e11d522a06cd263f3079027715.png">
</p>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi-Vue-FastAPI v1.6.0</h1>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi-Vue-FastAPI v1.6.1</h1>
<h4 align="center">基于RuoYi-Vue+FastAPI前后端分离的快速开发框架</h4>
<p align="center">
<a href="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI/stargazers"><img src="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI/badge/star.svg?theme=dark"></a>
<a href="https://github.com/insistence/RuoYi-Vue-FastAPI"><img src="https://img.shields.io/github/stars/insistence/RuoYi-Vue-FastAPI?style=social"></a>
<a href="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI"><img src="https://img.shields.io/badge/RuoYiVueFastAPI-v1.6.0-brightgreen.svg"></a>
<a href="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI"><img src="https://img.shields.io/badge/RuoYiVueFastAPI-v1.6.1-brightgreen.svg"></a>
<a href="https://gitee.com/insistence2022/RuoYi-Vue-FastAPI/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a>
<img src="https://img.shields.io/badge/python-≥3.9-blue">
<img src="https://img.shields.io/badge/MySQL-≥5.7-blue">
Expand Down
2 changes: 1 addition & 1 deletion ruoyi-fastapi-backend/.env.dev
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ APP_HOST = '0.0.0.0'
# 应用端口
APP_PORT = 9099
# 应用版本
APP_VERSION= '1.6.0'
APP_VERSION= '1.6.1'
# 应用是否开启热重载
APP_RELOAD = true
# 应用是否开启IP归属区域查询
Expand Down
2 changes: 1 addition & 1 deletion ruoyi-fastapi-backend/.env.prod
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ APP_HOST = '0.0.0.0'
# 应用端口
APP_PORT = 9099
# 应用版本
APP_VERSION= '1.6.0'
APP_VERSION= '1.6.1'
# 应用是否开启热重载
APP_RELOAD = false
# 应用是否开启IP归属区域查询
Expand Down
8 changes: 8 additions & 0 deletions ruoyi-fastapi-backend/config/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import sys
from dotenv import load_dotenv
from functools import lru_cache
from pydantic import computed_field
from pydantic_settings import BaseSettings
from typing import Literal

Expand Down Expand Up @@ -51,6 +52,13 @@ class DataBaseSettings(BaseSettings):
db_pool_recycle: int = 3600
db_pool_timeout: int = 30

@computed_field
@property
def sqlglot_parse_dialect(self) -> str:
if self.db_type == 'postgresql':
return 'postgres'
return self.db_type


class RedisSettings(BaseSettings):
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
from fastapi import Form, Query
from pydantic import BaseModel
from pydantic.fields import FieldInfo
from typing import Type
from typing import Type, TypeVar


def as_query(cls: Type[BaseModel]):
BaseModelVar = TypeVar('BaseModelVar', bound=BaseModel)


def as_query(cls: Type[BaseModelVar]) -> Type[BaseModelVar]:
"""
pydantic模型查询参数装饰器,将pydantic模型用于接收查询参数
"""
Expand Down Expand Up @@ -43,7 +46,7 @@ async def as_query_func(**data):
return cls


def as_form(cls: Type[BaseModel]):
def as_form(cls: Type[BaseModelVar]) -> Type[BaseModelVar]:
"""
pydantic模型表单参数装饰器,将pydantic模型用于接收表单参数
"""
Expand Down
9 changes: 6 additions & 3 deletions ruoyi-fastapi-backend/module_generator/dao/gen_dao.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from sqlalchemy import delete, func, select, text, update
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload
from sqlglot.expressions import Expression
from typing import List
from config.env import DataBaseConfig
from module_generator.entity.do.gen_do import GenTable, GenTableColumn
Expand Down Expand Up @@ -75,15 +76,17 @@ async def get_gen_table_all(cls, db: AsyncSession):
return gen_table_all

@classmethod
async def create_table_by_sql_dao(cls, db: AsyncSession, sql: str):
async def create_table_by_sql_dao(cls, db: AsyncSession, sql_statements: List[Expression]):
"""
根据sql语句创建表结构
:param db: orm对象
:param sql: sql语句
:param sql_statements: sql语句的ast列表
:return:
"""
await db.execute(text(sql))
for sql_statement in sql_statements:
sql = sql_statement.sql(dialect=DataBaseConfig.sqlglot_parse_dialect)
await db.execute(text(sql))

@classmethod
async def get_gen_table_list(cls, db: AsyncSession, query_object: GenTablePageQueryModel, is_page: bool = False):
Expand Down
45 changes: 32 additions & 13 deletions ruoyi-fastapi-backend/module_generator/service/gen_service.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import io
import json
import os
import re
import zipfile
from datetime import datetime
from sqlalchemy.ext.asyncio import AsyncSession
from sqlglot import parse as sqlglot_parse
from sqlglot.expressions import Add, Alter, Create, Delete, Drop, Expression, Insert, Table, TruncateTable, Update
from typing import List
from config.constant import GenConstant
from config.env import GenConfig
from config.env import DataBaseConfig, GenConfig
from exceptions.exception import ServiceException
from module_admin.entity.vo.common_vo import CrudResponseModel
from module_admin.entity.vo.user_vo import CurrentUserModel
Expand Down Expand Up @@ -197,10 +198,11 @@ async def create_table_services(cls, query_db: AsyncSession, sql: str, current_u
:param current_user: 当前用户信息对象
:return: 创建表结构结果
"""
if cls.__is_valid_create_table(sql):
sql_statements = sqlglot_parse(sql, dialect=DataBaseConfig.sqlglot_parse_dialect)
if cls.__is_valid_create_table(sql_statements):
try:
table_names = re.findall(r'create\s+table\s+(\w+)', sql, re.IGNORECASE)
await GenTableDao.create_table_by_sql_dao(query_db, sql)
table_names = cls.__get_table_names(sql_statements)
await GenTableDao.create_table_by_sql_dao(query_db, sql_statements)
gen_table_list = await cls.get_gen_db_table_list_by_name_services(query_db, table_names)
await cls.import_gen_table_services(query_db, gen_table_list, current_user)

Expand All @@ -211,22 +213,39 @@ async def create_table_services(cls, query_db: AsyncSession, sql: str, current_u
raise ServiceException(message='建表语句不合法')

@classmethod
def __is_valid_create_table(cls, sql: str):
def __is_valid_create_table(cls, sql_statements: List[Expression]):
"""
校验sql语句是否为合法的建表语句
:param sql: sql语句
:param sql_statements: sql语句的ast列表
:return: 校验结果
"""
create_table_pattern = r'^\s*CREATE\s+TABLE\s+'
if not re.search(create_table_pattern, sql, re.IGNORECASE):
validate_create = [isinstance(sql_statement, Create) for sql_statement in sql_statements]
validate_forbidden_keywords = [
isinstance(
sql_statement,
(Add, Alter, Delete, Drop, Insert, TruncateTable, Update),
)
for sql_statement in sql_statements
]
if not any(validate_create) or any(validate_forbidden_keywords):
return False
forbidden_keywords = ['INSERT', 'UPDATE', 'DELETE', 'DROP', 'ALTER', 'TRUNCATE']
for keyword in forbidden_keywords:
if re.search(rf'\b{keyword}\b', sql, re.IGNORECASE):
return False
return True

@classmethod
def __get_table_names(cls, sql_statements: List[Expression]):
"""
获取sql语句中所有的建表表名
:param sql_statements: sql语句的ast列表
:return: 建表表名列表
"""
table_names = []
for sql_statement in sql_statements:
if isinstance(sql_statement, Create):
table_names.append(sql_statement.find(Table).name)
return table_names

@classmethod
async def preview_code_services(cls, query_db: AsyncSession, table_id: int):
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class {{ BusinessName }}Dao:
await db.execute(
select({{ ClassName }}).where(
{% for column in columns %}
{% if column.required %}
{% if column.unique %}
{{ ClassName }}.{{ column.python_field | camel_to_snake }} == {{ businessName }}.{{ column.python_field | camel_to_snake }} if {{ businessName }}.{{ column.python_field | camel_to_snake }} else True,
{% endif %}
{% endfor %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
{% set vo_field_required.has_required = True %}
{% endif %}
{% endfor %}
{% if table.sub %}
{% set sub_vo_field_required = namespace(has_required=False) %}
{% if table.sub %}
{% for sub_column in subTable.columns %}
{% if sub_column.required %}
{% set sub_vo_field_required.has_required = True %}
Expand All @@ -21,7 +21,7 @@
{% endfor %}
from pydantic import BaseModel, ConfigDict, Field
from pydantic.alias_generators import to_camel
{% if vo_field_required.has_required %}
{% if vo_field_required.has_required or sub_vo_field_required.has_required %}
from pydantic_validation_decorator import NotBlank
{% endif %}
{% if table.sub %}
Expand Down
1 change: 1 addition & 0 deletions ruoyi-fastapi-backend/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ PyMySQL==1.1.1
redis==5.2.1
requests==2.32.3
SQLAlchemy[asyncio]==2.0.38
sqlglot[rs]==26.6.0
user-agents==2.2.0
2 changes: 1 addition & 1 deletion ruoyi-fastapi-frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "vfadmin",
"version": "1.6.0",
"version": "1.6.1",
"description": "vfadmin管理系统",
"author": "insistence",
"license": "MIT",
Expand Down

0 comments on commit 6527e42

Please sign in to comment.