Name | query-builder-tool JSON |
Version |
0.2.0
JSON |
| download |
home_page | None |
Summary | A secure SQL query builder for Python using Rust and pyo3. Supports dynamic templates with safety checks against SQL injection. |
upload_time | 2025-09-15 08:34:55 |
maintainer | None |
docs_url | None |
author | None |
requires_python | <3.13,>=3.8 |
license | None |
keywords |
sql
query
builder
security
rust
pyo3
|
VCS |
 |
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# Query Builder
一个高性能的SQL查询构建器,使用Rust + PyO3开发,为Python提供内存缓存的SQL模板渲染功能。
## 🚀 特性
- **⚡ 极速性能**: 使用Rust开发 + 内存模板缓存,提供原生级别的性能
- **🔒 安全第一**: 内置SQL注入防护和危险关键词检测
- **🧠 智能缓存**: 启动时一次性加载所有模板到内存,查询时零IO操作
- **🎯 模板引擎**: 基于Tera模板引擎,支持条件语句、循环等高级功能
- **🐍 Python友好**: 完整的类型提示支持,VS Code智能感知
- **🌐 跨平台**: 支持macOS、Windows、Linux多平台
## 🏗️ 架构优势
### 🔥 性能优化
```
传统方式: 查询时读取文件 → 解析YAML → 渲染SQL
新架构: 启动时加载全部 → 查询时内存读取 ⚡ → 渲染SQL
```
### 💾 内存缓存机制
- **一次加载** - 应用启动时将所有SQL模板加载到内存
- **零IO查询** - 构建SQL时直接从内存获取模板
- **生产就绪** - 适合高并发、低延迟的生产环境
### 🎯 VS Code完整支持
- **智能感知** - 完整的方法和属性提示
- **类型检查** - 参数类型验证和错误预防
- **文档悬浮** - 丰富的API说明和示例
## 🔒 安全特性
- **仅支持 SELECT 查询** - 严格限制只能构造查询语句
- **SQL 注入防护** - 检测和阻止常见的 SQL 注入攻击模式
- **危险关键词过滤** - 阻止 DROP、UPDATE、DELETE 等危险操作
- **模式匹配检测** - 识别注释注入、UNION 注入等攻击
## 📦 安装
```bash
pip install query-builder-tool
```
## 🚀 快速开始
### 1. 组织SQL模板
创建模板目录结构:
```
sql/
├── users.yaml # 用户查询
├── orders.yaml # 订单查询
└── api.yaml # API查询
```
#### users.yaml
```yaml
select_by_id: |
SELECT id, name, email, created_at
FROM users
WHERE id = {{ user_id }};
list_active: |
SELECT id, name, email
FROM users
WHERE status = "{{ status }}"
{% if limit %}LIMIT {{ limit }}{% endif %};
search: |
SELECT id, name, email
FROM users
WHERE name LIKE "%{{ keyword }}%"
ORDER BY created_at DESC
{% if limit %}LIMIT {{ limit }}{% endif %};
```
#### orders.yaml
```yaml
recent: |
SELECT * FROM orders
WHERE created_at >= "{{ start_date }}"
ORDER BY created_at DESC
LIMIT {{ limit }};
by_customer: |
SELECT * FROM orders
WHERE customer_id = {{ customer_id }}
AND status = "{{ status }}";
```
### 2. 基本用法(新架构)
```python
from query_builder import PyQueryBuilder
# 🔥 新的优化用法
qb = PyQueryBuilder()
# 1. 设置模板目录
qb.sql_path = "./sql"
# 2. 一次性加载所有模板到内存(重要!)
qb.load_all_templates()
# 3. 现在可以快速构建查询(从内存)
sql = qb.build("users.select_by_id", user_id=123)
print(sql)
# 输出: SELECT id, name, email, created_at FROM users WHERE id = 123;
# 复杂查询示例
sql = qb.build("users.list_active", status="active", limit=10)
sql = qb.build("orders.recent", start_date="2024-01-01", limit=50)
sql = qb.build("users.search", keyword="john", limit=20)
```
### 3. 模板键格式
使用 `文件名.模板名` 的格式:
- `users.select_by_id` → `sql/users.yaml` 中的 `select_by_id`
- `orders.recent` → `sql/orders.yaml` 中的 `recent`
- `api.search` → `sql/api.yaml` 中的 `search`
### 4. 查看可用模板
```python
# 获取所有已加载的模板键
keys = qb.get_template_keys()
print("可用模板:", keys)
# ['users.select_by_id', 'users.list_active', 'orders.recent', ...]
# 检查特定模板是否存在
if "users.select_by_id" in keys:
sql = qb.build("users.select_by_id", user_id=123)
```
### 5. 错误处理
```python
try:
qb = PyQueryBuilder()
qb.sql_path = "./sql"
qb.load_all_templates() # 可能抛出 ValueError 或 IOError
sql = qb.build("users.select_by_id", user_id=123) # 可能抛出 KeyError
except ValueError as e:
print(f"配置错误: {e}")
except IOError as e:
print(f"文件读取错误: {e}")
except KeyError as e:
print(f"模板不存在: {e}")
```
## 🎨 模板语法
Query Builder使用Tera模板引擎,支持以下语法:
### 变量替换
```sql
SELECT * FROM users WHERE id = {{ user_id }};
```
### 条件语句
```sql
SELECT * FROM products
WHERE category = "{{ category }}"
{% if min_price %}AND price >= {{ min_price }}{% endif %}
{% if max_price %}AND price <= {{ max_price }}{% endif %};
```
### 循环
```sql
SELECT * FROM users
WHERE id IN ({% for id in user_ids %}{{ id }}{% if not loop.last %},{% endif %}{% endfor %});
```
### 字符串处理
```sql
SELECT * FROM users
WHERE name LIKE "%{{ keyword | lower }}%";
```
## 🛡️ 安全检查
以下类型的 SQL 会被自动阻止:
- 非 SELECT 语句(UPDATE、DELETE、INSERT 等)
- 包含危险关键词(DROP、TRUNCATE、EXEC 等)
- SQL 注入攻击模式(注释注入、UNION 注入等)
- 脚本注入攻击(JavaScript、VBScript 等)
### 安全示例
```python
# ❌ 这些操作会被阻止
try:
qb.build('malicious', query='DROP TABLE users;') # 抛出 ValueError
except ValueError as e:
print("安全检查阻止了危险操作:", e)
# ✅ 只允许安全的SELECT查询
sql = qb.build('users.select_by_id', user_id=123) # 正常工作
```
## 📋 完整API参考
### PyQueryBuilder 类
#### 属性
- `sql_path: Optional[str]` - SQL模板目录路径
#### 方法
##### `__init__() -> None`
创建新的查询构建器实例。
##### `load_all_templates() -> None`
将所有SQL模板加载到内存。必须在构建查询前调用。
- **异常**: `ValueError`, `IOError`
##### `build(key: str, **kwargs) -> str`
从内存中的模板构建SQL查询。
- **参数**:
- `key`: 模板键(格式: "文件.模板")
- `**kwargs`: 模板变量
- **返回**: 渲染后的SQL字符串
- **异常**: `KeyError`, `ValueError`
##### `get_template_keys() -> List[str]`
获取所有已加载的模板键。
- **返回**: 模板键列表
### 便利函数
#### `builder() -> PyQueryBuilder`
创建新的PyQueryBuilder实例的便利函数。
## 🚀 性能基准
### 内存缓存 vs 文件读取
```python
import time
from query_builder import PyQueryBuilder
# 传统方式模拟(每次读取文件)
def old_way():
# 假设每次查询需要 5ms 文件IO
time.sleep(0.005)
return "SELECT * FROM users"
# 新的内存缓存方式
qb = PyQueryBuilder()
qb.sql_path = "./sql"
qb.load_all_templates() # 一次性加载
# 性能对比
queries = 1000
# 新方式:从内存查询
start = time.time()
for i in range(queries):
sql = qb.build("users.select_by_id", user_id=i)
new_time = time.time() - start
print(f"内存缓存方式: {new_time:.4f}s")
print(f"平均每查询: {new_time/queries*1000:.2f}ms")
```
## 🛠️ 开发
### 本地构建
```bash
# 克隆仓库
git clone https://github.com/miaokela/query-builder.git
cd query-builder
# 安装依赖
pip install maturin pyyaml
# 开发模式构建
maturin develop
# 运行测试
python example_with_types.py
```
### 测试
```bash
# 测试基本功能
python -c "
from query_builder import PyQueryBuilder
qb = PyQueryBuilder()
print('Query Builder 正常工作!')
"
```
## 🏗️ 项目架构
```
query-builder/
├── src/
│ └── lib.rs # Rust核心代码
├── sql/ # SQL模板示例
│ ├── users.yaml
│ └── orders.yaml
├── query_builder.pyi # 类型提示文件
├── example_with_types.py # 使用示例
├── TYPE_HINTS_GUIDE.md # 详细指南
├── .github/
│ └── workflows/
│ └── build-simple-maturin.yml # CI/CD配置
├── Cargo.toml # Rust依赖配置
├── pyproject.toml # Python包配置
└── README.md
```
## 🚦 CI/CD状态
- ✅ 自动化构建支持macOS(x86_64 + ARM64)、Windows x64、Linux x64
- ✅ 支持Python 3.8-3.12
- ✅ 自动发布到PyPI
- ✅ 全面的安全测试
## 📄 许可证
MIT License - 详见 [LICENSE](LICENSE) 文件。
## 🤝 贡献
欢迎提交Issue和Pull Request!请确保:
1. 所有测试通过
2. 遵循安全编码规范
3. 更新相关文档
## 📞 联系
- 作者: 缪克拉
- 邮箱: 2972799448@qq.com
- GitHub: https://github.com/miaokela/query-builder
## 🙏 致谢
- [PyO3](https://github.com/PyO3/pyo3) - 优秀的Rust-Python绑定库
- [Tera](https://github.com/Keats/tera) - 强大的模板引擎
- [maturin](https://github.com/PyO3/maturin) - Python包构建工具
Raw data
{
"_id": null,
"home_page": null,
"name": "query-builder-tool",
"maintainer": null,
"docs_url": null,
"requires_python": "<3.13,>=3.8",
"maintainer_email": null,
"keywords": "sql, query, builder, security, rust, pyo3",
"author": null,
"author_email": "\u7f2a\u514b\u62c9 <2972799448@qq.com>",
"download_url": null,
"platform": null,
"description": "# Query Builder\n\n\u4e00\u4e2a\u9ad8\u6027\u80fd\u7684SQL\u67e5\u8be2\u6784\u5efa\u5668\uff0c\u4f7f\u7528Rust + PyO3\u5f00\u53d1\uff0c\u4e3aPython\u63d0\u4f9b\u5185\u5b58\u7f13\u5b58\u7684SQL\u6a21\u677f\u6e32\u67d3\u529f\u80fd\u3002\n\n## \ud83d\ude80 \u7279\u6027\n\n- **\u26a1 \u6781\u901f\u6027\u80fd**: \u4f7f\u7528Rust\u5f00\u53d1 + \u5185\u5b58\u6a21\u677f\u7f13\u5b58\uff0c\u63d0\u4f9b\u539f\u751f\u7ea7\u522b\u7684\u6027\u80fd\n- **\ud83d\udd12 \u5b89\u5168\u7b2c\u4e00**: \u5185\u7f6eSQL\u6ce8\u5165\u9632\u62a4\u548c\u5371\u9669\u5173\u952e\u8bcd\u68c0\u6d4b\n- **\ud83e\udde0 \u667a\u80fd\u7f13\u5b58**: \u542f\u52a8\u65f6\u4e00\u6b21\u6027\u52a0\u8f7d\u6240\u6709\u6a21\u677f\u5230\u5185\u5b58\uff0c\u67e5\u8be2\u65f6\u96f6IO\u64cd\u4f5c\n- **\ud83c\udfaf \u6a21\u677f\u5f15\u64ce**: \u57fa\u4e8eTera\u6a21\u677f\u5f15\u64ce\uff0c\u652f\u6301\u6761\u4ef6\u8bed\u53e5\u3001\u5faa\u73af\u7b49\u9ad8\u7ea7\u529f\u80fd\n- **\ud83d\udc0d Python\u53cb\u597d**: \u5b8c\u6574\u7684\u7c7b\u578b\u63d0\u793a\u652f\u6301\uff0cVS Code\u667a\u80fd\u611f\u77e5\n- **\ud83c\udf10 \u8de8\u5e73\u53f0**: \u652f\u6301macOS\u3001Windows\u3001Linux\u591a\u5e73\u53f0\n\n## \ud83c\udfd7\ufe0f \u67b6\u6784\u4f18\u52bf\n\n### \ud83d\udd25 \u6027\u80fd\u4f18\u5316\n```\n\u4f20\u7edf\u65b9\u5f0f: \u67e5\u8be2\u65f6\u8bfb\u53d6\u6587\u4ef6 \u2192 \u89e3\u6790YAML \u2192 \u6e32\u67d3SQL\n\u65b0\u67b6\u6784: \u542f\u52a8\u65f6\u52a0\u8f7d\u5168\u90e8 \u2192 \u67e5\u8be2\u65f6\u5185\u5b58\u8bfb\u53d6 \u26a1 \u2192 \u6e32\u67d3SQL\n```\n\n### \ud83d\udcbe \u5185\u5b58\u7f13\u5b58\u673a\u5236\n- **\u4e00\u6b21\u52a0\u8f7d** - \u5e94\u7528\u542f\u52a8\u65f6\u5c06\u6240\u6709SQL\u6a21\u677f\u52a0\u8f7d\u5230\u5185\u5b58\n- **\u96f6IO\u67e5\u8be2** - \u6784\u5efaSQL\u65f6\u76f4\u63a5\u4ece\u5185\u5b58\u83b7\u53d6\u6a21\u677f\n- **\u751f\u4ea7\u5c31\u7eea** - \u9002\u5408\u9ad8\u5e76\u53d1\u3001\u4f4e\u5ef6\u8fdf\u7684\u751f\u4ea7\u73af\u5883\n\n### \ud83c\udfaf VS Code\u5b8c\u6574\u652f\u6301\n- **\u667a\u80fd\u611f\u77e5** - \u5b8c\u6574\u7684\u65b9\u6cd5\u548c\u5c5e\u6027\u63d0\u793a\n- **\u7c7b\u578b\u68c0\u67e5** - \u53c2\u6570\u7c7b\u578b\u9a8c\u8bc1\u548c\u9519\u8bef\u9884\u9632\n- **\u6587\u6863\u60ac\u6d6e** - \u4e30\u5bcc\u7684API\u8bf4\u660e\u548c\u793a\u4f8b\n\n## \ud83d\udd12 \u5b89\u5168\u7279\u6027\n\n- **\u4ec5\u652f\u6301 SELECT \u67e5\u8be2** - \u4e25\u683c\u9650\u5236\u53ea\u80fd\u6784\u9020\u67e5\u8be2\u8bed\u53e5\n- **SQL \u6ce8\u5165\u9632\u62a4** - \u68c0\u6d4b\u548c\u963b\u6b62\u5e38\u89c1\u7684 SQL \u6ce8\u5165\u653b\u51fb\u6a21\u5f0f\n- **\u5371\u9669\u5173\u952e\u8bcd\u8fc7\u6ee4** - \u963b\u6b62 DROP\u3001UPDATE\u3001DELETE \u7b49\u5371\u9669\u64cd\u4f5c\n- **\u6a21\u5f0f\u5339\u914d\u68c0\u6d4b** - \u8bc6\u522b\u6ce8\u91ca\u6ce8\u5165\u3001UNION \u6ce8\u5165\u7b49\u653b\u51fb\n\n## \ud83d\udce6 \u5b89\u88c5\n\n```bash\npip install query-builder-tool\n```\n\n## \ud83d\ude80 \u5feb\u901f\u5f00\u59cb\n\n### 1. \u7ec4\u7ec7SQL\u6a21\u677f\n\n\u521b\u5efa\u6a21\u677f\u76ee\u5f55\u7ed3\u6784\uff1a\n```\nsql/\n\u251c\u2500\u2500 users.yaml # \u7528\u6237\u67e5\u8be2\n\u251c\u2500\u2500 orders.yaml # \u8ba2\u5355\u67e5\u8be2\n\u2514\u2500\u2500 api.yaml # API\u67e5\u8be2\n```\n\n#### users.yaml\n```yaml\nselect_by_id: |\n SELECT id, name, email, created_at \n FROM users \n WHERE id = {{ user_id }};\n\nlist_active: |\n SELECT id, name, email \n FROM users \n WHERE status = \"{{ status }}\"\n {% if limit %}LIMIT {{ limit }}{% endif %};\n\nsearch: |\n SELECT id, name, email \n FROM users \n WHERE name LIKE \"%{{ keyword }}%\" \n ORDER BY created_at DESC\n {% if limit %}LIMIT {{ limit }}{% endif %};\n```\n\n#### orders.yaml\n```yaml\nrecent: |\n SELECT * FROM orders \n WHERE created_at >= \"{{ start_date }}\"\n ORDER BY created_at DESC\n LIMIT {{ limit }};\n\nby_customer: |\n SELECT * FROM orders \n WHERE customer_id = {{ customer_id }}\n AND status = \"{{ status }}\";\n```\n\n### 2. \u57fa\u672c\u7528\u6cd5\uff08\u65b0\u67b6\u6784\uff09\n\n```python\nfrom query_builder import PyQueryBuilder\n\n# \ud83d\udd25 \u65b0\u7684\u4f18\u5316\u7528\u6cd5\nqb = PyQueryBuilder()\n\n# 1. \u8bbe\u7f6e\u6a21\u677f\u76ee\u5f55\nqb.sql_path = \"./sql\"\n\n# 2. \u4e00\u6b21\u6027\u52a0\u8f7d\u6240\u6709\u6a21\u677f\u5230\u5185\u5b58\uff08\u91cd\u8981\uff01\uff09\nqb.load_all_templates()\n\n# 3. \u73b0\u5728\u53ef\u4ee5\u5feb\u901f\u6784\u5efa\u67e5\u8be2\uff08\u4ece\u5185\u5b58\uff09\nsql = qb.build(\"users.select_by_id\", user_id=123)\nprint(sql)\n# \u8f93\u51fa: SELECT id, name, email, created_at FROM users WHERE id = 123;\n\n# \u590d\u6742\u67e5\u8be2\u793a\u4f8b\nsql = qb.build(\"users.list_active\", status=\"active\", limit=10)\nsql = qb.build(\"orders.recent\", start_date=\"2024-01-01\", limit=50)\nsql = qb.build(\"users.search\", keyword=\"john\", limit=20)\n```\n\n### 3. \u6a21\u677f\u952e\u683c\u5f0f\n\n\u4f7f\u7528 `\u6587\u4ef6\u540d.\u6a21\u677f\u540d` \u7684\u683c\u5f0f\uff1a\n- `users.select_by_id` \u2192 `sql/users.yaml` \u4e2d\u7684 `select_by_id`\n- `orders.recent` \u2192 `sql/orders.yaml` \u4e2d\u7684 `recent` \n- `api.search` \u2192 `sql/api.yaml` \u4e2d\u7684 `search`\n\n### 4. \u67e5\u770b\u53ef\u7528\u6a21\u677f\n\n```python\n# \u83b7\u53d6\u6240\u6709\u5df2\u52a0\u8f7d\u7684\u6a21\u677f\u952e\nkeys = qb.get_template_keys()\nprint(\"\u53ef\u7528\u6a21\u677f:\", keys)\n# ['users.select_by_id', 'users.list_active', 'orders.recent', ...]\n\n# \u68c0\u67e5\u7279\u5b9a\u6a21\u677f\u662f\u5426\u5b58\u5728\nif \"users.select_by_id\" in keys:\n sql = qb.build(\"users.select_by_id\", user_id=123)\n```\n\n### 5. \u9519\u8bef\u5904\u7406\n\n```python\ntry:\n qb = PyQueryBuilder()\n qb.sql_path = \"./sql\"\n qb.load_all_templates() # \u53ef\u80fd\u629b\u51fa ValueError \u6216 IOError\n \n sql = qb.build(\"users.select_by_id\", user_id=123) # \u53ef\u80fd\u629b\u51fa KeyError\n \nexcept ValueError as e:\n print(f\"\u914d\u7f6e\u9519\u8bef: {e}\")\nexcept IOError as e:\n print(f\"\u6587\u4ef6\u8bfb\u53d6\u9519\u8bef: {e}\")\nexcept KeyError as e:\n print(f\"\u6a21\u677f\u4e0d\u5b58\u5728: {e}\")\n```\n\n## \ud83c\udfa8 \u6a21\u677f\u8bed\u6cd5\n\nQuery Builder\u4f7f\u7528Tera\u6a21\u677f\u5f15\u64ce\uff0c\u652f\u6301\u4ee5\u4e0b\u8bed\u6cd5\uff1a\n\n### \u53d8\u91cf\u66ff\u6362\n```sql\nSELECT * FROM users WHERE id = {{ user_id }};\n```\n\n### \u6761\u4ef6\u8bed\u53e5\n```sql\nSELECT * FROM products \nWHERE category = \"{{ category }}\"\n{% if min_price %}AND price >= {{ min_price }}{% endif %}\n{% if max_price %}AND price <= {{ max_price }}{% endif %};\n```\n\n### \u5faa\u73af\n```sql\nSELECT * FROM users \nWHERE id IN ({% for id in user_ids %}{{ id }}{% if not loop.last %},{% endif %}{% endfor %});\n```\n\n### \u5b57\u7b26\u4e32\u5904\u7406\n```sql\nSELECT * FROM users \nWHERE name LIKE \"%{{ keyword | lower }}%\";\n```\n\n## \ud83d\udee1\ufe0f \u5b89\u5168\u68c0\u67e5\n\n\u4ee5\u4e0b\u7c7b\u578b\u7684 SQL \u4f1a\u88ab\u81ea\u52a8\u963b\u6b62\uff1a\n\n- \u975e SELECT \u8bed\u53e5\uff08UPDATE\u3001DELETE\u3001INSERT \u7b49\uff09\n- \u5305\u542b\u5371\u9669\u5173\u952e\u8bcd\uff08DROP\u3001TRUNCATE\u3001EXEC \u7b49\uff09\n- SQL \u6ce8\u5165\u653b\u51fb\u6a21\u5f0f\uff08\u6ce8\u91ca\u6ce8\u5165\u3001UNION \u6ce8\u5165\u7b49\uff09\n- \u811a\u672c\u6ce8\u5165\u653b\u51fb\uff08JavaScript\u3001VBScript \u7b49\uff09\n\n### \u5b89\u5168\u793a\u4f8b\n\n```python\n# \u274c \u8fd9\u4e9b\u64cd\u4f5c\u4f1a\u88ab\u963b\u6b62\ntry:\n qb.build('malicious', query='DROP TABLE users;') # \u629b\u51fa ValueError\nexcept ValueError as e:\n print(\"\u5b89\u5168\u68c0\u67e5\u963b\u6b62\u4e86\u5371\u9669\u64cd\u4f5c:\", e)\n\n# \u2705 \u53ea\u5141\u8bb8\u5b89\u5168\u7684SELECT\u67e5\u8be2\nsql = qb.build('users.select_by_id', user_id=123) # \u6b63\u5e38\u5de5\u4f5c\n```\n\n## \ud83d\udccb \u5b8c\u6574API\u53c2\u8003\n\n### PyQueryBuilder \u7c7b\n\n#### \u5c5e\u6027\n- `sql_path: Optional[str]` - SQL\u6a21\u677f\u76ee\u5f55\u8def\u5f84\n\n#### \u65b9\u6cd5\n\n##### `__init__() -> None`\n\u521b\u5efa\u65b0\u7684\u67e5\u8be2\u6784\u5efa\u5668\u5b9e\u4f8b\u3002\n\n##### `load_all_templates() -> None`\n\u5c06\u6240\u6709SQL\u6a21\u677f\u52a0\u8f7d\u5230\u5185\u5b58\u3002\u5fc5\u987b\u5728\u6784\u5efa\u67e5\u8be2\u524d\u8c03\u7528\u3002\n- **\u5f02\u5e38**: `ValueError`, `IOError`\n\n##### `build(key: str, **kwargs) -> str`\n\u4ece\u5185\u5b58\u4e2d\u7684\u6a21\u677f\u6784\u5efaSQL\u67e5\u8be2\u3002\n- **\u53c2\u6570**: \n - `key`: \u6a21\u677f\u952e\uff08\u683c\u5f0f: \"\u6587\u4ef6.\u6a21\u677f\"\uff09\n - `**kwargs`: \u6a21\u677f\u53d8\u91cf\n- **\u8fd4\u56de**: \u6e32\u67d3\u540e\u7684SQL\u5b57\u7b26\u4e32\n- **\u5f02\u5e38**: `KeyError`, `ValueError`\n\n##### `get_template_keys() -> List[str]`\n\u83b7\u53d6\u6240\u6709\u5df2\u52a0\u8f7d\u7684\u6a21\u677f\u952e\u3002\n- **\u8fd4\u56de**: \u6a21\u677f\u952e\u5217\u8868\n\n### \u4fbf\u5229\u51fd\u6570\n\n#### `builder() -> PyQueryBuilder`\n\u521b\u5efa\u65b0\u7684PyQueryBuilder\u5b9e\u4f8b\u7684\u4fbf\u5229\u51fd\u6570\u3002\n\n## \ud83d\ude80 \u6027\u80fd\u57fa\u51c6\n\n### \u5185\u5b58\u7f13\u5b58 vs \u6587\u4ef6\u8bfb\u53d6\n```python\nimport time\nfrom query_builder import PyQueryBuilder\n\n# \u4f20\u7edf\u65b9\u5f0f\u6a21\u62df\uff08\u6bcf\u6b21\u8bfb\u53d6\u6587\u4ef6\uff09\ndef old_way():\n # \u5047\u8bbe\u6bcf\u6b21\u67e5\u8be2\u9700\u8981 5ms \u6587\u4ef6IO\n time.sleep(0.005)\n return \"SELECT * FROM users\"\n\n# \u65b0\u7684\u5185\u5b58\u7f13\u5b58\u65b9\u5f0f\nqb = PyQueryBuilder()\nqb.sql_path = \"./sql\"\nqb.load_all_templates() # \u4e00\u6b21\u6027\u52a0\u8f7d\n\n# \u6027\u80fd\u5bf9\u6bd4\nqueries = 1000\n\n# \u65b0\u65b9\u5f0f\uff1a\u4ece\u5185\u5b58\u67e5\u8be2\nstart = time.time()\nfor i in range(queries):\n sql = qb.build(\"users.select_by_id\", user_id=i)\nnew_time = time.time() - start\n\nprint(f\"\u5185\u5b58\u7f13\u5b58\u65b9\u5f0f: {new_time:.4f}s\")\nprint(f\"\u5e73\u5747\u6bcf\u67e5\u8be2: {new_time/queries*1000:.2f}ms\")\n```\n\n## \ud83d\udee0\ufe0f \u5f00\u53d1\n\n### \u672c\u5730\u6784\u5efa\n\n```bash\n# \u514b\u9686\u4ed3\u5e93\ngit clone https://github.com/miaokela/query-builder.git\ncd query-builder\n\n# \u5b89\u88c5\u4f9d\u8d56\npip install maturin pyyaml\n\n# \u5f00\u53d1\u6a21\u5f0f\u6784\u5efa\nmaturin develop\n\n# \u8fd0\u884c\u6d4b\u8bd5\npython example_with_types.py\n```\n\n### \u6d4b\u8bd5\n\n```bash\n# \u6d4b\u8bd5\u57fa\u672c\u529f\u80fd\npython -c \"\nfrom query_builder import PyQueryBuilder\nqb = PyQueryBuilder()\nprint('Query Builder \u6b63\u5e38\u5de5\u4f5c\uff01')\n\"\n```\n\n## \ud83c\udfd7\ufe0f \u9879\u76ee\u67b6\u6784\n\n```\nquery-builder/\n\u251c\u2500\u2500 src/\n\u2502 \u2514\u2500\u2500 lib.rs # Rust\u6838\u5fc3\u4ee3\u7801\n\u251c\u2500\u2500 sql/ # SQL\u6a21\u677f\u793a\u4f8b\n\u2502 \u251c\u2500\u2500 users.yaml\n\u2502 \u2514\u2500\u2500 orders.yaml\n\u251c\u2500\u2500 query_builder.pyi # \u7c7b\u578b\u63d0\u793a\u6587\u4ef6\n\u251c\u2500\u2500 example_with_types.py # \u4f7f\u7528\u793a\u4f8b\n\u251c\u2500\u2500 TYPE_HINTS_GUIDE.md # \u8be6\u7ec6\u6307\u5357\n\u251c\u2500\u2500 .github/\n\u2502 \u2514\u2500\u2500 workflows/\n\u2502 \u2514\u2500\u2500 build-simple-maturin.yml # CI/CD\u914d\u7f6e\n\u251c\u2500\u2500 Cargo.toml # Rust\u4f9d\u8d56\u914d\u7f6e\n\u251c\u2500\u2500 pyproject.toml # Python\u5305\u914d\u7f6e\n\u2514\u2500\u2500 README.md\n```\n\n## \ud83d\udea6 CI/CD\u72b6\u6001\n\n- \u2705 \u81ea\u52a8\u5316\u6784\u5efa\u652f\u6301macOS\uff08x86_64 + ARM64\uff09\u3001Windows x64\u3001Linux x64\n- \u2705 \u652f\u6301Python 3.8-3.12\n- \u2705 \u81ea\u52a8\u53d1\u5e03\u5230PyPI\n- \u2705 \u5168\u9762\u7684\u5b89\u5168\u6d4b\u8bd5\n\n## \ud83d\udcc4 \u8bb8\u53ef\u8bc1\n\nMIT License - \u8be6\u89c1 [LICENSE](LICENSE) \u6587\u4ef6\u3002\n\n## \ud83e\udd1d \u8d21\u732e\n\n\u6b22\u8fce\u63d0\u4ea4Issue\u548cPull Request\uff01\u8bf7\u786e\u4fdd\uff1a\n\n1. \u6240\u6709\u6d4b\u8bd5\u901a\u8fc7\n2. \u9075\u5faa\u5b89\u5168\u7f16\u7801\u89c4\u8303\n3. \u66f4\u65b0\u76f8\u5173\u6587\u6863\n\n## \ud83d\udcde \u8054\u7cfb\n\n- \u4f5c\u8005: \u7f2a\u514b\u62c9\n- \u90ae\u7bb1: 2972799448@qq.com\n- GitHub: https://github.com/miaokela/query-builder\n\n## \ud83d\ude4f \u81f4\u8c22\n\n- [PyO3](https://github.com/PyO3/pyo3) - \u4f18\u79c0\u7684Rust-Python\u7ed1\u5b9a\u5e93\n- [Tera](https://github.com/Keats/tera) - \u5f3a\u5927\u7684\u6a21\u677f\u5f15\u64ce\n- [maturin](https://github.com/PyO3/maturin) - Python\u5305\u6784\u5efa\u5de5\u5177\n",
"bugtrack_url": null,
"license": null,
"summary": "A secure SQL query builder for Python using Rust and pyo3. Supports dynamic templates with safety checks against SQL injection.",
"version": "0.2.0",
"project_urls": {
"Bug Tracker": "https://github.com/miaokela/query-builder/issues",
"Documentation": "https://github.com/miaokela/query-builder#readme",
"Homepage": "https://github.com/miaokela/query-builder",
"Repository": "https://github.com/miaokela/query-builder"
},
"split_keywords": [
"sql",
" query",
" builder",
" security",
" rust",
" pyo3"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "f39c2ffc3bc484f56cc7c8a7925b0f777647df4187f21f0474dabb014d1adad4",
"md5": "8852d8f1dc8821d1450963a1d5769eaa",
"sha256": "5a005cddddc5aa764013da66572ec22ff26f9292e13bd8634e89e6724c58b200"
},
"downloads": -1,
"filename": "query_builder_tool-0.2.0-cp38-abi3-macosx_11_0_arm64.whl",
"has_sig": false,
"md5_digest": "8852d8f1dc8821d1450963a1d5769eaa",
"packagetype": "bdist_wheel",
"python_version": "cp38",
"requires_python": "<3.13,>=3.8",
"size": 1809909,
"upload_time": "2025-09-15T08:34:55",
"upload_time_iso_8601": "2025-09-15T08:34:55.287207Z",
"url": "https://files.pythonhosted.org/packages/f3/9c/2ffc3bc484f56cc7c8a7925b0f777647df4187f21f0474dabb014d1adad4/query_builder_tool-0.2.0-cp38-abi3-macosx_11_0_arm64.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "ff422527d77a6758aaebb59c0cf937b310dad8434a39d2b027c0f9217a62d2d2",
"md5": "e0bdb2395cacabe4957a16ba1eda2ab1",
"sha256": "348820b10c93741772a02c527d2bcde3d534c7486e5ed82f5ce3e4a6d1e1c353"
},
"downloads": -1,
"filename": "query_builder_tool-0.2.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
"has_sig": false,
"md5_digest": "e0bdb2395cacabe4957a16ba1eda2ab1",
"packagetype": "bdist_wheel",
"python_version": "cp38",
"requires_python": "<3.13,>=3.8",
"size": 2128181,
"upload_time": "2025-09-15T08:34:56",
"upload_time_iso_8601": "2025-09-15T08:34:56.711897Z",
"url": "https://files.pythonhosted.org/packages/ff/42/2527d77a6758aaebb59c0cf937b310dad8434a39d2b027c0f9217a62d2d2/query_builder_tool-0.2.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "5a3e12864773bffe8d28216fdde746215eca224661419e2180212e20d8bac461",
"md5": "5e91a3c46b1b9e54b05f6a3f2d5daaef",
"sha256": "95b73fc7f5aa8d0f064e37d2e9f7fc2a1c6ed0ab9073314a08dbf8ad67f49198"
},
"downloads": -1,
"filename": "query_builder_tool-0.2.0-cp38-abi3-win_amd64.whl",
"has_sig": false,
"md5_digest": "5e91a3c46b1b9e54b05f6a3f2d5daaef",
"packagetype": "bdist_wheel",
"python_version": "cp38",
"requires_python": "<3.13,>=3.8",
"size": 1701969,
"upload_time": "2025-09-15T08:34:58",
"upload_time_iso_8601": "2025-09-15T08:34:58.228682Z",
"url": "https://files.pythonhosted.org/packages/5a/3e/12864773bffe8d28216fdde746215eca224661419e2180212e20d8bac461/query_builder_tool-0.2.0-cp38-abi3-win_amd64.whl",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-09-15 08:34:55",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "miaokela",
"github_project": "query-builder",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "query-builder-tool"
}