Initial commit

This commit is contained in:
Misaka_Company
2026-07-30 14:17:18 +08:00
commit 4dc563cdd9
16 changed files with 1144 additions and 0 deletions

65
core/db.py Normal file
View File

@@ -0,0 +1,65 @@
"""数据库访问层。
提供 run_query读取 .sql 文件、剥离注释、参数化绑定执行、返回 list[dict]。
所有报表查询必须走参数绑定,禁止字符串拼接 SQL防注入
"""
from __future__ import annotations
import re
from pathlib import Path
from typing import Any
from sqlalchemy import create_engine, text
from sqlalchemy.engine import Engine
from core.settings import settings
_engine: Engine | None = None
def get_engine() -> Engine:
"""惰性创建并缓存 SQLAlchemy engine。"""
global _engine
if _engine is None:
_engine = create_engine(
settings.database_url,
pool_pre_ping=True,
pool_recycle=1800,
)
return _engine
def load_sql(sql_path: str | Path) -> str:
"""读取 .sql 文件并剥离行级 `--` 注释,返回纯 SQL 文本。
支持 SQL 文件里自由书写中文注释(便于阅读与 AI 理解)。
仅剥离以 `--` 开头的整行注释(行首可有空白),不处理行内注释,
避免误删含 `--` 的字符串字面量。
"""
path = Path(sql_path)
if not path.is_absolute():
from core.settings import PROJECT_ROOT
path = PROJECT_ROOT / path
raw = path.read_text(encoding="utf-8")
lines = []
for line in raw.splitlines():
# 去掉行首空白后判断是否为注释行
if re.match(r"\s*--", line):
continue
lines.append(line)
return "\n".join(lines).strip()
def run_query(sql_path: str | Path, params: dict[str, Any]) -> list[dict[str, Any]]:
"""执行参数化查询,返回 list[dict](每行一个 dict键为列别名
:param sql_path: .sql 文件路径(相对项目根或绝对路径)。
:param params: 绑定参数,键名对应 SQL 中的 :name 占位符。
"""
sql_text = load_sql(sql_path)
engine = get_engine()
with engine.connect() as conn:
result = conn.execute(text(sql_text), params)
cols = list(result.keys())
return [dict(zip(cols, row)) for row in result.fetchall()]