ahserver/aidocs/sqldsProcessor.md
2025-10-05 12:07:12 +08:00

303 lines
8.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

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

# SQL 数据源处理器技术文档
## 概述
`SQLDataSourceProcessor` 是一个基于 `DataSourceProcessor` 的子类,用于处理以 `.sqlds` 格式定义的 SQL 数据源。它允许通过配置文件描述 SQL 查询、参数和数据库连接,并动态执行查询获取数据。
该模块主要用于从数据库中提取结构化数据,支持普通查询、分页查询以及自动推导返回字段结构(`datadesc`),并能将推导结果持久化回源文件。
---
## 依赖模块
```python
import codecs
from .dsProcessor import DataSourceProcessor
from appPublic.jsonConfig import getConfig
from sqlor.dbpools import DBPools
import json
```
- `codecs`: 用于安全地读写带编码的文件(如 UTF-8
- `DataSourceProcessor`: 抽象基类,定义了数据源处理器的标准接口。
- `getConfig` (from `appPublic.jsonConfig`): 获取全局配置对象。
- `DBPools` (from `sqlor.dbpools`): 提供异步数据库连接池及 SQL 执行装饰器。
- `json`: 用于序列化/反序列化 JSON 数据。
---
## 配置文件格式(`.sqlds`
`.sqlds` 文件是标准的 JSON 格式,描述了一个 SQL 查询的数据源信息:
```json
{
"sqldesc": {
"sql_string": "select * from dbo.stock_daily_hist where stock_num=${stock_num}$ order by trade_date desc",
"db": "mydb",
"sortfield": "trade_date"
},
"arguments": [
{
"name": "stock_num",
"type": "str",
"iotype": "text",
"default": "600804"
}
],
"datadesc": []
}
```
### 字段说明
| 字段 | 类型 | 必需 | 描述 |
|------|------|------|------|
| `sqldesc.sql_string` | string | 是 | 实际执行的 SQL 查询语句,支持 `${param}$` 形式的参数占位符。 |
| `sqldesc.db` | string | 是 | 数据库连接名称(在 DBPools 中注册过的别名)。 |
| `sqldesc.sortfield` | string | 否 | 排序字段,可用于前端排序或分页逻辑参考。 |
| `arguments` | array | 否 | 定义传入 SQL 的参数列表,每个参数包含:`name`, `type`, `iotype`, `default`。 |
| `datadesc` | array | 否 | 描述查询结果字段结构的数组。若为空,则首次访问时自动推导并写回文件。 |
> ⚠️ 注意:`${param}$` 是模板语法,运行时会被 `ns` 上下文中的对应值替换。
---
## 类定义
```python
class SQLDataSourceProcessor(DataSourceProcessor):
```
继承自 `DataSourceProcessor`,实现针对 `.sqlds` 类型数据源的具体行为。
---
## 方法说明
### `isMe(name) -> bool`
判断当前处理器是否适用于指定类型的数据源。
#### 参数
- `name` (`str`):数据源类型名。
#### 返回值
- `True` 当且仅当 `name == 'sqlds'`
#### 示例
```python
if SQLDataSourceProcessor.isMe('sqlds'):
processor = SQLDataSourceProcessor(...)
```
---
### `getArgumentsDesc(dict_data, ns, request) -> list or None`
获取数据源所需的输入参数描述。
#### 参数
- `dict_data` (`dict`):解析后的 `.sqlds` 文件内容。
- `ns` (`dict`):命名空间(通常为请求参数)。
- `request` (`Request`)HTTP 请求对象(可选用途扩展)。
#### 返回值
- `list`:参数描述数组(来自 `arguments` 字段)。
- `None`:若未定义 `arguments`
#### 示例返回
```python
[
{
"name": "stock_num",
"type": "str",
"iotype": "text",
"default": "600804"
}
]
```
---
### `async getDataDesc(dict_data, ns, request) -> list`
异步获取查询结果的字段元信息(即 `datadesc`)。如果尚未生成,则自动从数据库中推导并保存到原文件。
#### 参数
- `dict_data` (`dict`):原始数据源配置。
- `ns` (`dict`):参数上下文,用于填充 SQL 占位符。
- `request` (`Request`):请求对象。
#### 行为流程
1.`datadesc` 已存在且非空,直接返回。
2. 否则:
- 调用 `runSQLResultFields` 获取 SQL 查询的实际返回字段(不含 `_row_id`)。
- 将推导出的字段结构写入 `dict_data['datadesc']`
- 序列化整个 `dict_data` 回源文件(路径为 `self.src_file`),保持缩进与中文不转义。
#### 使用的装饰器
- `@pool.runSQLResultFields`:执行 SQL 并返回字段元信息(列名、类型等)。
#### 返回值
- `list`:字段描述列表,每项为字段元数据字典(如 `{ "name": "trade_date", "type": "datetime" }`)。
#### 示例输出
```python
[
{"name": "stock_num", "type": "string"},
{"name": "trade_date", "type": "date"},
{"name": "close_price", "type": "float"}
]
```
> ✅ 自动持久化:一旦推导完成,会更新 `.sqlds` 文件以避免重复分析。
---
### `async getData(dict_data, ns, request) -> list`
执行完整 SQL 查询并返回所有结果记录。
#### 参数
- `dict_data` (`dict`):数据源定义。
- `ns` (`dict`):参数上下文。
- `request` (`Request`):请求对象。
#### 行为
- 使用 `@pool.runSQL` 执行 `sqldesc.sql_string`
- 替换 `${}` 中的参数。
- 返回所有行组成的列表。
#### 使用的装饰器
- `@pool.runSQL`:执行查询并返回异步迭代器,转换为列表。
#### 返回值
- `list[dict]`:每条记录为一个字典。
#### 示例返回
```python
[
{"stock_num": "600804", "trade_date": "2023-09-01", "close_price": 12.5},
{"stock_num": "600804", "trade_date": "2023-08-31", "close_price": 12.3}
]
```
---
### `async getPagingData(dict_data, ns, request) -> dict`
执行分页查询,返回带分页信息的结果集。
#### 参数
- `dict_data` (`dict`)
- `ns` (`dict`):必须包含分页参数,如 `page`, `pageSize` 或等效字段。
- `request` (`Request`)
#### 行为
- 使用 `@pool.runSQLPaging` 执行分页 SQL。
- 自动处理偏移量和限制数量。
- 返回结构化分页响应。
#### 使用的装饰器
- `@pool.runSQLPaging`:支持分页的 SQL 执行器,返回包含 `data`, `total`, `page`, `pageSize` 的对象。
#### 返回值(示例)
```json
{
"data": [...],
"total": 100,
"page": 1,
"pageSize": 10
}
```
---
## 内部机制说明
### SQL 模板替换
使用 `${param}$` 语法进行变量注入,例如:
```sql
select * from table where id = ${user_id}$
```
运行时由 `DBPools` 的装饰器根据 `ns` 字典替换为实际值。
### 自动字段推导与缓存
首次访问 `getDataDesc` 时,若 `datadesc` 为空,系统将:
1. 执行 SQL 获取字段结构;
2. 过滤掉内部字段 `_row_id`
3. 写入本地 `.sqlds` 文件以供后续使用。
这提高了性能并减少了对数据库元数据的频繁访问。
### 编码与文件写入
使用 `codecs.open(..., encoding=config.website.coding)` 确保文件按项目设定编码保存(通常是 UTF-8并通过 `ensure_ascii=False` 保留中文字符。
---
## 使用场景
适合以下情况:
- 需要灵活配置 SQL 查询作为 API 输出。
- 前端需要知道返回字段结构(用于表格渲染)。
- 支持参数化查询和分页。
- 开发阶段快速原型设计,无需编写后端代码。
---
## 示例 `.sqlds` 文件应用
假设文件名为 `stock_history.sqlds`,配置如下:
```json
{
"sqldesc": {
"sql_string": "SELECT stock_num, trade_date, open, high, low, close FROM stock_daily WHERE stock_num = ${code}$ ORDER BY trade_date DESC",
"db": "financial_db",
"sortfield": "trade_date"
},
"arguments": [
{
"name": "code",
"type": "str",
"iotype": "text",
"default": "600804"
}
],
"datadesc": []
}
```
调用 `getDataDesc()` 后,`datadesc` 将被自动填充为:
```json
[
{"name": "stock_num", "type": "string"},
{"name": "trade_date", "type": "date"},
{"name": "open", "type": "float"},
{"name": "high", "type": "float"},
{"name": "low", "type": "float"},
{"name": "close", "type": "float"}
]
```
---
## 注意事项
1. **安全性**:确保 `${}` 参数经过验证,防止 SQL 注入(建议配合白名单或类型校验)。
2. **性能**:大数据集应优先使用 `getPagingData`
3. **文件权限**:写回 `.sqlds` 文件时需保证进程有写权限。
4. **缓存失效**:修改 SQL 后建议手动清除 `datadesc` 以触发重新推导。
---
## 总结
`SQLDataSourceProcessor` 提供了一种声明式的方式来定义基于 SQL 的数据接口,结合配置文件与异步数据库访问,实现了高效、可维护的数据服务层组件。特别适用于报表、配置化页面、低代码平台等场景。