fastapi-augment 0.1.2__tar.gz → 0.1.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/PKG-INFO +96 -6
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/README.md +95 -5
- fastapi_augment-0.1.3/VERSION +1 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/config/settings.py +17 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/db/sqlalchemy/__init__.py +12 -0
- fastapi_augment-0.1.3/src/fastapi_augment/db/sqlalchemy/query_parser.py +447 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/db/sqlalchemy/repository_base.py +29 -1
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/db/sqlalchemy/session.py +27 -18
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/factory.py +7 -7
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/openapi.py +0 -13
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment.egg-info/PKG-INFO +96 -6
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment.egg-info/SOURCES.txt +2 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/tests/test_db_repository.py +429 -412
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/tests/test_openapi.py +0 -31
- fastapi_augment-0.1.3/tests/test_query_parser.py +246 -0
- fastapi_augment-0.1.2/VERSION +0 -1
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/pyproject.toml +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/setup.cfg +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/__init__.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/common/__init__.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/common/constants.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/common/exception_handlers.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/common/exceptions.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/common/utils/__init__.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/common/utils/paths.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/common/utils/strings.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/config/__init__.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/db/__init__.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/db/sqlalchemy/alembic/README +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/db/sqlalchemy/alembic/__init__.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/db/sqlalchemy/alembic/env.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/db/sqlalchemy/alembic/script.py.mako +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/db/sqlalchemy/base.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/db/sqlalchemy/engine.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/db/sqlalchemy/migrate.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/db/sqlalchemy/mixins/__init__.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/db/sqlalchemy/mixins/audit.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/db/sqlalchemy/mixins/soft_delete.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/db/sqlalchemy/mixins/timestamp.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/db/sqlalchemy/model_base.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/health/__init__.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/health/checker.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/health/checkers.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/health/router.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/lifespan.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/log/__init__.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/log/config.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/log/factory.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/log/filters.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/log/handlers.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/middlewares/__init__.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/middlewares/base.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/middlewares/request_id.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/py.typed +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/schemas/__init__.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/schemas/base.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/schemas/pagination.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/schemas/request.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/schemas/response.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/schemas/types.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment.egg-info/dependency_links.txt +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment.egg-info/entry_points.txt +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment.egg-info/requires.txt +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment.egg-info/top_level.txt +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/tests/test_config.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/tests/test_constants.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/tests/test_db_engine.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/tests/test_db_session_models.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/tests/test_exception_handlers.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/tests/test_exceptions.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/tests/test_factory.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/tests/test_health.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/tests/test_lifespan.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/tests/test_log.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/tests/test_middlewares.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/tests/test_migrate.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/tests/test_model_base.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/tests/test_schemas.py +0 -0
- {fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/tests/test_settings.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastapi-augment
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: FastAPI 通用代码工具包,跨项目复用
|
|
5
5
|
Author-email: zarkhan <hanguangzheng@qq.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -45,10 +45,11 @@ Requires-Dist: fastapi-augment[config,orjson,sqlalchemy,uvicorn]; extra == "stan
|
|
|
45
45
|
- **生命周期管理** — 多注册表、优先级、超时控制、异常策略的启动/关闭钩子
|
|
46
46
|
- **读写分离** — 单库 / 主从 / 集群拓扑的异步引擎管理,线程安全的 Session 自动路由
|
|
47
47
|
- **泛型仓储** — 类型安全的异步 Repository,支持直接实例化与子类继承两种方式
|
|
48
|
+
- **查询解析器** — REST 风格 query string 转 SQLAlchemy 表达式,支持 FIQL 条件、关键字搜索、排序
|
|
48
49
|
- **可组合 Mixin** — 时间戳、审计、软删除等列混入,自由组合
|
|
49
50
|
- **统一响应** — 全局 `APIResponse` 格式,自动追踪 `request_id`
|
|
50
51
|
- **HTTP 异常** — 完整的 4xx 异常子类,内置默认文案
|
|
51
|
-
- **OpenAPI 优化** — 自动清理 422
|
|
52
|
+
- **OpenAPI 优化** — 自动清理 422 响应与验证错误模型
|
|
52
53
|
- **日志管理** — request_id 自动注入、uvicorn 接管、多进程安全轮转、幂等初始化、一键配置
|
|
53
54
|
- **健康检查** — 可扩展的检查器模式,内置应用状态与数据库连通性检查,一行开关
|
|
54
55
|
- **配置管理** — 基于 pydantic-settings,支持 `.env` 文件、环境变量前缀、嵌套配置
|
|
@@ -130,7 +131,7 @@ app = create_app(
|
|
|
130
131
|
| 生命周期 | 接入 `fastapi_lifespan`,合并用户注册表与 `core_registry` |
|
|
131
132
|
| 中间件 | 自动添加 `RequestIdMiddleware`,可选 CORS |
|
|
132
133
|
| 路由 | 支持 `APIRouter` 列表或 `(router, kwargs)` 元组 |
|
|
133
|
-
| OpenAPI | 自动清理 422
|
|
134
|
+
| OpenAPI | 自动清理 422 响应与验证错误模型 |
|
|
134
135
|
| 数据库 | 可选挂载 `EngineManager` / `SessionFactory` 到 `app.state` |
|
|
135
136
|
| 健康检查 | `health_check=True` 一键启用 `/health` 端点 |
|
|
136
137
|
|
|
@@ -147,7 +148,6 @@ app = create_app(
|
|
|
147
148
|
title='My Service',
|
|
148
149
|
registries=registry, # 单个或列表均可
|
|
149
150
|
cors_allow_origins=['*'],
|
|
150
|
-
openapi_enable_bearer_auth=True,
|
|
151
151
|
health_check=True, # 启用健康检查
|
|
152
152
|
)
|
|
153
153
|
```
|
|
@@ -260,10 +260,12 @@ from fastapi_augment.db.sqlalchemy import RepositoryBase
|
|
|
260
260
|
# 方式 1:直接实例化 — 显式传入模型类
|
|
261
261
|
user_repo = RepositoryBase(User)
|
|
262
262
|
|
|
263
|
+
|
|
263
264
|
# 方式 2:子类继承 — 通过泛型参数绑定模型,可扩展自定义方法
|
|
264
265
|
class UserRepo(RepositoryBase[User]):
|
|
265
266
|
async def find_by_email(self, session, email: str) -> User | None:
|
|
266
|
-
return await self.
|
|
267
|
+
return await self.get_first(session, email=email)
|
|
268
|
+
|
|
267
269
|
|
|
268
270
|
user_repo = UserRepo() # 无需再传 User
|
|
269
271
|
```
|
|
@@ -279,7 +281,8 @@ async with sessions.transaction() as session:
|
|
|
279
281
|
# Read(实例方法)
|
|
280
282
|
async with sessions.read_session() as session:
|
|
281
283
|
user = await user_repo.get(session, id_='01HXK...')
|
|
282
|
-
user = await user_repo.
|
|
284
|
+
user = await user_repo.get_first(session, name='alice') # 取第一条,无匹配返回 None
|
|
285
|
+
user = await user_repo.get_unique(session, email='a@b.com') # 精确唯一,多条匹配抛 MultipleResultsFound
|
|
283
286
|
users = await user_repo.list(session, role='admin', order_by=['-created_at'], limit=10)
|
|
284
287
|
total = await user_repo.count(session, is_active=True)
|
|
285
288
|
has_admin = await user_repo.exists(session, role='admin')
|
|
@@ -319,6 +322,92 @@ await user_repo.list(session, expressions=(User.age > 18,))
|
|
|
319
322
|
await user_repo.list(session, order_by=['-created_at', 'name'])
|
|
320
323
|
```
|
|
321
324
|
|
|
325
|
+
### 查询解析器 — `query_parser`
|
|
326
|
+
|
|
327
|
+
将 REST 风格的 query string 转为 SQLAlchemy `ColumnElement` 条件表达式,可直接传入 `RepositoryBase` 的 `expressions` / `order_by` 参数。
|
|
328
|
+
|
|
329
|
+
#### where 组合条件(FIQL 风格)
|
|
330
|
+
|
|
331
|
+
```
|
|
332
|
+
where = and_group ("," and_group)* , 表示 OR
|
|
333
|
+
and_group = unit (";" unit)* ; 表示 AND
|
|
334
|
+
unit = "(" where ")" | condition
|
|
335
|
+
condition = field OP value
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
**支持的操作符:**
|
|
339
|
+
|
|
340
|
+
| 语法 | 含义 | 示例 |
|
|
341
|
+
| ---------------- | -------------------- | ------------------------- |
|
|
342
|
+
| `field==value` | 等于 | `status==1` |
|
|
343
|
+
| `field!=value` | 不等 | `status!=0` |
|
|
344
|
+
| `field~=value` | 模糊包含 (ILIKE) | `name~=张` |
|
|
345
|
+
| `field>value` | 大于 | `age>18` |
|
|
346
|
+
| `field>=value` | 大于等于 | `age>=18` |
|
|
347
|
+
| `field<value` | 小于 | `age<60` |
|
|
348
|
+
| `field<=value` | 小于等于 | `age<=60` |
|
|
349
|
+
| `field~start~end`| 区间 (BETWEEN) | `age~18~60` |
|
|
350
|
+
|
|
351
|
+
```python
|
|
352
|
+
from fastapi_augment.db.sqlalchemy import parse_where
|
|
353
|
+
|
|
354
|
+
# 昵称含张 且 状态非禁用
|
|
355
|
+
expr = parse_where('nickname~=张;status!=0', User)
|
|
356
|
+
|
|
357
|
+
# 括号内 OR,与区间 AND
|
|
358
|
+
expr = parse_where('(nickname~=张,username~=王);age~20~30', User)
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
#### lookup 精确匹配
|
|
362
|
+
|
|
363
|
+
```python
|
|
364
|
+
from fastapi_augment.db.sqlalchemy import parse_lookup
|
|
365
|
+
|
|
366
|
+
# 单字段精确匹配
|
|
367
|
+
expr = parse_lookup('phone==13800138000', User, fields={'phone', 'email'})
|
|
368
|
+
|
|
369
|
+
# 多字段 AND(; 分隔)
|
|
370
|
+
expr = parse_lookup('phone==138;status==1', User, fields={'phone', 'status'})
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
#### 关键字搜索
|
|
374
|
+
|
|
375
|
+
```python
|
|
376
|
+
from fastapi_augment.db.sqlalchemy import parse_keyword
|
|
377
|
+
|
|
378
|
+
# 多字段 OR 模糊搜索
|
|
379
|
+
expr = parse_keyword('admin', 'username,email,nickname', User)
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
#### 排序
|
|
383
|
+
|
|
384
|
+
```python
|
|
385
|
+
from fastapi_augment.db.sqlalchemy import parse_sort
|
|
386
|
+
|
|
387
|
+
# - 前缀表示降序,无前缀为升序
|
|
388
|
+
order_by = parse_sort('-created_at,nickname', User)
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
#### 一键组合 — `build_query_expressions`
|
|
392
|
+
|
|
393
|
+
```python
|
|
394
|
+
from fastapi_augment.db.sqlalchemy import build_query_expressions
|
|
395
|
+
|
|
396
|
+
expressions, order_by = build_query_expressions(
|
|
397
|
+
User,
|
|
398
|
+
where='status!=0;age>=18',
|
|
399
|
+
q='admin',
|
|
400
|
+
q_field='username,nickname',
|
|
401
|
+
sort='-created_at',
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
# 直接传给 paginate / list
|
|
405
|
+
result = await user_repo.paginate(
|
|
406
|
+
session, page=1, size=10,
|
|
407
|
+
expressions=expressions, order_by=order_by,
|
|
408
|
+
)
|
|
409
|
+
```
|
|
410
|
+
|
|
322
411
|
### 数据库迁移 CLI — `fastapi-augment-migrate`
|
|
323
412
|
|
|
324
413
|
内置 Alembic 迁移工具,提供 `init` / `generate` / `upgrade` 三个子命令,开箱即用。
|
|
@@ -654,6 +743,7 @@ fastapi_augment/
|
|
|
654
743
|
│ ├── session.py # SessionFactory(读写分离)
|
|
655
744
|
│ ├── model_base.py # ModelBase(ULID 主键)
|
|
656
745
|
│ ├── repository_base.py # RepositoryBase(泛型仓储 + paginate)
|
|
746
|
+
│ ├── query_parser.py # 查询解析器(where / lookup / keyword / sort)
|
|
657
747
|
│ ├── migrate.py # 数据库迁移 CLI
|
|
658
748
|
│ ├── migrations/ # Alembic 迁移环境(env.py / script.py.mako)
|
|
659
749
|
│ └── mixins/ # Timestamp / Audit / SoftDelete
|
|
@@ -8,10 +8,11 @@
|
|
|
8
8
|
- **生命周期管理** — 多注册表、优先级、超时控制、异常策略的启动/关闭钩子
|
|
9
9
|
- **读写分离** — 单库 / 主从 / 集群拓扑的异步引擎管理,线程安全的 Session 自动路由
|
|
10
10
|
- **泛型仓储** — 类型安全的异步 Repository,支持直接实例化与子类继承两种方式
|
|
11
|
+
- **查询解析器** — REST 风格 query string 转 SQLAlchemy 表达式,支持 FIQL 条件、关键字搜索、排序
|
|
11
12
|
- **可组合 Mixin** — 时间戳、审计、软删除等列混入,自由组合
|
|
12
13
|
- **统一响应** — 全局 `APIResponse` 格式,自动追踪 `request_id`
|
|
13
14
|
- **HTTP 异常** — 完整的 4xx 异常子类,内置默认文案
|
|
14
|
-
- **OpenAPI 优化** — 自动清理 422
|
|
15
|
+
- **OpenAPI 优化** — 自动清理 422 响应与验证错误模型
|
|
15
16
|
- **日志管理** — request_id 自动注入、uvicorn 接管、多进程安全轮转、幂等初始化、一键配置
|
|
16
17
|
- **健康检查** — 可扩展的检查器模式,内置应用状态与数据库连通性检查,一行开关
|
|
17
18
|
- **配置管理** — 基于 pydantic-settings,支持 `.env` 文件、环境变量前缀、嵌套配置
|
|
@@ -93,7 +94,7 @@ app = create_app(
|
|
|
93
94
|
| 生命周期 | 接入 `fastapi_lifespan`,合并用户注册表与 `core_registry` |
|
|
94
95
|
| 中间件 | 自动添加 `RequestIdMiddleware`,可选 CORS |
|
|
95
96
|
| 路由 | 支持 `APIRouter` 列表或 `(router, kwargs)` 元组 |
|
|
96
|
-
| OpenAPI | 自动清理 422
|
|
97
|
+
| OpenAPI | 自动清理 422 响应与验证错误模型 |
|
|
97
98
|
| 数据库 | 可选挂载 `EngineManager` / `SessionFactory` 到 `app.state` |
|
|
98
99
|
| 健康检查 | `health_check=True` 一键启用 `/health` 端点 |
|
|
99
100
|
|
|
@@ -110,7 +111,6 @@ app = create_app(
|
|
|
110
111
|
title='My Service',
|
|
111
112
|
registries=registry, # 单个或列表均可
|
|
112
113
|
cors_allow_origins=['*'],
|
|
113
|
-
openapi_enable_bearer_auth=True,
|
|
114
114
|
health_check=True, # 启用健康检查
|
|
115
115
|
)
|
|
116
116
|
```
|
|
@@ -223,10 +223,12 @@ from fastapi_augment.db.sqlalchemy import RepositoryBase
|
|
|
223
223
|
# 方式 1:直接实例化 — 显式传入模型类
|
|
224
224
|
user_repo = RepositoryBase(User)
|
|
225
225
|
|
|
226
|
+
|
|
226
227
|
# 方式 2:子类继承 — 通过泛型参数绑定模型,可扩展自定义方法
|
|
227
228
|
class UserRepo(RepositoryBase[User]):
|
|
228
229
|
async def find_by_email(self, session, email: str) -> User | None:
|
|
229
|
-
return await self.
|
|
230
|
+
return await self.get_first(session, email=email)
|
|
231
|
+
|
|
230
232
|
|
|
231
233
|
user_repo = UserRepo() # 无需再传 User
|
|
232
234
|
```
|
|
@@ -242,7 +244,8 @@ async with sessions.transaction() as session:
|
|
|
242
244
|
# Read(实例方法)
|
|
243
245
|
async with sessions.read_session() as session:
|
|
244
246
|
user = await user_repo.get(session, id_='01HXK...')
|
|
245
|
-
user = await user_repo.
|
|
247
|
+
user = await user_repo.get_first(session, name='alice') # 取第一条,无匹配返回 None
|
|
248
|
+
user = await user_repo.get_unique(session, email='a@b.com') # 精确唯一,多条匹配抛 MultipleResultsFound
|
|
246
249
|
users = await user_repo.list(session, role='admin', order_by=['-created_at'], limit=10)
|
|
247
250
|
total = await user_repo.count(session, is_active=True)
|
|
248
251
|
has_admin = await user_repo.exists(session, role='admin')
|
|
@@ -282,6 +285,92 @@ await user_repo.list(session, expressions=(User.age > 18,))
|
|
|
282
285
|
await user_repo.list(session, order_by=['-created_at', 'name'])
|
|
283
286
|
```
|
|
284
287
|
|
|
288
|
+
### 查询解析器 — `query_parser`
|
|
289
|
+
|
|
290
|
+
将 REST 风格的 query string 转为 SQLAlchemy `ColumnElement` 条件表达式,可直接传入 `RepositoryBase` 的 `expressions` / `order_by` 参数。
|
|
291
|
+
|
|
292
|
+
#### where 组合条件(FIQL 风格)
|
|
293
|
+
|
|
294
|
+
```
|
|
295
|
+
where = and_group ("," and_group)* , 表示 OR
|
|
296
|
+
and_group = unit (";" unit)* ; 表示 AND
|
|
297
|
+
unit = "(" where ")" | condition
|
|
298
|
+
condition = field OP value
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
**支持的操作符:**
|
|
302
|
+
|
|
303
|
+
| 语法 | 含义 | 示例 |
|
|
304
|
+
| ---------------- | -------------------- | ------------------------- |
|
|
305
|
+
| `field==value` | 等于 | `status==1` |
|
|
306
|
+
| `field!=value` | 不等 | `status!=0` |
|
|
307
|
+
| `field~=value` | 模糊包含 (ILIKE) | `name~=张` |
|
|
308
|
+
| `field>value` | 大于 | `age>18` |
|
|
309
|
+
| `field>=value` | 大于等于 | `age>=18` |
|
|
310
|
+
| `field<value` | 小于 | `age<60` |
|
|
311
|
+
| `field<=value` | 小于等于 | `age<=60` |
|
|
312
|
+
| `field~start~end`| 区间 (BETWEEN) | `age~18~60` |
|
|
313
|
+
|
|
314
|
+
```python
|
|
315
|
+
from fastapi_augment.db.sqlalchemy import parse_where
|
|
316
|
+
|
|
317
|
+
# 昵称含张 且 状态非禁用
|
|
318
|
+
expr = parse_where('nickname~=张;status!=0', User)
|
|
319
|
+
|
|
320
|
+
# 括号内 OR,与区间 AND
|
|
321
|
+
expr = parse_where('(nickname~=张,username~=王);age~20~30', User)
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
#### lookup 精确匹配
|
|
325
|
+
|
|
326
|
+
```python
|
|
327
|
+
from fastapi_augment.db.sqlalchemy import parse_lookup
|
|
328
|
+
|
|
329
|
+
# 单字段精确匹配
|
|
330
|
+
expr = parse_lookup('phone==13800138000', User, fields={'phone', 'email'})
|
|
331
|
+
|
|
332
|
+
# 多字段 AND(; 分隔)
|
|
333
|
+
expr = parse_lookup('phone==138;status==1', User, fields={'phone', 'status'})
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
#### 关键字搜索
|
|
337
|
+
|
|
338
|
+
```python
|
|
339
|
+
from fastapi_augment.db.sqlalchemy import parse_keyword
|
|
340
|
+
|
|
341
|
+
# 多字段 OR 模糊搜索
|
|
342
|
+
expr = parse_keyword('admin', 'username,email,nickname', User)
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
#### 排序
|
|
346
|
+
|
|
347
|
+
```python
|
|
348
|
+
from fastapi_augment.db.sqlalchemy import parse_sort
|
|
349
|
+
|
|
350
|
+
# - 前缀表示降序,无前缀为升序
|
|
351
|
+
order_by = parse_sort('-created_at,nickname', User)
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
#### 一键组合 — `build_query_expressions`
|
|
355
|
+
|
|
356
|
+
```python
|
|
357
|
+
from fastapi_augment.db.sqlalchemy import build_query_expressions
|
|
358
|
+
|
|
359
|
+
expressions, order_by = build_query_expressions(
|
|
360
|
+
User,
|
|
361
|
+
where='status!=0;age>=18',
|
|
362
|
+
q='admin',
|
|
363
|
+
q_field='username,nickname',
|
|
364
|
+
sort='-created_at',
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
# 直接传给 paginate / list
|
|
368
|
+
result = await user_repo.paginate(
|
|
369
|
+
session, page=1, size=10,
|
|
370
|
+
expressions=expressions, order_by=order_by,
|
|
371
|
+
)
|
|
372
|
+
```
|
|
373
|
+
|
|
285
374
|
### 数据库迁移 CLI — `fastapi-augment-migrate`
|
|
286
375
|
|
|
287
376
|
内置 Alembic 迁移工具,提供 `init` / `generate` / `upgrade` 三个子命令,开箱即用。
|
|
@@ -617,6 +706,7 @@ fastapi_augment/
|
|
|
617
706
|
│ ├── session.py # SessionFactory(读写分离)
|
|
618
707
|
│ ├── model_base.py # ModelBase(ULID 主键)
|
|
619
708
|
│ ├── repository_base.py # RepositoryBase(泛型仓储 + paginate)
|
|
709
|
+
│ ├── query_parser.py # 查询解析器(where / lookup / keyword / sort)
|
|
620
710
|
│ ├── migrate.py # 数据库迁移 CLI
|
|
621
711
|
│ ├── migrations/ # Alembic 迁移环境(env.py / script.py.mako)
|
|
622
712
|
│ └── mixins/ # Timestamp / Audit / SoftDelete
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.1.3
|
|
@@ -52,6 +52,23 @@ class EnvSettings(BaseSettings):
|
|
|
52
52
|
extra='ignore',
|
|
53
53
|
)
|
|
54
54
|
|
|
55
|
+
# ------------------------------
|
|
56
|
+
# 项目信息
|
|
57
|
+
# ------------------------------
|
|
58
|
+
project_debug: bool = True
|
|
59
|
+
project_title: str = 'FastAPI Augment'
|
|
60
|
+
project_summary: str = 'FastAPI Augment - Extended utilities and patterns for FastAPI'
|
|
61
|
+
project_description: str = (
|
|
62
|
+
'FastAPI Augment is a lightweight extension library for FastAPI that '
|
|
63
|
+
'provides out-of-the-box solutions for common backend challenges. It '
|
|
64
|
+
'includes asynchronous database session management (with read-write splitting), '
|
|
65
|
+
'unified API response models, pagination helpers, and streamlined dependency '
|
|
66
|
+
'injection for transactional operations. Designed to reduce boilerplate and '
|
|
67
|
+
'enforce clean architecture, it accelerates the development of production-ready '
|
|
68
|
+
'web services.'
|
|
69
|
+
)
|
|
70
|
+
project_version: str = '0.1.0'
|
|
71
|
+
|
|
55
72
|
@classmethod
|
|
56
73
|
def from_env(cls: type[_S], **kwargs: Any) -> _S:
|
|
57
74
|
"""从环境加载配置,支持 ``SettingsConfigDict`` 所有参数。
|
{fastapi_augment-0.1.2 → fastapi_augment-0.1.3}/src/fastapi_augment/db/sqlalchemy/__init__.py
RENAMED
|
@@ -6,6 +6,13 @@
|
|
|
6
6
|
from .base import Base
|
|
7
7
|
from .engine import NodeConfig, ClusterTopology, EngineManager
|
|
8
8
|
from .model_base import ModelBase
|
|
9
|
+
from .query_parser import (
|
|
10
|
+
parse_lookup,
|
|
11
|
+
parse_where,
|
|
12
|
+
parse_keyword,
|
|
13
|
+
parse_sort,
|
|
14
|
+
build_query_expressions
|
|
15
|
+
)
|
|
9
16
|
from .repository_base import RepositoryBase
|
|
10
17
|
from .session import SessionFactory
|
|
11
18
|
|
|
@@ -15,6 +22,11 @@ __all__ = [
|
|
|
15
22
|
'ClusterTopology',
|
|
16
23
|
'EngineManager',
|
|
17
24
|
'ModelBase',
|
|
25
|
+
'parse_lookup',
|
|
26
|
+
'parse_where',
|
|
27
|
+
'parse_keyword',
|
|
28
|
+
'parse_sort',
|
|
29
|
+
'build_query_expressions',
|
|
18
30
|
'RepositoryBase',
|
|
19
31
|
'SessionFactory'
|
|
20
32
|
]
|