Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Develop #53

Merged
merged 2 commits into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Workflow for Codecov example-python
on: [push, pull_request]
jobs:
run:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python 3.11
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
run: pip install -r requirements-test.txt
- name: Run tests and collect coverage
run: pytest --cov --cov-report xml:coverage.xml --cov-report term-missing
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
flags: smart-tests
verbose: true
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# dfs-generate
# dfs-generate [![codecov](https://codecov.io/gh/zy7y/dfs-generate/graph/badge.svg?token=ZTBA7CYTFC)](https://codecov.io/gh/zy7y/dfs-generate)
通过已有数据库表,生成FastAPI接口的工具项目,最终目的为FastAPI使用者,减少代码; 项目启发 Mybatis 逆向工程、[pdmaner](https://gitee.com/robergroup/pdmaner)

# 支持ORM
# 已支持从数据库表生成
- [x] SQLModel
- [x] Tortoise ORM
- [x] Vue
- [x] FastAPI 增加、删除、分页查询、详情查询、更新接口

# Generate Code
[FastAPI SQLModel MySQL](docs/sqlmodel)
Expand Down Expand Up @@ -56,6 +58,8 @@ source venv/bin/activate
pip install -r requirements.txt
```
### 运行
> 解决找不到模块问题
> mac / linux `export PYTHONPATH=./` windows `set PYTHONPATH=./`
```shell
python dfs_generate/server.py
```
Expand Down
4 changes: 2 additions & 2 deletions dfs_generate/conversion.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from string import Template

from templates import (
from dfs_generate.templates import (
SQLMODEL_DAO,
TORTOISE_DAO,
RESPONSE_SCHEMA,
Expand All @@ -13,7 +13,7 @@
VUE_INDEX_VUE,
VUE_CRUD_TS,
)
from tools import to_pascal, tran, to_snake
from dfs_generate.tools import to_pascal, tran, to_snake


def _pydantic_field(column, imports):
Expand Down
4 changes: 2 additions & 2 deletions dfs_generate/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
import isort
from yapf.yapflib.yapf_api import FormatCode

from conversion import SQLModelConversion, TortoiseConversion
from tools import MySQLConf, MySQLHelper
from dfs_generate.conversion import SQLModelConversion, TortoiseConversion
from dfs_generate.tools import MySQLConf, MySQLHelper

app = bottle.Bottle()

Expand Down
2 changes: 1 addition & 1 deletion dfs_generate/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import pymysql

from types_map import TYPES
from dfs_generate.types_map import TYPES


def tran(t, mode) -> dict:
Expand Down
3 changes: 2 additions & 1 deletion requirements-test.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
-r requirements.txt
pytest
pytest==8.2.0
pytest-cov==5.0.0
30 changes: 25 additions & 5 deletions tests/test_conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,23 @@
"IS_NULLABLE": "NO",
"COLUMN_KEY": "PRI",
"COLUMN_COMMENT": "主键ID",
"CHARACTER_MAXIMUM_LENGTH": "",
"NUMERIC_PRECISION": "",
"NUMERIC_SCALE": "",
"COLUMN_DEFAULT": "",
"EXTRA": "",
},
{
"COLUMN_NAME": "name",
"DATA_TYPE": "varchar(100)",
"DATA_TYPE": "varchar",
"IS_NULLABLE": "YES",
"COLUMN_COMMENT": "姓名",
"CHARACTER_MAXIMUM_LENGTH": "100",
"NUMERIC_PRECISION": "",
"NUMERIC_SCALE": "",
"COLUMN_DEFAULT": "",
"EXTRA": "",
"COLUMN_KEY": "",
},
]

Expand Down Expand Up @@ -64,8 +75,11 @@ def test_tortoise_conversion_model(tortoise_conversion_fixture):
"""测试TortoiseConversion的model方法输出格式"""
model_code = tortoise_conversion_fixture.model()
assert "class Users(Model):" in model_code
assert "id = fields.Int(pk=True)" in model_code
assert "name = fields.CharField(max_length=100)" in model_code
assert 'id = fields.IntField(description="主键ID", pk=True)' in model_code
assert (
'name = fields.CharField(null=True, max_length=100, description="姓名")'
in model_code
)


def test_pydantic_field():
Expand All @@ -79,7 +93,10 @@ def test_sqlmodel_field_repr():
"""测试_sqlmodel_field_repr函数的输出"""
column = MOCK_COLUMNS[0] # 使用id字段作为测试
imports, field_code = set(), _sqlmodel_field_repr(column, set())
assert "id: Optional[int] = Field(nullable=False)" in field_code
assert (
'id: Optional[int] = Field(default=None,primary_key=True,description="主键ID")'
== field_code
)
assert (
"from datetime import datetime" not in imports
) # id字段不应触发默认时间戳逻辑
Expand All @@ -89,4 +106,7 @@ def test_tortoise_field_repr():
"""测试_tortoise_field_repr函数的输出"""
column = MOCK_COLUMNS[1]
field_code = _tortoise_field_repr(column)
assert "name = fields.CharField(max_length=100, description='姓名')" in field_code
assert (
'name = fields.CharField(null=True, max_length=100, description="姓名")'
== field_code
)
55 changes: 2 additions & 53 deletions tests/test_tools.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import pymysql
import pytest
from dfs_generate.tools import tran, to_pascal, to_snake
from dfs_generate.tools import MySQLConf, MySQLHelper
from unittest.mock import MagicMock
from pymysql.err import OperationalError
from dfs_generate.tools import MySQLConf


# 测试 tran 函数
Expand All @@ -16,7 +13,7 @@
],
)
def test_tran(t, mode, expected):
assert tran(t, mode) == expected
assert tran(t, mode)["type"] == expected["type"]


# 测试 to_pascal 函数
Expand Down Expand Up @@ -75,51 +72,3 @@ def test_mysqlconf_json():
"charset": "utf8mb4",
}
assert conf.json() == expected_json


@pytest.fixture
def mysql_helper_mock(monkeypatch):
"""Fixture to create a mocked MySQLHelper instance."""
mock_conn = MagicMock()
mock_cursor = MagicMock()
mock_conn.cursor.return_value = mock_cursor
monkeypatch.setattr("pymysql.connect", lambda *args, **kwargs: mock_conn)
helper = MySQLHelper(
MySQLConf(host="localhost", user="test", password="pwd", db="test_db")
)
return helper, mock_conn, mock_cursor


def test_mysqlhelper_init(mysql_helper_mock):
helper, mock_conn, _ = mysql_helper_mock
mock_conn.assert_called_once()
assert helper.conn == mock_conn
assert helper.cursor == mock_conn.cursor.return_value


def test_mysqlhelper_set_conn(mysql_helper_mock):
helper, mock_conn, _ = mysql_helper_mock
new_conf = MySQLConf(
host="new_host", user="new_user", password="new_pwd", db="new_db"
)
helper.set_conn(new_conf)
mock_conn.assert_called_with(
**new_conf.json(), cursorclass=pymysql.cursors.DictCursor
)


def test_mysqlhelper_close(mysql_helper_mock):
_, mock_conn, mock_cursor = mysql_helper_mock
helper = MySQLHelper(
MySQLConf(host="localhost", user="test", password="pwd", db="test_db")
)
helper.close()
mock_cursor.close.assert_called_once()
mock_conn.close.assert_called_once()


def test_mysqlhelper_get_tables_error(mysql_helper_mock):
helper, _, mock_cursor = mysql_helper_mock
mock_cursor.execute.side_effect = OperationalError
with pytest.raises(OperationalError):
helper.get_tables()
Loading