sqlor/aidocs/mysqlor.md
2025-10-05 11:24:24 +08:00

462 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

以下是针对你提供的 Python 代码编写的 **Markdown 格式技术文档**,适用于项目内部文档或开发者参考手册。
---
# `MySqlor` 类技术文档
## 概述
`MySqlor` 是一个用于操作 MySQL 数据库的 SQL 构建与元数据提取类,继承自 `SQLor` 基类。它封装了与 MySQL 相关的 DDL 模板、类型映射、分页查询、表结构查询等功能,支持从数据库中提取表、字段、主键、外键、索引等元信息,并提供模型与数据库之间的类型转换机制。
该类主要配合 `pymysql` 驱动使用,通过动态生成 SQL 查询语句实现对数据库结构的反向工程Reverse Engineering和 ORM 映射支持。
---
## 继承关系
```python
class MySqlor(SQLor)
```
- 父类:`SQLor`
- 所属模块:`.sor.SQLor`
---
## 导入依赖
```python
from appPublic.argsConvert import ArgsConvert, ConditionConvert
from .sor import SQLor
from .const import ROWS
from .ddl_template_mysql import mysql_ddl_tmpl
```
> - `ArgsConvert`, `ConditionConvert`: 参数与条件转换工具。
> - `ROWS`: 分页常量定义。
> - `mysql_ddl_tmpl`: MySQL 的 DDL 模板(如建表语句模板)。
---
## 类属性
### `ddl_template`
```python
ddl_template = mysql_ddl_tmpl
```
- 类型:`dict`
- 描述MySQL 的 DDL 建表语句模板,用于根据模型生成建表 SQL。
- 来源:导入自 `ddl_template_mysql.py` 文件中的 `mysql_ddl_tmpl` 变量。
---
### `db2modelTypeMapping`
将 MySQL 数据库字段类型映射为应用层模型类型Model Type
| 数据库类型 | 模型类型 |
|--------------------|--------------|
| tinyint | short |
| smallint | short |
| mediumint | long |
| int | long |
| bigint | long |
| decimal | float |
| double | float |
| float | float |
| char | char |
| varchar | str |
| tinyblob / tinytext| text |
| mediumblob / mediumtext | text |
| blob / text | text |
| longblob | bin |
| longtext | text |
| binary / varbinary | text |
| date | date |
| time | time |
| datetime | datetime |
| timestamp | datestamp |
| year | short |
> **说明**
> - BLOB 类型统一映射为 `bin` 或 `text`,取决于大小。
> - 时间类型做了精细化区分,例如 `timestamp` 映射为 `datestamp`,便于后续处理。
---
### `model2dbTypemapping`
将模型类型映射回数据库字段类型。
| 模型类型 | 数据库类型 |
|------------|----------------|
| date | date |
| time | date |
| timestamp | timestamp |
| str | varchar |
| char | char |
| short | int |
| long | bigint |
| float | double |
| text | longtext |
| bin | longblob |
| file | longblob |
> **注意**`time` 类型在数据库中仍以 `date` 存储,可能需结合上下文解析;实际应考虑使用 `time` 类型优化。
---
## 类方法
### `isMe(cls, name)`
判断当前数据库驱动是否匹配。
#### 参数
- `name` (`str`):数据库连接驱动名称(如 `'pymysql'`
#### 返回值
- `bool`:若为 `'pymysql'` 则返回 `True`,否则 `False`
#### 示例
```python
if MySqlor.isMe('pymysql'):
print("This is MySQL")
```
---
## 实例方法
### `grammar(self)`
> ⚠️ **当前存在语法错误!**
此方法尝试返回一个包含 `select` 语句模板的字典,但引用了未定义的变量 `select_stmt`
#### 代码问题
```python
def grammar(self):
return {
'select': select_stmt, # ❌ NameError: name 'select_stmt' is not defined
}
```
#### 建议修复
应确保 `select_stmt` 已在作用域内定义,或改为字符串形式:
```python
def grammar(self):
return {
'select': 'SELECT $[fields]$ FROM $[table]$ WHERE $[where]$',
}
```
---
### `placeHolder(self, varname, pos=None)`
返回参数占位符格式(用于预编译 SQL
#### 参数
- `varname` (`str`):变量名
- `pos` (`int`, optional):位置参数索引(未使用)
#### 返回值
-`varname == '__mainsql__'`,返回空字符串 `''`
- 其他情况返回标准占位符 `'%s'`(适配 `pymysql`
#### 用途
用于构建参数化查询,防止 SQL 注入。
#### 示例
```python
cursor.execute(sql, values) # values 将以 %s 替代
```
---
### `dataConvert(self, dataList)`
将输入数据标准化为元组格式,供 SQL 执行使用。
#### 参数
- `dataList` (`dict``list[dict]`):待转换的数据
#### 返回值
- `tuple`:提取出的值组成的元组
#### 行为逻辑
- 如果是字典 → 提取 `.values()`
- 如果是字典列表 → 提取每个元素的 `'value'` 字段
- 最终转为 `tuple`
#### 示例
```python
data1 = {'a': 1, 'b': 2}
# 结果: (1, 2)
data2 = [{'value': 1}, {'value': 2}]
# 结果: (1, 2)
```
---
### `pagingSQLmodel(self)`
返回 MySQL 分页查询模板(基于 `LIMIT offset, count`)。
#### 当前代码问题
```python
def pagingSQLmodel(self):
return """..."""
return """...""" # ❌ 第二个 return 永远不会执行
```
#### 正确版本(推荐)
```python
def pagingSQLmodel(self):
return """
SELECT * FROM (%s) A
ORDER BY $[sort]$
LIMIT $[from_line]$, $[rows]$
"""
```
#### 占位符说明
| 占位符 | 含义 |
|----------------|------------------------|
| `%s` | 子查询原始 SQL |
| `$[sort]$` | 排序字段(如 `id ASC`|
| `$[from_line]$`| 起始行偏移量offset |
| `$[rows]$` | 每页记录数limit |
#### 示例输出
```sql
SELECT * FROM (
SELECT id, name FROM users
) A
ORDER BY id DESC
LIMIT 10, 20
```
---
### `tablesSQL(self)`
生成查询当前数据库所有表名及其注释的 SQL。
#### 返回值
- `str`:查询 `INFORMATION_SCHEMA.TABLES` 的 SQL 语句
#### SQL 内容
```sql
SELECT
lower(TABLE_NAME) AS name,
lower(TABLE_COMMENT) AS title
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'your_db_name'
```
#### 动态填充
- 使用 `self.dbdesc.get('dbname', 'unknown')` 获取数据库名
#### 输出字段
| 字段 | 说明 |
|-------|----------------|
| name | 小写表名 |
| title | 表注释(小写) |
---
### `fieldsSQL(self, tablename=None)`
查询指定表的所有字段元信息。
#### 参数
- `tablename` (`str`, optional):表名,若不传则查询所有表
#### 返回值
- `str`:查询 `information_schema.columns` 的 SQL
#### SQL 片段
```sql
SELECT
lower(column_name) AS name,
data_type AS type,
CASE
WHEN character_maximum_length IS NULL THEN NUMERIC_PRECISION
ELSE character_maximum_length
END AS length,
NUMERIC_SCALE AS dec,
lower(is_nullable) AS nullable,
column_comment AS title,
lower(table_name) AS table_name
FROM information_schema.columns
WHERE lower(TABLE_SCHEMA) = 'your_dbname'
AND lower(table_name) = 'your_table' -- 可选
```
#### 输出字段说明
| 字段 | 说明 |
|--------------|----------------------------------|
| name | 字段名(小写) |
| type | 数据类型 |
| length | 长度或精度 |
| dec | 小数位数 |
| nullable | 是否可为空yes/no |
| title | 字段注释 |
| table_name | 所属表名(小写) |
---
### `fkSQL(self, tablename=None)`
查询外键约束信息。
#### 参数
- `tablename` (`str`, optional):仅查询与该表相关的外键
#### 返回值
- `str`:查询外键关系的 SQL
#### SQL 逻辑
联查三张系统表:
- `KEY_COLUMN_USAGE`
- `TABLES`
- `REFERENTIAL_CONSTRAINTS`
#### 查询内容
| 字段 | 说明 |
|----------------------|--------------------------|
| 拥有者 | Schema 名称 |
| 父表名称 | 被引用表 |
| 父表字段 | 被引用列 |
| 子表名称 | 引用表 |
| 子表字段 | 引用列 |
| 约束名 | 外键约束名称 |
| 表注释 | 子表的注释 |
| 约束更新规则 | ON UPDATE 规则 |
| 约束删除规则 | ON DELETE 规则 |
> **过滤条件**:只返回 `REFERENCED_TABLE_NAME IS NOT NULL` 的记录(即真正的外键)
---
### `pkSQL(self, tablename=None)`
查询指定表的主键字段。
#### 参数
- `tablename` (`str`):必须传入表名
#### 返回值
- `str`:查询主键字段的 SQL
#### SQL
```sql
SELECT DISTINCT column_name AS name
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE table_name='your_table'
AND constraint_name='PRIMARY'
```
#### 注意事项
- `table_name` 会被强制转为小写
- 使用 `DISTINCT` 避免重复
---
### `indexesSQL(self, tablename=None)`
查询索引信息(包括唯一索引)。
#### 参数
- `tablename` (`str`, optional):指定表名
#### 返回值
- `str`:获取索引元数据的 SQL
#### SQL
```sql
SELECT DISTINCT
lower(index_name) AS index_name,
CASE NON_UNIQUE
WHEN 1 THEN 'unique'
ELSE ''
END AS is_unique,
lower(column_name) AS column_name
FROM information_schema.statistics
WHERE table_schema = 'your_dbname'
AND table_name = 'your_table' -- 可选
```
#### 输出字段
| 字段 | 说明 |
|--------------|----------------------------------------|
| index_name | 索引名称(小写) |
| is_unique | 是否唯一索引(值为 `'unique'` 或空) |
| column_name | 索引包含的字段(单个字段一行) |
> **注意**:复合索引会拆分为多行显示。
---
## 使用示例
```python
# 初始化 MySqlor 实例
dbdesc = {'dbname': 'testdb'}
mysqlor = MySqlor(dbdesc=dbdesc)
# 获取所有表
sql_tables = mysqlor.tablesSQL()
print(sql_tables)
# 获取某表字段
sql_fields = mysqlor.fieldsSQL('users')
print(sql_fields)
# 获取主键
sql_pk = mysqlor.pkSQL('users')
# 分页模板
paging_model = mysqlor.pagingSQLmodel()
final_sql = paging_model % "(SELECT * FROM users)" \
.replace("$[sort]$", "id DESC") \
.replace("$[from_line]$", "0") \
.replace("$[rows]$", "10")
```
---
## 已知问题与改进建议
| 问题 | 描述 | 建议 |
|------|------|------|
| `grammar()` 方法报错 | 引用了未定义的 `select_stmt` | 定义常量或抛出 `NotImplementedError` |
| `pagingSQLmodel()` 多余返回 | 第二个 `return` 不可达 | 删除无效行 |
| `dataConvert()` 缺少健壮性检查 | 对非 dict/list 输入无保护 | 添加类型校验和异常处理 |
| `placeHolder` 忽略 `pos` 参数 | 参数未使用 | 可移除或用于未来扩展 |
---
## 总结
`MySqlor` 是一个功能完整的 MySQL 元数据操作类,具备以下能力:
✅ 类型双向映射
✅ 表/字段/主键/外键/索引信息提取
✅ 分页 SQL 模板支持
✅ 参数占位符兼容 `pymysql`
✅ 支持模型驱动开发MDD / ORM
建议结合模板引擎(如 Jinja2进一步提升 SQL 拼接灵活性。
---
> 📝 文档版本v1.0
> 📅 更新时间2025-04-05
> © 项目公共组件库团队