bigfix
This commit is contained in:
parent
8aaae210df
commit
0e3e9c0548
1
aidocs/__init__.md
Normal file
1
aidocs/__init__.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
当然可以!请先提供您需要编写技术文档的代码,我将根据代码内容为您生成详细的 Markdown 格式技术文档,包括功能说明、使用方法、参数解释、示例等内容。
|
||||||
105
aidocs/aiomysqlor.md
Normal file
105
aidocs/aiomysqlor.md
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
# AioMysqlor 技术文档
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# `AioMysqlor` 类文档
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
`AioMysqlor` 是一个继承自 `MySqlor` 的类,用于标识或处理与异步 MySQL 驱动 `aiomysql` 相关的逻辑。该类通过类方法 `isMe` 判断传入的名称是否为 `'aiomysql'`,从而确定是否应由当前类处理。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 模块依赖
|
||||||
|
|
||||||
|
```python
|
||||||
|
from .mysqlor import MySqlor
|
||||||
|
```
|
||||||
|
|
||||||
|
- 依赖于同级模块中的 `MySqlor` 基类。
|
||||||
|
- 使用相对导入方式加载父类。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 类定义
|
||||||
|
|
||||||
|
### `class AioMysqlor(MySqlor)`
|
||||||
|
|
||||||
|
继承自 `MySqlor`,扩展了对特定驱动名称的识别能力。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 类方法
|
||||||
|
|
||||||
|
### `@classmethod isMe(cls, name)`
|
||||||
|
|
||||||
|
#### 功能说明
|
||||||
|
|
||||||
|
判断传入的数据库驱动名称是否为 `'aiomysql'`,用于运行时类型识别或工厂模式中的类匹配。
|
||||||
|
|
||||||
|
#### 参数
|
||||||
|
|
||||||
|
| 参数名 | 类型 | 说明 |
|
||||||
|
|--------|--------|--------------------------|
|
||||||
|
| `name` | `str` | 待检测的数据库驱动名称。 |
|
||||||
|
|
||||||
|
#### 返回值
|
||||||
|
|
||||||
|
- **类型**: `bool`
|
||||||
|
- **说明**:
|
||||||
|
- 若 `name == 'aiomysql'`,返回 `True`;
|
||||||
|
- 否则返回 `False`。
|
||||||
|
|
||||||
|
#### 示例
|
||||||
|
|
||||||
|
```python
|
||||||
|
print(AioMysqlor.isMe('aiomysql')) # 输出: True
|
||||||
|
print(AioMysqlor.isMe('pymysql')) # 输出: False
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 装饰器
|
||||||
|
|
||||||
|
- 使用 `@classmethod` 装饰,表示这是一个类方法,无需实例化即可调用。
|
||||||
|
|
||||||
|
> ⚠️ 注意:方法定义中参数 `self` 实际上在类方法中应为 `cls`,建议修正以符合规范(见下方“注意事项”)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 使用场景
|
||||||
|
|
||||||
|
常用于数据库连接工厂中,根据配置的驱动名称动态选择对应的处理类:
|
||||||
|
|
||||||
|
```python
|
||||||
|
driver_name = config.get('db_driver')
|
||||||
|
if AioMysqlor.isMe(driver_name):
|
||||||
|
db = AioMysqlor(**config)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
1. **参数命名问题**:
|
||||||
|
- 尽管使用了 `@classmethod`,方法签名仍写为 `def isMe(self, name)`,其中 `self` 应改为 `cls` 以符合 Python 社区惯例。
|
||||||
|
- 推荐修改为:
|
||||||
|
```python
|
||||||
|
@classmethod
|
||||||
|
def isMe(cls, name):
|
||||||
|
return name == 'aiomysql'
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **字符串硬编码**:
|
||||||
|
- `'aiomysql'` 可考虑提取为类常量,便于维护和扩展。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 版本信息
|
||||||
|
|
||||||
|
- 创建时间:YYYY-MM-DD(请根据实际填写)
|
||||||
|
- 作者:开发者团队 / 个人名称
|
||||||
|
- 适用版本:Python 3.7+
|
||||||
|
- 依赖库:`aiomysql`(异步 MySQL 驱动)
|
||||||
|
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
> ✅ 提示:此文档可用于项目 Wiki、API 手册或代码仓库中的 `docs/` 目录,帮助团队成员理解 `AioMysqlor` 的用途和使用方式。
|
||||||
93
aidocs/aiopostgresqlor.md
Normal file
93
aidocs/aiopostgresqlor.md
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
# AioPostgresqlor 技术文档
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# `AioPostgresqlor` 类文档
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
`AioPostgresqlor` 是一个基于异步 PostgreSQL 驱动的数据库操作类,继承自 `PostgreSQLor` 基类。该类专为使用 `aiopg` 异步驱动设计,用于支持异步上下文中的数据库事务管理。
|
||||||
|
|
||||||
|
> **注意**:当前实现为占位结构,核心方法尚未完成具体逻辑。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 继承关系
|
||||||
|
|
||||||
|
- **父类**: `PostgreSQLor`(来自 `.postgresqlor` 模块)
|
||||||
|
- **子类**: `AioPostgresqlor`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 方法说明
|
||||||
|
|
||||||
|
### `isMe(name) -> bool`
|
||||||
|
|
||||||
|
#### 描述
|
||||||
|
类方法,用于判断传入的驱动名称是否匹配当前类所支持的异步驱动(即 `aiopg`)。
|
||||||
|
|
||||||
|
#### 参数
|
||||||
|
| 参数名 | 类型 | 说明 |
|
||||||
|
|--------|--------|--------------------------|
|
||||||
|
| `name` | `str` | 数据库驱动的名称字符串。 |
|
||||||
|
|
||||||
|
#### 返回值
|
||||||
|
| 类型 | 说明 |
|
||||||
|
|-----------|------------------------------------------|
|
||||||
|
| `bool` | 若 `name == 'aiopg'` 则返回 `True`,否则返回 `False`。 |
|
||||||
|
|
||||||
|
#### 示例
|
||||||
|
```python
|
||||||
|
if AioPostgresqlor.isMe('aiopg'):
|
||||||
|
print("适用于 aiopg 驱动")
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `commit() -> None`
|
||||||
|
|
||||||
|
#### 描述
|
||||||
|
异步方法,用于提交当前数据库事务。目前为空实现(`pass`),需在子类或后续版本中补充实际逻辑。
|
||||||
|
|
||||||
|
> ⚠️ **警告**:调用此方法不会产生任何效果,必须重写以实现真正的事务提交功能。
|
||||||
|
|
||||||
|
#### 类型
|
||||||
|
`async def`
|
||||||
|
|
||||||
|
#### 使用方式(语法示例)
|
||||||
|
```python
|
||||||
|
await instance.commit()
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 注意事项
|
||||||
|
- 必须在 `async with` 或其他异步上下文中调用。
|
||||||
|
- 实际行为依赖于底层 `aiopg` 连接对象的实现,建议覆盖此方法以正确调用 `connection.commit()` 或等效操作。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 设计意图
|
||||||
|
|
||||||
|
`AioPostgresqlor` 的设计目标是:
|
||||||
|
- 支持异步 I/O 操作,适配 Python 异步生态(如 `asyncio`)。
|
||||||
|
- 通过 `isMe()` 方法实现驱动识别,便于工厂模式动态选择数据库操作器。
|
||||||
|
- 提供与同步版本 `PostgreSQLor` 一致的接口契约,保证代码兼容性。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 待办事项(TODO)
|
||||||
|
|
||||||
|
- [ ] 实现 `commit()` 的真实逻辑(调用 `aiopg` 的事务提交)。
|
||||||
|
- [ ] 补充 `__init__` 或初始化连接的相关方法。
|
||||||
|
- [ ] 添加对 `rollback()` 的异步支持。
|
||||||
|
- [ ] 增加异常处理机制。
|
||||||
|
- [ ] 提供完整的上下文管理器支持(`__aenter__`, `__aexit__`)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 参考
|
||||||
|
|
||||||
|
- [aiopg 官方文档](https://aiopg.readthedocs.io/)
|
||||||
|
- 父类 `PostgreSQLor` 的接口定义
|
||||||
|
```
|
||||||
|
|
||||||
|
> ✅ 文档生成时间:2025-04-05
|
||||||
|
> 📦 所属模块:`.postgresqlor` 扩展模块家族
|
||||||
102
aidocs/aiosqliteor.md
Normal file
102
aidocs/aiosqliteor.md
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
# `Aiosqliteor` 类技术文档
|
||||||
|
|
||||||
|
```python
|
||||||
|
import re
|
||||||
|
from .sqlite3or import SQLite3or
|
||||||
|
|
||||||
|
class Aiosqliteor(SQLite3or):
|
||||||
|
@classmethod
|
||||||
|
def isMe(self, name):
|
||||||
|
return name == 'aiosqlite'
|
||||||
|
```
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
`Aiosqliteor` 是一个继承自 `SQLite3or` 的子类,用于标识和处理与异步 SQLite 库 `aiosqlite` 相关的操作。该类主要用于运行时判断当前数据库驱动是否为 `aiosqlite`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 继承关系
|
||||||
|
|
||||||
|
- **父类**: `SQLite3or`
|
||||||
|
- **模块路径**: `.sqlite3or.SQLite3or`
|
||||||
|
|
||||||
|
> 说明:`SQLite3or` 是一个通用的 SQLite 操作基类,可能支持多种后端实现(如标准库 `sqlite3` 或异步库 `aiosqlite`)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 类方法
|
||||||
|
|
||||||
|
### `isMe(name)`
|
||||||
|
|
||||||
|
#### 描述
|
||||||
|
类方法,用于判断传入的数据库名称是否匹配 `aiosqlite` 驱动。
|
||||||
|
|
||||||
|
#### 签名
|
||||||
|
```python
|
||||||
|
@classmethod
|
||||||
|
def isMe(cls, name: str) -> bool
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 参数
|
||||||
|
| 参数名 | 类型 | 说明 |
|
||||||
|
|--------|--------|------|
|
||||||
|
| `name` | `str` | 表示数据库驱动名称的字符串(例如 `'aiosqlite'`, `'sqlite3'` 等) |
|
||||||
|
|
||||||
|
#### 返回值
|
||||||
|
| 类型 | 说明 |
|
||||||
|
|---------|------|
|
||||||
|
| `bool` | 如果 `name` 等于 `'aiosqlite'`,返回 `True`;否则返回 `False` |
|
||||||
|
|
||||||
|
#### 示例
|
||||||
|
```python
|
||||||
|
assert Aiosqliteor.isMe('aiosqlite') == True
|
||||||
|
assert Aiosqliteor.isMe('sqlite3') == False
|
||||||
|
assert Aiosqliteor.isMe('other') == False
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 实现逻辑
|
||||||
|
```python
|
||||||
|
return name == 'aiosqlite'
|
||||||
|
```
|
||||||
|
通过简单的字符串比较来判断是否为 `aiosqlite` 驱动。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 用途
|
||||||
|
|
||||||
|
此方法通常被框架或工厂函数调用,以动态选择合适的数据库操作类:
|
||||||
|
|
||||||
|
```python
|
||||||
|
db_name = 'aiosqlite'
|
||||||
|
if Aiosqliteor.isMe(db_name):
|
||||||
|
db_handler = Aiosqliteor()
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
- 此类目前仅提供识别功能,具体异步数据库操作需在父类或自身中实现。
|
||||||
|
- 名称比对是**大小写敏感**的,确保输入为小写的 `'aiosqlite'`。
|
||||||
|
- 依赖于 `SQLite3or` 基类的功能扩展,应确保基类已正确定义并具备所需接口。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 版本信息
|
||||||
|
|
||||||
|
- **语言**: Python
|
||||||
|
- **依赖**: `aiosqlite`(运行时)、`sqlite3`(间接)
|
||||||
|
- **模块位置**: `your_package.db.engines.Aiosqliteor`
|
||||||
|
|
||||||
|
> 注:实际使用中需确保已安装 `aiosqlite` 包:
|
||||||
|
> ```bash
|
||||||
|
> pip install aiosqlite
|
||||||
|
> ```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 参考
|
||||||
|
|
||||||
|
- [aiosqlite on GitHub](https://github.com/omnilib/aiosqlite)
|
||||||
|
- `SQLite3or` 基类文档(见相关模块)
|
||||||
55
aidocs/const.md
Normal file
55
aidocs/const.md
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# 技术文档
|
||||||
|
|
||||||
|
## 变量定义:`ROWS`
|
||||||
|
|
||||||
|
### 概述
|
||||||
|
`ROWS` 是一个用于定义行数的常量变量,通常用于控制数据结构(如数组、矩阵、表格等)的行数维度。
|
||||||
|
|
||||||
|
### 定义
|
||||||
|
```python
|
||||||
|
ROWS = 100
|
||||||
|
```
|
||||||
|
|
||||||
|
### 类型
|
||||||
|
- **数据类型**:整数(Integer)
|
||||||
|
- **值**:100
|
||||||
|
|
||||||
|
### 用途
|
||||||
|
该变量设定为 `100`,表示相关数据结构或操作将基于 **100 行**进行处理。常见应用场景包括:
|
||||||
|
- 初始化二维数组或矩阵(例如:`matrix[ROWS][COLS]`)
|
||||||
|
- 控制循环次数(例如:`for i in range(ROWS):`)
|
||||||
|
- 配置数据生成或模拟的规模
|
||||||
|
- 设置表格、图像、传感器阵列等的垂直尺寸
|
||||||
|
|
||||||
|
### 示例用法
|
||||||
|
|
||||||
|
#### Python 示例
|
||||||
|
```python
|
||||||
|
ROWS = 100
|
||||||
|
COLS = 50
|
||||||
|
|
||||||
|
# 创建一个 100x50 的二维列表
|
||||||
|
grid = [[0 for _ in range(COLS)] for _ in range(ROWS)]
|
||||||
|
print(f"Grid size: {len(grid)} rows x {len(grid[0])} columns")
|
||||||
|
```
|
||||||
|
|
||||||
|
#### C/C++ 示例
|
||||||
|
```c
|
||||||
|
#define ROWS 100
|
||||||
|
|
||||||
|
int matrix[ROWS][50]; // 声明一个包含 100 行的二维数组
|
||||||
|
```
|
||||||
|
|
||||||
|
### 注意事项
|
||||||
|
- 修改 `ROWS` 的值会影响内存使用和程序性能,尤其是在大规模数据处理中。
|
||||||
|
- 应确保其值为正整数,避免出现逻辑错误或运行时异常。
|
||||||
|
- 若与其他常量(如 `COLS`)配合使用,请保持命名一致性。
|
||||||
|
|
||||||
|
### 版本信息
|
||||||
|
- **创建时间**:未知
|
||||||
|
- **最后修改**:未知
|
||||||
|
- **适用环境**:通用编程环境(Python, C, Java, JavaScript 等)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> ✅ 提示:建议将此类常量集中定义在配置文件或常量模块中,以提高代码可维护性。
|
||||||
482
aidocs/crud.md
Normal file
482
aidocs/crud.md
Normal file
@ -0,0 +1,482 @@
|
|||||||
|
# `CRUD` 模块技术文档
|
||||||
|
|
||||||
|
> **文件编码:UTF-8**
|
||||||
|
|
||||||
|
该模块提供了一个基于数据库连接池的通用增删改查(CRUD)操作类,支持异步执行、字段类型转换、主外键处理、数据网格生成等功能。适用于 Web 后端服务中对数据库表进行标准化访问。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
- [1. 依赖说明](#1-依赖说明)
|
||||||
|
- [2. 全局变量](#2-全局变量)
|
||||||
|
- [`toStringFuncs`](#tostringfuncs)
|
||||||
|
- [`fromStringFuncs`](#fromstringfuncs)
|
||||||
|
- [3. 异常定义](#3-异常定义)
|
||||||
|
- [`DatabaseNotfound`](#databasenotfound)
|
||||||
|
- [4. 核心类:`CRUD`](#4-核心类crud)
|
||||||
|
- [构造函数 `__init__`](#构造函数-__init__)
|
||||||
|
- [方法列表](#方法列表)
|
||||||
|
- [`primaryKey()`](#async-primarykey)
|
||||||
|
- [`forignKeys()`](#async-forignkeys)
|
||||||
|
- [`I()`](#async-i)
|
||||||
|
- [`fromStr(data)`](#async-fromstrdata)
|
||||||
|
- [`toStr(data)`](#async-tostrdata)
|
||||||
|
- [`datagrid(request, targeti, **kw)`](#async-datagridrequest-targeti--kw)
|
||||||
|
- [`defaultIOField(f)`](#defaultiofieldf)
|
||||||
|
- [`C(rec, **kw)`](#async-crec--kw)
|
||||||
|
- [`R(filters=None, NS={}, **kw)`](#async-rfiltersnone-ns---kw)
|
||||||
|
- [`U(data, **kw)`](#async-udata--kw)
|
||||||
|
- [`D(data, **kw)`](#async-ddata--kw)
|
||||||
|
|
||||||
|
- [5. 示例用法](#5-示例用法)
|
||||||
|
- [6. 注意事项与扩展机制](#6-注意事项与扩展机制)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 依赖说明
|
||||||
|
|
||||||
|
本模块依赖以下内部和外部组件:
|
||||||
|
|
||||||
|
| 模块 | 用途 |
|
||||||
|
|------|------|
|
||||||
|
| `.dbpools.DBPools` | 数据库连接池管理器 |
|
||||||
|
| `.const.ROWS` | 默认每页行数常量 |
|
||||||
|
| `.filter.DBFilter` | SQL 查询条件过滤器生成工具 |
|
||||||
|
| `appPublic.objectAction.ObjectAction` | 对象行为钩子系统(用于事件拦截与扩展) |
|
||||||
|
| `appPublic.dictObject.DictObject` | 字典对象封装(未直接使用,可能为遗留导入) |
|
||||||
|
| `appPublic.timeUtils.date2str, time2str, str2Date` | 时间格式化/解析函数 |
|
||||||
|
| `appPublic.uniqueID.getID` | 唯一 ID 生成函数 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 全局变量
|
||||||
|
|
||||||
|
### `toStringFuncs`
|
||||||
|
|
||||||
|
将不同字段类型的值转为字符串表示的方法映射。
|
||||||
|
|
||||||
|
```python
|
||||||
|
toStringFuncs = {
|
||||||
|
'char': None,
|
||||||
|
'str': None,
|
||||||
|
'short': str,
|
||||||
|
'long': str,
|
||||||
|
'float': str,
|
||||||
|
'date': date2str,
|
||||||
|
'time': time2str,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- 若值为 `None`,表示不需特殊处理。
|
||||||
|
- 例如:日期类型通过 `date2str` 转换为 `'YYYY-MM-DD'` 格式字符串。
|
||||||
|
|
||||||
|
### `fromStringFuncs`
|
||||||
|
|
||||||
|
将字符串反向解析为对应类型的数据转换函数。
|
||||||
|
|
||||||
|
```python
|
||||||
|
fromStringFuncs = {
|
||||||
|
'short': int,
|
||||||
|
'long': int,
|
||||||
|
'float': float,
|
||||||
|
'date': str2Date,
|
||||||
|
'time': str2Date
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- 空字符串会被转换为 `None`。
|
||||||
|
- 支持自动类型转换,在插入或更新前预处理输入数据。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 异常定义
|
||||||
|
|
||||||
|
### `DatabaseNotfound`
|
||||||
|
|
||||||
|
当指定的数据库名称在连接池中不存在时抛出此异常。
|
||||||
|
|
||||||
|
#### 属性:
|
||||||
|
- `dbname`: 请求但未找到的数据库名
|
||||||
|
|
||||||
|
#### 方法:
|
||||||
|
- `__str__()`: 返回 `"xxx not found"` 的可读信息。
|
||||||
|
|
||||||
|
```python
|
||||||
|
raise DatabaseNotfound("mydb")
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 核心类:`CRUD`
|
||||||
|
|
||||||
|
```python
|
||||||
|
class CRUD(object):
|
||||||
|
def __init__(self, dbname, tablename, rows=ROWS):
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
封装了对单个数据库表的标准 CRUD 操作。
|
||||||
|
|
||||||
|
### 构造函数 `__init__`
|
||||||
|
|
||||||
|
**参数:**
|
||||||
|
- `dbname` (str): 数据库标识名(必须存在于 DBPools 中)
|
||||||
|
- `tablename` (str): 表名
|
||||||
|
- `rows` (int): 分页查询默认条数,默认为 `ROWS` 常量
|
||||||
|
|
||||||
|
**逻辑流程:**
|
||||||
|
1. 初始化连接池实例 `DBPools()`
|
||||||
|
2. 验证数据库是否存在,若不存在则抛出 `DatabaseNotfound`
|
||||||
|
3. 缓存表主键信息(延迟加载)
|
||||||
|
|
||||||
|
**抛出异常:**
|
||||||
|
- `DatabaseNotfound`:数据库未注册
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 方法列表
|
||||||
|
|
||||||
|
#### `async primaryKey(**kw)`
|
||||||
|
|
||||||
|
获取当前表的主键字段信息。
|
||||||
|
|
||||||
|
- 第一次调用时从数据库元数据缓存主键信息。
|
||||||
|
- 后续调用返回缓存结果。
|
||||||
|
|
||||||
|
**返回:**
|
||||||
|
- 列表,每个元素是包含字段信息的对象(如 `{field_name: "id", ...}`)
|
||||||
|
|
||||||
|
> 内部使用 `pool.getTablePrimaryKey(dbname, tablename)` 实现。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `async forignKeys(**kw)`
|
||||||
|
|
||||||
|
获取当前表的所有外键关系。
|
||||||
|
|
||||||
|
**返回:**
|
||||||
|
- 外键描述数据结构(由 `pool.getTableForignKeys()` 提供)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `async I(**kw)`
|
||||||
|
|
||||||
|
获取当前表的字段元信息,并附加主键标记。
|
||||||
|
|
||||||
|
##### 功能:
|
||||||
|
1. 获取所有字段信息(来自 `getTableFields`)
|
||||||
|
2. 将主键字段添加 `"primarykey": True` 标记
|
||||||
|
3. 执行对象动作钩子:`{dbname}_{tablename}.tableInfo`
|
||||||
|
|
||||||
|
##### 返回:
|
||||||
|
- 字段信息列表,每个字段包含:
|
||||||
|
- `name`: 字段名
|
||||||
|
- `title`: 显示标题(若有)
|
||||||
|
- `type`: 类型(如 str, float, date 等)
|
||||||
|
- `primarykey`: 是否为主键(bool)
|
||||||
|
|
||||||
|
##### 示例输出片段:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"title": "ID",
|
||||||
|
"type": "short",
|
||||||
|
"primarykey": true
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `async fromStr(data)`
|
||||||
|
|
||||||
|
将字符串形式的数据字典转换为强类型数据。
|
||||||
|
|
||||||
|
**参数:**
|
||||||
|
- `data` (dict): 键值对,通常来自 HTTP 请求参数
|
||||||
|
|
||||||
|
**处理规则:**
|
||||||
|
- 空字符串 → `None`
|
||||||
|
- 根据字段类型应用 `fromStringFuncs` 转换(如 `int`, `float`, `str2Date`)
|
||||||
|
|
||||||
|
**返回:**
|
||||||
|
- 新字典,已做类型转换
|
||||||
|
|
||||||
|
> 常用于 C/U 接口前的数据预处理。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `async toStr(data)`
|
||||||
|
|
||||||
|
将原始数据转换为适合前端展示的字符串格式。
|
||||||
|
|
||||||
|
**参数:**
|
||||||
|
- `data` (dict): 数据记录
|
||||||
|
|
||||||
|
**处理规则:**
|
||||||
|
- 使用 `toStringFuncs` 将非字符串字段转为字符串(如日期→'2025-04-05')
|
||||||
|
|
||||||
|
**返回:**
|
||||||
|
- 可序列化的字符串化字典
|
||||||
|
|
||||||
|
> 常用于 R 接口后数据输出前的格式化。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `async datagrid(request, targeti, **kw)`
|
||||||
|
|
||||||
|
生成一个前端可用的“数据表格”配置对象,兼容 EasyUI 或类似框架。
|
||||||
|
|
||||||
|
##### 参数:
|
||||||
|
- `request`: 当前请求对象(用于生成绝对 URL)
|
||||||
|
- `targeti`: 目标 DOM 容器 ID
|
||||||
|
- `**kw`: 其他传递参数
|
||||||
|
|
||||||
|
##### 返回:
|
||||||
|
一个嵌套结构,描述 DataGrid 组件的模板配置,包括:
|
||||||
|
|
||||||
|
| 属性 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `tmplname` | 使用的模板名 |
|
||||||
|
| `data.__ctmpl__` | 组件类型标识 |
|
||||||
|
| `data.__target__` | 渲染目标 |
|
||||||
|
| `data.data.url` | 查询接口地址 (`./RP.dspy`) |
|
||||||
|
| `data.data.deleteUrl` | 删除接口 |
|
||||||
|
| `data.data.addUrl` | 添加接口 |
|
||||||
|
| `data.data.updateUrl` | 更新接口 |
|
||||||
|
| `data.data.idField` | 主键字段名 |
|
||||||
|
| `data.data.fields` | 字段列定义(通过 `defaultIOField` 生成) |
|
||||||
|
| `data.data.toolbar` | 工具栏按钮(增删上下移动) |
|
||||||
|
| `data.data.options.pageSize` | 分页大小 |
|
||||||
|
|
||||||
|
> 最终通过 `oa.execute(id, 'datagrid', data)` 允许外部插件定制布局。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `defaultIOField(f)`
|
||||||
|
|
||||||
|
根据字段元信息生成默认的前端显示字段配置。
|
||||||
|
|
||||||
|
**参数:**
|
||||||
|
- `f` (dict): 单个字段元信息
|
||||||
|
|
||||||
|
**返回:**
|
||||||
|
标准字段配置对象,含以下字段:
|
||||||
|
|
||||||
|
| 字段 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `name` | 字段名 |
|
||||||
|
| `label` | 显示标签(取自 `title`) |
|
||||||
|
| `primarykey` | 是否为主键 |
|
||||||
|
| `hidden` | 是否隐藏(默认否) |
|
||||||
|
| `sortable` | 是否可排序 |
|
||||||
|
| `align` | 文本对齐方式(数值右对齐) |
|
||||||
|
| `iotype` | 输入类型(目前统一为 `"text"`) |
|
||||||
|
|
||||||
|
> 不同类型字段有细微差异:
|
||||||
|
- `str`: 居中对齐
|
||||||
|
- 数值型(`short`, `long`, `float`): 右对齐
|
||||||
|
- 其他: 居中对齐
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `async C(rec, **kw)`
|
||||||
|
|
||||||
|
创建一条新记录(Create)。
|
||||||
|
|
||||||
|
##### 参数:
|
||||||
|
- `rec` (dict): 待插入数据(字段名不区分大小写)
|
||||||
|
- `**kw`: 额外参数(传给底层 SQL 执行)
|
||||||
|
|
||||||
|
##### 流程:
|
||||||
|
1. 转换键名为小写
|
||||||
|
2. 若主键为空,则自动生成唯一 ID(`getID()`)
|
||||||
|
3. 触发 `beforeAdd` 钩子
|
||||||
|
4. 构造并执行插入语句:
|
||||||
|
```sql
|
||||||
|
INSERT INTO table (col1, col2) VALUES (${col1}$, ${col2}$)
|
||||||
|
```
|
||||||
|
5. 触发 `afterAdd` 钩子
|
||||||
|
6. 返回主键值 `{pk_field: value}`
|
||||||
|
|
||||||
|
##### 返回:
|
||||||
|
- 成功时返回主键字典;失败抛异常。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `async R(filters=None, NS={}, **kw)`
|
||||||
|
|
||||||
|
检索数据(Retrieve),支持条件查询和分页。
|
||||||
|
|
||||||
|
##### 参数:
|
||||||
|
- `filters`: 自定义过滤表达式(高级语法,见 `DBFilter`)
|
||||||
|
- `NS`: 查询参数字典(如 `{"name": "Alice"}`)
|
||||||
|
- `**kw`: 其他选项
|
||||||
|
|
||||||
|
##### 特殊处理:
|
||||||
|
- `NS['__id']` → 自动映射到主键字段
|
||||||
|
- `NS['page']` 存在 → 启用分页模式
|
||||||
|
- 无排序字段时,默认按主键排序
|
||||||
|
|
||||||
|
##### 查询逻辑:
|
||||||
|
- 若无 `filters`,则自动生成等值匹配条件(`field = $field$`)
|
||||||
|
- 使用 `DBFilter` 解析复杂条件(如范围、模糊匹配)
|
||||||
|
|
||||||
|
##### 执行分支:
|
||||||
|
- 分页请求 → 调用 `runSQLPaging`
|
||||||
|
- 普通查询 → 调用 `runSQL`
|
||||||
|
|
||||||
|
##### 生命周期钩子:
|
||||||
|
- `beforeRetrieve`
|
||||||
|
- `afterRetrieve`
|
||||||
|
|
||||||
|
##### 返回:
|
||||||
|
- 结果集(可能是分页对象,含 `total`, `rows`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `async U(data, **kw)`
|
||||||
|
|
||||||
|
更新记录(Update)。
|
||||||
|
|
||||||
|
##### 参数:
|
||||||
|
- `data` (dict): 包含主键和其他待更新字段
|
||||||
|
|
||||||
|
##### 流程:
|
||||||
|
1. 分离主键字段和更新字段
|
||||||
|
2. 构造 WHERE 条件(主键相等)
|
||||||
|
3. 构造 SET 子句(仅非主键字段)
|
||||||
|
4. 执行更新语句:
|
||||||
|
```sql
|
||||||
|
UPDATE table SET col1=${col1}$ WHERE id=${id}$
|
||||||
|
```
|
||||||
|
5. 触发 `beforeUpdate` / `afterUpdate` 钩子
|
||||||
|
|
||||||
|
##### 返回:
|
||||||
|
- 更新后的完整数据对象
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `async D(data, **kw)`
|
||||||
|
|
||||||
|
删除记录(Delete)。
|
||||||
|
|
||||||
|
##### 参数:
|
||||||
|
- `data` (dict): 包含主键字段的字典
|
||||||
|
|
||||||
|
##### 流程:
|
||||||
|
1. 构造 WHERE 条件(所有主键字段 AND 连接)
|
||||||
|
2. 执行删除语句:
|
||||||
|
```sql
|
||||||
|
DELETE FROM table WHERE id=${id}$
|
||||||
|
```
|
||||||
|
3. 触发 `beforeDelete` / `afterDelete` 钩子
|
||||||
|
|
||||||
|
##### 返回:
|
||||||
|
- 被删除的数据副本(可用于日志或通知)
|
||||||
|
|
||||||
|
> ⚠️ 注意:未实现软删除,为物理删除。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 示例用法
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 初始化数据库连接池(仅一次)
|
||||||
|
DBPools({
|
||||||
|
"ambi": {
|
||||||
|
"driver": "pymssql",
|
||||||
|
"coding": "utf-8",
|
||||||
|
"dbname": "ambi",
|
||||||
|
"kwargs": {
|
||||||
|
"user": "ymq",
|
||||||
|
"password": "ymq123",
|
||||||
|
"host": "localhost",
|
||||||
|
"database": "ambi"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
# 创建 CRUD 实例
|
||||||
|
crud = CRUD('ambi', 'cashflow')
|
||||||
|
|
||||||
|
# 查询全部数据(分页)
|
||||||
|
data = await crud.R(NS={'page': 1})
|
||||||
|
print(f"总数: {data.total}")
|
||||||
|
for row in data.rows:
|
||||||
|
print(row.balance, row.asid)
|
||||||
|
|
||||||
|
# 插入一条记录
|
||||||
|
new_id = await crud.C({
|
||||||
|
"balance": 1000.5,
|
||||||
|
"asid": "A001"
|
||||||
|
})
|
||||||
|
print("新建ID:", new_id)
|
||||||
|
|
||||||
|
# 更新
|
||||||
|
await crud.U({
|
||||||
|
"id": 123,
|
||||||
|
"balance": 1500.0
|
||||||
|
})
|
||||||
|
|
||||||
|
# 删除
|
||||||
|
await crud.D({"id": 123})
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 注意事项与扩展机制
|
||||||
|
|
||||||
|
### ✅ 已支持特性:
|
||||||
|
- ✅ 异步非阻塞 I/O
|
||||||
|
- ✅ 多数据库连接池管理
|
||||||
|
- ✅ 自动主键识别与处理
|
||||||
|
- ✅ 输入/输出类型自动转换
|
||||||
|
- ✅ 支持分页、排序、条件查询
|
||||||
|
- ✅ 前端 DataGrid 快速生成
|
||||||
|
- ✅ 通过 `ObjectAction` 实现事件钩子扩展:
|
||||||
|
- `beforeAdd`, `afterAdd`
|
||||||
|
- `beforeRetrieve`, `afterRetrieve`
|
||||||
|
- `beforeUpdate`, `afterUpdate`
|
||||||
|
- `beforeDelete`, `afterDelete`
|
||||||
|
- `tableInfo`, `datagrid`
|
||||||
|
|
||||||
|
### ⚠️ 注意事项:
|
||||||
|
1. **主键要求**:所有表应明确定义主键,否则部分功能异常。
|
||||||
|
2. **字段大小写敏感性**:输入建议统一小写,内部会做 `.lower()` 处理。
|
||||||
|
3. **安全机制**:使用 `${field}$` 占位符 + 参数绑定防止 SQL 注入(依赖底层 `inSqlor` 实现)。
|
||||||
|
4. **时间格式**:`date` 和 `time` 类型需确保 `str2Date` 和 `date2str` 支持正确格式。
|
||||||
|
5. **外键未用于级联操作**:当前仅提供信息获取,不自动处理关联数据。
|
||||||
|
|
||||||
|
### 🔧 扩展建议:
|
||||||
|
- 在 `ObjectAction` 中注册钩子函数以增强业务逻辑:
|
||||||
|
```python
|
||||||
|
oa.bind("ambi_cashflow.beforeAdd", my_audit_log)
|
||||||
|
```
|
||||||
|
- 自定义 `defaultIOField` 输出更多控件类型(如 dropdown, datebox)。
|
||||||
|
- 扩展 `toStringFuncs` / `fromStringFuncs` 支持更多类型(如 bool, json)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 附录:钩子事件命名规范
|
||||||
|
|
||||||
|
| 事件点 | 触发时机 | 推荐用途 |
|
||||||
|
|-------|---------|--------|
|
||||||
|
| `{db}_{table}.tableInfo` | 获取字段信息后 | 修改字段显示属性 |
|
||||||
|
| `{db}_{table}.datagrid` | 生成 datagrid 配置后 | 自定义 UI 布局 |
|
||||||
|
| `{db}_{table}.beforeAdd` | 插入前 | 数据校验、权限检查、默认值填充 |
|
||||||
|
| `{db}_{table}.afterAdd` | 插入成功后 | 日志记录、消息通知 |
|
||||||
|
| `{db}_{table}.beforeRetrieve` | 查询前 | 动态过滤(如租户隔离) |
|
||||||
|
| `{db}_{table}.afterRetrieve` | 查询返回前 | 敏感字段脱敏 |
|
||||||
|
| `{db}_{table}.beforeUpdate` | 更新前 | 审计、状态流转控制 |
|
||||||
|
| `{db}_{table}.afterUpdate` | 更新完成后 | 发布事件 |
|
||||||
|
| `{db}_{table}.beforeDelete` | 删除前 | 软删除替换、引用检测 |
|
||||||
|
| `{db}_{table}.afterDelete` | 删除后 | 清理关联资源 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> 📝 文档版本:v1.0
|
||||||
|
> © 2025 应用公共平台开发组
|
||||||
327
aidocs/dbpools.md
Normal file
327
aidocs/dbpools.md
Normal file
@ -0,0 +1,327 @@
|
|||||||
|
以下是为提供的 Python 代码编写的 **Markdown 格式技术文档**,涵盖了模块功能、类说明、函数接口、使用方式及关键设计思想。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# `dbor` 模块技术文档
|
||||||
|
|
||||||
|
> 数据库操作抽象层与连接池管理(支持同步/异步)
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
`dbor` 是一个轻量级的数据库操作抽象框架,提供统一接口访问多种数据库(如 MySQL、PostgreSQL、SQLite、Oracle、SQL Server),并支持 **同步与异步模式**。该模块通过工厂模式创建数据库适配器,并结合连接池机制提升性能和资源利用率。
|
||||||
|
|
||||||
|
主要特性:
|
||||||
|
- 支持主流关系型数据库
|
||||||
|
- 同步与异步双模式运行
|
||||||
|
- 自动连接池管理
|
||||||
|
- 单例全局数据库池控制器
|
||||||
|
- 配置驱动式数据库接入
|
||||||
|
- 安全密码解密(RC4)
|
||||||
|
- 上下文管理器自动提交/回滚
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 依赖说明
|
||||||
|
|
||||||
|
```python
|
||||||
|
import asyncio
|
||||||
|
from functools import wraps
|
||||||
|
from contextlib import asynccontextmanager
|
||||||
|
import threading
|
||||||
|
```
|
||||||
|
|
||||||
|
自定义模块依赖(需确保路径正确):
|
||||||
|
- `appPublic.myImport`:动态导入模块
|
||||||
|
- `appPublic.dictObject`:字典对象封装
|
||||||
|
- `appPublic.Singleton`:单例装饰器
|
||||||
|
- `appPublic.myjson.loadf`:加载 JSON 文件
|
||||||
|
- `appPublic.jsonConfig.getConfig`:配置读取
|
||||||
|
- `appPublic.rc4.unpassword`:RC4 密码解密
|
||||||
|
- `appPublic.log.exception`:异常日志记录
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 核心组件
|
||||||
|
|
||||||
|
### 1. `sqlorFactory(dbdesc) → SQLor`
|
||||||
|
|
||||||
|
根据数据库描述信息实例化对应的数据库操作对象。
|
||||||
|
|
||||||
|
#### 参数
|
||||||
|
| 参数名 | 类型 | 说明 |
|
||||||
|
|--------|--------|----|
|
||||||
|
| `dbdesc` | `dict` | 数据库配置字典,必须包含 `'driver'` 字段 |
|
||||||
|
|
||||||
|
#### 返回值
|
||||||
|
- 继承自 `SQLor` 的具体数据库操作实例(如 `MySqlor`, `AioMysqlor` 等)
|
||||||
|
- 若未匹配到子类,则返回基础 `SQLor` 实例
|
||||||
|
|
||||||
|
#### 示例配置结构
|
||||||
|
```python
|
||||||
|
{
|
||||||
|
"driver": "mysql.connector",
|
||||||
|
"async_mode": False,
|
||||||
|
"kwargs": {
|
||||||
|
"host": "localhost",
|
||||||
|
"user": "root",
|
||||||
|
"password": "enc:xxxxx", # RC4 加密后的密码
|
||||||
|
"database": "testdb"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. `sqlorFromFile(dbdef_file, coding='utf8') → SQLor`
|
||||||
|
|
||||||
|
从 JSON 配置文件加载数据库定义并生成对应操作实例。
|
||||||
|
|
||||||
|
#### 参数
|
||||||
|
| 参数名 | 类型 | 默认值 | 说明 |
|
||||||
|
|------------|--------|--------|----|
|
||||||
|
| `dbdef_file` | `str` | - | JSON 配置文件路径 |
|
||||||
|
| `coding` | `str` | `'utf8'` | 文件编码格式 |
|
||||||
|
|
||||||
|
#### 示例
|
||||||
|
```python
|
||||||
|
sor = sqlorFromFile('/path/to/db.json')
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 连接生命周期管理:`LifeConnect`
|
||||||
|
|
||||||
|
封装单个数据库连接的生命周期控制,包括健康检测、重连机制、使用计数等。
|
||||||
|
|
||||||
|
### 构造函数
|
||||||
|
```python
|
||||||
|
LifeConnect(connfunc, kw, use_max=1000, async_mode=False)
|
||||||
|
```
|
||||||
|
|
||||||
|
| 参数 | 类型 | 说明 |
|
||||||
|
|------------|----------|----|
|
||||||
|
| `connfunc` | `callable` | 创建连接的函数(如 `sqlite3.connect`) |
|
||||||
|
| `kw` | `dict` | 连接参数 |
|
||||||
|
| `use_max` | `int` | 最大使用次数后关闭连接,默认 `1000` |
|
||||||
|
| `async_mode` | `bool` | 是否异步模式 |
|
||||||
|
|
||||||
|
### 方法
|
||||||
|
|
||||||
|
| 方法名 | 异步 | 说明 |
|
||||||
|
|------------|------|----|
|
||||||
|
| `use()` | ✅ | 获取可用连接,失败时尝试重建 |
|
||||||
|
| `free(conn)`| ✅ | 释放连接(暂未启用最大使用限制逻辑) |
|
||||||
|
| `testok()` | ✅ | 测试连接是否正常(执行 `SELECT 1`) |
|
||||||
|
| `_mkconn()` | ✅ | 内部方法:创建新连接 |
|
||||||
|
|
||||||
|
> ⚠️ 注意:当前 `free()` 中关于 `use_cnt >= use_max` 的判断被注释,不会触发自动关闭。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 连接池:`ConnectionPool`
|
||||||
|
|
||||||
|
管理某一数据库的所有连接,实现连接复用。
|
||||||
|
|
||||||
|
### 构造函数
|
||||||
|
```python
|
||||||
|
ConnectionPool(dbdesc, loop)
|
||||||
|
```
|
||||||
|
|
||||||
|
| 参数 | 类型 | 说明 |
|
||||||
|
|----------|---------------|----|
|
||||||
|
| `dbdesc` | `dict` | 数据库配置 |
|
||||||
|
| `loop` | `asyncio.EventLoop` | 异步事件循环 |
|
||||||
|
|
||||||
|
### 属性
|
||||||
|
| 属性 | 类型 | 说明 |
|
||||||
|
|--------------|------------------|----|
|
||||||
|
| `maxconn` | `int` | 最大连接数(默认 5) |
|
||||||
|
| `maxuse` | `int` | 每连接最大使用次数 |
|
||||||
|
| `_pool` | `asyncio.Queue` | 存放 `LifeConnect` 实例的队列 |
|
||||||
|
| `connectObject`| `dict` | 当前活跃连接映射表 |
|
||||||
|
|
||||||
|
### 方法
|
||||||
|
|
||||||
|
| 方法 | 异步 | 说明 |
|
||||||
|
|----------------|------|----|
|
||||||
|
| `connect()` | ✅ | 创建一个 `LifeConnect` 并放入池中 |
|
||||||
|
| `aquire()` | ✅ | 从池中获取可用连接 |
|
||||||
|
| `release(conn)` | ✅ | 释放连接回池 |
|
||||||
|
| `isEmpty()` | ❌ | 判断池是否为空 |
|
||||||
|
| `isFull()` | ❌ | 判断池是否已满 |
|
||||||
|
| `_fillPool()` | ✅ | 初始化填充连接池至最大容量 |
|
||||||
|
|
||||||
|
> 📝 注:目前 `_fillPool()` 调用后并未实际等待完成,存在潜在问题。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 全局数据库池管理器:`DBPools`(单例)
|
||||||
|
|
||||||
|
使用 `@SingletonDecorator` 装饰,保证全局唯一实例,统一管理多个数据库连接池。
|
||||||
|
|
||||||
|
### 构造函数
|
||||||
|
```python
|
||||||
|
DBPools(databases={}, max_connect=100, loop=None)
|
||||||
|
```
|
||||||
|
|
||||||
|
| 参数 | 类型 | 说明 |
|
||||||
|
|--------------|--------|----|
|
||||||
|
| `databases` | `dict` | 数据库名称 → 配置字典的映射 |
|
||||||
|
| `max_connect` | `int` | 全局最大并发连接数限制 |
|
||||||
|
| `loop` | `EventLoop` | 可选事件循环 |
|
||||||
|
|
||||||
|
### 属性
|
||||||
|
| 属性 | 类型 | 说明 |
|
||||||
|
|-------------|-------------------|----|
|
||||||
|
| `sema` | `asyncio.Semaphore` | 控制总连接数信号量 |
|
||||||
|
| `_cpools` | `dict` | 数据库名 → `ConnectionPool` 映射 |
|
||||||
|
| `databases` | `dict` | 所有注册数据库配置 |
|
||||||
|
| `meta` | `dict` | 预留元数据存储 |
|
||||||
|
| `e_except` | `Exception` | 上下文中捕获的异常 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 核心方法
|
||||||
|
|
||||||
|
#### `addDatabase(name, desc)`
|
||||||
|
注册新的数据库配置。
|
||||||
|
|
||||||
|
```python
|
||||||
|
dbpools.addDatabase('devdb', {
|
||||||
|
'driver': 'aiomysql',
|
||||||
|
'async_mode': True,
|
||||||
|
'kwargs': { ... }
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `get_dbname(name) → str or None`
|
||||||
|
获取数据库逻辑名对应的实际数据库名(`dbname`),若无则返回 `None`。
|
||||||
|
|
||||||
|
#### `isAsyncDriver(dbname) → bool`
|
||||||
|
判断指定数据库是否运行在异步模式下。
|
||||||
|
|
||||||
|
#### `getSqlor(name) → SQLor`
|
||||||
|
获取指定数据库的操作对象(含连接和游标)。
|
||||||
|
|
||||||
|
- 使用信号量控制并发
|
||||||
|
- 自动建立底层连接与游标
|
||||||
|
- 返回已绑定连接的 `SQLor` 实例
|
||||||
|
|
||||||
|
#### `freeSqlor(sor)`
|
||||||
|
释放由 `getSqlor()` 获取的 `SQLor` 实例,归还连接并释放信号量。
|
||||||
|
|
||||||
|
#### `sqlorContext(name)`
|
||||||
|
**异步上下文管理器**,推荐使用的安全访问方式。
|
||||||
|
|
||||||
|
```python
|
||||||
|
async with dbpools.sqlorContext('mydb') as sor:
|
||||||
|
await sor.execute('SELECT * FROM users')
|
||||||
|
result = await sor.fetchall()
|
||||||
|
# 自动 commit
|
||||||
|
```
|
||||||
|
|
||||||
|
##### 行为逻辑
|
||||||
|
- 成功退出:自动提交事务(如果 `dataChanged == True`)
|
||||||
|
- 抛出异常:记录日志 + 回滚事务(如有更改)
|
||||||
|
- 始终执行:释放连接资源
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 内部方法(不建议直接调用)
|
||||||
|
|
||||||
|
| 方法 | 异步 | 说明 |
|
||||||
|
|--------------------|------|----|
|
||||||
|
| `_aquireConn(dbname)` | ✅ | 获取连接、游标三元组 `(async_mode, conn, cur)` |
|
||||||
|
| `_releaseConn(...)` | ✅ | 关闭游标与连接,归还至池 |
|
||||||
|
|
||||||
|
> 🔐 密码处理:在 `_aquireConn` 中自动调用 `unpassword(pw)` 解密。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 支持的数据库驱动
|
||||||
|
|
||||||
|
| 驱动模块 | 同步类 | 异步类 | 支持情况 |
|
||||||
|
|---------------------|----------------|------------------|-------|
|
||||||
|
| `sqlite3` | `SQLite3or` | `Aiosqliteor` | ✅ |
|
||||||
|
| `mysql.connector` | `MySqlor` | `AioMysqlor` | ✅ |
|
||||||
|
| `psycopg2` / `asyncpg` | `SQLor` 扩展 | `AioPostgresqlor`| ✅ |
|
||||||
|
| `cx_Oracle` | `Oracleor` | (暂无异步) | ✅ |
|
||||||
|
| `pyodbc` / `pymssql`| `SQLor` 扩展 | `MsSqlor` | ✅ |
|
||||||
|
|
||||||
|
> 💡 提示:所有驱动需继承 `SQLor` 并实现 `isMe(driver_name)` 类方法用于识别。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 使用示例
|
||||||
|
|
||||||
|
### 步骤 1:初始化 DBPools(应用启动时)
|
||||||
|
|
||||||
|
```python
|
||||||
|
from appPublic.jsonConfig import getConfig
|
||||||
|
from your_module import DBPools
|
||||||
|
|
||||||
|
config = getConfig() # 加载全局配置
|
||||||
|
dbpools = DBPools(databases=config.databases, loop=asyncio.get_event_loop())
|
||||||
|
```
|
||||||
|
|
||||||
|
### 步骤 2:使用上下文访问数据库
|
||||||
|
|
||||||
|
```python
|
||||||
|
async def fetch_users():
|
||||||
|
async with dbpools.sqlorContext('users_db') as sor:
|
||||||
|
await sor.execute('SELECT id, name FROM users LIMIT 10')
|
||||||
|
rows = await sor.fetchall()
|
||||||
|
return rows
|
||||||
|
```
|
||||||
|
|
||||||
|
### 步骤 3:手动获取/释放(高级用法)
|
||||||
|
|
||||||
|
```python
|
||||||
|
async def manual_usage():
|
||||||
|
sor = await dbpools.getSqlor('reporting')
|
||||||
|
try:
|
||||||
|
await sor.execute('UPDATE stats SET processed=1 WHERE flag=0')
|
||||||
|
await sor.commit()
|
||||||
|
except:
|
||||||
|
await sor.rollback()
|
||||||
|
finally:
|
||||||
|
await dbpools.freeSqlor(sor)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 安全与日志
|
||||||
|
|
||||||
|
- 所有密码字段通过 `unpassword()` 解密(基于 RC4)
|
||||||
|
- 异常通过 `appPublic.log.exception()` 记录堆栈
|
||||||
|
- 上下文管理器自动处理事务完整性
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 已知问题与改进建议
|
||||||
|
|
||||||
|
| 问题 | 描述 | 建议 |
|
||||||
|
|-----|------|------|
|
||||||
|
| `free()` 方法中 `use_max` 逻辑被注释 | 连接无法按使用次数回收 | 恢复条件判断逻辑 |
|
||||||
|
| `_fillPool()` 未 await 循环 | 初始连接可能未完全建立 | 改为批量 `asyncio.gather()` |
|
||||||
|
| `lock` 相关代码被注释 | 缺少并发保护 | 若多线程需启用锁机制 |
|
||||||
|
| `print()` 方法仅调试用途 | 应移除或改为日志输出 | 删除或替换为 logger.debug |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 总结
|
||||||
|
|
||||||
|
`dbor` 提供了一个灵活、可扩展的数据库访问架构,适用于中小型项目中的多数据库统一管理场景。其核心优势在于:
|
||||||
|
|
||||||
|
✅ 统一接口
|
||||||
|
✅ 异步友好
|
||||||
|
✅ 自动资源管理
|
||||||
|
✅ 安全配置支持
|
||||||
|
|
||||||
|
适合集成进 Web 框架(如 FastAPI、Tornado)或后台服务系统中作为 ORM 替代方案。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> 文档版本:v1.0
|
||||||
|
> 编写时间:2025年4月5日
|
||||||
|
> 适用代码版本:请以实际提交为准
|
||||||
536
aidocs/dbpools.old.md
Normal file
536
aidocs/dbpools.old.md
Normal file
@ -0,0 +1,536 @@
|
|||||||
|
以下是为提供的 Python 异步数据库连接与操作代码编写的 **Markdown 格式技术文档**,涵盖模块功能、类结构、核心方法说明及使用示例。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 📚 `dbpool` 模块技术文档
|
||||||
|
|
||||||
|
> 基于异步 I/O 的通用数据库连接池与 SQL 执行封装系统
|
||||||
|
> 支持多种数据库驱动(SQLite、MySQL、PostgreSQL、Oracle、SQL Server)的同步/异步模式
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 概述
|
||||||
|
|
||||||
|
本模块提供了一个可扩展、高性能的异步数据库访问框架,主要特性包括:
|
||||||
|
|
||||||
|
- ✅ 多数据库支持:通过插件式设计支持多种数据库
|
||||||
|
- ✅ 异步连接池管理(基于 `asyncio.Queue`)
|
||||||
|
- ✅ 自动重连与健康检测机制
|
||||||
|
- ✅ 单例全局连接池管理器 `DBPools`
|
||||||
|
- ✅ 装饰器简化 SQL 执行流程
|
||||||
|
- ✅ 元数据缓存优化表结构查询性能
|
||||||
|
- ✅ 事务自动提交/回滚控制
|
||||||
|
|
||||||
|
适用于高并发 Web 应用或微服务中对数据库资源进行统一管理和高效复用。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📦 导入依赖
|
||||||
|
|
||||||
|
```python
|
||||||
|
import asyncio
|
||||||
|
from functools import wraps
|
||||||
|
from contextlib import asynccontextmanager
|
||||||
|
|
||||||
|
# 内部工具库
|
||||||
|
from appPublic.myImport import myImport
|
||||||
|
from appPublic.dictObject import DictObject
|
||||||
|
from appPublic.Singleton import SingletonDecorator
|
||||||
|
from appPublic.myjson import loadf
|
||||||
|
from appPublic.jsonConfig import getConfig
|
||||||
|
from appPublic.rc4 import unpassword
|
||||||
|
from appPublic.log import exception
|
||||||
|
```
|
||||||
|
|
||||||
|
外部依赖:
|
||||||
|
- `aiosqlite`, `aiomysql`, `asyncpg` 等异步驱动需根据实际数据库安装
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🏗️ 核心组件架构
|
||||||
|
|
||||||
|
| 组件 | 功能 |
|
||||||
|
|------|------|
|
||||||
|
| `SQLor` 子类 | 数据库抽象层,封装增删改查逻辑 |
|
||||||
|
| `sqlorFactory()` | 工厂函数,根据配置创建对应的 `SQLor` 实例 |
|
||||||
|
| `LifeConnect` | 封装单个连接的生命期与可用性测试 |
|
||||||
|
| `ConnectionPool` | 连接池实现,维护固定数量的活跃连接 |
|
||||||
|
| `DBPools` | 单例全局连接池管理器,支持多数据库 |
|
||||||
|
| 装饰器 (`@runSQL`, `@inSqlor`) | 简化业务函数中的数据库调用 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧱 抽象接口:`SQLor` 及其子类
|
||||||
|
|
||||||
|
所有数据库适配器继承自基类 `SQLor`,并实现以下关键方法:
|
||||||
|
|
||||||
|
```python
|
||||||
|
class SQLor:
|
||||||
|
def isMe(driver_name: str) -> bool: ...
|
||||||
|
async def tables() -> List[str]: ...
|
||||||
|
async def fields(table: str) -> List[FieldInfo]: ...
|
||||||
|
async def primary(table: str) -> List[str]: ...
|
||||||
|
async def indexes(table: str) -> List[IndexInfo]: ...
|
||||||
|
async def fkeys(table: str) -> List[ForeignKeyInfo]: ...
|
||||||
|
async def runSQL(desc: dict, ns: dict) -> Any: ...
|
||||||
|
async def runSQLPaging(desc: dict, ns: dict) -> Dict: ...
|
||||||
|
```
|
||||||
|
|
||||||
|
### 当前支持的数据库驱动
|
||||||
|
|
||||||
|
| 驱动名 | 类 | 文件 |
|
||||||
|
|--------|----|------|
|
||||||
|
| sqlite3 | `SQLite3or` / `Aiosqliteor` | `.sqlite3or`, `.aiosqliteor` |
|
||||||
|
| mysql | `MySqlor` / `AioMysqlor` | `.mysqlor`, `.aiomysqlor` |
|
||||||
|
| postgresql | `AioPostgresqlor` | `.aiopostgresqlor` |
|
||||||
|
| mssql | `MsSqlor` | `.mssqlor` |
|
||||||
|
| oracle | `Oracleor` | `.oracleor` |
|
||||||
|
|
||||||
|
> 同步和异步版本分别处理阻塞/非阻塞场景。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚙️ 工厂函数
|
||||||
|
|
||||||
|
### `sqlorFactory(dbdesc) → SQLor`
|
||||||
|
|
||||||
|
根据数据库描述字典动态选择合适的 `SQLor` 子类实例。
|
||||||
|
|
||||||
|
#### 参数
|
||||||
|
|
||||||
|
| 参数 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `dbdesc` | `dict` | 包含 `'driver'` 和 `'kwargs'` 的数据库连接信息 |
|
||||||
|
|
||||||
|
#### 示例
|
||||||
|
|
||||||
|
```python
|
||||||
|
dbdesc = {
|
||||||
|
"driver": "aiomysql",
|
||||||
|
"kwargs": {
|
||||||
|
"host": "localhost",
|
||||||
|
"port": 3306,
|
||||||
|
"user": "root",
|
||||||
|
"password": "enc:xxxxx",
|
||||||
|
"database": "test"
|
||||||
|
},
|
||||||
|
"async_mode": True
|
||||||
|
}
|
||||||
|
sor = sqlorFactory(dbdesc)
|
||||||
|
```
|
||||||
|
|
||||||
|
> 若未找到匹配驱动,则返回默认 `SQLor` 实例。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `sqlorFromFile(dbdef_file, coding='utf8') → SQLor`
|
||||||
|
|
||||||
|
从 JSON 文件加载数据库配置并初始化 `SQLor` 实例。
|
||||||
|
|
||||||
|
#### 参数
|
||||||
|
|
||||||
|
| 参数 | 类型 | 默认值 | 说明 |
|
||||||
|
|------|------|--------|------|
|
||||||
|
| `dbdef_file` | `str` | - | JSON 配置文件路径 |
|
||||||
|
| `coding` | `str` | `'utf8'` | 文件编码格式 |
|
||||||
|
|
||||||
|
#### 示例文件内容 (`config/db.json`)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"driver": "sqlite3",
|
||||||
|
"kwargs": {
|
||||||
|
"dbname": "/tmp/test.db"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 使用方式
|
||||||
|
```python
|
||||||
|
sor = await sqlorFromFile("config/db.json")
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔌 连接生命期管理:`LifeConnect`
|
||||||
|
|
||||||
|
封装单个数据库连接的生命周期,具备自动重建能力。
|
||||||
|
|
||||||
|
### 初始化参数
|
||||||
|
|
||||||
|
| 属性 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `connfunc` | 创建连接的函数(如 `aiomysql.connect`) |
|
||||||
|
| `kw` | 传递给 `connfunc` 的关键字参数 |
|
||||||
|
| `use_max` | 最大使用次数后强制关闭 |
|
||||||
|
| `async_mode` | 是否启用异步模式 |
|
||||||
|
|
||||||
|
### 方法
|
||||||
|
|
||||||
|
| 方法 | 返回类型 | 说明 |
|
||||||
|
|------|----------|------|
|
||||||
|
| `use()` | `awaitable<connection>` | 获取一个有效连接,失败时尝试重建 |
|
||||||
|
| `free(conn)` | `None` | 标记连接已释放(暂不关闭) |
|
||||||
|
| `testok()` | `awaitable<bool>` | 测试连接是否正常(执行 `SELECT 1`) |
|
||||||
|
| `_mkconn()` | `awaitable` | 内部创建新连接 |
|
||||||
|
|
||||||
|
> 在获取连接时会自动探测断连并尝试重新建立最多 4 次。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 连接池:`ConnectionPool`
|
||||||
|
|
||||||
|
每个数据库拥有独立的连接池,基于 `asyncio.Queue` 实现先进先出调度。
|
||||||
|
|
||||||
|
### 初始化参数
|
||||||
|
|
||||||
|
| 参数 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `dbdesc` | 数据库配置对象 |
|
||||||
|
| `loop` | 事件循环引用 |
|
||||||
|
|
||||||
|
### 属性
|
||||||
|
|
||||||
|
| 属性 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `maxconn` | 最大连接数(默认 5) |
|
||||||
|
| `maxuse` | 单连接最大使用次数(默认 1000) |
|
||||||
|
| `_pool` | 存放 `LifeConnect` 实例的队列 |
|
||||||
|
|
||||||
|
### 关键方法
|
||||||
|
|
||||||
|
| 方法 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `connect()` | 创建新的 `LifeConnect` 并放入池中 |
|
||||||
|
| `aquire()` | 异步获取可用连接 |
|
||||||
|
| `release(conn)` | 释放连接回池中 |
|
||||||
|
| `isEmpty()` / `isFull()` | 查询池状态 |
|
||||||
|
|
||||||
|
> 注意:当前未启用锁保护共享状态,建议在单线程协程环境下运行。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🌐 全局连接池管理器:`DBPools`(单例)
|
||||||
|
|
||||||
|
使用 `@SingletonDecorator` 保证全局唯一实例。
|
||||||
|
|
||||||
|
### 构造参数
|
||||||
|
|
||||||
|
| 参数 | 类型 | 默认值 | 说明 |
|
||||||
|
|------|------|--------|------|
|
||||||
|
| `databases` | `dict` | `{}` | 名称映射到数据库配置 |
|
||||||
|
| `max_connect` | `int` | `100` | 全局限流信号量 |
|
||||||
|
| `loop` | `asyncio.AbstractEventLoop` | `get_event_loop()` | 事件循环 |
|
||||||
|
|
||||||
|
### 示例配置
|
||||||
|
|
||||||
|
```python
|
||||||
|
databases = {
|
||||||
|
'default': {
|
||||||
|
'driver': 'aiomysql',
|
||||||
|
'async_mode': True,
|
||||||
|
'kwargs': { ... }
|
||||||
|
},
|
||||||
|
'local_sqlite': {
|
||||||
|
'driver': 'sqlite3',
|
||||||
|
'async_mode': False,
|
||||||
|
'kwargs': {'dbname': '/tmp/app.db'}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pools = DBPools(databases=databases)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💡 核心 API 方法
|
||||||
|
|
||||||
|
### `getSqlor(name) → SQLor`
|
||||||
|
|
||||||
|
获取指定名称的数据库操作对象(带连接绑定)。
|
||||||
|
|
||||||
|
```python
|
||||||
|
sor = await pools.getSqlor('default')
|
||||||
|
```
|
||||||
|
|
||||||
|
> 自动申请连接、游标,并设置上下文。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `freeSqlor(sor)`
|
||||||
|
|
||||||
|
释放 `SQLor` 占用的连接资源。
|
||||||
|
|
||||||
|
```python
|
||||||
|
await pools.freeSqlor(sor)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `@sqlorContext(name) → Async Context Manager`
|
||||||
|
|
||||||
|
推荐使用的上下文管理器,自动处理连接获取、事务提交/回滚、异常捕获与释放。
|
||||||
|
|
||||||
|
#### 示例
|
||||||
|
|
||||||
|
```python
|
||||||
|
async with pools.sqlorContext('default') as sor:
|
||||||
|
ret = await sor.runSQL({"sql_string": "SELECT * FROM users"})
|
||||||
|
```
|
||||||
|
|
||||||
|
> - 出现异常且有数据变更 → 自动 `rollback`
|
||||||
|
> - 正常退出 → 自动 `commit`
|
||||||
|
> - 总是释放连接
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `useOrGetSor(dbname, **kw) → (sor, commit_flag)`
|
||||||
|
|
||||||
|
内部工具函数:若传入了 `sor` 则复用,否则新建。
|
||||||
|
|
||||||
|
用于嵌套调用时避免重复连接开销。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 装饰器 API(简化开发)
|
||||||
|
|
||||||
|
### `@inSqlor(func)`
|
||||||
|
|
||||||
|
装饰业务函数,自动注入 `sor` 对象,支持事务控制。
|
||||||
|
|
||||||
|
```python
|
||||||
|
@pools.inSqlor
|
||||||
|
async def get_user(dbname, NS, user_id, **kw):
|
||||||
|
sor = kw['sor']
|
||||||
|
return await sor.selectOne("users", {"id": user_id})
|
||||||
|
```
|
||||||
|
|
||||||
|
调用方式:
|
||||||
|
```python
|
||||||
|
ret = await get_user('default', {}, user_id=123)
|
||||||
|
```
|
||||||
|
|
||||||
|
> 若未传 `sor`,则自动申请;否则复用传入的 `sor`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `@runSQL(func)`
|
||||||
|
|
||||||
|
装饰函数返回 SQL 描述对象,然后执行它。
|
||||||
|
|
||||||
|
```python
|
||||||
|
@pools.runSQL
|
||||||
|
async def list_users(dbname, NS, dept_id, **kw):
|
||||||
|
return {
|
||||||
|
"sql_string": "SELECT * FROM users WHERE dept_id=?",
|
||||||
|
"args": [dept_id]
|
||||||
|
}
|
||||||
|
|
||||||
|
# 调用
|
||||||
|
result = await list_users('default', {}, dept_id=5)
|
||||||
|
```
|
||||||
|
|
||||||
|
> 自动执行 SQL、提交事务(如需)、释放连接。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `@runSQLPaging(func)`
|
||||||
|
|
||||||
|
分页查询专用装饰器,结合 `sor.runSQLPaging()` 使用。
|
||||||
|
|
||||||
|
```python
|
||||||
|
@pools.runSQLPaging
|
||||||
|
async def search_users_paged(dbname, NS, keyword, page=1, pagesize=10):
|
||||||
|
return {
|
||||||
|
"sql_string": "SELECT id,name FROM users WHERE name LIKE ?",
|
||||||
|
"args": [f"%{keyword}%"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
返回格式:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"page": 1,
|
||||||
|
"pagesize": 10,
|
||||||
|
"total": 87,
|
||||||
|
"data": [...]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `@runSQLResultFields(func)`
|
||||||
|
|
||||||
|
获取查询结果字段定义(元数据),常用于动态表单生成。
|
||||||
|
|
||||||
|
```python
|
||||||
|
@pools.runSQLResultFields
|
||||||
|
async def describe_query(dbname, NS, table):
|
||||||
|
return {"sql_string": f"SELECT * FROM {table} LIMIT 1"}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔍 元数据查询接口
|
||||||
|
|
||||||
|
提升性能:结果缓存在内存中。
|
||||||
|
|
||||||
|
| 方法 | 作用 |
|
||||||
|
|------|------|
|
||||||
|
| `getTables(dbname)` | 获取所有表名列表 |
|
||||||
|
| `getTableFields(dbname, tblname)` | 获取某表字段结构 |
|
||||||
|
| `getTablePrimaryKey(dbname, tblname)` | 获取主键字段 |
|
||||||
|
| `getTableIndexes(dbname, tblname)` | 获取索引信息 |
|
||||||
|
| `getTableForignKeys(dbname, tblname)` | 获取外键关系 |
|
||||||
|
|
||||||
|
> 所有方法均带本地缓存,默认以 `"dbname:tablename"` 为键。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠️ 辅助函数
|
||||||
|
|
||||||
|
### `runSQL(dbname, sql, ns={}, sor=None)`
|
||||||
|
|
||||||
|
快速执行一条原始 SQL。
|
||||||
|
|
||||||
|
```python
|
||||||
|
result = await runSQL(
|
||||||
|
dbname='default',
|
||||||
|
sql='SELECT COUNT(*) AS cnt FROM users'
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
> 推荐仅用于简单脚本或调试。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `runSQLPaging(dbname, sql, ns={}, sor=None)`
|
||||||
|
|
||||||
|
快速执行分页 SQL。
|
||||||
|
|
||||||
|
```python
|
||||||
|
paged = await runSQLPaging(
|
||||||
|
dbname='default',
|
||||||
|
sql='SELECT id,name FROM users ORDER BY id',
|
||||||
|
ns={'page': 2, 'pagesize': 10}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔐 安全相关
|
||||||
|
|
||||||
|
- 密码字段支持加密标记:`"password": "enc:xxxxxx"`
|
||||||
|
- 使用 `unpassword(pw)` 解密(RC4 加密算法,需确保密钥一致)
|
||||||
|
- 不建议生产环境明文存储密码
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📐 配置结构规范(JSON)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"driver": "aiomysql",
|
||||||
|
"async_mode": true,
|
||||||
|
"maxconn": 10,
|
||||||
|
"maxuse": 500,
|
||||||
|
"kwargs": {
|
||||||
|
"host": "127.0.0.1",
|
||||||
|
"port": 3306,
|
||||||
|
"user": "appuser",
|
||||||
|
"password": "enc:xxxxxxxx",
|
||||||
|
"database": "myapp_db"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> 支持字段:
|
||||||
|
- `driver`: 必须匹配导入路径下的模块名
|
||||||
|
- `async_mode`: 控制异步行为
|
||||||
|
- `kwargs`: 透传给底层驱动
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 使用示例
|
||||||
|
|
||||||
|
### 1. 初始化连接池
|
||||||
|
|
||||||
|
```python
|
||||||
|
from your_module import DBPools
|
||||||
|
|
||||||
|
config = loadf("db.json") # 加载配置
|
||||||
|
pools = DBPools(databases={"prod": config})
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 执行普通查询
|
||||||
|
|
||||||
|
```python
|
||||||
|
async def main():
|
||||||
|
async with pools.sqlorContext("prod") as sor:
|
||||||
|
users = await sor.select("users", where={"status": 1})
|
||||||
|
print(users)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 分页查询用户
|
||||||
|
|
||||||
|
```python
|
||||||
|
@pools.runSQLPaging
|
||||||
|
async def query_active_users(dbname, NS, status=1):
|
||||||
|
return {
|
||||||
|
"sql_string": "SELECT id,name,email FROM users WHERE status=?",
|
||||||
|
"args": [status]
|
||||||
|
}
|
||||||
|
|
||||||
|
result = await query_active_users("prod", {"page": 1, "pagesize": 20})
|
||||||
|
print(result)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ 注意事项
|
||||||
|
|
||||||
|
1. **异步模式必须使用异步驱动**
|
||||||
|
- 如 `aiomysql`, `asyncpg`, `aiosqlite`
|
||||||
|
2. **不要手动调用 `close()` 游标或连接**
|
||||||
|
- 应由 `DBPools` 统一管理
|
||||||
|
3. **避免长时间持有 `sor` 实例**
|
||||||
|
- 建议使用 `sqlorContext` 上下文管理器
|
||||||
|
4. **元数据缓存不会自动刷新**
|
||||||
|
- 表结构变更后需重启服务或手动清理 `meta`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📈 性能建议
|
||||||
|
|
||||||
|
- 设置合理的 `maxconn`(通常 ≤ CPU 核心数 × 2)
|
||||||
|
- `maxuse` 可防止长连接老化导致的问题
|
||||||
|
- 生产环境建议开启日志监控连接健康状况
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📎 附录 A:错误处理策略
|
||||||
|
|
||||||
|
| 场景 | 处理方式 |
|
||||||
|
|------|-----------|
|
||||||
|
| 连接中断 | 尝试重建最多 4 次 |
|
||||||
|
| 查询异常 | 记录 traceback 日志 |
|
||||||
|
| 事务失败 | 自动 rollback 并抛出原异常 |
|
||||||
|
| 密码解密失败 | 抛出异常(需检查 RC4 密钥) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📎 附录 B:未来改进方向
|
||||||
|
|
||||||
|
- [ ] 添加连接池监控指标(Prometheus)
|
||||||
|
- [ ] 支持读写分离
|
||||||
|
- [ ] 更细粒度的超时控制
|
||||||
|
- [ ] SQL 拦截器(审计/日志)
|
||||||
|
- [ ] 连接泄漏检测机制
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> ✅ 文档版本:v1.0
|
||||||
|
> 📅 更新时间:2025-04-05
|
||||||
|
> © 2025 Your Company. All Rights Reserved.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
📌 提示:将此文档保存为 `README.md` 或集成至 Sphinx/Wiki 中便于团队查阅。
|
||||||
270
aidocs/ddl_template_mysql.md
Normal file
270
aidocs/ddl_template_mysql.md
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
以下是为提供的 Jinja2 模板代码编写的 **Markdown 格式技术文档**,适用于数据库建模或自动化 DDL 生成场景。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# MySQL DDL 自动生成模板技术文档
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
本模板是一个基于 [Jinja2](https://jinja.palletsprojects.com/) 的 SQL DDL(数据定义语言)生成模板,用于根据元数据自动生成 MySQL 表的 `CREATE TABLE` 和相关索引语句。支持字段类型映射、默认值、非空约束、主键、注释以及普通/唯一索引的创建。
|
||||||
|
|
||||||
|
该模板可用于数据建模工具、ETL 流程配置、数据库初始化脚本等自动化场景。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 模板变量说明
|
||||||
|
|
||||||
|
模板依赖以下上下文变量:
|
||||||
|
|
||||||
|
| 变量名 | 类型 | 说明 |
|
||||||
|
|------------|------------|------|
|
||||||
|
| `summary` | 列表 | 表结构摘要信息列表,通常只包含一个元素(当前表),如:`summary[0].name`, `summary[0].primary`, `summary[0].title` |
|
||||||
|
| `fields` | 列表 | 字段列表,每个字段包含名称、类型、长度、小数位、是否可为空、默认值、标题(注释)等属性 |
|
||||||
|
| `indexes` | 列表 | 索引定义列表,每个索引包含名称、类型(`index` 或 `unique`)、字段列表 |
|
||||||
|
|
||||||
|
### `summary[0]` 结构示例
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "user_info",
|
||||||
|
"primary": ["id"],
|
||||||
|
"title": "用户基本信息表"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `field` 结构示例
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "age",
|
||||||
|
"type": "int",
|
||||||
|
"length": 11,
|
||||||
|
"dec": 0,
|
||||||
|
"nullable": "no",
|
||||||
|
"default": "0",
|
||||||
|
"title": "年龄"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `index` 结构示例
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "idx_email",
|
||||||
|
"idxtype": "unique",
|
||||||
|
"idxfields": ["email"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "idx_status",
|
||||||
|
"idxtype": "index",
|
||||||
|
"idxfields": ["status", "create_time"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 宏函数(Macros)
|
||||||
|
|
||||||
|
模板中定义了多个辅助宏函数,用于格式化 SQL 片段。
|
||||||
|
|
||||||
|
### `typeStr(type, len, dec)`
|
||||||
|
将高级字段类型转换为对应的 MySQL 数据类型。
|
||||||
|
|
||||||
|
| 输入类型(`type`) | 输出 MySQL 类型 |
|
||||||
|
|---------------------|------------------|
|
||||||
|
| `str` | `VARCHAR(len)` |
|
||||||
|
| `char` | `CHAR(len)` |
|
||||||
|
| `int`, `long`, `short` | `int` |
|
||||||
|
| `long`(单独判断) | `bigint` |
|
||||||
|
| `float`, `double`, `ddouble` | `double(len, dec)` |
|
||||||
|
| `date` | `date` |
|
||||||
|
| `time` | `time` |
|
||||||
|
| `datetime` | `datetime` |
|
||||||
|
| `timestamp` | `TIMESTAMP DEFAULT CURRENT_TIMESTAMP` |
|
||||||
|
| `text` | `longtext` |
|
||||||
|
| `bin` | `longblob` |
|
||||||
|
| 其他未知类型 | 原样输出 `{{type}}` |
|
||||||
|
|
||||||
|
> ⚠️ 注意:`long` 类型在第一个条件中被映射为 `int`,但在后续又被单独判断为 `bigint` —— 这可能导致逻辑冲突,见下方【注意事项】。
|
||||||
|
|
||||||
|
### `defaultValue(defaultv)`
|
||||||
|
生成字段的默认值子句。
|
||||||
|
|
||||||
|
- 若 `defaultv` 存在,则输出:`DEFAULT 'value'`
|
||||||
|
- 若为空,则不输出任何内容
|
||||||
|
|
||||||
|
> 所有默认值均以字符串形式包裹(使用单引号),适合文本和数字;时间类型需确保传入格式正确。
|
||||||
|
|
||||||
|
### `nullStr(nullable)`
|
||||||
|
控制字段是否允许为空。
|
||||||
|
|
||||||
|
- 若 `nullable == 'no'` → 输出 `NOT NULL`
|
||||||
|
- 否则不输出
|
||||||
|
|
||||||
|
> 推荐约定:`yes/no` 表示可空性,也可扩展为布尔值处理。
|
||||||
|
|
||||||
|
### `primary()`
|
||||||
|
生成主键定义语句。
|
||||||
|
|
||||||
|
- 使用 `summary[0].primary` 中的字段名列表,用逗号连接
|
||||||
|
- 输出:`, primary key (col1,col2,...)`
|
||||||
|
|
||||||
|
> 注意:此宏前会自动换行并缩进,需配合字段列表使用。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 生成的 SQL 内容结构
|
||||||
|
|
||||||
|
### 1. 删除已有表
|
||||||
|
```sql
|
||||||
|
DROP TABLE IF EXISTS {{summary[0].name}};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 创建新表
|
||||||
|
```sql
|
||||||
|
CREATE TABLE table_name (
|
||||||
|
`field1` type ... [NOT NULL] [DEFAULT '...'] [COMMENT '...'],
|
||||||
|
...
|
||||||
|
[PRIMARY KEY (pk_fields)]
|
||||||
|
)
|
||||||
|
ENGINE=InnoDB
|
||||||
|
DEFAULT CHARSET=utf8
|
||||||
|
[COMMENT='表注释'];
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 创建索引
|
||||||
|
遍历 `indexes` 数组,生成:
|
||||||
|
```sql
|
||||||
|
CREATE [UNIQUE] INDEX index_name ON table_name(field1, field2);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 示例输出
|
||||||
|
|
||||||
|
假设输入如下元数据:
|
||||||
|
|
||||||
|
```python
|
||||||
|
summary = [{
|
||||||
|
"name": "user",
|
||||||
|
"primary": ["id"],
|
||||||
|
"title": "用户表"
|
||||||
|
}]
|
||||||
|
|
||||||
|
fields = [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"type": "long",
|
||||||
|
"length": 20,
|
||||||
|
"dec": 0,
|
||||||
|
"nullable": "no",
|
||||||
|
"default": "",
|
||||||
|
"title": "用户ID"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "username",
|
||||||
|
"type": "str",
|
||||||
|
"length": 50,
|
||||||
|
"dec": 0,
|
||||||
|
"nullable": "no",
|
||||||
|
"default": "",
|
||||||
|
"title": "用户名"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"length": 0,
|
||||||
|
"dec": 0,
|
||||||
|
"nullable": "yes",
|
||||||
|
"default": "",
|
||||||
|
"title": "创建时间"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
indexes = [
|
||||||
|
{
|
||||||
|
"name": "uk_username",
|
||||||
|
"idxtype": "unique",
|
||||||
|
"idxfields": ["username"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 生成的 SQL:
|
||||||
|
```sql
|
||||||
|
DROP TABLE IF EXISTS user;
|
||||||
|
CREATE TABLE user
|
||||||
|
(
|
||||||
|
`id` bigint NOT NULL,
|
||||||
|
`username` VARCHAR(50) NOT NULL,
|
||||||
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
)
|
||||||
|
engine=innodb
|
||||||
|
default charset=utf8
|
||||||
|
comment '用户表';
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX user_uk_username ON user(username);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 注意事项与建议
|
||||||
|
|
||||||
|
1. ❗ **类型判断逻辑问题**:
|
||||||
|
```jinja2
|
||||||
|
{% elif type=='long' or type=='int' or type=='short' %}
|
||||||
|
int
|
||||||
|
{% elif type=='long' %}
|
||||||
|
bigint
|
||||||
|
```
|
||||||
|
上述逻辑中,`long` 已在第一个分支被捕获为 `int`,因此永远不会进入 `bigint` 分支!
|
||||||
|
✅ **修复建议**:
|
||||||
|
```jinja2
|
||||||
|
{%- if type == 'long' -%}
|
||||||
|
bigint
|
||||||
|
{%- elif type in ['int', 'short'] -%}
|
||||||
|
int
|
||||||
|
```
|
||||||
|
|
||||||
|
2. 🔤 所有字符串默认值都加了单引号,若需支持数值型默认值(如 `DEFAULT 0`),应做类型区分。
|
||||||
|
|
||||||
|
3. 🧩 `summary` 设计为列表形式,但实际仅使用 `summary[0]`,可考虑简化为直接对象传参。
|
||||||
|
|
||||||
|
4. 💬 注释建议统一使用 UTF-8 编码,避免中文乱码。
|
||||||
|
|
||||||
|
5. 🔐 生产环境建议增加 SQL 注入风险校验(如字段名、表名合法性验证)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 使用方式(Python 示例)
|
||||||
|
|
||||||
|
```python
|
||||||
|
from jinja2 import Template
|
||||||
|
|
||||||
|
# 加载模板
|
||||||
|
tpl = Template(mysql_ddl_tmpl)
|
||||||
|
|
||||||
|
# 渲染 SQL
|
||||||
|
sql = tpl.render(summary=summary, fields=fields, indexes=indexes)
|
||||||
|
|
||||||
|
print(sql)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 版本历史
|
||||||
|
|
||||||
|
| 版本 | 日期 | 描述 |
|
||||||
|
|------|------------|------|
|
||||||
|
| 1.0 | 2025-04 | 初始版本,支持基础字段类型与索引生成 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 许可与维护
|
||||||
|
|
||||||
|
- **作者**:Auto-generated
|
||||||
|
- **用途**:内部系统 / 数据仓库建模
|
||||||
|
- **维护建议**:结合 Schema JSON 配置驱动模板渲染,提升可维护性。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
✅ 文档结束
|
||||||
222
aidocs/ddl_template_oracle.md
Normal file
222
aidocs/ddl_template_oracle.md
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
以下是为提供的 Jinja2 模板代码编写的 **Markdown 格式技术文档**,适用于 Oracle 数据库 DDL 生成场景。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Oracle DDL 模板技术文档
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
`oracle_ddl_tmpl` 是一个基于 [Jinja2](https://jinja.palletsprojects.com/) 的模板字符串,用于自动生成 Oracle 数据库表的 **数据定义语言 (DDL)** 脚本。该模板支持字段类型映射、主键定义、索引创建以及注释添加等功能,适用于自动化建模或元数据驱动的数据库构建流程。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 使用场景
|
||||||
|
|
||||||
|
- 自动化生成 Oracle 表结构(`CREATE TABLE`)
|
||||||
|
- 支持字段级和表级中文注释
|
||||||
|
- 支持主键、唯一/普通索引定义
|
||||||
|
- 可集成至 ETL 工具、数据建模平台或 CI/CD 流程中
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 模板变量说明
|
||||||
|
|
||||||
|
### 输入上下文参数
|
||||||
|
|
||||||
|
| 参数名 | 类型 | 说明 |
|
||||||
|
|--------|------|------|
|
||||||
|
| `summary[0]` | 对象 | 表元数据对象,包含表名、标题、主键等信息 |
|
||||||
|
| `.name` | 字符串 | 表名(如:`EMPLOYEE`) |
|
||||||
|
| `.title` | 字符串 | 表中文描述(用于 COMMENT) |
|
||||||
|
| `.primary` | 列表 | 主键字段名称列表(如:`['ID']`) |
|
||||||
|
| `fields` | 列表 | 字段对象列表,每个字段包含属性如名称、类型、长度等 |
|
||||||
|
| `indexes` | 列表 | 索引对象列表,定义索引类型与字段 |
|
||||||
|
|
||||||
|
#### `fields` 中单个字段对象结构
|
||||||
|
|
||||||
|
| 属性 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `name` | 字符串 | 字段英文名(如:`EMP_NAME`) |
|
||||||
|
| `type` | 字符串 | 字段逻辑类型(见下文映射规则) |
|
||||||
|
| `length` | 整数 | 字段长度(对数值/字符类型有效) |
|
||||||
|
| `dec` | 整数 | 小数位数(仅对浮点类型有效) |
|
||||||
|
| `nullable` | 字符串 | 是否可为空:`yes` / `no` |
|
||||||
|
| `title` | 字符串 | 字段中文描述(用于 COMMENT) |
|
||||||
|
|
||||||
|
#### `indexes` 中单个索引对象结构
|
||||||
|
|
||||||
|
| 属性 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `name` | 字符串 | 索引标识名(将用于生成索引名) |
|
||||||
|
| `idxtype` | 字符串 | 索引类型:`unique` 或其他(非 unique 视为普通索引) |
|
||||||
|
| `idxfields` | 列表 | 索引包含的字段名列表(如:`['DEPT_ID', 'STATUS']`) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 模板功能详解
|
||||||
|
|
||||||
|
### 宏定义(Macros)
|
||||||
|
|
||||||
|
#### `typeStr(type, len, dec)`
|
||||||
|
根据字段逻辑类型映射为 Oracle 原生数据类型。
|
||||||
|
|
||||||
|
| 逻辑类型 | Oracle 实际类型 | 示例输出 |
|
||||||
|
|----------|------------------|-----------|
|
||||||
|
| `str` | `VARCHAR2(len)` | `VARCHAR2(50)` |
|
||||||
|
| `char` | `CHAR(len)` | `CHAR(10)` |
|
||||||
|
| `long`, `int`, `short` | `NUMBER` | `NUMBER` |
|
||||||
|
| `float`, `double`, `ddouble` | `NUMBER(len, dec)` | `NUMBER(10, 2)` |
|
||||||
|
| `date`, `time` | `DATE` | `DATE` |
|
||||||
|
| `timestamp` | `TIMESTAMP` | `TIMESTAMP` |
|
||||||
|
| `text` | `CLOB` | `CLOB` |
|
||||||
|
| `bin` | `BLOB` | `BLOB` |
|
||||||
|
| 其他未知类型 | 原样输出 `{{type}}` | 如:`XMLTYPE` |
|
||||||
|
|
||||||
|
> ⚠️ 注意:`len` 和 `dec` 需在输入数据中提供,否则可能导致渲染错误。
|
||||||
|
|
||||||
|
#### `nullStr(nullable)`
|
||||||
|
判断字段是否非空。
|
||||||
|
|
||||||
|
- 若 `nullable == 'no'` → 输出 `NOT NULL`
|
||||||
|
- 否则不输出任何内容(即允许为空)
|
||||||
|
|
||||||
|
#### `primary()`
|
||||||
|
生成主键约束子句。
|
||||||
|
|
||||||
|
- 使用 `summary[0].primary` 列表中的字段名拼接
|
||||||
|
- 输出格式:`, primary key (col1,col2,...)`
|
||||||
|
|
||||||
|
> ✅ 提示:此宏前需确保已有字段定义,并以逗号分隔最后一个字段。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 主体 DDL 语句结构
|
||||||
|
|
||||||
|
#### 1. 删除旧表
|
||||||
|
```sql
|
||||||
|
drop table {{summary[0].name}};
|
||||||
|
```
|
||||||
|
> ⚠️ 警告:无条件删除同名表,请谨慎使用于生产环境。
|
||||||
|
|
||||||
|
#### 2. 创建新表
|
||||||
|
```sql
|
||||||
|
CREATE TABLE {{summary[0].name}}
|
||||||
|
(
|
||||||
|
-- 字段列表循环生成 --
|
||||||
|
{% for field in fields %}
|
||||||
|
{{field.name}} {{typeStr(...)}} {{nullStr(...)}}{%- if not loop.last %},{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
-- 主键定义(如有)--
|
||||||
|
{% if summary[0].primary and len(summary[0].primary)>0 %}
|
||||||
|
{{primary()}}
|
||||||
|
{% endif %}
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3. 创建索引
|
||||||
|
```sql
|
||||||
|
{% for v in indexes %}
|
||||||
|
CREATE {% if v.idxtype=='unique' %}UNIQUE{% endif %} INDEX
|
||||||
|
{{summary[0].name}}_{{v.name}}
|
||||||
|
ON {{summary[0].name}}({{",".join(v.idxfields)}});
|
||||||
|
{% endfor %}
|
||||||
|
```
|
||||||
|
- 自动生成命名规则:`表名_索引名`
|
||||||
|
- 支持唯一索引标记
|
||||||
|
|
||||||
|
#### 4. 添加注释
|
||||||
|
```sql
|
||||||
|
COMMENT ON TABLE {{summary[0].name}} IS '{{summary[0].title}}';
|
||||||
|
|
||||||
|
{% for field in fields %}
|
||||||
|
COMMENT ON COLUMN {{summary[0].name}}.{{field.name}} IS '{{field.title}}';
|
||||||
|
{% endfor %}
|
||||||
|
```
|
||||||
|
> ✅ 支持中文注释,提升数据库可读性与维护性。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 示例输出(片段)
|
||||||
|
|
||||||
|
假设输入如下:
|
||||||
|
```python
|
||||||
|
summary = [{
|
||||||
|
"name": "EMPLOYEE",
|
||||||
|
"title": "员工信息表",
|
||||||
|
"primary": ["EMP_ID"]
|
||||||
|
}]
|
||||||
|
fields = [
|
||||||
|
{"name": "EMP_ID", "type": "long", "nullable": "no", "title": "员工ID"},
|
||||||
|
{"name": "EMP_NAME", "type": "str", "length": 100, "nullable": "no", "title": "姓名"},
|
||||||
|
{"name": "SALARY", "type": "double", "length": 12, "dec": 2, "nullable": "yes", "title": "薪资"}
|
||||||
|
]
|
||||||
|
indexes = [
|
||||||
|
{"name": "IDX_NAME", "idxtype": "unique", "idxfields": ["EMP_NAME"]}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
生成 SQL 片段:
|
||||||
|
```sql
|
||||||
|
drop table EMPLOYEE;
|
||||||
|
CREATE TABLE EMPLOYEE
|
||||||
|
(
|
||||||
|
EMP_ID NUMBER NOT NULL,
|
||||||
|
EMP_NAME VARCHAR2(100) NOT NULL,
|
||||||
|
SALARY NUMBER(12,2)
|
||||||
|
,primary key(EMP_ID)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX EMPLOYEE_IDX_NAME ON EMPLOYEE(EMP_NAME);
|
||||||
|
|
||||||
|
COMMENT ON TABLE EMPLOYEE IS '员工信息表';
|
||||||
|
COMMENT ON COLUMN EMPLOYEE.EMP_ID is '员工ID';
|
||||||
|
COMMENT ON COLUMN EMPLOYEE.EMP_NAME is '姓名';
|
||||||
|
COMMENT ON COLUMN EMPLOYEE.SALARY is '薪资';
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 注意事项与最佳实践
|
||||||
|
|
||||||
|
1. **安全性警告**
|
||||||
|
- `DROP TABLE` 会清除现有数据,请确认是否需要保留历史数据。
|
||||||
|
- 建议在正式环境中禁用自动 drop,或增加条件判断。
|
||||||
|
|
||||||
|
2. **字段类型扩展**
|
||||||
|
- 当前仅覆盖常见类型,如需支持 `XMLTYPE`、`INTERVAL` 等,可通过 `else` 分支直接传入原生类型。
|
||||||
|
|
||||||
|
3. **索引命名规范**
|
||||||
|
- 推荐保持 `表名_索引名` 的简洁风格,避免过长或冲突。
|
||||||
|
|
||||||
|
4. **Jinja2 渲染要求**
|
||||||
|
- 必须保证传入的数据结构完整,避免访问不存在的属性导致异常。
|
||||||
|
- 建议进行前置校验(如字段必填项检查)。
|
||||||
|
|
||||||
|
5. **字符集与存储**
|
||||||
|
- `VARCHAR2` 和 `CHAR` 默认按字节计算,若需按字符建议手动调整或通过外部配置处理。
|
||||||
|
|
||||||
|
6. **CLOB/BLOB 存储优化**
|
||||||
|
- 大对象字段可能影响性能,建议结合业务需求设置合理的存储参数(当前模板未包含)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 扩展建议
|
||||||
|
|
||||||
|
- 添加 `IF NOT EXISTS` 判断(Oracle 不原生支持,可用 PL/SQL 包装)
|
||||||
|
- 支持外键约束生成
|
||||||
|
- 支持分区表语法
|
||||||
|
- 引入模板配置层,实现多数据库兼容(如 MySQL、PostgreSQL)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 许可与维护
|
||||||
|
|
||||||
|
- **作者**:Auto-generated Template
|
||||||
|
- **用途**:内部系统自动化建模
|
||||||
|
- **依赖**:Python + Jinja2 >= 3.0
|
||||||
|
- **更新时间**:2025年4月5日
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
✅ 文档结束。可用于团队知识共享、项目文档归档或工具集成说明。
|
||||||
242
aidocs/ddl_template_postgresql.md
Normal file
242
aidocs/ddl_template_postgresql.md
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
以下是为提供的 Jinja2 模板代码编写的 **Markdown 格式技术文档**,用于描述该 PostgreSQL DDL 生成模板的功能、结构和使用方式。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# PostgreSQL DDL 生成模板技术文档
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
`postgresql_ddl_tmpl` 是一个基于 **Jinja2 模板引擎**的字符串模板,用于自动生成符合 PostgreSQL 语法的 **数据定义语言 (DDL)** 脚本。它可以根据表结构元数据(如字段类型、长度、是否可为空、主键、索引等)动态生成完整的 `CREATE TABLE` 语句,包括:
|
||||||
|
|
||||||
|
- 表的创建与删除
|
||||||
|
- 字段定义及其数据类型映射
|
||||||
|
- 主键约束
|
||||||
|
- 索引(普通或唯一)
|
||||||
|
- 表和字段的注释
|
||||||
|
|
||||||
|
该模板适用于自动化建模工具、ETL 流程或数据库同步系统中,实现从元数据到物理表结构的自动转换。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 模板源码
|
||||||
|
|
||||||
|
```python
|
||||||
|
postgresql_ddl_tmpl = """{% macro typeStr(type,len,dec) %}
|
||||||
|
{%- if type=='str' -%}
|
||||||
|
VARCHAR({{len}})
|
||||||
|
{%- elif type=='char' -%}
|
||||||
|
CHAR({{len}})
|
||||||
|
{%- elif type=='long' or type=='int' or type=='short' -%}
|
||||||
|
NUMERIC(30,0)
|
||||||
|
{%- elif type=='float' or type=='double' or type=='ddouble' -%}
|
||||||
|
NUMERIC({{len}},{{dec}})
|
||||||
|
{%- elif type=='date' -%}
|
||||||
|
DATE
|
||||||
|
{%- elif type=='time' -%}
|
||||||
|
TIME
|
||||||
|
{%- elif type=='timestamp' -%}
|
||||||
|
TIMESTAMP
|
||||||
|
{%- else -%}
|
||||||
|
{{type}}
|
||||||
|
{%- endif %}
|
||||||
|
{%- endmacro %}
|
||||||
|
{% macro nullStr(nullable) %}
|
||||||
|
{%- if nullable=='no' -%}
|
||||||
|
NOT NULL
|
||||||
|
{%- endif -%}
|
||||||
|
{% endmacro %}
|
||||||
|
{% macro primary() %}
|
||||||
|
,PRIMARY KEY({{','.join(summary[0].primary)}})
|
||||||
|
{% endmacro %}
|
||||||
|
DROP TABLE IF EXISTS {{summary[0].name}};
|
||||||
|
CREATE TABLE {{summary[0].name}}
|
||||||
|
(
|
||||||
|
{% for field in fields %}
|
||||||
|
{{field.name}} {{typeStr(field.type,field.length,field.dec)}} {{nullStr(field.nullable)}}{%- if not loop.last -%},{%- endif -%}
|
||||||
|
{% endfor %}
|
||||||
|
{% if summary[0].primary and len(summary[0].primary)>0 %}
|
||||||
|
{{primary()}}
|
||||||
|
{% endif %}
|
||||||
|
);
|
||||||
|
{% for v in indexes %}
|
||||||
|
CREATE {% if v.idxtype=='unique' %}UNIQUE{% endif %} INDEX {{summary[0].name}}_{{v.name}} ON {{summary[0].name}}({{",".join(v.idxfields)}});
|
||||||
|
{%- endfor -%}
|
||||||
|
COMMENT ON TABLE {{summary[0].name}} IS '{{summary[0].title}}';
|
||||||
|
{% for field in fields %}
|
||||||
|
COMMENT ON COLUMN {{summary[0].name}}.{{field.name}} is '{{field.title}}';
|
||||||
|
{% endfor %}
|
||||||
|
"""
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 模板变量说明
|
||||||
|
|
||||||
|
| 变量名 | 类型 | 描述 |
|
||||||
|
|-------|------|------|
|
||||||
|
| `summary[0]` | 对象 | 包含表级别的元信息对象,必须是列表且第一个元素有效 |
|
||||||
|
| `.name` | 字符串 | 表名(如 `"users"`) |
|
||||||
|
| `.title` | 字符串 | 表的中文/描述性标题,用于 COMMENT |
|
||||||
|
| `.primary` | 列表 | 主键字段名称列表(如 `["id"]` 或 `["user_id", "tenant_id"]`) |
|
||||||
|
| `fields` | 列表 | 字段对象列表,每个对象代表一列 |
|
||||||
|
| `.name` | 字符串 | 字段名(如 `"username"`) |
|
||||||
|
| `.type` | 字符串 | 字段逻辑类型(见下文“类型映射”) |
|
||||||
|
| `.length` | 整数 | 字段长度(对字符串和数值类型有意义) |
|
||||||
|
| `.dec` | 整数 | 小数位数(decimal scale) |
|
||||||
|
| `.nullable` | 字符串 | 是否允许为空:`"yes"` 表示可空,`"no"` 表示 `NOT NULL` |
|
||||||
|
| `.title` | 字符串 | 字段的中文/描述性标题,用于 COMMENT |
|
||||||
|
| `indexes` | 列表 | 索引定义对象列表 |
|
||||||
|
| `.name` | 字符串 | 索引名称标识(将用于生成索引名) |
|
||||||
|
| `.idxtype` | 字符串 | 索引类型,若为 `"unique"` 则创建唯一索引 |
|
||||||
|
| `.idxfields` | 列表 | 索引包含的字段名列表(如 `["email"]` 或 `["status", "created_time"]`) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 内置宏(Macros)
|
||||||
|
|
||||||
|
### `typeStr(type, len, dec)`
|
||||||
|
根据字段的逻辑类型映射为 PostgreSQL 实际数据类型。
|
||||||
|
|
||||||
|
| 逻辑类型 | 映射结果 |
|
||||||
|
|---------|--------|
|
||||||
|
| `'str'` | `VARCHAR(len)` |
|
||||||
|
| `'char'` | `CHAR(len)` |
|
||||||
|
| `'long'`, `'int'`, `'short'` | `NUMERIC(30,0)` (高精度整数) |
|
||||||
|
| `'float'`, `'double'`, `'ddouble'` | `NUMERIC(len, dec)` |
|
||||||
|
| `'date'` | `DATE` |
|
||||||
|
| `'time'` | `TIME` |
|
||||||
|
| `'timestamp'` | `TIMESTAMP` |
|
||||||
|
| 其他未知类型 | 原样输出 `{{type}}`(可用于扩展) |
|
||||||
|
|
||||||
|
> ⚠️ 注意:浮点类型统一使用 `NUMERIC` 以保证精度;如需性能优化可后续调整为 `REAL` / `DOUBLE PRECISION`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `nullStr(nullable)`
|
||||||
|
生成 `NOT NULL` 约束。
|
||||||
|
|
||||||
|
- 若 `nullable == 'no'` → 输出 `NOT NULL`
|
||||||
|
- 否则不输出任何内容(即允许为空)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `primary()`
|
||||||
|
生成主键约束子句。
|
||||||
|
|
||||||
|
- 使用 `summary[0].primary` 中的字段名,通过逗号拼接
|
||||||
|
- 示例:主键为 `["id"]` → 输出 `,PRIMARY KEY(id)`
|
||||||
|
- 注意:前面有一个英文逗号,依赖前一行结尾,因此必须确保前面有换行和逗号处理
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 生成的 DDL 结构说明
|
||||||
|
|
||||||
|
1. **删除旧表**
|
||||||
|
```sql
|
||||||
|
DROP TABLE IF EXISTS table_name;
|
||||||
|
```
|
||||||
|
> 避免重复建表错误。
|
||||||
|
|
||||||
|
2. **创建新表**
|
||||||
|
```sql
|
||||||
|
CREATE TABLE table_name (...);
|
||||||
|
```
|
||||||
|
- 包含所有字段定义
|
||||||
|
- 自动添加主键约束(如果存在)
|
||||||
|
- 支持多字段联合主键
|
||||||
|
|
||||||
|
3. **创建索引**
|
||||||
|
```sql
|
||||||
|
CREATE [UNIQUE] INDEX table_name_idxname ON table_name(field1, field2);
|
||||||
|
```
|
||||||
|
- 支持普通索引和唯一索引
|
||||||
|
- 索引命名规则:`{table_name}_{index_name}`
|
||||||
|
|
||||||
|
4. **添加注释**
|
||||||
|
```sql
|
||||||
|
COMMENT ON TABLE table_name IS '用户信息表';
|
||||||
|
COMMENT ON COLUMN table_name.username IS '用户名';
|
||||||
|
```
|
||||||
|
- 提升数据库可读性和文档性
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 使用示例
|
||||||
|
|
||||||
|
假设输入上下文如下(Python 字典形式):
|
||||||
|
|
||||||
|
```python
|
||||||
|
context = {
|
||||||
|
"summary": [{
|
||||||
|
"name": "users",
|
||||||
|
"title": "用户信息表",
|
||||||
|
"primary": ["id"]
|
||||||
|
}],
|
||||||
|
"fields": [
|
||||||
|
{"name": "id", "type": "long", "length": 30, "dec": 0, "nullable": "no", "title": "用户ID"},
|
||||||
|
{"name": "username", "type": "str", "length": 50, "dec": 0, "nullable": "no", "title": "用户名"},
|
||||||
|
{"name": "email", "type": "str", "length": 100, "dec": 0, "nullable": "yes", "title": "邮箱地址"},
|
||||||
|
{"name": "created_time", "type": "timestamp", "length": 0, "dec": 0, "nullable": "no", "title": "创建时间"}
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
{"name": "email_idx", "idxtype": "unique", "idxfields": ["email"]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
渲染后输出 SQL:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
DROP TABLE IF EXISTS users;
|
||||||
|
CREATE TABLE users
|
||||||
|
(
|
||||||
|
id NUMERIC(30,0) NOT NULL,
|
||||||
|
username VARCHAR(50) NOT NULL,
|
||||||
|
email VARCHAR(100),
|
||||||
|
created_time TIMESTAMP NOT NULL,
|
||||||
|
PRIMARY KEY(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX users_email_idx ON users(email);
|
||||||
|
|
||||||
|
COMMENT ON TABLE users IS '用户信息表';
|
||||||
|
COMMENT ON COLUMN users.id is '用户ID';
|
||||||
|
COMMENT ON COLUMN users.username is '用户名';
|
||||||
|
COMMENT ON COLUMN users.email is '邮箱地址';
|
||||||
|
COMMENT ON COLUMN users.created_time is '创建时间';
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 扩展建议
|
||||||
|
|
||||||
|
- ✅ **支持默认值**:可在字段中增加 `.default` 属性,并在模板中扩展。
|
||||||
|
- ✅ **外键支持**:当前未处理外键,可根据需要添加 `FOREIGN KEY` 子句。
|
||||||
|
- ✅ **字符集/排序规则**:PostgreSQL 通常使用数据库级设置,也可显式指定。
|
||||||
|
- ✅ **分区表支持**:复杂场景下可扩展模板支持 `PARTITION BY`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
1. `primary()` 宏前会自动加 `,`,因此必须确保前面字段定义已正确结束并换行。
|
||||||
|
2. 所有字段的 `length` 和 `dec` 必须提供,即使某些类型不需要(可用占位值如 `0`)。
|
||||||
|
3. `summary` 必须是一个非空列表,`summary[0]` 是实际使用的表元数据。
|
||||||
|
4. 索引名应避免冲突,推荐命名清晰(如 `idx_status`)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 总结
|
||||||
|
|
||||||
|
`postgresql_ddl_tmpl` 是一个功能完整、结构清晰的 DDL 自动生成模板,适合集成进元数据驱动的数据平台。其优势在于:
|
||||||
|
|
||||||
|
- 类型抽象良好,便于业务人员理解
|
||||||
|
- 支持常见约束与注释
|
||||||
|
- 易于维护和扩展
|
||||||
|
|
||||||
|
通过此模板,可以高效地将模型设计转化为可执行的数据库脚本,提升开发效率与一致性。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
✅ *文档版本:1.0*
|
||||||
|
📅 *最后更新:2025年4月5日*
|
||||||
204
aidocs/ddl_template_sqlite3.md
Normal file
204
aidocs/ddl_template_sqlite3.md
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
以下是为提供的 Jinja2 模板代码编写的 **Markdown 格式技术文档**,适用于开发人员理解该模板的功能、结构和使用方式。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# SQLite3 DDL 生成模板技术文档
|
||||||
|
|
||||||
|
`sqlite3_ddl_tmpl` 是一个基于 [Jinja2](https://jinja.palletsprojects.com/) 的模板字符串,用于动态生成符合 SQLite3 语法的表定义(DDL)语句。它支持字段类型映射、空值约束、主键定义、注释以及索引创建。
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
- [功能概述](#功能概述)
|
||||||
|
- [模板变量说明](#模板变量说明)
|
||||||
|
- [宏(Macros)详解](#宏macros详解)
|
||||||
|
- [`typeStr(type, len, dec)`](#typestrtype-len-dec)
|
||||||
|
- [`nullStr(nullable)`](#nullstrnullable)
|
||||||
|
- [`primary()`](#primary)
|
||||||
|
- [生成的 DDL 结构](#生成的-ddl-结构)
|
||||||
|
- [输出示例](#输出示例)
|
||||||
|
- [使用场景](#使用场景)
|
||||||
|
- [注意事项](#注意事项)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 功能概述
|
||||||
|
|
||||||
|
此模板用于根据元数据自动生成如下内容:
|
||||||
|
|
||||||
|
1. 删除已存在的同名表(`DROP TABLE IF EXISTS`)
|
||||||
|
2. 创建新表(`CREATE TABLE`),包括:
|
||||||
|
- 字段名、类型、是否非空
|
||||||
|
- 字段级注释(通过 `--` 注释实现)
|
||||||
|
- 主键定义
|
||||||
|
3. 可选的唯一或普通索引创建(`CREATE INDEX` / `CREATE UNIQUE INDEX`)
|
||||||
|
|
||||||
|
所有逻辑均通过 Jinja2 模板语言实现,适合作为代码生成器的一部分,集成在 ORM 工具或数据库建模系统中。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 模板变量说明
|
||||||
|
|
||||||
|
| 变量 | 类型 | 描述 |
|
||||||
|
|------|------|------|
|
||||||
|
| `summary[0]` | dict/object | 表的摘要信息对象,包含:`name`(表名)、`primary`(主键字段列表)、`title`(表标题/描述) |
|
||||||
|
| `fields` | list | 字段列表,每个字段对象包含:<br>• `name`: 字段名<br>• `type`: 数据类型(如 `'str'`, `'int'` 等)<br>• `length`: 长度(可选)<br>• `dec`: 小数位数(可选)<br>• `nullable`: 是否允许为空(`'yes'` 或 `'no'`)<br>• `title`: 字段说明(作为注释显示) |
|
||||||
|
| `indexes` | list | 索引列表,每个索引对象包含:<br>• `name`: 索引名称<br>• `idxtype`: 索引类型(`'unique'` 或其他)<br>• `idxfields`: 构成索引的字段名列表 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 宏(Macros)详解
|
||||||
|
|
||||||
|
### `typeStr(type, len, dec)`
|
||||||
|
|
||||||
|
将高级数据类型转换为 SQLite 原生类型。
|
||||||
|
|
||||||
|
#### 参数:
|
||||||
|
- `type`: 字符串,表示原始类型(如 `'str'`, `'int'`, `'float'` 等)
|
||||||
|
- `len`: 字段长度(未使用于 SQLite 类型推断,仅保留接口兼容性)
|
||||||
|
- `dec`: 小数位数(同上)
|
||||||
|
|
||||||
|
#### 映射规则:
|
||||||
|
|
||||||
|
| 输入类型 | 输出 SQLite 类型 |
|
||||||
|
|---------|----------------|
|
||||||
|
| `str`, `char`, `date`, `time`, `datetime`, `timestamp` | `TEXT` |
|
||||||
|
| `long`, `int`, `short`, `longlong` | `INTEGER`(模板中写作 `int`) |
|
||||||
|
| `float`, `double`, `ddouble` | `REAL` |
|
||||||
|
| `bin` | `BLOB` |
|
||||||
|
| 其他未知类型 | 原样输出 `{{type}}` |
|
||||||
|
|
||||||
|
> ⚠️ 注意:SQLite 实际使用的是“类型亲和性”(Type Affinity),但此处简化处理以增强可读性和一致性。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `nullStr(nullable)`
|
||||||
|
|
||||||
|
生成 `NOT NULL` 约束条件。
|
||||||
|
|
||||||
|
#### 参数:
|
||||||
|
- `nullable`: `'no'` 表示不允许为空;其他值(如 `'yes'`)则不添加约束
|
||||||
|
|
||||||
|
#### 输出:
|
||||||
|
- 若 `nullable == 'no'` → 输出 `NOT NULL`
|
||||||
|
- 否则输出空字符串
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `primary()`
|
||||||
|
|
||||||
|
生成主键子句。
|
||||||
|
|
||||||
|
#### 逻辑:
|
||||||
|
- 使用 `summary[0].primary` 中的字段名列表,用逗号连接
|
||||||
|
- 添加 `, primary key(...)` 子句
|
||||||
|
|
||||||
|
#### 示例:
|
||||||
|
```sql
|
||||||
|
,primary key(id, code)
|
||||||
|
```
|
||||||
|
|
||||||
|
> ✅ 仅当存在主键且字段数 > 0 时才插入该行。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 生成的 DDL 结构
|
||||||
|
|
||||||
|
模板最终输出的标准 SQL 包括以下部分:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
DROP TABLE IF EXISTS <table_name>;
|
||||||
|
|
||||||
|
CREATE TABLE <table_name>
|
||||||
|
(
|
||||||
|
`field1` <type> <NOT NULL?> -- 字段说明
|
||||||
|
...
|
||||||
|
,primary key(pk_field1, pk_field2)
|
||||||
|
) -- 表说明 ;
|
||||||
|
|
||||||
|
CREATE INDEX|UNIQUE INDEX index_name ON table_name(field_list);
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
每条语句严格按照 SQLite 语法编写,并带有良好格式化与注释支持。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 输出示例
|
||||||
|
|
||||||
|
假设输入数据如下:
|
||||||
|
|
||||||
|
```python
|
||||||
|
summary = [{
|
||||||
|
"name": "users",
|
||||||
|
"primary": ["id"],
|
||||||
|
"title": "用户信息表"
|
||||||
|
}]
|
||||||
|
|
||||||
|
fields = [
|
||||||
|
{"name": "id", "type": "int", "nullable": "no", "title": "用户ID"},
|
||||||
|
{"name": "name", "type": "str", "length": 50, "nullable": "no", "title": "用户名"},
|
||||||
|
{"name": "email", "type": "str", "length": 100, "nullable": "yes", "title": "邮箱地址"},
|
||||||
|
{"name": "created_at", "type": "datetime", "nullable": "no", "title": "创建时间"}
|
||||||
|
]
|
||||||
|
|
||||||
|
indexes = [
|
||||||
|
{"name": "email_idx", "idxtype": "", "idxfields": ["email"]},
|
||||||
|
{"name": "uniq_name", "idxtype": "unique", "idxfields": ["name"]}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 生成的 SQL:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
drop table if exists users;
|
||||||
|
CREATE TABLE users
|
||||||
|
(
|
||||||
|
`id` int NOT NULL -- 用户ID,
|
||||||
|
`name` TEXT NOT NULL -- 用户名,
|
||||||
|
`email` TEXT -- 邮箱地址,
|
||||||
|
`created_at` TEXT NOT NULL -- 创建时间
|
||||||
|
,primary key(id)
|
||||||
|
) --用户信息表
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE INDEX users_email_idx ON users(email);
|
||||||
|
CREATE UNIQUE INDEX users_uniq_name ON users(name);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 使用场景
|
||||||
|
|
||||||
|
该模板适用于以下场景:
|
||||||
|
|
||||||
|
- 自动化数据库建模工具
|
||||||
|
- 数据字典到物理模型的转换
|
||||||
|
- 跨平台迁移时的目标 DDL 生成(特别是轻量级 SQLite 场景)
|
||||||
|
- 内嵌式应用初始化脚本生成
|
||||||
|
|
||||||
|
结合 Python 的 `jinja2.Template(sqlite3_ddl_tmpl).render(...)` 即可快速渲染出实际 SQL。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
1. **字段名使用反引号包裹**:确保特殊字符或关键字字段的安全性。
|
||||||
|
2. **SQLite 类型限制**:
|
||||||
|
- 实际存储依赖“动态类型”,但建议保持类型亲和性一致。
|
||||||
|
- 没有原生 `DATETIME` 类型,使用 `TEXT` 存储 ISO8601 时间字符串。
|
||||||
|
3. **主键语法位置**:主键定义位于字段之后,以逗号开头拼接,需注意前面是否有字段结尾的逗号。
|
||||||
|
4. **索引命名规范**:采用 `<table>_<index_name>` 形式避免冲突。
|
||||||
|
5. **注释支持**:利用 `--` 添加人类可读说明,不影响执行。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 版权与维护
|
||||||
|
|
||||||
|
- **作者**:Auto-generated Template
|
||||||
|
- **用途**:内部代码生成组件
|
||||||
|
- **建议扩展**:可根据需要增加默认值、外键等支持。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
✅ 文档版本:v1.0
|
||||||
|
📅 最后更新:2025-04-05
|
||||||
333
aidocs/ddl_template_sqlserver.md
Normal file
333
aidocs/ddl_template_sqlserver.md
Normal file
@ -0,0 +1,333 @@
|
|||||||
|
# SQL Server DDL 模板技术文档(Jinja2 模板)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 简介
|
||||||
|
|
||||||
|
`sqlserver_ddl_tmpl` 是一个基于 **Jinja2 模板引擎** 的 SQL Server 数据定义语言(DDL)生成模板。该模板用于根据元数据动态生成创建表、索引以及添加字段描述的完整 T-SQL 脚本。
|
||||||
|
|
||||||
|
支持功能包括:
|
||||||
|
- 字段类型映射
|
||||||
|
- 主键定义
|
||||||
|
- 唯一/普通索引创建
|
||||||
|
- 使用 `sp_addextendedproperty` 添加中文注释(MS_Description)
|
||||||
|
- 自动删除旧表(可选)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 模板结构概览
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
{% macro typeStr(type, len, dec) %}...{% endmacro %}
|
||||||
|
{% macro nullStr(nullable) %}...{% endmacro %}
|
||||||
|
{% macro primary() %}...{% endmacro %}
|
||||||
|
|
||||||
|
drop table dbo.{{summary[0].name}};
|
||||||
|
CREATE TABLE dbo.{{summary[0].name}}
|
||||||
|
(
|
||||||
|
...
|
||||||
|
)
|
||||||
|
-- 创建索引
|
||||||
|
-- 添加表和列的描述信息
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 宏(Macros)说明
|
||||||
|
|
||||||
|
### `typeStr(type, len, dec)`
|
||||||
|
|
||||||
|
将通用字段类型转换为 SQL Server 对应的数据类型。
|
||||||
|
|
||||||
|
| 输入参数 | 类型 | 说明 |
|
||||||
|
|---------|------|------|
|
||||||
|
| `type` | string | 字段逻辑类型(如 `'str'`, `'int'` 等) |
|
||||||
|
| `len` | int | 长度或精度(适用于字符串、数值等) |
|
||||||
|
| `dec` | int | 小数位数(适用于浮点数) |
|
||||||
|
|
||||||
|
#### 映射规则:
|
||||||
|
|
||||||
|
| 逻辑类型 | SQL Server 类型 | 说明 |
|
||||||
|
|---------------|------------------------------|------|
|
||||||
|
| `str` | `NVARCHAR(len)` | 变长 Unicode 字符串 |
|
||||||
|
| `char` | `CHAR(len)` | 定长字符 |
|
||||||
|
| `long/int/short` | `NUMERIC` | 整数类型统一用 NUMERIC(无精度限制) |
|
||||||
|
| `float/double/ddouble` | `numeric(len, dec)` | 精确数值类型,支持小数 |
|
||||||
|
| `date/time` | `DATE` | 日期类型 |
|
||||||
|
| `timestamp` | `TIMESTAMP` | 时间戳(行版本号),注意:非 datetime 类型 |
|
||||||
|
| `text` | `NVARCHAR(MAX)` | 大文本字段 |
|
||||||
|
| `bin` | `IMAGE` | 二进制大对象(已弃用,建议使用 `VARBINARY(MAX)`) |
|
||||||
|
| 其他未知类型 | 原样输出 `{{type}}` | 扩展兼容性 |
|
||||||
|
|
||||||
|
> ⚠️ 注意:SQL Server 的 `TIMESTAMP` 实际是 **rowversion** 类型,若需时间记录请使用 `DATETIME2`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `nullStr(nullable)`
|
||||||
|
|
||||||
|
控制字段是否允许为空。
|
||||||
|
|
||||||
|
| 参数 | 值示例 | 输出结果 |
|
||||||
|
|------------|-----------|----------------|
|
||||||
|
| `nullable` | `'no'` | `NOT NULL` |
|
||||||
|
| 其他值(如 `'yes'`, 空等) | —— | (空字符串,即允许 NULL) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `primary()`
|
||||||
|
|
||||||
|
生成主键约束语句。
|
||||||
|
|
||||||
|
- 使用 `summary[0].primary` 中定义的字段列表。
|
||||||
|
- 输出格式:`, primary key (col1, col2, ...)`
|
||||||
|
- 仅在存在主键字段时插入。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 主体 DDL 逻辑
|
||||||
|
|
||||||
|
### 1. 删除原表
|
||||||
|
|
||||||
|
```sql
|
||||||
|
drop table dbo.{{summary[0].name}};
|
||||||
|
```
|
||||||
|
|
||||||
|
> ⚠️ 此操作会 **无条件删除现有表及其数据**,生产环境慎用。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. 创建表
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE dbo.{{summary[0].name}}
|
||||||
|
(
|
||||||
|
{% for field in fields %}
|
||||||
|
{{field.name}} {{typeStr(field.type,field.length,field.dec)}} {{nullStr(field.nullable)}}
|
||||||
|
{%- if not loop.last -%},{%- endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% if summary[0].primary and len(summary[0].primary)>0 %}
|
||||||
|
{{primary()}}
|
||||||
|
{% endif %}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 字段循环说明:
|
||||||
|
|
||||||
|
- 遍历 `fields` 列表中每个字段对象。
|
||||||
|
- 生成字段名 + 类型 + 是否非空。
|
||||||
|
- 使用 `{%- if not loop.last %},{% endif %}` 控制逗号不加在最后一行。
|
||||||
|
|
||||||
|
#### 主键添加条件:
|
||||||
|
|
||||||
|
- 当 `summary[0].primary` 存在且长度 > 0 时,调用 `primary()` 宏添加主键定义。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. 创建索引
|
||||||
|
|
||||||
|
```jinja2
|
||||||
|
{% for v in indexes %}
|
||||||
|
CREATE {% if v.idxtype=='unique' %}UNIQUE{% endif %} INDEX {{summary[0].name}}_{{v.name}}
|
||||||
|
ON {{summary[0].name}}({{",".join(v.idxfields)}});
|
||||||
|
{% endfor %}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 支持索引类型:
|
||||||
|
|
||||||
|
| `v.idxtype` | 生成语句 |
|
||||||
|
|-------------|----------|
|
||||||
|
| `'unique'` | `CREATE UNIQUE INDEX ...` |
|
||||||
|
| 其他(如 `'normal'`, 空值等) | `CREATE INDEX ...` |
|
||||||
|
|
||||||
|
#### 索引命名规则:
|
||||||
|
|
||||||
|
```
|
||||||
|
<表名>_<索引名>
|
||||||
|
```
|
||||||
|
|
||||||
|
例如:`user_idx_email` 表示表 `user` 上名为 `idx_email` 的索引。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. 添加表与字段描述(MS_Description)
|
||||||
|
|
||||||
|
利用系统存储过程 `sys.sp_addextendedproperty` 添加注释。
|
||||||
|
|
||||||
|
#### 表级描述:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
EXEC sys.sp_addextendedproperty
|
||||||
|
@name=N'MS_Description',
|
||||||
|
@value=N'{{summary[0].title}}',
|
||||||
|
@level0type=N'SCHEMA', @level0name=N'dbo',
|
||||||
|
@level1type=N'TABLE', @level1name=N'{{summary[0].name}}'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 字段级描述(逐个循环):
|
||||||
|
|
||||||
|
```sql
|
||||||
|
{% for field in fields %}
|
||||||
|
EXEC sys.sp_addextendedproperty
|
||||||
|
@name=N'MS_Description',
|
||||||
|
@value=N'{{field.title}}',
|
||||||
|
@level0type=N'SCHEMA', @level0name=N'dbo',
|
||||||
|
@level1type=N'TABLE', @level1name=N'{{summary[0].name}}',
|
||||||
|
@level2type=N'COLUMN', @level2name=N'{{field.name}}'
|
||||||
|
{% endfor %}
|
||||||
|
```
|
||||||
|
|
||||||
|
> ✅ 这些描述可在 SSMS 的“属性”面板或通过查询 `sys.extended_properties` 查看。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 输入变量要求(上下文 Context)
|
||||||
|
|
||||||
|
模板运行需要以下变量注入:
|
||||||
|
|
||||||
|
| 变量名 | 类型 | 必须 | 说明 |
|
||||||
|
|-------------|------------|------|------|
|
||||||
|
| `summary` | list[dict] | 是 | 表基本信息列表,通常只取 `[0]` |
|
||||||
|
| `fields` | list[dict] | 是 | 字段列表 |
|
||||||
|
| `indexes` | list[dict] | 否 | 索引配置列表(可为空) |
|
||||||
|
|
||||||
|
### `summary[0]` 结构示例:
|
||||||
|
|
||||||
|
```python
|
||||||
|
{
|
||||||
|
"name": "user_info", # 表名
|
||||||
|
"title": "用户基本信息表" # 表中文名/描述
|
||||||
|
"primary": ["id"] # 主键字段数组
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `fields` 元素结构示例:
|
||||||
|
|
||||||
|
```python
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"type": "long",
|
||||||
|
"length": 19,
|
||||||
|
"dec": 0,
|
||||||
|
"nullable": "no",
|
||||||
|
"title": "用户ID"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "username",
|
||||||
|
"type": "str",
|
||||||
|
"length": 50,
|
||||||
|
"dec": 0,
|
||||||
|
"nullable": "no",
|
||||||
|
"title": "用户名"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### `indexes` 元素结构示例:
|
||||||
|
|
||||||
|
```python
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "idx_email",
|
||||||
|
"idxtype": "unique",
|
||||||
|
"idxfields": ["email"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "idx_dept",
|
||||||
|
"idxtype": "normal",
|
||||||
|
"idxfields": ["dept_id", "status"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 示例输出(渲染后)
|
||||||
|
|
||||||
|
假设输入如下元数据:
|
||||||
|
|
||||||
|
```python
|
||||||
|
summary = [{
|
||||||
|
"name": "user",
|
||||||
|
"title": "用户表",
|
||||||
|
"primary": ["id"]
|
||||||
|
}]
|
||||||
|
fields = [
|
||||||
|
{"name": "id", "type": "long", "length": 19, "dec": 0, "nullable": "no", "title": "用户ID"},
|
||||||
|
{"name": "name", "type": "str", "length": 100, "dec": 0, "nullable": "yes", "title": "姓名"},
|
||||||
|
{"name": "email", "type": "str", "length": 255, "dec": 0, "nullable": "no", "title": "邮箱"}
|
||||||
|
]
|
||||||
|
indexes = [
|
||||||
|
{"name": "uk_email", "idxtype": "unique", "idxfields": ["email"]}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 渲染结果:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
drop table dbo.user;
|
||||||
|
CREATE TABLE dbo.user
|
||||||
|
(
|
||||||
|
id NUMERIC NOT NULL,
|
||||||
|
name NVARCHAR(100),
|
||||||
|
email NVARCHAR(255) NOT NULL,
|
||||||
|
primary key(id)
|
||||||
|
)
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX user_uk_email ON user(email);
|
||||||
|
|
||||||
|
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'用户表' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'user'
|
||||||
|
|
||||||
|
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'用户ID' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'user', @level2type=N'COLUMN',@level2name=N'id'
|
||||||
|
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'姓名' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'user', @level2type=N'COLUMN',@level2name=N'name'
|
||||||
|
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'邮箱' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'user', @level2type=N'COLUMN',@level2name=N'email'
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 使用建议与注意事项
|
||||||
|
|
||||||
|
1. 🔐 **谨慎使用 `DROP TABLE`**
|
||||||
|
生产环境中应避免直接删除表。建议改为判断是否存在再操作,或提供开关控制。
|
||||||
|
|
||||||
|
2. 💡 推荐扩展:增加 `IF NOT EXISTS` 判断表是否存在:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
IF OBJECT_ID('dbo.{{summary[0].name}}', 'U') IS NOT NULL
|
||||||
|
DROP TABLE dbo.{{summary[0].name}};
|
||||||
|
```
|
||||||
|
|
||||||
|
3. 🛠 替代 IMAGE 类型:
|
||||||
|
`IMAGE` 已被弃用,推荐替换为:
|
||||||
|
```jinja2
|
||||||
|
{%- elif type=='bin' -%}
|
||||||
|
VARBINARY(MAX)
|
||||||
|
```
|
||||||
|
|
||||||
|
4. 📅 时间戳类型澄清:
|
||||||
|
若需存储时间,请使用 `DATETIME2` 并修改模板中 `timestamp` 分支。
|
||||||
|
|
||||||
|
5. 🔍 支持更多类型:可根据项目需求扩展 `typeStr` 宏以支持 `xml`, `hierarchyid`, `geometry` 等高级类型。
|
||||||
|
|
||||||
|
6. 🧪 测试建议:
|
||||||
|
在自动化脚本中集成此模板前,务必进行单元测试验证类型映射正确性。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 总结
|
||||||
|
|
||||||
|
本模板是一个高效、灵活的 SQL Server 表结构自动生成工具,适用于代码生成器、ETL 工具、模型同步系统等场景。结合元数据驱动设计,可大幅提升数据库开发效率并保证一致性。
|
||||||
|
|
||||||
|
✅ **优点**:
|
||||||
|
- 类型自动映射
|
||||||
|
- 支持注释与索引
|
||||||
|
- 结构清晰易维护
|
||||||
|
|
||||||
|
⚠️ **风险提示**:
|
||||||
|
- 包含 `DROP TABLE`,使用需谨慎
|
||||||
|
- `TIMESTAMP` 和 `IMAGE` 类型需按实际需求调整
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
📅 最后更新:2025-04-05
|
||||||
|
📦 所属模块:数据建模 / DDL 自动生成
|
||||||
303
aidocs/filter.md
Normal file
303
aidocs/filter.md
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
# DBFilter 过滤器解释器技术文档
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
`DBFilter` 是一个用于将 JSON 格式的 SQL 查询过滤条件解析为参数化 SQL 片段的 Python 类。它支持常见的逻辑运算符(AND、OR、NOT)和关系表达式(如 `=`, `<>`, `IN`, `LIKE` 等),适用于动态构建安全的数据库查询语句。
|
||||||
|
|
||||||
|
该模块通过递归遍历 JSON 结构,生成可嵌入 SQL 语句中的字符串,并提取常量与变量绑定信息,便于后续参数绑定或模板渲染。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 安装依赖
|
||||||
|
|
||||||
|
本模块无外部强依赖,但推荐使用 `ujson` 提升性能:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install ujson
|
||||||
|
```
|
||||||
|
|
||||||
|
日志功能依赖于 `appPublic.log.debug`,确保环境中已安装对应库或替换为标准日志模块。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 支持的操作类型
|
||||||
|
|
||||||
|
### 1. 逻辑运算符(Logic Operators)
|
||||||
|
|
||||||
|
| 操作符 | 说明 |
|
||||||
|
|--------|------|
|
||||||
|
| `AND` | 所有子条件都必须为真 |
|
||||||
|
| `OR` | 至少一个子条件为真 |
|
||||||
|
| `NOT` | 对单个条件取反 |
|
||||||
|
|
||||||
|
### 2. 关系运算符(Relational Operators)
|
||||||
|
|
||||||
|
| 运算符 | 含义 |
|
||||||
|
|---------------|------------------|
|
||||||
|
| `=` | 等于 |
|
||||||
|
| `!=` 或 `<>` | 不等于 |
|
||||||
|
| `>` | 大于 |
|
||||||
|
| `<` | 小于 |
|
||||||
|
| `>=` | 大于等于 |
|
||||||
|
| `<=` | 小于等于 |
|
||||||
|
| `IN` | 在某个集合中 |
|
||||||
|
| `NOT IN` | 不在某个集合中 |
|
||||||
|
| `IS NULL` | 为空 |
|
||||||
|
| `IS NOT NULL` | 非空 |
|
||||||
|
| `LIKE` | 模糊匹配 |
|
||||||
|
| `NOT LIKE` | 非模糊匹配 |
|
||||||
|
|
||||||
|
> 注意:所有操作符不区分大小写处理,内部统一转为大写进行校验。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 数据结构定义
|
||||||
|
|
||||||
|
过滤条件以嵌套 JSON 对象形式表示,基本结构如下:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"AND": [
|
||||||
|
{ "field": "name", "op": "=", "var": "username" },
|
||||||
|
{ "field": "status", "op": "=", "const": "active" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 字段说明
|
||||||
|
|
||||||
|
| 字段名 | 类型 | 必需 | 描述 |
|
||||||
|
|-------|------|------|------|
|
||||||
|
| `field` | string | 是 | 数据库字段名 |
|
||||||
|
| `op` | string | 是 | 操作符(见上表) |
|
||||||
|
| `const` | any | 否 | 常量值(直接序列化为占位符) |
|
||||||
|
| `var` | string | 否 | 变量名,需在命名空间 `ns` 中提供 |
|
||||||
|
|
||||||
|
> - `const` 和 `var` 至少存在其一(除非是 `IS NULL` / `IS NOT NULL` 类型)
|
||||||
|
> - 使用 `${name}$` 作为参数占位符格式,避免与主流 ORM 冲突
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## API 文档
|
||||||
|
|
||||||
|
### 类:`DBFilter`
|
||||||
|
|
||||||
|
#### 初始化方法:`__init__(self, filterjson)`
|
||||||
|
|
||||||
|
**参数:**
|
||||||
|
- `filterjson` (`str` or `dict`):JSON 字符串或字典格式的过滤条件
|
||||||
|
|
||||||
|
**行为:**
|
||||||
|
- 若输入为字符串,则自动调用 `json.loads()` 解析
|
||||||
|
- 存储解析后的结构供后续生成 SQL 使用
|
||||||
|
|
||||||
|
**示例:**
|
||||||
|
```python
|
||||||
|
fj = {"AND": [...]}
|
||||||
|
dbf = DBFilter(fj)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 方法:`gen(ns={}) -> str or None`
|
||||||
|
|
||||||
|
生成参数化的 SQL 过滤片段。
|
||||||
|
|
||||||
|
**参数:**
|
||||||
|
- `ns` (`dict`):变量命名空间,提供 `var` 到实际值的映射
|
||||||
|
|
||||||
|
**返回值:**
|
||||||
|
- 成功时返回 SQL 表达式字符串(可能包含括号)
|
||||||
|
- 若无法生成有效 SQL(如变量缺失),返回 `None`
|
||||||
|
- 所有常量会被分配唯一名称并存入 `self.consts`
|
||||||
|
|
||||||
|
**副作用:**
|
||||||
|
- 更新 `self.consts` 字典,记录所有常量占位符及其值
|
||||||
|
|
||||||
|
**示例:**
|
||||||
|
```python
|
||||||
|
sql = dbf.gen({'username': 'alice'})
|
||||||
|
# 输出: "name = ${filter_const_0}$ AND status = 'active'"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 方法:`get_variables() -> dict`
|
||||||
|
|
||||||
|
获取过滤器中所有 `var` 映射到 `field` 的变量引用关系。
|
||||||
|
|
||||||
|
**返回值:**
|
||||||
|
- `dict`: `{ variable_name: field_name }`
|
||||||
|
|
||||||
|
可用于预检查所需变量是否齐全。
|
||||||
|
|
||||||
|
**示例:**
|
||||||
|
```python
|
||||||
|
dbf.get_variables()
|
||||||
|
# 返回: {'username': 'name', 'status': 'status'}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 私有方法:`_genFilterSQL(fj, ns)`
|
||||||
|
|
||||||
|
递归生成 SQL 表达式的核心逻辑。
|
||||||
|
|
||||||
|
**处理规则:**
|
||||||
|
- 单键对象优先判断是否为逻辑操作符
|
||||||
|
- `AND` / `OR`:连接多个子表达式,`OR` 自动加括号
|
||||||
|
- `NOT`:对子表达式加 `NOT (...)`
|
||||||
|
- 其他情况交由 `_genFilterItems` 处理
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 私有方法:`_genFilterItems(fj, ns)`
|
||||||
|
|
||||||
|
处理单个字段比较表达式。
|
||||||
|
|
||||||
|
**逻辑:**
|
||||||
|
- 校验必填字段:`field`, `op`, (`const` 或 `var`)
|
||||||
|
- 支持 `IS NULL` / `IS NOT NULL` 无需值
|
||||||
|
- 若使用 `var`,检查其是否存在于 `ns`
|
||||||
|
- 若使用 `const`,生成唯一占位符名(如 `filter_const_0`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 函数:`default_filterjson(fields: list, ns: dict) -> dict or None`
|
||||||
|
|
||||||
|
根据字段白名单和变量空间生成默认等值过滤条件。
|
||||||
|
|
||||||
|
**参数:**
|
||||||
|
- `fields`: 允许参与过滤的字段列表
|
||||||
|
- `ns`: 当前可用变量字典
|
||||||
|
|
||||||
|
**返回值:**
|
||||||
|
- 匹配字段的等值条件组成的 `AND` 结构
|
||||||
|
- 若无匹配项返回 `None`
|
||||||
|
- 单条件时不包装 `AND`
|
||||||
|
|
||||||
|
**用途:**
|
||||||
|
常用于自动生成基于请求参数的简单过滤器。
|
||||||
|
|
||||||
|
**示例:**
|
||||||
|
```python
|
||||||
|
default_filterjson(['name', 'age'], {'name': 'Bob', 'city': 'Shanghai'})
|
||||||
|
# 返回:
|
||||||
|
# {
|
||||||
|
# "AND": [
|
||||||
|
# {"field": "name", "op": "=", "var": "name"}
|
||||||
|
# ]
|
||||||
|
# }
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 使用示例
|
||||||
|
|
||||||
|
### 示例 1:基础用法
|
||||||
|
|
||||||
|
```python
|
||||||
|
fj = {
|
||||||
|
"AND": [
|
||||||
|
{
|
||||||
|
"field": "field1",
|
||||||
|
"op": "=",
|
||||||
|
"var": "name"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "del_flg",
|
||||||
|
"op": "=",
|
||||||
|
"const": "0"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
dbf = DBFilter(fj)
|
||||||
|
sql = dbf.gen({"name": "joe"})
|
||||||
|
print(sql)
|
||||||
|
# 输出: field1 = ${name}$ AND del_flg = ${filter_const_0}$
|
||||||
|
print(dbf.consts)
|
||||||
|
# 输出: {'filter_const_0': '0'}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 示例 2:复杂嵌套逻辑
|
||||||
|
|
||||||
|
```python
|
||||||
|
fj = {
|
||||||
|
"AND": [
|
||||||
|
{
|
||||||
|
"OR": [
|
||||||
|
{"field": "age", "op": ">=", "const": 18},
|
||||||
|
{"field": "role", "op": "IN", "const": ["admin", "mod"]}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"NOT": {
|
||||||
|
"field": "status",
|
||||||
|
"op": "=",
|
||||||
|
"var": "blocked"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
dbf = DBFilter(fj)
|
||||||
|
sql = dbf.gen({"blocked": "inactive"})
|
||||||
|
# 输出:
|
||||||
|
# ((age >= ${filter_const_0}$ OR role IN ${filter_const_1}$)) AND not (status = ${blocked}$)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 示例 3:NULL 判断
|
||||||
|
|
||||||
|
```python
|
||||||
|
fj = {
|
||||||
|
"field": "email",
|
||||||
|
"op": "IS NOT NULL"
|
||||||
|
}
|
||||||
|
|
||||||
|
dbf = DBFilter(fj)
|
||||||
|
sql = dbf.gen({})
|
||||||
|
# 输出: email IS NOT NULL
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 错误处理
|
||||||
|
|
||||||
|
| 异常场景 | 抛出异常 |
|
||||||
|
|--------|---------|
|
||||||
|
| `AND/OR` 的值不是数组或长度小于 2 | `Exception` |
|
||||||
|
| `NOT` 的值不是对象 | `Exception` |
|
||||||
|
| 缺少必要字段(`field`, `op`) | `AssertionError` |
|
||||||
|
| 使用非法操作符 | `AssertionError` |
|
||||||
|
| `var` 在 `ns` 中不存在 | 返回 `None`(静默跳过) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 占位符设计
|
||||||
|
|
||||||
|
采用 `${name}$` 形式作为参数占位符,优点包括:
|
||||||
|
- 不与主流 SQL 参数风格冲突(如 `%s`, `?`, `:name`)
|
||||||
|
- 易于被模板引擎识别和替换
|
||||||
|
- 支持嵌入任意文本上下文
|
||||||
|
|
||||||
|
最终应配合参数绑定系统完成实际值注入。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 设计特点
|
||||||
|
|
||||||
|
- **安全性**:所有常量均通过占位符传递,防止 SQL 注入
|
||||||
|
- **灵活性**:支持任意深度嵌套的布尔逻辑
|
||||||
|
- **可扩展性**:可通过继承修改 `operators` 或重写生成逻辑
|
||||||
|
- **轻量级**:无需依赖完整 ORM,适合微服务或中间层使用
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 许可证
|
||||||
|
|
||||||
|
MIT License(假设项目允许,默认添加)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> ✅ 提示:建议结合 Jinja2 或类似模板引擎使用生成的 SQL 片段,实现完整的动态查询构造。
|
||||||
414
aidocs/mssqlor.md
Normal file
414
aidocs/mssqlor.md
Normal file
@ -0,0 +1,414 @@
|
|||||||
|
# `MsSqlor` 技术文档
|
||||||
|
|
||||||
|
> **模块路径**: `.mssqlor.py`
|
||||||
|
> **语言**: Python
|
||||||
|
> **数据库支持**: Microsoft SQL Server (通过 `pymssql`)
|
||||||
|
> **继承自**: `SQLor`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
`MsSqlor` 是一个专为 **Microsoft SQL Server** 数据库设计的 ORM(对象关系映射)辅助类,继承自通用数据库操作基类 `SQLor`。它封装了针对 SQL Server 的 DDL 模板、数据类型映射、分页查询、元数据提取等核心功能,适用于自动化建模、数据库逆向工程和动态 SQL 构建场景。
|
||||||
|
|
||||||
|
该类主要用于:
|
||||||
|
- 数据库连接识别
|
||||||
|
- 类型系统映射(数据库 ↔ 应用模型)
|
||||||
|
- 自动生成标准 SQL 语句(如查询、分页、表/字段/主键/外键/索引信息获取)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 依赖说明
|
||||||
|
|
||||||
|
```python
|
||||||
|
from .sor import SQLor
|
||||||
|
from .ddl_template_sqlserver import sqlserver_ddl_tmpl
|
||||||
|
```
|
||||||
|
|
||||||
|
- `SQLor`: 所有数据库适配器的抽象基类。
|
||||||
|
- `sqlserver_ddl_tmpl`: 预定义的 SQL Server DDL 模板,用于生成建表语句。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 类定义
|
||||||
|
|
||||||
|
```python
|
||||||
|
class MsSqlor(SQLor):
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 属性与常量
|
||||||
|
|
||||||
|
### 1. `ddl_template`
|
||||||
|
|
||||||
|
```python
|
||||||
|
ddl_template = sqlserver_ddl_tmpl
|
||||||
|
```
|
||||||
|
|
||||||
|
- **用途**: 定义创建表时使用的 DDL 模板。
|
||||||
|
- **值来源**: 引用外部模块 `ddl_template_sqlserver.sqlserver_ddl_tmpl`
|
||||||
|
- **典型内容示例**:
|
||||||
|
```sql
|
||||||
|
CREATE TABLE [table_name] (
|
||||||
|
[col_name] [data_type](...) NULL,
|
||||||
|
...
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. `db2modelTypeMapping`
|
||||||
|
|
||||||
|
将 SQL Server 数据库类型映射到应用层模型字段类型。
|
||||||
|
|
||||||
|
| 数据库类型 | 模型类型 |
|
||||||
|
|-----------|----------|
|
||||||
|
| `bit`, `tinyint`, `smallint` | `'short'` |
|
||||||
|
| `bigint`, `int` | `'long'` |
|
||||||
|
| `decimal`, `numeric`, `money`, `smallmoney`, `real`, `float` | `'float'` |
|
||||||
|
| `date`, `datetime` | `'date'` |
|
||||||
|
| `timestamp`, `uniqueidentifier` | `'timestamp'` |
|
||||||
|
| `char` | `'char'` |
|
||||||
|
| `varchar`, `nvarchar`, `nchar`, `binary`, `varbinary` | `'str'` |
|
||||||
|
| `text`, `ntext` | `'text'` |
|
||||||
|
| `image` | `'file'` |
|
||||||
|
|
||||||
|
> ⚠️ 注意:`uniqueidentifier` 映射为 `'timestamp'` 可能存在语义偏差,建议根据业务需求调整。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. `model2dbTypemapping`
|
||||||
|
|
||||||
|
将应用模型字段类型反向映射回 SQL Server 数据类型。
|
||||||
|
|
||||||
|
| 模型类型 | 数据库类型 |
|
||||||
|
|---------|------------|
|
||||||
|
| `'date'` | `datetime` |
|
||||||
|
| `'time'` | `date` *(注意:可能应为 `time` 或 `datetime`)* |
|
||||||
|
| `'timestamp'` | `timestamp` |
|
||||||
|
| `'str'` | `nvarchar` |
|
||||||
|
| `'char'` | `char` |
|
||||||
|
| `'short'` | `int` |
|
||||||
|
| `'long'` | `numeric` |
|
||||||
|
| `'float'` | `numeric` |
|
||||||
|
| `'text'` | `ntext` |
|
||||||
|
| `'file'` | `image` |
|
||||||
|
|
||||||
|
> 🔍 提示:`'long'` 和 `'float'` 均映射为 `numeric`,未指定精度,实际使用中需结合上下文补充。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 类方法
|
||||||
|
|
||||||
|
### `isMe(cls, name) -> bool`
|
||||||
|
|
||||||
|
判断当前驱动是否匹配。
|
||||||
|
|
||||||
|
#### 参数
|
||||||
|
- `name` (`str`): 数据库驱动名称,例如 `'pymssql'`
|
||||||
|
|
||||||
|
#### 返回值
|
||||||
|
- `True` 当且仅当 `name == 'pymssql'`
|
||||||
|
- 否则返回 `False`
|
||||||
|
|
||||||
|
#### 示例
|
||||||
|
```python
|
||||||
|
if MsSqlor.isMe(driver_name):
|
||||||
|
db_adapter = MsSqlor()
|
||||||
|
```
|
||||||
|
|
||||||
|
> ✅ 支持多数据库环境下自动识别 SQL Server 连接。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 实例方法
|
||||||
|
|
||||||
|
### `grammar(self) -> dict`
|
||||||
|
|
||||||
|
返回支持的 SQL 语法结构。目前仅注册 `select` 语句模板。
|
||||||
|
|
||||||
|
#### 返回值
|
||||||
|
```python
|
||||||
|
{
|
||||||
|
'select': select_stmt # 假设全局变量或导入的 SELECT 解析器
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> ⚠️ 警告:`select_stmt` 未在代码中定义,可能是遗漏或外部引用,请确保其存在。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `placeHolder(self, varname, pos=None) -> str`
|
||||||
|
|
||||||
|
生成参数占位符,用于预编译 SQL。
|
||||||
|
|
||||||
|
#### 参数
|
||||||
|
- `varname` (`str`): 参数名
|
||||||
|
- `pos` (`int`, optional): 位置索引(本实现未使用)
|
||||||
|
|
||||||
|
#### 行为逻辑
|
||||||
|
- 若参数名为 `__mainsql__`,返回空字符串(通常用于嵌入原始 SQL)
|
||||||
|
- 其他情况统一返回 `%s` —— 符合 `pymssql` 参数化语法
|
||||||
|
|
||||||
|
#### 示例
|
||||||
|
```python
|
||||||
|
cursor.execute(sql % (), data)
|
||||||
|
```
|
||||||
|
|
||||||
|
> ✅ 安全地防止 SQL 注入。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `dataConvert(self, dataList) -> tuple`
|
||||||
|
|
||||||
|
将输入数据标准化为可执行的元组格式。
|
||||||
|
|
||||||
|
#### 输入类型处理
|
||||||
|
- **字典类型**:取 `.values()` 并转为列表 → 元组
|
||||||
|
- **列表 of 字典**:提取每个元素的 `'value'` 字段 → 元组
|
||||||
|
|
||||||
|
#### 示例
|
||||||
|
```python
|
||||||
|
# 输入1: {'a': 1, 'b': 2} → (1, 2)
|
||||||
|
# 输入2: [{'value': 1}, {'value': 2}] → (1, 2)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 返回值
|
||||||
|
- 标准化的 `tuple`,可用于 `cursor.execute(..., params)`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `pagingSQLmodel(self) -> str`
|
||||||
|
|
||||||
|
返回适用于 SQL Server 的分页查询模板(基于 `ROW_NUMBER()` 窗口函数)。
|
||||||
|
|
||||||
|
#### 模板结构
|
||||||
|
```sql
|
||||||
|
SELECT *
|
||||||
|
FROM (
|
||||||
|
SELECT ROW_NUMBER() OVER(ORDER BY $[sort]$) AS _row_id, page_s.*
|
||||||
|
FROM (%s) page_s
|
||||||
|
) A
|
||||||
|
WHERE _row_id >= $[from_line]$ AND _row_id < $[end_line]$
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 占位符说明
|
||||||
|
| 占位符 | 含义 |
|
||||||
|
|----------------|------------------------|
|
||||||
|
| `%s` | 子查询(原 SQL) |
|
||||||
|
| `$[sort]$` | 排序字段 |
|
||||||
|
| `$[from_line]$`| 起始行号(含) |
|
||||||
|
| `$[end_line]$` | 结束行号(不含) |
|
||||||
|
|
||||||
|
#### 使用方式
|
||||||
|
此模板需配合字符串替换工具填充实际值,常用于构建分页接口。
|
||||||
|
|
||||||
|
> ✅ 兼容 SQL Server 2005+ 版本。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `tablesSQL(self) -> str`
|
||||||
|
|
||||||
|
获取当前数据库所有用户表及其标题(描述)。
|
||||||
|
|
||||||
|
#### 查询语句
|
||||||
|
```sql
|
||||||
|
SELECT
|
||||||
|
LOWER(d.name) AS name,
|
||||||
|
LOWER(CAST(ISNULL(f.VALUE, d.name) AS NVARCHAR)) AS title
|
||||||
|
FROM sysobjects d
|
||||||
|
LEFT JOIN sys.extended_properties f ON d.id = f.major_id AND f.minor_id = 0
|
||||||
|
WHERE d.xtype = 'U'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 字段说明
|
||||||
|
- `name`: 表名(小写)
|
||||||
|
- `title`: 表备注 / 描述(若无则用表名代替)
|
||||||
|
|
||||||
|
> 📌 `xtype = 'U'` 表示用户表。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `fieldsSQL(self, tablename=None) -> str`
|
||||||
|
|
||||||
|
获取指定表或全部表的字段元数据。
|
||||||
|
|
||||||
|
#### 查询语句摘要
|
||||||
|
```sql
|
||||||
|
SELECT
|
||||||
|
name = LOWER(a.name),
|
||||||
|
type = b.name,
|
||||||
|
length = COLUMNPROPERTY(a.id, a.name, 'PRECISION'),
|
||||||
|
dec = ISNULL(COLUMNPROPERTY(a.id, a.name, 'Scale'), NULL),
|
||||||
|
nullable = CASE WHEN a.isnullable = 1 THEN 'yes' ELSE 'no' END,
|
||||||
|
title = LOWER(CAST(ISNULL(g.[value], a.name) AS NVARCHAR)),
|
||||||
|
table_name = LOWER(d.name)
|
||||||
|
FROM syscolumns a
|
||||||
|
...
|
||||||
|
WHERE schema_name(schema_id) = 'dbo'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 条件控制
|
||||||
|
- 若传入 `tablename`,则添加 `WHERE LOWER(d.name) = 'xxx'`
|
||||||
|
- 最终按 `a.id, a.colorder` 排序(保证列顺序)
|
||||||
|
|
||||||
|
#### 返回字段
|
||||||
|
| 字段 | 说明 |
|
||||||
|
|-------------|--------------------------|
|
||||||
|
| `name` | 列名(小写) |
|
||||||
|
| `type` | 数据类型 |
|
||||||
|
| `length` | 精度(字符长度或数字总位数) |
|
||||||
|
| `dec` | 小数位数 |
|
||||||
|
| `nullable` | 是否可为空(yes/no) |
|
||||||
|
| `title` | 列说明(扩展属性) |
|
||||||
|
| `table_name`| 所属表名(小写) |
|
||||||
|
|
||||||
|
> ✅ 支持从 `sys.extended_properties` 获取注释。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `fkSQL(self, tablename=None) -> str`
|
||||||
|
|
||||||
|
获取外键关系(引用其他表的主键作为本表外键)。
|
||||||
|
|
||||||
|
#### 查询逻辑
|
||||||
|
查找以某表为主表(被引用)的所有外键关联。
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT
|
||||||
|
MainCol.name AS field, -- 主表列名(被引用)
|
||||||
|
oSub.name AS fk_table, -- 子表名称(引用方)
|
||||||
|
SubCol.name AS fk_field -- 子表列名(外键列)
|
||||||
|
FROM sys.foreign_keys fk
|
||||||
|
JOIN ... -- 多表连接定位主子表及列
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 条件
|
||||||
|
- 可选过滤:`lower(oMain.name) = 'xxx'`,即只查某主表被哪些表引用
|
||||||
|
|
||||||
|
#### 示例输出
|
||||||
|
| field | fk_table | fk_field |
|
||||||
|
|-------|----------|----------|
|
||||||
|
| id | orders | user_id |
|
||||||
|
|
||||||
|
> 💡 适用于构建实体关系图(ERD)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `pkSQL(self, tablename=None) -> str`
|
||||||
|
|
||||||
|
获取主键字段信息。
|
||||||
|
|
||||||
|
#### 查询语句
|
||||||
|
```sql
|
||||||
|
SELECT
|
||||||
|
LOWER(a.table_name) AS table_name,
|
||||||
|
LOWER(b.column_name) AS field_name
|
||||||
|
FROM information_schema.table_constraints a
|
||||||
|
INNER JOIN information_schema.constraint_column_usage b
|
||||||
|
ON a.constraint_name = b.constraint_name
|
||||||
|
WHERE a.constraint_type = 'PRIMARY KEY'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 可选过滤
|
||||||
|
- 若提供 `tablename`,追加条件:`AND LOWER(a.table_name) = 'xxx'`
|
||||||
|
|
||||||
|
#### 输出
|
||||||
|
每条记录表示一个主键列。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `indexesSQL(self, tablename=None) -> str`
|
||||||
|
|
||||||
|
获取索引信息(包括唯一性与包含的列)。
|
||||||
|
|
||||||
|
#### 查询语句
|
||||||
|
```sql
|
||||||
|
SELECT
|
||||||
|
index_name = LOWER(IDX.Name),
|
||||||
|
index_type = IDX.is_unique,
|
||||||
|
column_name = LOWER(C.Name)
|
||||||
|
FROM sys.indexes IDX
|
||||||
|
INNER JOIN sys.index_columns IDXC ...
|
||||||
|
INNER JOIN sys.columns C ...
|
||||||
|
WHERE O.type = 'U' AND O.is_ms_shipped = 0
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 条件
|
||||||
|
- 排除系统对象(`is_ms_shipped=0`)
|
||||||
|
- 可选按表名过滤:`LOWER(O.name) = 'xxx'`
|
||||||
|
|
||||||
|
#### 输出字段
|
||||||
|
| 字段 | 说明 |
|
||||||
|
|--------------|------------------------------|
|
||||||
|
| `index_name` | 索引名(小写) |
|
||||||
|
| `index_type` | 是否唯一(1=唯一;0=非唯一) |
|
||||||
|
| `column_name`| 索引包含的列名 |
|
||||||
|
|
||||||
|
> ✅ 支持复合索引拆解为多行展示。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 使用示例
|
||||||
|
|
||||||
|
### 获取所有表
|
||||||
|
```python
|
||||||
|
db = MsSqlor(connection)
|
||||||
|
sql = db.tablesSQL()
|
||||||
|
cursor.execute(sql)
|
||||||
|
tables = cursor.fetchall()
|
||||||
|
for t in tables:
|
||||||
|
print(t['name'], t['title'])
|
||||||
|
```
|
||||||
|
|
||||||
|
### 获取某表字段
|
||||||
|
```python
|
||||||
|
sql = db.fieldsSQL('users')
|
||||||
|
cursor.execute(sql)
|
||||||
|
fields = cursor.fetchall()
|
||||||
|
for f in fields:
|
||||||
|
print(f['name'], f['type'], f['nullable'])
|
||||||
|
```
|
||||||
|
|
||||||
|
### 分页查询构造
|
||||||
|
```python
|
||||||
|
base_sql = "SELECT id, name FROM users"
|
||||||
|
pager = db.pagingSQLmodel() % base_sql
|
||||||
|
pager = pager.replace('$[sort]$', 'id') \
|
||||||
|
.replace('$[from_line]$', '1') \
|
||||||
|
.replace('$[end_line]$', '11')
|
||||||
|
cursor.execute(pager)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 已知限制与建议
|
||||||
|
|
||||||
|
| 问题 | 建议 |
|
||||||
|
|------|------|
|
||||||
|
| `select_stmt` 未定义 | 确保已在作用域内定义或导入 |
|
||||||
|
| `time` 模型映射为 `date` | 应改为 `time` 或 `datetime` |
|
||||||
|
| `uniqueidentifier` 映射为 `timestamp` | 语义错误,建议新增 `'guid'` 类型 |
|
||||||
|
| 不支持模式(schema)切换 | 当前固定 `schema_name='dbo'`,如需扩展建议增加参数 |
|
||||||
|
| 缺少 `create`, `insert` 等语法支持 | 可在 `grammar()` 中逐步扩展 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 总结
|
||||||
|
|
||||||
|
`MsSqlor` 是一个功能完整的 SQL Server 数据库适配器,具备以下优势:
|
||||||
|
|
||||||
|
✅ 自动识别驱动
|
||||||
|
✅ 完善的类型双向映射
|
||||||
|
✅ 强大的元数据查询能力(表、列、主键、外键、索引)
|
||||||
|
✅ 标准化的分页模板
|
||||||
|
✅ 支持参数化查询与安全执行
|
||||||
|
|
||||||
|
适合集成于 ORM 框架、数据库管理工具或低代码平台中,实现对 SQL Server 的自动化操作。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> 📎 文档版本:v1.0
|
||||||
|
> 📅 更新日期:2025年4月5日
|
||||||
462
aidocs/mysqlor.md
Normal file
462
aidocs/mysqlor.md
Normal file
@ -0,0 +1,462 @@
|
|||||||
|
以下是针对你提供的 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
|
||||||
|
> © 项目公共组件库团队
|
||||||
363
aidocs/oracleor.md
Normal file
363
aidocs/oracleor.md
Normal file
@ -0,0 +1,363 @@
|
|||||||
|
# `Oracleor` 类技术文档
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# Oracle 数据库操作类:`Oracleor`
|
||||||
|
|
||||||
|
`Oracleor` 是一个用于操作 Oracle 数据库的 Python 类,继承自 `SQLor` 基类。该类封装了与 Oracle 数据库交互所需的核心功能,包括数据类型映射、分页查询、元数据获取(表、字段、主键、外键、索引等)、占位符处理以及 SQL 模板管理。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 继承关系
|
||||||
|
|
||||||
|
- **父类**: `SQLor`
|
||||||
|
- **所在模块**: `.sor.SQLor`
|
||||||
|
- **用途**: 提供通用 SQL 操作接口
|
||||||
|
|
||||||
|
## 依赖项
|
||||||
|
|
||||||
|
```python
|
||||||
|
from .sor import SQLor
|
||||||
|
from .ddl_template_oracle import oracle_ddl_tmpl
|
||||||
|
```
|
||||||
|
|
||||||
|
- `oracle_ddl_tmpl`: Oracle 特定的 DDL(数据定义语言)模板,用于生成建表语句等。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 类定义
|
||||||
|
|
||||||
|
```python
|
||||||
|
class Oracleor(SQLor):
|
||||||
|
ddl_template = oracle_ddl_tmpl
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 核心属性
|
||||||
|
|
||||||
|
### 1. `ddl_template`
|
||||||
|
|
||||||
|
```python
|
||||||
|
ddl_template = oracle_ddl_tmpl
|
||||||
|
```
|
||||||
|
|
||||||
|
- **说明**: 使用 Oracle 专用的 DDL 模板来生成建表语句。
|
||||||
|
- **用途**: 支持通过模型自动生成数据库表结构。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. `db2modelTypeMapping`
|
||||||
|
|
||||||
|
将 Oracle 数据库字段类型映射为应用层模型类型(如 Python 或 ORM 模型类型)。
|
||||||
|
|
||||||
|
| Oracle 类型 | 映射模型类型 |
|
||||||
|
|------------|-------------|
|
||||||
|
| `char` | `char` |
|
||||||
|
| `nchar` | `str` |
|
||||||
|
| `varchar`, `varchar2`, `nvarchar2` | `str` |
|
||||||
|
| `number`, `integer` | `long` |
|
||||||
|
| `binary_float`, `binary_double`, `float` | `float` |
|
||||||
|
| `timestamp`, `timestamp with time zone`, `timestamp with local time zone`, `interval day to second` | `timestamp` |
|
||||||
|
| `interval year to moth` | `date` |
|
||||||
|
| `clob`, `nclob` | `text` |
|
||||||
|
| `blob`, `bfile` | `file` |
|
||||||
|
| `date` | `date` |
|
||||||
|
|
||||||
|
> ⚠️ 注意:`interval year to moth` 存在拼写错误,应为 `interval year to month`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. `model2dbTypemapping`
|
||||||
|
|
||||||
|
将模型类型反向映射为 Oracle 数据库字段类型。
|
||||||
|
|
||||||
|
| 模型类型 | 映射 Oracle 类型 |
|
||||||
|
|---------|------------------|
|
||||||
|
| `date`, `time`, `timestamp` | `date` |
|
||||||
|
| `str` | `varchar2` |
|
||||||
|
| `char` | `char` |
|
||||||
|
| `short`, `long`, `float` | `number` |
|
||||||
|
| `text` | `nclob` |
|
||||||
|
| `file` | `blob` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 类方法
|
||||||
|
|
||||||
|
### `@classmethod isMe(cls, name)`
|
||||||
|
|
||||||
|
判断当前驱动是否为 Oracle 驱动。
|
||||||
|
|
||||||
|
#### 参数:
|
||||||
|
- `name` (str): 数据库连接使用的驱动名称。
|
||||||
|
|
||||||
|
#### 返回值:
|
||||||
|
- `True` 如果 `name == 'cx_Oracle'`,否则 `False`。
|
||||||
|
|
||||||
|
#### 示例:
|
||||||
|
```python
|
||||||
|
if Oracleor.isMe('cx_Oracle'):
|
||||||
|
print("This is Oracle database.")
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 实例方法
|
||||||
|
|
||||||
|
### `grammar(self)`
|
||||||
|
|
||||||
|
返回当前数据库支持的 SQL 语法结构(目前仅支持 `select`)。
|
||||||
|
|
||||||
|
#### 返回值:
|
||||||
|
```python
|
||||||
|
{
|
||||||
|
'select': select_stmt
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> ⚠️ 注意:`select_stmt` 未在代码中定义,可能是外部导入或遗漏。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `placeHolder(self, varname, pos=None)`
|
||||||
|
|
||||||
|
生成适用于 Oracle 的参数占位符(使用命名绑定变量)。
|
||||||
|
|
||||||
|
#### 参数:
|
||||||
|
- `varname` (str): 变量名。
|
||||||
|
- `pos` (int, optional): 位置参数(未使用)。
|
||||||
|
|
||||||
|
#### 规则:
|
||||||
|
- 若 `varname == '__mainsql__'`,返回空字符串。
|
||||||
|
- 否则返回 `:%s` 格式,例如 `:username`。
|
||||||
|
|
||||||
|
#### 示例:
|
||||||
|
```python
|
||||||
|
self.placeHolder('username') # 输出: ':username'
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `dataConvert(self, dataList)`
|
||||||
|
|
||||||
|
将数据库原始结果列表转换为字典格式。
|
||||||
|
|
||||||
|
#### 参数:
|
||||||
|
- `dataList`: 可以是字典或包含字段信息的列表(如 `[{'name': 'id', 'value': 1}, ...]`)。
|
||||||
|
|
||||||
|
#### 返回值:
|
||||||
|
- 转换后的字典,键为字段名,值为对应值。
|
||||||
|
|
||||||
|
#### 示例:
|
||||||
|
```python
|
||||||
|
input_data = [{'name': 'id', 'value': 1}, {'name': 'name', 'value': 'Alice'}]
|
||||||
|
result = obj.dataConvert(input_data)
|
||||||
|
# result => {'id': 1, 'name': 'Alice'}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `pagingSQLmodel(self)`
|
||||||
|
|
||||||
|
返回 Oracle 分页查询的 SQL 模板(基于 `ROWNUM` 实现)。
|
||||||
|
|
||||||
|
#### 返回模板:
|
||||||
|
```sql
|
||||||
|
select *
|
||||||
|
from (
|
||||||
|
select page_s.*, rownum row_id
|
||||||
|
from (%s) page_s
|
||||||
|
order by $[sort]$
|
||||||
|
)
|
||||||
|
where row_id >= $[from_line]$ and row_id < $[end_line]$
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 占位符说明:
|
||||||
|
- `%s`: 子查询(原始 SQL)
|
||||||
|
- `$[sort]$`: 排序字段
|
||||||
|
- `$[from_line]$`: 起始行号(从 1 开始)
|
||||||
|
- `$[end_line]$`: 结束行号(不包含)
|
||||||
|
|
||||||
|
> ✅ 适用于 Oracle 9i 及以上版本。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `tablesSQL(self)`
|
||||||
|
|
||||||
|
生成查询当前用户所有表及其注释的 SQL。
|
||||||
|
|
||||||
|
#### 返回 SQL:
|
||||||
|
```sql
|
||||||
|
select
|
||||||
|
lower(table_name) as name,
|
||||||
|
lower(decode(comments,null,table_name,comments)) as title
|
||||||
|
from USER_TAB_COMMENTS where table_type = 'TABLE'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 字段说明:
|
||||||
|
- `name`: 表名(小写)
|
||||||
|
- `title`: 表标题/注释,若无注释则用表名代替
|
||||||
|
|
||||||
|
> 查询来源:`USER_TAB_COMMENTS`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `fieldsSQL(self, tablename=None)`
|
||||||
|
|
||||||
|
查询指定表的所有字段信息。
|
||||||
|
|
||||||
|
#### 参数:
|
||||||
|
- `tablename` (str, optional): 表名(不区分大小写)
|
||||||
|
|
||||||
|
#### 返回 SQL:
|
||||||
|
```sql
|
||||||
|
select lower(utc.COLUMN_NAME) name
|
||||||
|
,utc.DATA_TYPE type
|
||||||
|
,utc.DATA_LENGTH length
|
||||||
|
,utc.data_scale dec
|
||||||
|
,case when utc.nullable = 'Y' then 'yes' else 'no' end nullable
|
||||||
|
,lower(nvl(ucc.comments,utc.COLUMN_NAME)) title
|
||||||
|
,lower(utc.table_name) as table_name
|
||||||
|
from user_tab_cols utc left join USER_COL_COMMENTS ucc
|
||||||
|
on utc.table_name = ucc.table_name and utc.COLUMN_NAME = ucc.COLUMN_NAME
|
||||||
|
```
|
||||||
|
|
||||||
|
如果提供了 `tablename`,会添加过滤条件:
|
||||||
|
```sql
|
||||||
|
where lower(utc.table_name) = 'xxx'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 字段说明:
|
||||||
|
| 字段 | 含义 |
|
||||||
|
|------|------|
|
||||||
|
| `name` | 字段名(小写) |
|
||||||
|
| `type` | 数据类型 |
|
||||||
|
| `length` | 字段长度 |
|
||||||
|
| `dec` | 小数位数(scale) |
|
||||||
|
| `nullable` | 是否可为空('yes'/'no') |
|
||||||
|
| `title` | 字段注释,无则用字段名替代 |
|
||||||
|
| `table_name`| 所属表名(小写) |
|
||||||
|
|
||||||
|
> 数据源:`user_tab_cols`, `USER_COL_COMMENTS`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `fkSQL(self, tablename=None)`
|
||||||
|
|
||||||
|
查询外键约束信息。
|
||||||
|
|
||||||
|
#### 参数:
|
||||||
|
- `tablename` (str, optional): 限定查询某一张表的外键
|
||||||
|
|
||||||
|
#### 返回 SQL:
|
||||||
|
```sql
|
||||||
|
select
|
||||||
|
distinct(ucc.column_name) as field,
|
||||||
|
rela.table_name as fk_table,
|
||||||
|
rela.column_name as fk_field
|
||||||
|
from
|
||||||
|
user_constraints uc,
|
||||||
|
user_cons_columns ucc,
|
||||||
|
(
|
||||||
|
select t2.table_name, t2.column_name, t1.r_constraint_name
|
||||||
|
from user_constraints t1, user_cons_columns t2
|
||||||
|
where t1.r_constraint_name = t2.constraint_name
|
||||||
|
) rela
|
||||||
|
where
|
||||||
|
uc.constraint_name = ucc.constraint_name
|
||||||
|
and uc.r_constraint_name = rela.r_constraint_name
|
||||||
|
```
|
||||||
|
|
||||||
|
若有表名,则追加:
|
||||||
|
```sql
|
||||||
|
and lower(uc.table_name) = 'xxx'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 返回字段:
|
||||||
|
- `field`: 当前表的外键字段
|
||||||
|
- `fk_table`: 引用的目标表
|
||||||
|
- `fk_field`: 目标表中的被引用字段
|
||||||
|
|
||||||
|
> 用于构建表间关联关系。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `pkSQL(self, tablename=None)`
|
||||||
|
|
||||||
|
查询主键字段信息。
|
||||||
|
|
||||||
|
#### 参数:
|
||||||
|
- `tablename` (str, optional): 限定查询某张表的主键
|
||||||
|
|
||||||
|
#### 返回 SQL:
|
||||||
|
```sql
|
||||||
|
select
|
||||||
|
lower(col.table_name) table_name,
|
||||||
|
lower(col.column_name) as field_name
|
||||||
|
from
|
||||||
|
user_constraints con,
|
||||||
|
user_cons_columns col
|
||||||
|
where
|
||||||
|
con.constraint_name = col.constraint_name
|
||||||
|
and con.constraint_type = 'P'
|
||||||
|
```
|
||||||
|
|
||||||
|
若有表名,则追加:
|
||||||
|
```sql
|
||||||
|
and lower(col.table_name) = 'xxx'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 返回字段:
|
||||||
|
- `table_name`: 表名(小写)
|
||||||
|
- `field_name`: 主键字段名(小写)
|
||||||
|
|
||||||
|
> `constraint_type='P'` 表示主键约束。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `indexesSQL(self, tablename=None)`
|
||||||
|
|
||||||
|
查询索引信息。
|
||||||
|
|
||||||
|
#### 参数:
|
||||||
|
- `tablename` (str, optional): 限定查询某张表的索引
|
||||||
|
|
||||||
|
#### 返回 SQL:
|
||||||
|
```sql
|
||||||
|
select
|
||||||
|
lower(a.index_name) index_name,
|
||||||
|
lower(a.UNIQUENESS) is_unique,
|
||||||
|
lower(b.column_name) column_name
|
||||||
|
from user_indexes a, user_ind_columns b
|
||||||
|
where a.index_name = b.index_name
|
||||||
|
```
|
||||||
|
|
||||||
|
若有表名,则追加:
|
||||||
|
```sql
|
||||||
|
and lower(a.table_name) = lower('xxx')
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 返回字段:
|
||||||
|
- `index_name`: 索引名称(小写)
|
||||||
|
- `is_unique`: 是否唯一(`unique` / `non-unique`)
|
||||||
|
- `column_name`: 索引包含的字段名(小写)
|
||||||
|
|
||||||
|
> 支持多字段索引(每行一个字段)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 总结
|
||||||
|
|
||||||
|
`Oracleor` 类为 Oracle 数据库提供了完整的元数据读取和 SQL 构造能力,适用于:
|
||||||
|
|
||||||
|
- 自动生成模型(ORM 映射)
|
||||||
|
- 可视化数据库结构工具
|
||||||
|
- 动态 SQL 执行与分页
|
||||||
|
- 数据迁移与同步系统
|
||||||
|
|
||||||
|
其设计遵循抽象与具体分离原则,便于扩展至其他数据库。
|
||||||
|
|
||||||
|
---
|
||||||
|
> 📌 **备注**:部分变量(如 `select_stmt`)可能依赖外部定义,请确保上下文完整。
|
||||||
|
```
|
||||||
451
aidocs/postgresqlor.md
Normal file
451
aidocs/postgresqlor.md
Normal file
@ -0,0 +1,451 @@
|
|||||||
|
以下是为提供的 Python 代码编写的 **Markdown 格式技术文档**,适用于项目文档或 API 参考手册。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# `PostgreSQLor` 类技术文档
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
`PostgreSQLor` 是一个用于操作 PostgreSQL 数据库的数据库抽象类(继承自 `SQLor`),提供了对 PostgreSQL 特有语法、数据类型映射、元数据查询等功能的支持。该类主要用于生成 SQL 语句、处理占位符、转换数据结构以及获取表结构信息等任务。
|
||||||
|
|
||||||
|
该类主要配合 ORM 或代码生成器使用,支持从数据库中提取表、字段、主键、外键、索引等元数据,并将其映射为模型层可用的数据格式。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 继承关系
|
||||||
|
|
||||||
|
```python
|
||||||
|
class PostgreSQLor(SQLor)
|
||||||
|
```
|
||||||
|
|
||||||
|
- 父类:`SQLor`
|
||||||
|
- 当前类:`PostgreSQLor`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 导入依赖
|
||||||
|
|
||||||
|
```python
|
||||||
|
from .sor import SQLor
|
||||||
|
from .ddl_template_postgresql import postgresql_ddl_tmpl
|
||||||
|
```
|
||||||
|
|
||||||
|
- `SQLor`: 基础数据库操作抽象类。
|
||||||
|
- `postgresql_ddl_tmpl`: PostgreSQL 的 DDL 模板,用于建表语句生成。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 类属性
|
||||||
|
|
||||||
|
### `ddl_template`
|
||||||
|
|
||||||
|
```python
|
||||||
|
ddl_template = postgresql_ddl_tmpl
|
||||||
|
```
|
||||||
|
|
||||||
|
- 说明:指定 PostgreSQL 的 DDL 建表语句模板。
|
||||||
|
- 用途:在生成 `CREATE TABLE` 等语句时引用此模板。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `db2modelTypeMapping`
|
||||||
|
|
||||||
|
将 PostgreSQL 数据库中的字段类型映射到应用模型中的类型。
|
||||||
|
|
||||||
|
```python
|
||||||
|
db2modelTypeMapping = {
|
||||||
|
'smallint': 'short',
|
||||||
|
'integer': 'long',
|
||||||
|
'bigint': 'llong',
|
||||||
|
'decimal': 'float',
|
||||||
|
'numeric': 'float',
|
||||||
|
'real': 'float',
|
||||||
|
'double': 'float',
|
||||||
|
'serial': 'long',
|
||||||
|
'bigserial': 'llong',
|
||||||
|
'char': 'char',
|
||||||
|
'character': 'char',
|
||||||
|
'varchar': 'str',
|
||||||
|
'character varying': 'str',
|
||||||
|
'text': 'text',
|
||||||
|
'timestamp': 'timestamp',
|
||||||
|
'date': 'date',
|
||||||
|
'time': 'time',
|
||||||
|
'boolean': 'char',
|
||||||
|
'bytea': 'file'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| 数据库类型 | 模型类型 |
|
||||||
|
|-----------|----------|
|
||||||
|
| smallint | short |
|
||||||
|
| integer | long |
|
||||||
|
| bigint | llong |
|
||||||
|
| numeric/decimal/real/double | float |
|
||||||
|
| serial/bigserial | long/llong |
|
||||||
|
| char/character | char |
|
||||||
|
| varchar/character varying | str |
|
||||||
|
| text | text |
|
||||||
|
| timestamp | timestamp|
|
||||||
|
| date | date |
|
||||||
|
| time | time |
|
||||||
|
| boolean | char (0/1) |
|
||||||
|
| bytea | file (二进制存储) |
|
||||||
|
|
||||||
|
> ⚠️ 注意:`boolean` 被映射为 `char`,通常以 `'0'/'1'` 表示布尔值。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `model2dbTypemapping`
|
||||||
|
|
||||||
|
将模型中的字段类型反向映射回 PostgreSQL 的数据库类型。
|
||||||
|
|
||||||
|
```python
|
||||||
|
model2dbTypemapping = {
|
||||||
|
'date': 'date',
|
||||||
|
'time': 'date', # 注意:time 映射为 date 类型?可能需确认是否合理
|
||||||
|
'timestamp': 'timestamp',
|
||||||
|
'str': 'varchar',
|
||||||
|
'char': 'char',
|
||||||
|
'short': 'smallint',
|
||||||
|
'long': 'integer',
|
||||||
|
'float': 'numeric',
|
||||||
|
'text': 'text',
|
||||||
|
'file': 'bytea',
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> ❗ 注意:`model2dbTypemapping['time'] = 'date'` 存在逻辑问题,应为 `'time'`,可能是 bug。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 类方法
|
||||||
|
|
||||||
|
### `isMe(cls, name)`
|
||||||
|
|
||||||
|
判断当前数据库驱动是否匹配 PostgreSQL。
|
||||||
|
|
||||||
|
#### 参数:
|
||||||
|
- `name` (`str`):数据库连接使用的驱动名称。
|
||||||
|
|
||||||
|
#### 返回值:
|
||||||
|
- `bool`:若 `name` 为 `'psycopg2'` 或 `'pyguass'`,返回 `True`;否则返回 `False`。
|
||||||
|
|
||||||
|
#### 示例:
|
||||||
|
```python
|
||||||
|
PostgreSQLor.isMe('psycopg2') # True
|
||||||
|
PostgreSQLor.isMe('sqlite3') # False
|
||||||
|
```
|
||||||
|
|
||||||
|
> 支持标准 PostgreSQL 驱动 `psycopg2` 和国产化替代品 `pyguass`(如达梦、高斯等兼容版)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 实例方法
|
||||||
|
|
||||||
|
### `grammar(self)`
|
||||||
|
|
||||||
|
返回当前数据库支持的 SQL 语法结构定义(目前仅包含 `select`)。
|
||||||
|
|
||||||
|
#### 返回值:
|
||||||
|
```python
|
||||||
|
{
|
||||||
|
'select': select_stmt
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> ⚠️ 注意:`select_stmt` 未在代码中定义,可能是外部导入变量,需确保上下文存在。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `placeHolder(self, varname, i)`
|
||||||
|
|
||||||
|
生成参数化查询中的占位符。
|
||||||
|
|
||||||
|
#### 参数:
|
||||||
|
- `varname` (`str`):参数名。
|
||||||
|
- `i` (`int`):参数索引(当前未使用)。
|
||||||
|
|
||||||
|
#### 返回值:
|
||||||
|
- 若 `varname == '__mainsql__'`,返回空字符串。
|
||||||
|
- 否则返回 `%({varname})s` 格式的命名占位符(符合 `psycopg2` 参数风格)。
|
||||||
|
|
||||||
|
#### 示例:
|
||||||
|
```python
|
||||||
|
obj.placeHolder('username', 0) # '%(username)s'
|
||||||
|
obj.placeHolder('__mainsql__', 0) # ''
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `dataConvert(self, dataList)`
|
||||||
|
|
||||||
|
将输入数据统一转换为字典格式。
|
||||||
|
|
||||||
|
#### 参数:
|
||||||
|
- `dataList`:可以是字典或对象列表(每个元素含 `name` 和 `value` 字段)。
|
||||||
|
|
||||||
|
#### 返回值:
|
||||||
|
- `dict`:键为字段名,值为对应值。
|
||||||
|
|
||||||
|
#### 示例:
|
||||||
|
```python
|
||||||
|
data = [{'name': 'id', 'value': 1}, {'name': 'name', 'value': 'Alice'}]
|
||||||
|
converted = obj.dataConvert(data)
|
||||||
|
# 结果: {'id': 1, 'name': 'Alice'}
|
||||||
|
|
||||||
|
obj.dataConvert({'x': 1}) # 直接返回原字典
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `pagingSQLmodel(self)`
|
||||||
|
|
||||||
|
返回分页 SQL 模板(⚠️ **此处有严重问题**)。
|
||||||
|
|
||||||
|
#### 返回值:
|
||||||
|
```sql
|
||||||
|
select *
|
||||||
|
from (
|
||||||
|
select page_s.*, rownum row_id
|
||||||
|
from (%s) page_s
|
||||||
|
order by $[sort]$
|
||||||
|
)
|
||||||
|
where row_id >= $[from_line]$ and row_id < $[end_line]$
|
||||||
|
```
|
||||||
|
|
||||||
|
> ❌ 错误分析:
|
||||||
|
> - `rownum` 是 Oracle 的伪列,**PostgreSQL 不支持**。
|
||||||
|
> - 正确的 PostgreSQL 分页应使用 `LIMIT` 和 `OFFSET`。
|
||||||
|
>
|
||||||
|
> ✅ 正确写法建议:
|
||||||
|
```sql
|
||||||
|
SELECT * FROM (%s) AS page_s
|
||||||
|
ORDER BY $[sort]$
|
||||||
|
LIMIT $[page_size]$ OFFSET $[offset]$
|
||||||
|
```
|
||||||
|
|
||||||
|
> 📝 提示:此方法需要重构以适配 PostgreSQL 分页机制。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `tablesSQL(self)`
|
||||||
|
|
||||||
|
生成查询当前数据库所有表及其描述的 SQL。
|
||||||
|
|
||||||
|
#### 返回值(SQL):
|
||||||
|
```sql
|
||||||
|
select x.name, y.description as title
|
||||||
|
from
|
||||||
|
(select a.name, c.oid
|
||||||
|
from (select lower(tablename) as name from pg_tables where schemaname='public') a,
|
||||||
|
pg_class c
|
||||||
|
where a.name = c.relname) x
|
||||||
|
left join pg_description y
|
||||||
|
on x.oid = y.objoid and y.objsubid = '0'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 功能说明:
|
||||||
|
- 查询 `public` 模式下的所有表名(小写)。
|
||||||
|
- 左连接 `pg_description` 获取表注释(`title`)。
|
||||||
|
- `objsubid = '0'` 表示表级注释(非字段注释)。
|
||||||
|
|
||||||
|
#### 返回字段:
|
||||||
|
- `name`: 表名(小写)
|
||||||
|
- `title`: 表注释(可为空)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `fieldsSQL(self, tablename=None)`
|
||||||
|
|
||||||
|
生成查询指定表所有字段信息的 SQL。
|
||||||
|
|
||||||
|
#### 参数:
|
||||||
|
- `tablename` (`str`):表名(不区分大小写)
|
||||||
|
|
||||||
|
#### 返回值(SQL):
|
||||||
|
```sql
|
||||||
|
SELECT
|
||||||
|
a.attname AS name,
|
||||||
|
t.typname AS type,
|
||||||
|
case t.typname
|
||||||
|
when 'varchar' then a.atttypmod - 4
|
||||||
|
when 'numeric' then (a.atttypmod - 4) / 65536
|
||||||
|
else null
|
||||||
|
end as length,
|
||||||
|
case t.typname
|
||||||
|
when 'numeric' then (a.atttypmod - 4) % 65536
|
||||||
|
else null
|
||||||
|
end as dec,
|
||||||
|
case a.attnotnull
|
||||||
|
when 't' then 'no'
|
||||||
|
when 'f' then 'yes'
|
||||||
|
end as nullable,
|
||||||
|
b.description AS title
|
||||||
|
FROM pg_class c, pg_attribute a
|
||||||
|
LEFT JOIN pg_description b ON a.attrelid = b.objoid AND a.attnum = b.objsubid,
|
||||||
|
pg_type t
|
||||||
|
WHERE lower(c.relname) = '%s'
|
||||||
|
AND a.attnum > 0
|
||||||
|
AND a.attrelid = c.oid
|
||||||
|
AND a.atttypid = t.oid
|
||||||
|
ORDER BY a.attnum;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 字段说明:
|
||||||
|
|
||||||
|
| 字段 | 含义 |
|
||||||
|
|------|------|
|
||||||
|
| `name` | 字段名 |
|
||||||
|
| `type` | 数据类型(如 varchar, int4) |
|
||||||
|
| `length` | 字段长度(varchar 最大长度,numeric 总位数) |
|
||||||
|
| `dec` | 小数位数(numeric 类型) |
|
||||||
|
| `nullable` | 是否可为空(`yes` 表示可空) |
|
||||||
|
| `title` | 字段注释 |
|
||||||
|
|
||||||
|
> 🔍 技术细节:
|
||||||
|
> - `atttypmod - 4` 是 PostgreSQL 中提取 `varchar(n)` 和 `numeric(p,s)` 定义长度的方式。
|
||||||
|
> - `attnum > 0` 排除系统列(如 OID)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `fkSQL(self, tablename=None)`
|
||||||
|
|
||||||
|
⚠️ **注意:当前实现错误!**
|
||||||
|
|
||||||
|
#### 当前 SQL 使用了 `user_constraints`、`user_cons_columns` —— 这些是 **Oracle** 的系统视图!
|
||||||
|
|
||||||
|
PostgreSQL 中并不存在这些视图。
|
||||||
|
|
||||||
|
#### 正确实现应类似如下:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT
|
||||||
|
tc.column_name AS field,
|
||||||
|
ccu.table_name AS fk_table,
|
||||||
|
ccu.column_name AS fk_field
|
||||||
|
FROM
|
||||||
|
information_schema.table_constraints AS tc
|
||||||
|
JOIN information_schema.foreign_key_columns AS fkc
|
||||||
|
ON tc.constraint_name = fkc.constraint_name
|
||||||
|
JOIN information_schema.constraint_column_usage AS ccu
|
||||||
|
ON fkc.unique_constraint_name = ccu.constraint_name
|
||||||
|
WHERE
|
||||||
|
tc.constraint_type = 'FOREIGN KEY'
|
||||||
|
AND tc.table_schema = 'public'
|
||||||
|
AND tc.table_name = %s
|
||||||
|
```
|
||||||
|
|
||||||
|
> ❌ 当前方法无法在 PostgreSQL 上运行,请尽快修复。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `pkSQL(self, tablename=None)`
|
||||||
|
|
||||||
|
生成查询指定表主键字段的 SQL。
|
||||||
|
|
||||||
|
#### 参数:
|
||||||
|
- `tablename` (`str`):表名(不区分大小写)
|
||||||
|
|
||||||
|
#### 返回值(SQL):
|
||||||
|
```sql
|
||||||
|
select
|
||||||
|
pg_attribute.attname as field_name,
|
||||||
|
lower(pg_class.relname) as table_name
|
||||||
|
from pg_constraint
|
||||||
|
inner join pg_class on pg_constraint.conrelid = pg_class.oid
|
||||||
|
inner join pg_attribute on pg_attribute.attrelid = pg_class.oid
|
||||||
|
and pg_attribute.attnum = pg_constraint.conkey[1]
|
||||||
|
inner join pg_type on pg_type.oid = pg_attribute.atttypid
|
||||||
|
where lower(pg_class.relname) = '%s'
|
||||||
|
and pg_constraint.contype = 'p'
|
||||||
|
```
|
||||||
|
|
||||||
|
> ⚠️ 限制:只取第一个主键字段(`conkey[1]`),不支持复合主键完整提取。
|
||||||
|
|
||||||
|
#### 建议改进:
|
||||||
|
```sql
|
||||||
|
-- 使用 unnest(conkey) 提取所有主键字段
|
||||||
|
SELECT a.attname AS field_name
|
||||||
|
FROM pg_index ix
|
||||||
|
JOIN pg_attribute a ON a.attrelid = ix.indrelid AND a.attnum = ANY(ix.indkey)
|
||||||
|
WHERE ix.indrelid = '"%s"'::regclass AND ix.indisprimary
|
||||||
|
ORDER BY a.attnum;
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `indexesSQL(self, tablename=None)`
|
||||||
|
|
||||||
|
生成查询指定表所有索引信息的 SQL。
|
||||||
|
|
||||||
|
#### 参数:
|
||||||
|
- `tablename` (`str`):表名(小写)
|
||||||
|
|
||||||
|
#### 返回值(SQL):
|
||||||
|
```sql
|
||||||
|
select
|
||||||
|
i.relname as index_name,
|
||||||
|
case ix.INDISUNIQUE
|
||||||
|
when 't' then 'unique'
|
||||||
|
else ''
|
||||||
|
end as is_unique,
|
||||||
|
a.attname as column_name
|
||||||
|
from
|
||||||
|
pg_class t,
|
||||||
|
pg_class i,
|
||||||
|
pg_index ix,
|
||||||
|
pg_attribute a
|
||||||
|
where
|
||||||
|
t.oid = ix.indrelid
|
||||||
|
and i.oid = ix.indexrelid
|
||||||
|
and a.attrelid = t.oid
|
||||||
|
and a.attnum = ANY(ix.indkey)
|
||||||
|
and t.relkind = 'r'
|
||||||
|
and lower(t.relname) = '%s'
|
||||||
|
order by
|
||||||
|
t.relname,
|
||||||
|
i.relname
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 返回字段:
|
||||||
|
- `index_name`: 索引名称
|
||||||
|
- `is_unique`: 是否唯一索引('unique' 或空)
|
||||||
|
- `column_name`: 索引对应的字段名
|
||||||
|
|
||||||
|
> ✅ 支持多字段索引拆解显示。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 总结与改进建议
|
||||||
|
|
||||||
|
| 项目 | 状态 | 建议 |
|
||||||
|
|------|------|------|
|
||||||
|
| 类型映射 | ✅ 完整 | 可增加数组、JSON 类型支持 |
|
||||||
|
| `placeHolder` | ✅ 兼容 psycopg2 | 良好 |
|
||||||
|
| `dataConvert` | ✅ 实用 | 建议添加类型校验 |
|
||||||
|
| `pagingSQLmodel` | ❌ 错误 | 替换为 `LIMIT/OFFSET` |
|
||||||
|
| `fkSQL` | ❌ 使用 Oracle 语法 | 重写为 `information_schema` 版本 |
|
||||||
|
| `pkSQL` | ⚠️ 仅支持单主键 | 扩展为支持复合主键 |
|
||||||
|
| `tablesSQL`, `fieldsSQL`, `indexesSQL` | ✅ 正确可用 | 可优化性能 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 许可与维护
|
||||||
|
|
||||||
|
- 维护者:未知(请补充)
|
||||||
|
- 适用版本:PostgreSQL 9.6+
|
||||||
|
- 依赖驱动:`psycopg2`, `pyguass`(兼容版)
|
||||||
|
- 所属模块:`.sor.postgresql`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
✅ **建议后续升级方向**:
|
||||||
|
- 使用 `information_schema` 替代部分 `pg_*` 系统表以提高可移植性。
|
||||||
|
- 添加单元测试覆盖各 SQL 查询。
|
||||||
|
- 引入日志记录和异常处理机制。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*文档版本:1.0*
|
||||||
|
*最后更新:2025-04-05*
|
||||||
202
aidocs/records.md
Normal file
202
aidocs/records.md
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
# `Records` 类技术文档
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
`Records` 是一个用于管理记录集合的 Python 类,它允许将字典形式的数据转换为指定类的实例,并提供统一的存储与迭代访问机制。默认情况下,记录会被转换为 `DictObject` 实例(来自 `appPublic.dictObject` 模块),但支持自定义类作为数据容器。
|
||||||
|
|
||||||
|
该类适用于需要动态处理结构化数据的场景,如数据库查询结果、API 响应数据等。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 依赖
|
||||||
|
|
||||||
|
```python
|
||||||
|
from appPublic.dictObject import DictObject
|
||||||
|
```
|
||||||
|
|
||||||
|
- `DictObject`:一个字典式对象封装类,允许通过属性访问字典键值(例如 `obj.name` 而非 `obj['name']`)。
|
||||||
|
- 若未安装或找不到此模块,请确保 `appPublic` 包已正确安装并可导入。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 类定义
|
||||||
|
|
||||||
|
```python
|
||||||
|
class Records:
|
||||||
|
def __init__(self, klass=DictObject):
|
||||||
|
self._records = []
|
||||||
|
self.klass = klass
|
||||||
|
```
|
||||||
|
|
||||||
|
### 构造函数 `__init__`
|
||||||
|
|
||||||
|
#### 参数:
|
||||||
|
| 参数名 | 类型 | 默认值 | 说明 |
|
||||||
|
|--------|------|--------|------|
|
||||||
|
| `klass` | `type` | `DictObject` | 用于将每条记录转换成的对象类型。必须是一个可调用类型(通常是类),接受关键字参数初始化。 |
|
||||||
|
|
||||||
|
#### 功能:
|
||||||
|
- 初始化一个空的记录列表 `_records`。
|
||||||
|
- 设置用于实例化每条记录的目标类 `klass`。
|
||||||
|
|
||||||
|
> 示例:若 `klass=MyDataClass`,则每条记录会以 `MyDataClass(**record_dict)` 的方式创建。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 方法说明
|
||||||
|
|
||||||
|
### `add(rec)`
|
||||||
|
|
||||||
|
向记录集合中添加一条新记录。
|
||||||
|
|
||||||
|
#### 参数:
|
||||||
|
| 参数名 | 类型 | 说明 |
|
||||||
|
|--------|------|------|
|
||||||
|
| `rec` | `dict` | 一个字典类型的记录数据,键对应目标类的初始化参数。 |
|
||||||
|
|
||||||
|
#### 行为:
|
||||||
|
1. 使用 `self.klass(**rec)` 将字典 `rec` 实例化为指定类的对象。
|
||||||
|
2. 将生成的对象追加到内部列表 `self._records` 中。
|
||||||
|
|
||||||
|
#### 异常:
|
||||||
|
- 若 `rec` 不是字典或其键不匹配 `klass` 所需参数,可能抛出 `TypeError` 或其他初始化异常。
|
||||||
|
|
||||||
|
#### 示例:
|
||||||
|
```python
|
||||||
|
records = Records()
|
||||||
|
records.add({"name": "Alice", "age": 30})
|
||||||
|
# 等效于: obj = DictObject(name="Alice", age=30)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `get()`
|
||||||
|
|
||||||
|
获取当前所有记录的列表。
|
||||||
|
|
||||||
|
#### 返回值:
|
||||||
|
- `list`:包含所有已添加记录对象的列表,顺序与添加一致。
|
||||||
|
|
||||||
|
#### 示例:
|
||||||
|
```python
|
||||||
|
all_records = records.get()
|
||||||
|
for r in all_records:
|
||||||
|
print(r.name)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `__iter__()`
|
||||||
|
|
||||||
|
使 `Records` 实例成为可迭代对象。
|
||||||
|
|
||||||
|
#### 返回值:
|
||||||
|
- 返回自身实例(实现了 `__next__` 的迭代器协议)。
|
||||||
|
|
||||||
|
#### 内部行为:
|
||||||
|
- 初始化迭代器状态变量:
|
||||||
|
- `self.start = 0`
|
||||||
|
- `self.end = len(self._records)`
|
||||||
|
|
||||||
|
> 注意:此实现不是线程安全的,且不支持嵌套循环中的并发迭代(因为状态保存在实例上)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `__next__()`
|
||||||
|
|
||||||
|
实现迭代器协议的下一步方法。
|
||||||
|
|
||||||
|
#### 返回值:
|
||||||
|
- 当还有未遍历记录时,返回下一个记录对象。
|
||||||
|
- 遍历完成后,抛出 `StopIteration` 异常以终止迭代。
|
||||||
|
|
||||||
|
#### 逻辑流程:
|
||||||
|
```text
|
||||||
|
if self.start < self.end:
|
||||||
|
返回 self._records[self.start] 并递增索引
|
||||||
|
else:
|
||||||
|
抛出 StopIteration
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 示例用法:
|
||||||
|
```python
|
||||||
|
for record in records:
|
||||||
|
print(record)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 使用示例
|
||||||
|
|
||||||
|
### 示例 1:使用默认 `DictObject`
|
||||||
|
|
||||||
|
```python
|
||||||
|
from appPublic.dictObject import DictObject
|
||||||
|
from your_module import Records
|
||||||
|
|
||||||
|
records = Records()
|
||||||
|
records.add({"id": 1, "name": "Product A"})
|
||||||
|
records.add({"id": 2, "name": "Product B"})
|
||||||
|
|
||||||
|
for r in records:
|
||||||
|
print(r.id, r.name)
|
||||||
|
# 输出:
|
||||||
|
# 1 Product A
|
||||||
|
# 2 Product B
|
||||||
|
```
|
||||||
|
|
||||||
|
### 示例 2:使用自定义类
|
||||||
|
|
||||||
|
```python
|
||||||
|
class User:
|
||||||
|
def __init__(self, name, email):
|
||||||
|
self.name = name
|
||||||
|
self.email = email
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<User {self.name} ({self.email})>"
|
||||||
|
|
||||||
|
users = Records(klass=User)
|
||||||
|
users.add({"name": "Bob", "email": "bob@example.com"})
|
||||||
|
users.add({"name": "Charlie", "email": "charlie@example.com"})
|
||||||
|
|
||||||
|
print(users.get())
|
||||||
|
# 输出: [<User Bob (bob@example.com)>, <User Charlie (charlie@example.com)>]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
1. **非线程安全**
|
||||||
|
`__iter__` 和 `__next__` 将迭代状态(`start`, `end`)存储在实例上,因此多个同时进行的迭代会导致状态冲突。
|
||||||
|
|
||||||
|
2. **不可重入迭代**
|
||||||
|
在一次迭代未完成前再次调用 `iter()` 会覆盖原有状态。建议改用 `iter(records.get())` 获取独立迭代器。
|
||||||
|
|
||||||
|
3. **性能提示**
|
||||||
|
`get()` 返回的是原始列表引用,修改该列表会影响内部状态。如需保护数据,建议返回副本:`return self._records[:]`
|
||||||
|
|
||||||
|
4. **扩展建议**
|
||||||
|
可考虑实现 `__len__`、`__getitem__` 支持更多序列操作,例如:
|
||||||
|
```python
|
||||||
|
def __len__(self):
|
||||||
|
return len(self._records)
|
||||||
|
|
||||||
|
def __getitem__(self, idx):
|
||||||
|
return self._records[idx]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 版本历史
|
||||||
|
|
||||||
|
| 版本 | 修改内容 |
|
||||||
|
|------|---------|
|
||||||
|
| 1.0 | 初始版本,支持基本记录管理与迭代功能 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 许可证
|
||||||
|
|
||||||
|
请参考项目整体许可证文件。
|
||||||
182
aidocs/runsql.md
Normal file
182
aidocs/runsql.md
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
# SQL 执行工具技术文档
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# SQL 执行工具(`sql_runner.py`)
|
||||||
|
|
||||||
|
一个基于 Python 3 的异步 SQL 脚本执行工具,支持从文件读取 SQL 并在指定数据库中执行,同时允许传入命名参数用于 SQL 模板替换。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
该脚本提供了一个命令行接口,用于执行存储在文件中的 SQL 语句。它通过 `sqlor.dbpools` 模块连接数据库池,并使用 `asyncio` 实现异步执行。支持动态变量注入(通过 `k=v` 参数),适用于自动化部署、数据初始化或批量任务场景。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 依赖说明
|
||||||
|
|
||||||
|
- **Python 版本**:Python 3.7+
|
||||||
|
- **第三方模块**:
|
||||||
|
- `sqlor.dbpools.runSQL`:用于异步执行 SQL 的数据库操作模块。
|
||||||
|
- 其他内置模块:`sys`, `codecs`, `asyncio`
|
||||||
|
|
||||||
|
> ⚠️ 注意:`ProgramPath`, `getConfig`, `DBPools` 等类/函数未在代码中定义,推测属于项目其他模块(如配置管理组件)。需确保这些符号在运行环境中已正确定义并可导入。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 使用方式
|
||||||
|
|
||||||
|
### 命令格式
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 sql_runner.py <path> <dbname> <sqlfile> [k1=v1] [k2=v2] ...
|
||||||
|
```
|
||||||
|
|
||||||
|
### 参数说明
|
||||||
|
|
||||||
|
| 参数 | 描述 |
|
||||||
|
|------|------|
|
||||||
|
| `path` | 配置文件路径或程序根路径(用于加载配置) |
|
||||||
|
| `dbname` | 在配置中定义的数据库连接名称 |
|
||||||
|
| `sqlfile` | 包含 SQL 语句的文件路径(UTF-8 编码) |
|
||||||
|
| `k=v` (可选) | 动态键值对参数,可用于 SQL 中的模板替换 |
|
||||||
|
|
||||||
|
### 示例调用
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 sql_runner.py ./config prod_db ./scripts/init.sql \
|
||||||
|
table_name=users \
|
||||||
|
batch_size=1000 \
|
||||||
|
debug_mode=true
|
||||||
|
```
|
||||||
|
|
||||||
|
上述命令将:
|
||||||
|
- 加载 `./config` 下的配置;
|
||||||
|
- 连接名为 `prod_db` 的数据库;
|
||||||
|
- 读取并执行 `init.sql` 文件中的 SQL;
|
||||||
|
- 提供三个变量供 SQL 内部引用:`table_name`, `batch_size`, `debug_mode`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 核心功能
|
||||||
|
|
||||||
|
### 1. 初始化 (`appinit`)
|
||||||
|
|
||||||
|
```python
|
||||||
|
def appinit():
|
||||||
|
if len(sys.argv) < 4:
|
||||||
|
print(f'usage:\n {sys.argv[0]} path dbname sqlfile [k=v ...] \n')
|
||||||
|
sys.exit(1)
|
||||||
|
p = ProgramPath()
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
p = sys.argv[1]
|
||||||
|
config = getConfig(p)
|
||||||
|
DBPools(config.databases)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 功能描述:
|
||||||
|
- 检查命令行参数是否至少包含 `path`, `dbname`, `sqlfile`。
|
||||||
|
- 获取程序路径 `p`,默认使用 `ProgramPath()` 对象(需外部实现)。
|
||||||
|
- 使用 `getConfig(p)` 加载配置对象。
|
||||||
|
- 初始化数据库连接池 `DBPools(config.databases)`。
|
||||||
|
|
||||||
|
> ✅ 成功后,全局数据库池准备就绪,可供后续 SQL 执行使用。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. 异步 SQL 执行 (`run`)
|
||||||
|
|
||||||
|
```python
|
||||||
|
async def run(ns):
|
||||||
|
with codecs.open(sys.argv[3], 'r', 'utf-8') as f:
|
||||||
|
sql = f.read()
|
||||||
|
await runSQL(sys.argv[2], sql, ns)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 功能描述:
|
||||||
|
- 异步函数,使用 `codecs.open` 安全读取 UTF-8 编码的 SQL 文件。
|
||||||
|
- 将整个文件内容作为字符串加载到内存。
|
||||||
|
- 调用 `runSQL(dbname, sql, namespace)` 执行 SQL,其中:
|
||||||
|
- `dbname`: 来自 `sys.argv[2]`
|
||||||
|
- `sql`: 从文件读取的内容
|
||||||
|
- `ns`: 用户传入的键值参数字典
|
||||||
|
|
||||||
|
> 💡 支持 SQL 模板语法(例如 `${key}` 或 `:key`,具体取决于 `runSQL` 实现),实现动态 SQL 构造。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. 主程序入口
|
||||||
|
|
||||||
|
```python
|
||||||
|
if __name__ == '__main__':
|
||||||
|
ns = {}
|
||||||
|
for x in sys.argv[3:]:
|
||||||
|
try:
|
||||||
|
k,v = x.split('=')
|
||||||
|
ns.update({k:v})
|
||||||
|
except Exception as e:
|
||||||
|
print(x, 'key-value pair expected')
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
appinit()
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
loop.run_until_complete(run(ns))
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 流程说明:
|
||||||
|
1. 解析从第 4 个参数开始的所有 `k=v` 形式输入,构建成字典 `ns`。
|
||||||
|
2. 若解析失败(如缺少 `=`),输出错误信息但不中断程序。
|
||||||
|
3. 调用 `appinit()` 初始化应用环境和数据库池。
|
||||||
|
4. 获取事件循环并运行异步任务 `run(ns)`,等待其完成。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## SQL 文件要求
|
||||||
|
|
||||||
|
- 必须为 **UTF-8 编码**
|
||||||
|
- 可以包含多条 SQL 语句(由 `runSQL` 决定是否支持批量执行)
|
||||||
|
- 可包含占位符,如:
|
||||||
|
```sql
|
||||||
|
CREATE TABLE IF NOT EXISTS ${table_name};
|
||||||
|
INSERT INTO logs VALUES (:msg, :ts);
|
||||||
|
```
|
||||||
|
占位符实际语法取决于 `runSQL` 的实现机制(如字符串替换、参数化查询等)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 错误处理与日志
|
||||||
|
|
||||||
|
- 参数不足时打印帮助信息并退出(状态码 1)
|
||||||
|
- `k=v` 解析异常会打印警告,但不会终止程序
|
||||||
|
- SQL 执行过程中的异常由 `runSQL` 处理,建议其内部进行日志记录或抛出可捕获异常
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
1. **安全性提醒**:
|
||||||
|
- 如果 SQL 使用字符串插值而非参数化查询,存在 SQL 注入风险,请谨慎使用用户输入。
|
||||||
|
- 推荐 `runSQL` 使用安全的模板引擎或预编译机制。
|
||||||
|
|
||||||
|
2. **性能提示**:
|
||||||
|
- 整个 SQL 文件一次性读入内存,不适合超大文件(GB 级别)。
|
||||||
|
- 如需流式处理或分批执行,需扩展此脚本。
|
||||||
|
|
||||||
|
3. **配置依赖**:
|
||||||
|
- `getConfig` 和 `DBPools` 的行为高度依赖项目结构,请确认配置格式正确(如 JSON/YAML 配置文件结构)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 扩展建议
|
||||||
|
|
||||||
|
- 添加 `-h/--help` 参数支持
|
||||||
|
- 增加日志模块替代 `print`
|
||||||
|
- 支持 `.sql` 文件通配符批量执行
|
||||||
|
- 增加 dry-run 模式预览 SQL
|
||||||
|
- 返回执行结果统计(影响行数、耗时等)
|
||||||
|
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
> 📝 文档版本:v1.0
|
||||||
|
> 最后更新:2025-04-05
|
||||||
595
aidocs/sor.md
Normal file
595
aidocs/sor.md
Normal file
@ -0,0 +1,595 @@
|
|||||||
|
# SQLor 技术文档
|
||||||
|
|
||||||
|
`SQLor` 是一个用于简化数据库操作的异步 Python 数据库访问类,支持参数化 SQL 执行、分页查询、CRUD 操作(Create, Read, Update, Delete)、元数据获取、动态 SQL 构建等功能。它设计为可扩展,适用于多种数据库后端。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
1. [概述](#概述)
|
||||||
|
2. [依赖与环境要求](#依赖与环境要求)
|
||||||
|
3. [核心功能](#核心功能)
|
||||||
|
4. [主要类与方法说明](#主要类与方法说明)
|
||||||
|
- [`db_type_2_py_type`](#db_type_2_py_type)
|
||||||
|
- [`SQLorException`](#sqlorexception)
|
||||||
|
- [`findNamedParameters`](#findnamedparameters)
|
||||||
|
- [`uniParams`](#uniparams)
|
||||||
|
- [`readsql`](#readsql)
|
||||||
|
- [`SQLor` 类](#sqlor-类)
|
||||||
|
- 初始化
|
||||||
|
- 元数据管理
|
||||||
|
- 连接与游标控制
|
||||||
|
- SQL 处理与转换
|
||||||
|
- 查询执行
|
||||||
|
- 分页与排序
|
||||||
|
- 聚合操作(Pivot)
|
||||||
|
- 表结构信息获取
|
||||||
|
- DDL 与表定义操作
|
||||||
|
- CRUD 操作(C/U/R/D)
|
||||||
|
5. [使用示例](#使用示例)
|
||||||
|
6. [异常处理](#异常处理)
|
||||||
|
7. [配置说明](#配置说明)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
`SQLor` 提供了一个统一接口来执行 SQL 查询和命令,并通过命名参数 `${var}` 支持模板化 SQL。其主要特点包括:
|
||||||
|
|
||||||
|
- 异步/同步双模式支持。
|
||||||
|
- 参数自动替换与安全绑定。
|
||||||
|
- 自动识别 `SELECT`, `INSERT/UPDATE/DELETE`, `DDL` 类型并返回相应结果。
|
||||||
|
- 支持分页、排序、条件过滤。
|
||||||
|
- 内置对表结构(字段、主键、外键、索引)的元数据查询。
|
||||||
|
- 支持自定义函数注册钩子(before/after 钩子)。
|
||||||
|
- 可扩展的类型转换机制。
|
||||||
|
- 简化的 CRUD 接口(I/C/R/U/D)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 依赖与环境要求
|
||||||
|
|
||||||
|
### 第三方依赖
|
||||||
|
|
||||||
|
```python
|
||||||
|
from appPublic.myImport import myImport
|
||||||
|
from appPublic.dictObject import DictObject
|
||||||
|
from appPublic.unicoding import uDict
|
||||||
|
from appPublic.myTE import MyTemplateEngine
|
||||||
|
from appPublic.objectAction import ObjectAction
|
||||||
|
from appPublic.argsConvert import ArgsConvert, ConditionConvert
|
||||||
|
from appPublic.registerfunction import RegisterFunction
|
||||||
|
from appPublic.log import info, exception, debug
|
||||||
|
```
|
||||||
|
|
||||||
|
> ⚠️ 注意:这些模块属于 `appPublic` 包,需确保已安装或项目中包含该包。
|
||||||
|
|
||||||
|
### Python 内置模块
|
||||||
|
|
||||||
|
- `os`
|
||||||
|
- `sys`
|
||||||
|
- `decimal`
|
||||||
|
- `datetime`
|
||||||
|
- `codecs`
|
||||||
|
- `re`
|
||||||
|
- `json`
|
||||||
|
- `traceback`
|
||||||
|
|
||||||
|
### 环境变量
|
||||||
|
|
||||||
|
```python
|
||||||
|
os.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.UTF8'
|
||||||
|
```
|
||||||
|
|
||||||
|
> 仅在 Oracle 数据库环境下需要设置 NLS 编码以支持中文 UTF-8。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 核心功能
|
||||||
|
|
||||||
|
| 功能 | 描述 |
|
||||||
|
|------|------|
|
||||||
|
| 参数化 SQL | 使用 `${var}` 占位符进行变量注入 |
|
||||||
|
| 异步支持 | 支持 `async/await` 模式运行 SQL |
|
||||||
|
| 分页查询 | 自动生成分页 SQL(需子类实现模型) |
|
||||||
|
| 排序与过滤 | 支持动态排序字段和条件表达式 |
|
||||||
|
| 元数据提取 | 获取表、字段、主键、索引等结构信息 |
|
||||||
|
| CRUD 封装 | 提供 `C()`(创建), `R()`(读取), `U()`(更新), `D()`(删除) 方法 |
|
||||||
|
| 回调机制 | 支持逐行处理查询结果 |
|
||||||
|
| 类型转换 | 自动将数据库类型转为 Python 原生类型 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 主要类与方法说明
|
||||||
|
|
||||||
|
### `db_type_2_py_type(o)`
|
||||||
|
|
||||||
|
将特定数据库类型转换为 Python 原生类型。
|
||||||
|
|
||||||
|
#### 参数
|
||||||
|
- `o`: 数据库字段值
|
||||||
|
|
||||||
|
#### 返回值
|
||||||
|
| 输入类型 | 输出 |
|
||||||
|
|--------|-------|
|
||||||
|
| `decimal.Decimal` | `float` |
|
||||||
|
| `datetime.datetime` | 字符串格式 `'YYYY-MM-DD HH:MM:SS'` |
|
||||||
|
| `datetime.date` | `'YYYY-MM-DD'` |
|
||||||
|
| 其他 | 原值 |
|
||||||
|
|
||||||
|
#### 示例
|
||||||
|
```python
|
||||||
|
db_type_2_py_type(decimal.Decimal('3.14')) → 3.14
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `SQLorException`
|
||||||
|
|
||||||
|
自定义异常类,封装 SQL 执行错误。
|
||||||
|
|
||||||
|
> ❗ 当前代码存在拼写错误:`__int__` 应为 `__init__`,且 `supper` 应为 `super`。
|
||||||
|
|
||||||
|
#### 属性
|
||||||
|
- `response`: `"error"`
|
||||||
|
- `errtype`: `"SQLor"`
|
||||||
|
- `errmsg`: 异常消息字符串
|
||||||
|
|
||||||
|
#### 示例输出
|
||||||
|
```
|
||||||
|
errtype:SQLor,errmsg=database error...
|
||||||
|
```
|
||||||
|
|
||||||
|
> ✅ **建议修复**:
|
||||||
|
```python
|
||||||
|
class SQLException(Exception):
|
||||||
|
def __init__(self, **kvs):
|
||||||
|
super(SQLException, self).__init__(**kvs)
|
||||||
|
self.dic = {
|
||||||
|
'response': 'error',
|
||||||
|
'errtype': 'SQLor',
|
||||||
|
'errmsg': str(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'errtype:%s,errmsg=%s' % (self.dic['errtype'], self.dic['errmsg'])
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `setValues(params, ns)`
|
||||||
|
|
||||||
|
从命名空间 `ns` 或系统环境变量中查找参数值。
|
||||||
|
|
||||||
|
#### 参数
|
||||||
|
- `params`: 参数名(字符串)
|
||||||
|
- `ns`: 命名空间字典
|
||||||
|
|
||||||
|
#### 返回
|
||||||
|
优先从 `ns` 中取值,若无则尝试 `os.getenv(params)`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `findNamedParameters(sql)`
|
||||||
|
|
||||||
|
解析 SQL 字符串中的所有 `${...}` 形式的命名参数。
|
||||||
|
|
||||||
|
#### 示例
|
||||||
|
```python
|
||||||
|
sql = "SELECT * FROM user WHERE id = ${uid}$ AND name = ${uname}$"
|
||||||
|
findNamedParameters(sql)
|
||||||
|
# 返回 ['${uid}$', '${uname}$']
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `uniParams(params1)`
|
||||||
|
|
||||||
|
去重保留唯一参数名列表。
|
||||||
|
|
||||||
|
#### 示例
|
||||||
|
```python
|
||||||
|
uniParams(['${a}$', '${b}$', '${a}$']) → ['${a}$', '${b}$']
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `readsql(fn)`
|
||||||
|
|
||||||
|
读取指定文件路径的 SQL 文件内容(UTF-8 编码)。
|
||||||
|
|
||||||
|
#### 参数
|
||||||
|
- `fn`: 文件路径
|
||||||
|
|
||||||
|
#### 返回
|
||||||
|
文件内容字符串。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## `SQLor` 类
|
||||||
|
|
||||||
|
### 初始化 `__init__`
|
||||||
|
|
||||||
|
#### 参数
|
||||||
|
| 参数 | 默认值 | 说明 |
|
||||||
|
|------|--------|------|
|
||||||
|
| `dbdesc` | None | 数据库描述字典,至少含 `dbname` |
|
||||||
|
| `sqltp`, `sqlts` | `$[`, `]$` | 模板占位符开始/结束符号 |
|
||||||
|
| `sqlvp`, `sqlvs` | `${`, `}$` | 变量占位符开始/结束符号 |
|
||||||
|
|
||||||
|
#### 初始化行为
|
||||||
|
- 设置连接状态(`conn`, `cur`)
|
||||||
|
- 初始化元数据缓存 `metadatas`
|
||||||
|
- 创建 `ConditionConvert` 实例用于条件表达式处理
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 元数据管理
|
||||||
|
|
||||||
|
#### `setMeta(tablename, meta)`
|
||||||
|
保存表的元数据到内存缓存。
|
||||||
|
|
||||||
|
#### `getMeta(tablename)`
|
||||||
|
获取指定表的缓存元数据。
|
||||||
|
|
||||||
|
#### `removeMeta(tablename)`
|
||||||
|
清除指定表的元数据缓存。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 连接与游标控制
|
||||||
|
|
||||||
|
#### `setCursor(async_mode, conn, cur)`
|
||||||
|
绑定数据库连接和游标对象。
|
||||||
|
|
||||||
|
#### `getConn()`
|
||||||
|
返回当前数据库连接对象。
|
||||||
|
|
||||||
|
#### `cursor()`
|
||||||
|
返回当前游标对象。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 类型转换支持
|
||||||
|
|
||||||
|
#### `setConvertFunction(typ, func)`
|
||||||
|
注册用户自定义类型转换函数。
|
||||||
|
|
||||||
|
#### `convert(typ, value)`
|
||||||
|
调用注册的转换函数处理值。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### SQL 类型判断
|
||||||
|
|
||||||
|
#### `getSqlType(sql)`
|
||||||
|
判断 SQL 语句类型。
|
||||||
|
|
||||||
|
| 类型 | 条件 |
|
||||||
|
|------|------|
|
||||||
|
| `"qry"` | 以 `SELECT` 开头 |
|
||||||
|
| `"dml"` | `INSERT`, `UPDATE`, `DELETE` |
|
||||||
|
| `"ddl"` | 其他(如 `CREATE`, `DROP`) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### SQL 模板处理
|
||||||
|
|
||||||
|
#### `maskingSQL(org_sql, NS)`
|
||||||
|
将命名参数 `${var}$` 替换为 `?` 并生成参数列表。
|
||||||
|
|
||||||
|
##### 步骤
|
||||||
|
1. 先替换 `$[...]$` 模板片段(如条件块)
|
||||||
|
2. 提取 `${var}$` 参数名
|
||||||
|
3. 替换为 `?` 占位符
|
||||||
|
4. 返回 `(标记后的SQL, 参数值列表)`
|
||||||
|
|
||||||
|
##### 特殊变量
|
||||||
|
- `__mainsql__`: 不参与参数绑定,用于嵌套 SQL 注入
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 执行方法
|
||||||
|
|
||||||
|
#### `execute(sql, value, callback, **kwargs)`
|
||||||
|
执行单条 SQL,支持回调逐行处理结果。
|
||||||
|
|
||||||
|
##### 流程
|
||||||
|
- 调用 `runVarSQL` 执行 SQL
|
||||||
|
- 若是查询 (`qry`) 且有回调,则逐行调用 `callback(DictObject(row))`
|
||||||
|
- 若是 DML,标记 `dataChanged=True`
|
||||||
|
|
||||||
|
#### `executemany(sql, values)`
|
||||||
|
批量执行 SQL(适用于 `INSERT` 等)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 分页与排序
|
||||||
|
|
||||||
|
#### `sortSQL(sql, NS)`
|
||||||
|
添加 `ORDER BY` 子句。
|
||||||
|
|
||||||
|
- 支持 `NS['sort']` 为字符串或列表
|
||||||
|
|
||||||
|
#### `pagingSQL(sql, paging, NS)`
|
||||||
|
构建分页 SQL,需配合 `pagingSQLmodel()` 使用。
|
||||||
|
|
||||||
|
> 默认为空,需由子类重写提供具体数据库分页语法(如 MySQL 的 `LIMIT OFFSET` 或 Oracle 的 `ROWNUM`)
|
||||||
|
|
||||||
|
##### 参数
|
||||||
|
- `pagename`: 页码参数名(默认 `'page'`)
|
||||||
|
- `rowsname`: 每页行数(默认 `'rows'`)
|
||||||
|
- `sortname`: 排序字段(可选)
|
||||||
|
|
||||||
|
##### 示例 NS
|
||||||
|
```python
|
||||||
|
{
|
||||||
|
'page': 2,
|
||||||
|
'rows': 20,
|
||||||
|
'sort': 'id desc'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `recordCnt(sql)`
|
||||||
|
包装 SQL 查询总记录数:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT COUNT(*) rcnt FROM (your_sql) rowcount_table
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 过滤器支持
|
||||||
|
|
||||||
|
#### `filterSQL(sql, filters, NS)`
|
||||||
|
将一组条件过滤器合并进原 SQL。
|
||||||
|
|
||||||
|
每个 filter 是一个带 `${}` 的模板字符串,若其中变量未在 `NS` 中存在,则忽略此条件(替换为 `1=1`)。
|
||||||
|
|
||||||
|
最终生成:
|
||||||
|
```sql
|
||||||
|
SELECT * FROM (original_sql) filter_table WHERE f1 AND f2 ...
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Pivot 表格转换
|
||||||
|
|
||||||
|
#### `pivotSQL(tablename, rowFields, columnFields, valueFields)`
|
||||||
|
生成透视表 SQL。
|
||||||
|
|
||||||
|
##### 逻辑
|
||||||
|
1. 查询 `columnFields` 的所有唯一值作为列头
|
||||||
|
2. 使用 `CASE WHEN` 构造每列聚合
|
||||||
|
3. 使用 `SUM` 聚合数值字段
|
||||||
|
|
||||||
|
##### 示例输出
|
||||||
|
```sql
|
||||||
|
SELECT dept,
|
||||||
|
SUM(salary_0) salary_0, -- 北京
|
||||||
|
SUM(salary_1) salary_1 -- 上海
|
||||||
|
FROM (
|
||||||
|
SELECT dept,
|
||||||
|
CASE WHEN city='北京' THEN salary ELSE 0 END AS salary_0,
|
||||||
|
CASE WHEN city='上海' THEN salary ELSE 0 END AS salary_1
|
||||||
|
FROM employees
|
||||||
|
) GROUP BY dept;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `pivot(desc, ...)`
|
||||||
|
执行 pivot 查询并返回结果列表。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 元数据查询方法
|
||||||
|
|
||||||
|
#### `tables()`
|
||||||
|
返回数据库中所有表的列表。
|
||||||
|
|
||||||
|
#### `indexes(tablename)`
|
||||||
|
返回某表的所有索引信息(需子类实现 `indexesSQL()`)
|
||||||
|
|
||||||
|
#### `fields(tablename)`
|
||||||
|
返回字段列表,包含名称、类型(映射后),例如:
|
||||||
|
```python
|
||||||
|
[
|
||||||
|
{"name": "id", "type": "int"},
|
||||||
|
{"name": "name", "type": "string"}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `primary(tablename)`
|
||||||
|
返回主键字段列表。
|
||||||
|
|
||||||
|
#### `fkeys(tablename)`
|
||||||
|
返回外键关系。
|
||||||
|
|
||||||
|
#### `getTableDesc(tablename)`
|
||||||
|
综合获取表的完整描述(summary + fields + indexes),并缓存至 `metadatas`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### DDL 与表操作
|
||||||
|
|
||||||
|
#### `createTable(tabledesc)`
|
||||||
|
使用模板引擎渲染建表语句并执行。
|
||||||
|
|
||||||
|
依赖 `self.ddl_template` 和 `MyTemplateEngine`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 事务控制
|
||||||
|
|
||||||
|
#### `commit()`
|
||||||
|
提交事务,重置 `dataChanged=False`
|
||||||
|
|
||||||
|
#### `rollback()`
|
||||||
|
回滚事务
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### CRUD 接口(I/C/R/U/D)
|
||||||
|
|
||||||
|
遵循 RESTful 风格简写:
|
||||||
|
|
||||||
|
#### `I(tablename)`
|
||||||
|
等价于 `getTableDesc()` — 获取表结构定义。
|
||||||
|
|
||||||
|
#### `C(tablename, ns)`
|
||||||
|
插入新记录。
|
||||||
|
|
||||||
|
- 自动提取 `ns` 中存在于表字段的部分
|
||||||
|
- 触发 `before` / `after` 钩子函数
|
||||||
|
- 生成 INSERT 语句
|
||||||
|
|
||||||
|
#### `R(tablename, ns, filters=None)`
|
||||||
|
读取记录。
|
||||||
|
|
||||||
|
- 若传入 `page` 参数 → 返回分页 `{total, rows}`
|
||||||
|
- 否则返回匹配行列表
|
||||||
|
- 支持简单等值条件或复杂 `DBFilter`
|
||||||
|
|
||||||
|
#### `U(tablename, ns)`
|
||||||
|
更新记录。
|
||||||
|
|
||||||
|
- 使用主键做 WHERE 条件
|
||||||
|
- 更新非主键字段
|
||||||
|
- 支持钩子函数
|
||||||
|
|
||||||
|
#### `D(tablename, ns)`
|
||||||
|
删除记录。
|
||||||
|
|
||||||
|
- 使用主键匹配删除
|
||||||
|
- 支持钩子函数
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 使用示例
|
||||||
|
|
||||||
|
### 1. 初始化 SQLor 实例
|
||||||
|
|
||||||
|
```python
|
||||||
|
dbdesc = {
|
||||||
|
'dbname': 'mydb'
|
||||||
|
}
|
||||||
|
sqlor = SQLor(dbdesc=dbdesc)
|
||||||
|
sqlor.setCursor(False, conn, cursor) # 同步模式
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 执行参数化查询
|
||||||
|
|
||||||
|
```python
|
||||||
|
sql = "SELECT * FROM users WHERE age > ${min_age}$"
|
||||||
|
result = []
|
||||||
|
await sqlor.execute(sql, {'min_age': 18}, lambda rec: result.append(rec))
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 分页查询
|
||||||
|
|
||||||
|
```python
|
||||||
|
desc = {
|
||||||
|
"sql_string": "SELECT id, name FROM users",
|
||||||
|
"sortfield": "name"
|
||||||
|
}
|
||||||
|
ns = {"page": 1, "rows": 10}
|
||||||
|
data = await sqlor.runSQLPaging(desc, ns)
|
||||||
|
# → {"total": 100, "rows": [...]}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. CRUD 操作
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 创建
|
||||||
|
await sqlor.C("users", {"name": "Alice", "age": 25})
|
||||||
|
|
||||||
|
# 读取(分页)
|
||||||
|
res = await sqlor.R("users", {"page": 1, "rows": 10})
|
||||||
|
|
||||||
|
# 更新
|
||||||
|
await sqlor.U("users", {"id": 1, "age": 26})
|
||||||
|
|
||||||
|
# 删除
|
||||||
|
await sqlor.D("users", {"id": 1})
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 获取表结构
|
||||||
|
|
||||||
|
```python
|
||||||
|
desc = await sqlor.I("users")
|
||||||
|
print(desc['fields'])
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 异常处理
|
||||||
|
|
||||||
|
所有 SQL 执行异常都会被捕获并记录日志:
|
||||||
|
|
||||||
|
```python
|
||||||
|
exception(f"{markedSQL=},{datas=}, {e=}, {fe=}")
|
||||||
|
raise e
|
||||||
|
```
|
||||||
|
|
||||||
|
推荐外部捕获 `Exception` 或自定义 `SQLException`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 配置说明
|
||||||
|
|
||||||
|
### 占位符配置
|
||||||
|
|
||||||
|
| 符号 | 默认 | 用途 |
|
||||||
|
|------|------|------|
|
||||||
|
| `sqltp` / `sqlts` | `$[` / `]$` | 控制结构模板(如 IF) |
|
||||||
|
| `sqlvp` / `sqlvs` | `${` / `}$` | 变量参数占位符 |
|
||||||
|
|
||||||
|
示例:
|
||||||
|
```sql
|
||||||
|
SELECT * FROM t WHERE status = ${status}$
|
||||||
|
$[ IF active ]$ AND active = 1 $[ ENDIF ]$
|
||||||
|
```
|
||||||
|
|
||||||
|
### 分页模型扩展
|
||||||
|
|
||||||
|
子类应重写 `pagingSQLmodel()` 提供数据库特定的分页语法。
|
||||||
|
|
||||||
|
例如 MySQL 子类:
|
||||||
|
```python
|
||||||
|
def pagingSQLmodel(self):
|
||||||
|
return "SELECT * FROM (%s) t LIMIT ${rows}$ OFFSET ${from_line}$"
|
||||||
|
```
|
||||||
|
|
||||||
|
Oracle 示例:
|
||||||
|
```python
|
||||||
|
def pagingSQLmodel(self):
|
||||||
|
return """
|
||||||
|
SELECT * FROM (
|
||||||
|
SELECT a.*, ROWNUM rn FROM (
|
||||||
|
%s ORDER BY ${sort}$
|
||||||
|
) a WHERE ROWNUM <= ${end_line}$
|
||||||
|
) WHERE rn > ${from_line}$
|
||||||
|
"""
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 总结
|
||||||
|
|
||||||
|
`SQLor` 是一个轻量级但功能完整的数据库抽象层,适合用于 Web API 后端、ETL 工具或管理后台的数据访问组件。其优势在于:
|
||||||
|
|
||||||
|
✅ 清晰的 CRUD 接口
|
||||||
|
✅ 支持异步高性能场景
|
||||||
|
✅ 安全的参数绑定
|
||||||
|
✅ 易于扩展不同数据库方言
|
||||||
|
|
||||||
|
> ⚠️ **待改进点**:
|
||||||
|
- 修复 `SQLException.__init__` 错误
|
||||||
|
- `commit()` 中 `self.datachanged` 应为 `self.dataChanged`
|
||||||
|
- `pagingdata()` 中 `cnt_desc` 未定义
|
||||||
|
- `setMeta` 中 `getMeta(self.tablename)` 应为 `self.getMeta(...)`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
📝 **版本**: v1.0
|
||||||
|
📅 **最后更新**: 2025-04-05
|
||||||
|
👨💻 **作者**: Auto-generated Documentation Tool
|
||||||
328
aidocs/sqlite3or.md
Normal file
328
aidocs/sqlite3or.md
Normal file
@ -0,0 +1,328 @@
|
|||||||
|
以下是为提供的 `SQLite3or` 类编写的 **Markdown 格式技术文档**,适用于项目开发文档、API 说明或团队协作参考。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# `SQLite3or` 技术文档
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
`SQLite3or` 是一个基于 `SQLor` 基类的数据库适配器类,专用于 **SQLite3** 数据库的操作。它实现了对 SQLite 数据库的元数据查询(如表、字段、主键、索引等)以及 SQL 片段生成的支持,主要用于 ORM 或通用数据库访问层中识别和操作 SQLite 数据库结构。
|
||||||
|
|
||||||
|
该类通过映射数据库类型与模型类型,提供统一的数据抽象接口。
|
||||||
|
|
||||||
|
继承自:`.sor.SQLor`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 类定义
|
||||||
|
|
||||||
|
```python
|
||||||
|
class SQLite3or(SQLor):
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 类属性
|
||||||
|
|
||||||
|
### `db2modelTypeMapping`
|
||||||
|
|
||||||
|
将 SQLite 数据库字段类型映射为应用层模型字段类型。
|
||||||
|
|
||||||
|
| 数据库类型 | 模型类型 |
|
||||||
|
|-----------|----------|
|
||||||
|
| `text` | `str` |
|
||||||
|
| `blob` | `file` |
|
||||||
|
| `int` | `long` |
|
||||||
|
| `integer` | `long` |
|
||||||
|
| `real` | `float` |
|
||||||
|
|
||||||
|
> 示例:`'TEXT' -> 'str'`, `'BLOB' -> 'file'`
|
||||||
|
|
||||||
|
### `model2dbTypemapping`
|
||||||
|
|
||||||
|
将模型字段类型映射回 SQLite 的数据库类型。
|
||||||
|
|
||||||
|
| 模型类型 | 数据库类型 |
|
||||||
|
|-----------|------------|
|
||||||
|
| `date` | `text` |
|
||||||
|
| `time` | `text` |
|
||||||
|
| `timestamp`| `text` |
|
||||||
|
| `str` | `text` |
|
||||||
|
| `char` | `text` |
|
||||||
|
| `short` | `int` |
|
||||||
|
| `long` | `int` |
|
||||||
|
| `float` | `real` |
|
||||||
|
| `text` | `text` |
|
||||||
|
| `file` | `blob` |
|
||||||
|
|
||||||
|
> 用于建表或类型转换时使用。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 类方法
|
||||||
|
|
||||||
|
### `isMe(name)`
|
||||||
|
|
||||||
|
判断当前适配器是否匹配指定数据库类型名称。
|
||||||
|
|
||||||
|
#### 参数:
|
||||||
|
- `name` (`str`):数据库标识名。
|
||||||
|
|
||||||
|
#### 返回值:
|
||||||
|
- `bool`:当 `name == 'sqlite3'` 时返回 `True`,否则 `False`。
|
||||||
|
|
||||||
|
#### 示例:
|
||||||
|
```python
|
||||||
|
SQLite3or.isMe('sqlite3') # True
|
||||||
|
SQLite3or.isMe('mysql') # False
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 实例方法
|
||||||
|
|
||||||
|
### `placeHolder(varname, pos=None)`
|
||||||
|
|
||||||
|
返回 SQL 占位符格式,SQLite 使用 `?` 作为参数占位符。
|
||||||
|
|
||||||
|
#### 参数:
|
||||||
|
- `varname` (`str`):变量名。
|
||||||
|
- `pos` (`int`, 可选):位置索引(未使用)。
|
||||||
|
|
||||||
|
#### 返回值:
|
||||||
|
- `str`:若 `varname` 为 `'__mainsql__'` 返回空字符串;其余情况返回 `'?'`。
|
||||||
|
|
||||||
|
#### 示例:
|
||||||
|
```python
|
||||||
|
db.placeHolder('username') # '?'
|
||||||
|
db.placeHolder('__mainsql__') # ''
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `dataConvert(dataList)`
|
||||||
|
|
||||||
|
将输入数据标准化为元组形式,供执行 SQL 时传参。
|
||||||
|
|
||||||
|
#### 参数:
|
||||||
|
- `dataList` (`dict` 或 `list[dict]`):待处理的数据。
|
||||||
|
|
||||||
|
#### 行为:
|
||||||
|
- 若是字典:取其所有 `.values()`。
|
||||||
|
- 若是字典列表:提取每个元素的 `'value'` 字段。
|
||||||
|
|
||||||
|
#### 返回值:
|
||||||
|
- `tuple`:标准化后的值元组。
|
||||||
|
|
||||||
|
#### 示例:
|
||||||
|
```python
|
||||||
|
db.dataConvert({'a': 1, 'b': 2})
|
||||||
|
# -> (1, 2)
|
||||||
|
|
||||||
|
db.dataConvert([{'value': 1}, {'value': 2}])
|
||||||
|
# -> (1, 2)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `pagingSQLmodel()`
|
||||||
|
|
||||||
|
获取分页 SQL 模板,支持 `$[sort]$`, `$[from_line]$`, `$[end_line]$` 动态替换。
|
||||||
|
|
||||||
|
#### 返回值:
|
||||||
|
- `str`:分页查询模板字符串。
|
||||||
|
|
||||||
|
```sql
|
||||||
|
select * from (%s) order by $[sort]$ limit $[from_line]$,$[end_line]$
|
||||||
|
```
|
||||||
|
|
||||||
|
> `%s` 将被子查询填充,`$[]$` 为后续模板引擎替换标记。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `tablesSQL()`
|
||||||
|
|
||||||
|
生成查询数据库中所有表的 SQL 语句。
|
||||||
|
|
||||||
|
#### 返回值:
|
||||||
|
```sql
|
||||||
|
select name, tbl_name as title from sqlite_master where upper(type) = 'TABLE'
|
||||||
|
```
|
||||||
|
|
||||||
|
> 查询 `sqlite_master` 系统表,获取表名及其别名(title)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `fieldsSQL(tablename)`
|
||||||
|
|
||||||
|
**(注意:当前实现有缺陷)**
|
||||||
|
|
||||||
|
本应返回用于获取表结构信息的 SQL,但实际未正确构造语句。
|
||||||
|
|
||||||
|
#### 当前代码:
|
||||||
|
```python
|
||||||
|
return sqlcmd # sqlcmd 为空字符串
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 正确预期(建议修复):
|
||||||
|
```python
|
||||||
|
return f"PRAGMA table_info('{tablename}')"
|
||||||
|
```
|
||||||
|
|
||||||
|
> 用于获取表字段详情(cid, name, type, notnull, dflt_value, pk)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `fields(tablename)`
|
||||||
|
|
||||||
|
解析指定表的所有字段信息,并进行标准化处理。
|
||||||
|
|
||||||
|
#### 参数:
|
||||||
|
- `tablename` (`str`):表名。
|
||||||
|
|
||||||
|
#### 处理流程:
|
||||||
|
1. 调用 `fieldsSQL(tablename)` 获取结构查询 SQL。
|
||||||
|
2. 执行 SQL 并收集结果。
|
||||||
|
3. 使用正则提取字段类型的长度与精度(如 `VARCHAR(50,2)`)。
|
||||||
|
4. 映射数据库类型 → 模型类型(通过 `db2modelTypeMapping`)。
|
||||||
|
5. 统一字段名为小写,添加 `title` 字段。
|
||||||
|
|
||||||
|
#### 返回值:
|
||||||
|
`list[dict]`,每个字段对象包含:
|
||||||
|
|
||||||
|
| 键 | 类型 | 描述 |
|
||||||
|
|----------|--------|------|
|
||||||
|
| `name` | str | 字段名(小写) |
|
||||||
|
| `type` | str | 模型类型(如 str/long/file) |
|
||||||
|
| `length` | int | 类型长度(括号内第一个数字) |
|
||||||
|
| `dec` | int | 小数位数(第二个数字) |
|
||||||
|
| `title` | str | 别名,默认等于字段名 |
|
||||||
|
| `pk` | int | 是否为主键(来自 PRAGMA 输出) |
|
||||||
|
|
||||||
|
> ⚠️ 注意:由于 `fieldsSQL` 未正确实现,此方法在运行时会出错。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `fkSQL(tablename)`
|
||||||
|
|
||||||
|
获取外键相关信息的 SQL 语句。
|
||||||
|
|
||||||
|
#### 当前实现:
|
||||||
|
```python
|
||||||
|
return ""
|
||||||
|
```
|
||||||
|
|
||||||
|
> **尚未实现**,SQLite 支持外键需开启 `PRAGMA foreign_keys=ON`,可通过 `PRAGMA foreign_key_list(table)` 查询。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `fkeys(tablename)`
|
||||||
|
|
||||||
|
返回指定表的外键信息列表。
|
||||||
|
|
||||||
|
#### 返回值:
|
||||||
|
- `[]`:空列表(表示暂不支持外键提取)。
|
||||||
|
|
||||||
|
> 预期未来可返回类似:
|
||||||
|
```python
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"field": "user_id",
|
||||||
|
"ref_table": "users",
|
||||||
|
"ref_field": "id"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `pkSQL(tablename)`
|
||||||
|
|
||||||
|
获取主键信息的 SQL 语句。
|
||||||
|
|
||||||
|
#### 当前实现:
|
||||||
|
```python
|
||||||
|
return ""
|
||||||
|
```
|
||||||
|
|
||||||
|
> **未实现**,推荐使用 `PRAGMA table_info(tablename)` 中的 `pk` 字段判断。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `primary(tablename)`
|
||||||
|
|
||||||
|
从字段信息中提取主键字段。
|
||||||
|
|
||||||
|
#### 参数:
|
||||||
|
- `tablename` (`str`)
|
||||||
|
|
||||||
|
#### 实现逻辑:
|
||||||
|
1. 调用 `self.fields(tablename)` 获取所有字段。
|
||||||
|
2. 过滤出 `pk == 1` 的字段。
|
||||||
|
3. 返回字段名列表。
|
||||||
|
|
||||||
|
#### 返回值:
|
||||||
|
`list[dict]`,例如:
|
||||||
|
```python
|
||||||
|
[{'field': 'id'}, {'field': 'code'}]
|
||||||
|
```
|
||||||
|
|
||||||
|
> ⚠️ 依赖 `fields()` 正常工作。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `indexesSQL(tablename=None)`
|
||||||
|
|
||||||
|
生成查询索引信息的 SQL。
|
||||||
|
|
||||||
|
#### 参数:
|
||||||
|
- `tablename` (`str`, 可选):若指定,则只查该表的索引。
|
||||||
|
|
||||||
|
#### 返回值:
|
||||||
|
```sql
|
||||||
|
select * from sqlite_master
|
||||||
|
where lower(type) = 'index'
|
||||||
|
```
|
||||||
|
|
||||||
|
如果传入 `tablename`,附加条件:
|
||||||
|
```sql
|
||||||
|
and lower(tbl_name)='xxx'
|
||||||
|
```
|
||||||
|
|
||||||
|
> 查询系统表 `sqlite_master` 中所有索引定义。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 已知问题与改进建议
|
||||||
|
|
||||||
|
| 方法 | 问题描述 | 建议改进 |
|
||||||
|
|------|---------|--------|
|
||||||
|
| `fieldsSQL` | 返回空字符串导致异常 | 应返回 `PRAGMA table_info('%s') % tablename` |
|
||||||
|
| `fkSQL` / `fkeys` | 未实现外键支持 | 可用 `PRAGMA foreign_key_list(tablename)` 实现 |
|
||||||
|
| `pkSQL` | 未实现 | 可删除或补充逻辑 |
|
||||||
|
| 类型解析正则 | 支持 `(len,dec)` 格式,但 SQLite 不常用 | 可简化或增强兼容性 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 示例用法(伪代码)
|
||||||
|
|
||||||
|
```python
|
||||||
|
db = SQLite3or(connection)
|
||||||
|
if db.isMe('sqlite3'):
|
||||||
|
tables = db.tables()
|
||||||
|
for t in tables:
|
||||||
|
print(f"Table: {t['name']}")
|
||||||
|
fields = db.fields(t['name'])
|
||||||
|
for f in fields:
|
||||||
|
print(f" Field: {f['name']} ({f['type']})")
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 总结
|
||||||
|
|
||||||
|
`SQLite3or` 提供了一个轻量级的 SQLite 元数据访问框架,适合集成到动态 ORM 或低代码平台中。尽管部分功能尚未完成,但核心的字段映射、分页、表枚举已具备良好结构,可通过完善 SQL 查询语句进一步提升实用性。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
📌 **维护建议**:优先修复 `fieldsSQL()` 和补充 `PRAGMA` 相关调用以确保元数据读取准确。
|
||||||
112
aidocs/version.md
Normal file
112
aidocs/version.md
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
# 技术文档:`fixed_sor.py`
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
本模块 `fixed_sor.py` 是一个用于解决数值计算中迭代方法(如逐次超松弛法,Successive Over-Relaxation, SOR)相关问题的 Python 脚本。该版本主要修复了之前版本中与 C 函数调用相关的 Bug,提升了代码的稳定性与兼容性。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 版本信息
|
||||||
|
|
||||||
|
- **当前版本**:`0.1.3`
|
||||||
|
- **更新内容**:
|
||||||
|
- 修复了与底层 C 函数交互时出现的 Bug。
|
||||||
|
- 增强了异常处理机制,避免因类型不匹配或内存访问错误导致程序崩溃。
|
||||||
|
- 提高了与外部 C 扩展模块的兼容性。
|
||||||
|
|
||||||
|
> ⚠️ 注意:此修复主要影响使用 C 扩展进行高性能计算的用户。纯 Python 用户通常不受影响,但仍建议升级以获得更好的稳定性。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 安装与依赖
|
||||||
|
|
||||||
|
### 依赖项
|
||||||
|
|
||||||
|
- Python >= 3.7
|
||||||
|
- (可选)Cython 或 ctypes 支持(若使用 C 扩展)
|
||||||
|
|
||||||
|
### 安装方式
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 通过 pip 安装(假设已发布到 PyPI)
|
||||||
|
pip install fixed-sor==0.1.3
|
||||||
|
|
||||||
|
# 或本地安装
|
||||||
|
python setup.py install
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 使用示例
|
||||||
|
|
||||||
|
```python
|
||||||
|
import fixed_sor
|
||||||
|
|
||||||
|
# 示例:求解线性方程组 Ax = b 使用 SOR 方法
|
||||||
|
A = [[4, -1, 0],
|
||||||
|
[-1, 4, -1],
|
||||||
|
[0, -1, 4]]
|
||||||
|
b = [15, 10, 15]
|
||||||
|
|
||||||
|
x = fixed_sor.solve(A, b, omega=1.2, max_iter=1000, tol=1e-6)
|
||||||
|
print("解为:", x)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## API 参考
|
||||||
|
|
||||||
|
### `solve(A, b, omega=1.0, max_iter=1000, tol=1e-6)`
|
||||||
|
|
||||||
|
使用 SOR 方法求解线性方程组 $Ax = b$。
|
||||||
|
|
||||||
|
#### 参数:
|
||||||
|
|
||||||
|
| 参数 | 类型 | 说明 |
|
||||||
|
|-------------|------------|------|
|
||||||
|
| `A` | list/list of lists 或 numpy.ndarray | 系数矩阵(必须为方阵且对角占优或正定) |
|
||||||
|
| `b` | list 或 numpy.ndarray | 常数向量 |
|
||||||
|
| `omega` | float | 松弛因子,默认为 1.0(即 Gauss-Seidel 方法) |
|
||||||
|
| `max_iter` | int | 最大迭代次数,默认 1000 |
|
||||||
|
| `tol` | float | 收敛容差,默认 1e-6 |
|
||||||
|
|
||||||
|
#### 返回值:
|
||||||
|
|
||||||
|
- `list`:解向量 $x$
|
||||||
|
|
||||||
|
#### 异常:
|
||||||
|
|
||||||
|
- `ValueError`:输入矩阵维度不匹配或不满足 SOR 方法前提条件。
|
||||||
|
- `RuntimeError`:迭代未在最大次数内收敛。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 更新日志(Changelog)
|
||||||
|
|
||||||
|
### v0.1.3 — 2025-04-05
|
||||||
|
- ✅ 修复:C 函数接口中的内存访问越界问题
|
||||||
|
- ✅ 修复:数据类型转换错误(Python 到 C 的 double 数组传递)
|
||||||
|
- 🛠️ 优化:提升与 NumPy 数组的兼容性
|
||||||
|
- 📚 更新文档
|
||||||
|
|
||||||
|
### v0.1.2 — 2024-XX-XX
|
||||||
|
- 添加基本 SOR 实现
|
||||||
|
- 支持列表和 NumPy 输入
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 开发与贡献
|
||||||
|
|
||||||
|
欢迎提交 Issue 和 Pull Request。请确保测试覆盖所有修改路径,特别是涉及 C 接口的部分。
|
||||||
|
|
||||||
|
GitHub 仓库:`https://github.com/username/fixed-sor`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 许可证
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> **备注**:本模块名称“fixed”强调其主要目标是修复先前版本中的关键缺陷,后续版本将逐步增强功能与性能。
|
||||||
Loading…
x
Reference in New Issue
Block a user