This commit is contained in:
yumoqing 2025-10-05 11:24:24 +08:00
parent 8aaae210df
commit 0e3e9c0548
23 changed files with 6384 additions and 0 deletions

1
aidocs/__init__.md Normal file
View File

@ -0,0 +1 @@
当然可以!请先提供您需要编写技术文档的代码,我将根据代码内容为您生成详细的 Markdown 格式技术文档,包括功能说明、使用方法、参数解释、示例等内容。

105
aidocs/aiomysqlor.md Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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 中便于团队查阅。

View 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 配置驱动模板渲染,提升可维护性。
---
✅ 文档结束

View 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]` | 对象 | 表元数据对象,包含表名、标题、主键等信息 |
| &nbsp;&nbsp;`.name` | 字符串 | 表名(如:`EMPLOYEE` |
| &nbsp;&nbsp;`.title` | 字符串 | 表中文描述(用于 COMMENT |
| &nbsp;&nbsp;`.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日
---
✅ 文档结束。可用于团队知识共享、项目文档归档或工具集成说明。

View 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]` | 对象 | 包含表级别的元信息对象,必须是列表且第一个元素有效 |
| &nbsp;&nbsp;`.name` | 字符串 | 表名(如 `"users"` |
| &nbsp;&nbsp;`.title` | 字符串 | 表的中文/描述性标题,用于 COMMENT |
| &nbsp;&nbsp;`.primary` | 列表 | 主键字段名称列表(如 `["id"]``["user_id", "tenant_id"]` |
| `fields` | 列表 | 字段对象列表,每个对象代表一列 |
| &nbsp;&nbsp;`.name` | 字符串 | 字段名(如 `"username"` |
| &nbsp;&nbsp;`.type` | 字符串 | 字段逻辑类型(见下文“类型映射”) |
| &nbsp;&nbsp;`.length` | 整数 | 字段长度(对字符串和数值类型有意义) |
| &nbsp;&nbsp;`.dec` | 整数 | 小数位数decimal scale |
| &nbsp;&nbsp;`.nullable` | 字符串 | 是否允许为空:`"yes"` 表示可空,`"no"` 表示 `NOT NULL` |
| &nbsp;&nbsp;`.title` | 字符串 | 字段的中文/描述性标题,用于 COMMENT |
| `indexes` | 列表 | 索引定义对象列表 |
| &nbsp;&nbsp;`.name` | 字符串 | 索引名称标识(将用于生成索引名) |
| &nbsp;&nbsp;`.idxtype` | 字符串 | 索引类型,若为 `"unique"` 则创建唯一索引 |
| &nbsp;&nbsp;`.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日*

View 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

View 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
View 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}$)
```
### 示例 3NULL 判断
```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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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”强调其主要目标是修复先前版本中的关键缺陷后续版本将逐步增强功能与性能。