toms-fast 0.2.1__py3-none-any.whl
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.
- toms_fast-0.2.1.dist-info/METADATA +467 -0
- toms_fast-0.2.1.dist-info/RECORD +60 -0
- toms_fast-0.2.1.dist-info/WHEEL +4 -0
- toms_fast-0.2.1.dist-info/entry_points.txt +2 -0
- tomskit/__init__.py +0 -0
- tomskit/celery/README.md +693 -0
- tomskit/celery/__init__.py +4 -0
- tomskit/celery/celery.py +306 -0
- tomskit/celery/config.py +377 -0
- tomskit/cli/__init__.py +207 -0
- tomskit/cli/__main__.py +8 -0
- tomskit/cli/scaffold.py +123 -0
- tomskit/cli/templates/__init__.py +42 -0
- tomskit/cli/templates/base.py +348 -0
- tomskit/cli/templates/celery.py +101 -0
- tomskit/cli/templates/extensions.py +213 -0
- tomskit/cli/templates/fastapi.py +400 -0
- tomskit/cli/templates/migrations.py +281 -0
- tomskit/cli/templates_config.py +122 -0
- tomskit/logger/README.md +466 -0
- tomskit/logger/__init__.py +4 -0
- tomskit/logger/config.py +106 -0
- tomskit/logger/logger.py +290 -0
- tomskit/py.typed +0 -0
- tomskit/redis/README.md +462 -0
- tomskit/redis/__init__.py +6 -0
- tomskit/redis/config.py +85 -0
- tomskit/redis/redis_pool.py +87 -0
- tomskit/redis/redis_sync.py +66 -0
- tomskit/server/__init__.py +47 -0
- tomskit/server/config.py +117 -0
- tomskit/server/exceptions.py +412 -0
- tomskit/server/middleware.py +371 -0
- tomskit/server/parser.py +312 -0
- tomskit/server/resource.py +464 -0
- tomskit/server/server.py +276 -0
- tomskit/server/type.py +263 -0
- tomskit/sqlalchemy/README.md +590 -0
- tomskit/sqlalchemy/__init__.py +20 -0
- tomskit/sqlalchemy/config.py +125 -0
- tomskit/sqlalchemy/database.py +125 -0
- tomskit/sqlalchemy/pagination.py +359 -0
- tomskit/sqlalchemy/property.py +19 -0
- tomskit/sqlalchemy/sqlalchemy.py +131 -0
- tomskit/sqlalchemy/types.py +32 -0
- tomskit/task/README.md +67 -0
- tomskit/task/__init__.py +4 -0
- tomskit/task/task_manager.py +124 -0
- tomskit/tools/README.md +63 -0
- tomskit/tools/__init__.py +18 -0
- tomskit/tools/config.py +70 -0
- tomskit/tools/warnings.py +37 -0
- tomskit/tools/woker.py +81 -0
- tomskit/utils/README.md +666 -0
- tomskit/utils/README_SERIALIZER.md +644 -0
- tomskit/utils/__init__.py +35 -0
- tomskit/utils/fields.py +434 -0
- tomskit/utils/marshal_utils.py +137 -0
- tomskit/utils/response_utils.py +13 -0
- tomskit/utils/serializers.py +447 -0
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
# SQLAlchemy Module Guide
|
|
2
|
+
|
|
3
|
+
该模块提供了一组用于与 SQLAlchemy 进行交互的实用工具和扩展,支持异步数据库操作、会话管理、分页等功能。
|
|
4
|
+
|
|
5
|
+
## 模块概述
|
|
6
|
+
|
|
7
|
+
SQLAlchemy 模块基于 SQLAlchemy 2.x 异步 API,提供了完整的异步数据库操作支持。主要特性包括:
|
|
8
|
+
|
|
9
|
+
- ⚡ **完全异步**:基于 `AsyncSession` 和 `async_sessionmaker` 实现
|
|
10
|
+
- 🔄 **会话管理**:使用 `ContextVar` 管理数据库会话上下文
|
|
11
|
+
- 📄 **分页支持**:提供灵活的分页查询功能
|
|
12
|
+
- 🛠️ **配置管理**:基于 Pydantic Settings 的配置类
|
|
13
|
+
- 🔧 **类型支持**:自定义 UUID 类型和工具函数
|
|
14
|
+
|
|
15
|
+
**Import Path:**
|
|
16
|
+
```python
|
|
17
|
+
from tomskit.sqlalchemy import (
|
|
18
|
+
SQLAlchemy,
|
|
19
|
+
DatabaseSession,
|
|
20
|
+
db,
|
|
21
|
+
DatabaseConfig,
|
|
22
|
+
Pagination,
|
|
23
|
+
SelectPagination,
|
|
24
|
+
StringUUID,
|
|
25
|
+
uuid_generate_v4,
|
|
26
|
+
cached_async_property
|
|
27
|
+
)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 核心类和函数
|
|
31
|
+
|
|
32
|
+
### DatabaseConfig
|
|
33
|
+
|
|
34
|
+
数据库配置类,继承自 `pydantic_settings.BaseSettings`,用于管理数据库连接配置。
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
class DatabaseConfig(BaseSettings):
|
|
38
|
+
DB_HOST: str = Field(default="localhost", ...)
|
|
39
|
+
DB_PORT: PositiveInt = Field(default=5432, ...)
|
|
40
|
+
DB_USERNAME: str = Field(default="", ...)
|
|
41
|
+
DB_PASSWORD: str = Field(default="", ...)
|
|
42
|
+
DB_DATABASE: str = Field(default="tomskitdb", ...)
|
|
43
|
+
DB_CHARSET: str = Field(default="", ...)
|
|
44
|
+
DB_EXTRAS: str = Field(default="", ...)
|
|
45
|
+
SQLALCHEMY_DATABASE_URI_SCHEME: str = Field(default="mysql+aiomysql", ...)
|
|
46
|
+
SQLALCHEMY_DATABASE_SYNC_URI_SCHEME: str = Field(default="mysql+pymysql", ...)
|
|
47
|
+
SQLALCHEMY_POOL_SIZE: NonNegativeInt = Field(default=300, ...)
|
|
48
|
+
SQLALCHEMY_MAX_OVERFLOW: NonNegativeInt = Field(default=10, ...)
|
|
49
|
+
SQLALCHEMY_POOL_RECYCLE: NonNegativeInt = Field(default=3600, ...)
|
|
50
|
+
SQLALCHEMY_POOL_PRE_PING: bool = Field(default=False, ...)
|
|
51
|
+
SQLALCHEMY_ECHO: bool = Field(default=False, ...)
|
|
52
|
+
SQLALCHEMY_POOL_ECHO: bool = Field(default=False, ...)
|
|
53
|
+
|
|
54
|
+
@computed_field
|
|
55
|
+
@property
|
|
56
|
+
def SQLALCHEMY_DATABASE_URI(self) -> str: ...
|
|
57
|
+
|
|
58
|
+
@computed_field
|
|
59
|
+
@property
|
|
60
|
+
def SQLALCHEMY_DATABASE_SYNC_URI(self) -> str: ...
|
|
61
|
+
|
|
62
|
+
@computed_field
|
|
63
|
+
@property
|
|
64
|
+
def SQLALCHEMY_ENGINE_OPTIONS(self) -> dict[str, Any]: ...
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**配置属性说明:**
|
|
68
|
+
- `DB_HOST`: 数据库主机地址,默认为 `localhost`
|
|
69
|
+
- `DB_PORT`: 数据库端口,默认为 `5432`,必须为正整数
|
|
70
|
+
- `DB_USERNAME`: 数据库用户名,默认为空字符串
|
|
71
|
+
- `DB_PASSWORD`: 数据库密码,默认为空字符串
|
|
72
|
+
- `DB_DATABASE`: 数据库名称,默认为 `tomskitdb`
|
|
73
|
+
- `DB_CHARSET`: 数据库字符集,默认为空字符串
|
|
74
|
+
- `DB_EXTRAS`: 数据库额外选项,例如 `keepalives_idle=60&keepalives=1`
|
|
75
|
+
- `SQLALCHEMY_DATABASE_URI_SCHEME`: 异步数据库 URI 协议,默认为 `mysql+aiomysql`
|
|
76
|
+
- `SQLALCHEMY_DATABASE_SYNC_URI_SCHEME`: 同步数据库 URI 协议,默认为 `mysql+pymysql`
|
|
77
|
+
- `SQLALCHEMY_POOL_SIZE`: SQLAlchemy 连接池大小,默认为 `300`
|
|
78
|
+
- `SQLALCHEMY_MAX_OVERFLOW`: SQLAlchemy 最大溢出连接数,默认为 `10`
|
|
79
|
+
- `SQLALCHEMY_POOL_RECYCLE`: SQLAlchemy 连接池回收时间,默认为 `3600` 秒
|
|
80
|
+
- `SQLALCHEMY_POOL_PRE_PING`: 是否启用连接池预检,默认为 `False`
|
|
81
|
+
- `SQLALCHEMY_ECHO`: 是否启用 SQLAlchemy 的回显,默认为 `False`
|
|
82
|
+
- `SQLALCHEMY_POOL_ECHO`: 是否启用连接池的回显,默认为 `False`
|
|
83
|
+
|
|
84
|
+
**使用示例:**
|
|
85
|
+
```python
|
|
86
|
+
from tomskit.sqlalchemy.config import DatabaseConfig
|
|
87
|
+
|
|
88
|
+
config = DatabaseConfig(
|
|
89
|
+
DB_USERNAME='user',
|
|
90
|
+
DB_PASSWORD='password',
|
|
91
|
+
DB_HOST='localhost',
|
|
92
|
+
DB_PORT=5432,
|
|
93
|
+
DB_DATABASE='mydb'
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
print(config.SQLALCHEMY_DATABASE_URI)
|
|
97
|
+
# 输出: mysql+aiomysql://user:password@localhost:5432/mydb
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### SQLAlchemy
|
|
101
|
+
|
|
102
|
+
SQLAlchemy 抽象基类,提供模型定义和常用 SQLAlchemy 构造。
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
class SQLAlchemy(ABC):
|
|
106
|
+
class Model(AsyncAttrs, DeclarativeBase): ...
|
|
107
|
+
|
|
108
|
+
# SQLAlchemy 类型和函数
|
|
109
|
+
Column = sa_Column
|
|
110
|
+
CHAR = sa_CHAR
|
|
111
|
+
BigInteger = sa_BigInteger
|
|
112
|
+
Boolean = sa_Boolean
|
|
113
|
+
DateTime = sa_DateTime
|
|
114
|
+
Float = sa_Float
|
|
115
|
+
Integer = sa_Integer
|
|
116
|
+
JSON = sa_JSON
|
|
117
|
+
LargeBinary = sa_LargeBinary
|
|
118
|
+
Numeric = sa_Numeric
|
|
119
|
+
PickleType = sa_PickleType
|
|
120
|
+
Sequence = sa_Sequence
|
|
121
|
+
String = sa_String
|
|
122
|
+
Text = sa_Text
|
|
123
|
+
uuid = sa_CHAR(36)
|
|
124
|
+
ForeignKey = sa_ForeignKey
|
|
125
|
+
Index = sa_Index
|
|
126
|
+
PrimaryKeyConstraint = sa_PrimaryKeyConstraint
|
|
127
|
+
UniqueConstraint = sa_UniqueConstraint
|
|
128
|
+
|
|
129
|
+
# SQLAlchemy 函数
|
|
130
|
+
text = staticmethod(sa_text)
|
|
131
|
+
select = staticmethod(sa_select)
|
|
132
|
+
delete = staticmethod(sa_delete)
|
|
133
|
+
update = staticmethod(sa_update)
|
|
134
|
+
insert = staticmethod(sa_insert)
|
|
135
|
+
func = sa_func
|
|
136
|
+
relationship = staticmethod(sa_relationship)
|
|
137
|
+
and_ = staticmethod(sa_and_)
|
|
138
|
+
|
|
139
|
+
@abstractmethod
|
|
140
|
+
async def paginate(
|
|
141
|
+
self,
|
|
142
|
+
select: Select[Any],
|
|
143
|
+
*,
|
|
144
|
+
page: int | None = None,
|
|
145
|
+
per_page: int | None = None,
|
|
146
|
+
max_per_page: int | None = None,
|
|
147
|
+
error_out: bool = True,
|
|
148
|
+
count: bool = True
|
|
149
|
+
) -> Pagination: ...
|
|
150
|
+
|
|
151
|
+
@property
|
|
152
|
+
@abstractmethod
|
|
153
|
+
def session(self) -> AsyncSession: ...
|
|
154
|
+
|
|
155
|
+
@abstractmethod
|
|
156
|
+
def create_session(self) -> AsyncSession: ...
|
|
157
|
+
|
|
158
|
+
@abstractmethod
|
|
159
|
+
async def close_session(self, session: AsyncSession) -> None: ...
|
|
160
|
+
|
|
161
|
+
@abstractmethod
|
|
162
|
+
def initialize_session_pool(self, db_url: str, engine_options: Optional[dict[str, Any]] = None) -> None: ...
|
|
163
|
+
|
|
164
|
+
@abstractmethod
|
|
165
|
+
async def close_session_pool(self) -> None: ...
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### DatabaseSession
|
|
169
|
+
|
|
170
|
+
数据库会话管理类,继承自 `SQLAlchemy`,使用 `ContextVar` 管理会话上下文,确保线程安全和异步安全。
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
class DatabaseSession(SQLAlchemy):
|
|
174
|
+
database_session_ctx: ContextVar[Optional[AsyncSession]] = ContextVar('database_session', default=None)
|
|
175
|
+
|
|
176
|
+
async def paginate(
|
|
177
|
+
self,
|
|
178
|
+
select: Select[Any],
|
|
179
|
+
*,
|
|
180
|
+
page: int | None = None,
|
|
181
|
+
per_page: int | None = None,
|
|
182
|
+
max_per_page: int | None = None,
|
|
183
|
+
error_out: bool = True,
|
|
184
|
+
count: bool = True,
|
|
185
|
+
) -> Pagination: ...
|
|
186
|
+
|
|
187
|
+
@property
|
|
188
|
+
def session(self) -> Optional[AsyncSession]: ...
|
|
189
|
+
|
|
190
|
+
def create_session(self) -> AsyncSession: ...
|
|
191
|
+
|
|
192
|
+
async def close_session(self, session: AsyncSession) -> None: ...
|
|
193
|
+
|
|
194
|
+
def initialize_session_pool(
|
|
195
|
+
self,
|
|
196
|
+
db_url: str,
|
|
197
|
+
engine_options: Optional[dict[str, Any]] = None
|
|
198
|
+
) -> None: ...
|
|
199
|
+
|
|
200
|
+
async def close_session_pool(self) -> None: ...
|
|
201
|
+
|
|
202
|
+
def get_session_pool_info(self) -> dict: ...
|
|
203
|
+
|
|
204
|
+
def create_celery_session(self, config: dict[str, Any]) -> AsyncSession: ...
|
|
205
|
+
|
|
206
|
+
async def close_celery_session(self, session: AsyncSession) -> None: ...
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
**功能特性:**
|
|
210
|
+
- 提供与数据库的连接管理
|
|
211
|
+
- 支持事务的开始、提交和回滚
|
|
212
|
+
- 确保会话的线程安全和异步安全(使用 ContextVar)
|
|
213
|
+
- 支持连接池管理和监控
|
|
214
|
+
- 支持 Celery 任务的数据库会话管理
|
|
215
|
+
|
|
216
|
+
**使用场景:**
|
|
217
|
+
在需要与数据库进行交互的任何地方使用 `DatabaseSession` 来确保会话的正确管理。
|
|
218
|
+
|
|
219
|
+
### db
|
|
220
|
+
|
|
221
|
+
`db` 是一个全局的 `DatabaseSession` 实例,提供对数据库的直接访问。
|
|
222
|
+
|
|
223
|
+
**功能:**
|
|
224
|
+
- 提供全局的数据库连接
|
|
225
|
+
- 支持直接执行 SQL 查询
|
|
226
|
+
- 支持异步数据库操作
|
|
227
|
+
|
|
228
|
+
**使用场景:**
|
|
229
|
+
在需要直接访问数据库的地方使用 `db` 实例。
|
|
230
|
+
|
|
231
|
+
**使用示例:**
|
|
232
|
+
```python
|
|
233
|
+
from tomskit.sqlalchemy.database import db
|
|
234
|
+
|
|
235
|
+
# 获取单个对象
|
|
236
|
+
dataset = await db.session.get(Dataset, dataset_document.dataset_id)
|
|
237
|
+
|
|
238
|
+
# 执行删除操作
|
|
239
|
+
await db.session.execute(
|
|
240
|
+
db.delete(Dataset).filter(Dataset.tenant_id == dest_tenant_id)
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
# 添加对象
|
|
244
|
+
db.session.add(dataset)
|
|
245
|
+
await db.session.commit()
|
|
246
|
+
await db.session.refresh(dataset)
|
|
247
|
+
|
|
248
|
+
# 删除对象
|
|
249
|
+
await db.session.delete(user)
|
|
250
|
+
|
|
251
|
+
# 执行更新操作
|
|
252
|
+
await db.session.execute(
|
|
253
|
+
db.update(DocumentSegment).where(
|
|
254
|
+
DocumentSegment.document_id == dataset_document.id,
|
|
255
|
+
DocumentSegment.dataset_id == dataset.id,
|
|
256
|
+
DocumentSegment.index_node_id.in_(document_ids),
|
|
257
|
+
DocumentSegment.status == "indexing"
|
|
258
|
+
).values({
|
|
259
|
+
DocumentSegment.status: "completed",
|
|
260
|
+
DocumentSegment.enabled: True,
|
|
261
|
+
DocumentSegment.completed_at: datetime.datetime.now(datetime.timezone.utc).replace(tzinfo=None)
|
|
262
|
+
})
|
|
263
|
+
)
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Pagination
|
|
267
|
+
|
|
268
|
+
分页基类,提供分页查询功能。
|
|
269
|
+
|
|
270
|
+
```python
|
|
271
|
+
class Pagination:
|
|
272
|
+
def __init__(
|
|
273
|
+
self,
|
|
274
|
+
page: int | None = None,
|
|
275
|
+
per_page: int | None = None,
|
|
276
|
+
max_per_page: int | None = 100,
|
|
277
|
+
error_out: bool = True,
|
|
278
|
+
count: bool = True,
|
|
279
|
+
**kwargs: Any,
|
|
280
|
+
) -> None: ...
|
|
281
|
+
|
|
282
|
+
async def initialize(self) -> "Pagination": ...
|
|
283
|
+
|
|
284
|
+
# 属性
|
|
285
|
+
page: int
|
|
286
|
+
per_page: int
|
|
287
|
+
max_per_page: int | None
|
|
288
|
+
items: list[Any]
|
|
289
|
+
total: int | None
|
|
290
|
+
|
|
291
|
+
@property
|
|
292
|
+
def first(self) -> int: ...
|
|
293
|
+
|
|
294
|
+
@property
|
|
295
|
+
def last(self) -> int: ...
|
|
296
|
+
|
|
297
|
+
@property
|
|
298
|
+
def pages(self) -> int: ...
|
|
299
|
+
|
|
300
|
+
@property
|
|
301
|
+
def has_prev(self) -> bool: ...
|
|
302
|
+
|
|
303
|
+
@property
|
|
304
|
+
def prev_num(self) -> int | None: ...
|
|
305
|
+
|
|
306
|
+
@property
|
|
307
|
+
def has_next(self) -> bool: ...
|
|
308
|
+
|
|
309
|
+
@property
|
|
310
|
+
def next_num(self) -> int | None: ...
|
|
311
|
+
|
|
312
|
+
async def prev(self, *, error_out: bool = False) -> "Pagination": ...
|
|
313
|
+
|
|
314
|
+
async def next(self, *, error_out: bool = False) -> "Pagination": ...
|
|
315
|
+
|
|
316
|
+
def iter_pages(
|
|
317
|
+
self,
|
|
318
|
+
*,
|
|
319
|
+
left_edge: int = 2,
|
|
320
|
+
left_current: int = 2,
|
|
321
|
+
right_current: int = 4,
|
|
322
|
+
right_edge: int = 2,
|
|
323
|
+
) -> Iterator[int | None]: ...
|
|
324
|
+
|
|
325
|
+
def __iter__(self) -> Iterator[Any]: ...
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
**参数说明:**
|
|
329
|
+
- `page`: 当前页码,用于计算偏移量。默认为请求中的 `page` 查询参数,或 1
|
|
330
|
+
- `per_page`: 每页最大项目数,用于计算偏移量和限制。默认为请求中的 `per_page` 查询参数,或 20
|
|
331
|
+
- `max_per_page`: `per_page` 的最大允许值,用于限制用户提供的值。使用 `None` 表示无限制。默认为 100
|
|
332
|
+
- `error_out`: 如果没有返回项目且 `page` 不是 1,或者 `page` 或 `per_page` 小于 1,或者两者都不是整数,则中止并返回 `404 Not Found` 错误
|
|
333
|
+
- `count`: 通过发出额外的计数查询来计算值的总数。对于非常复杂的查询,这可能不准确或缓慢,因此可以在必要时禁用手动设置
|
|
334
|
+
|
|
335
|
+
**属性说明:**
|
|
336
|
+
- `page`: 当前页码
|
|
337
|
+
- `per_page`: 每页项目数
|
|
338
|
+
- `max_per_page`: 每页最大项目数
|
|
339
|
+
- `items`: 当前页的项目列表
|
|
340
|
+
- `total`: 总项目数(如果 `count=True`)
|
|
341
|
+
- `first`: 第一页的页码
|
|
342
|
+
- `last`: 最后一页的页码
|
|
343
|
+
- `pages`: 总页数
|
|
344
|
+
- `has_prev`: 是否有上一页
|
|
345
|
+
- `prev_num`: 上一页的页码
|
|
346
|
+
- `has_next`: 是否有下一页
|
|
347
|
+
- `next_num`: 下一页的页码
|
|
348
|
+
|
|
349
|
+
### SelectPagination
|
|
350
|
+
|
|
351
|
+
基于 Select 语句的分页实现,继承自 `Pagination`。
|
|
352
|
+
|
|
353
|
+
```python
|
|
354
|
+
class SelectPagination(Pagination):
|
|
355
|
+
async def initialize(self) -> "SelectPagination": ...
|
|
356
|
+
|
|
357
|
+
async def _query_items(self) -> list[Any]: ...
|
|
358
|
+
|
|
359
|
+
async def _query_count(self) -> int: ...
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
**使用示例:**
|
|
363
|
+
```python
|
|
364
|
+
from tomskit.sqlalchemy import db, SelectPagination
|
|
365
|
+
|
|
366
|
+
# 创建查询
|
|
367
|
+
select_stmt = db.select(User).where(User.status == "active")
|
|
368
|
+
|
|
369
|
+
# 执行分页查询
|
|
370
|
+
pagination = await db.paginate(
|
|
371
|
+
select_stmt,
|
|
372
|
+
page=1,
|
|
373
|
+
per_page=20,
|
|
374
|
+
max_per_page=100
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
# 访问分页结果
|
|
378
|
+
for user in pagination.items:
|
|
379
|
+
print(user.name)
|
|
380
|
+
|
|
381
|
+
# 访问分页信息
|
|
382
|
+
print(f"当前页: {pagination.page}")
|
|
383
|
+
print(f"总页数: {pagination.pages}")
|
|
384
|
+
print(f"总记录数: {pagination.total}")
|
|
385
|
+
print(f"是否有上一页: {pagination.has_prev}")
|
|
386
|
+
print(f"是否有下一页: {pagination.has_next}")
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### StringUUID
|
|
390
|
+
|
|
391
|
+
自定义的 UUID 字符串类型,用于在数据库中存储 UUID 字符串。
|
|
392
|
+
|
|
393
|
+
```python
|
|
394
|
+
class StringUUID(TypeDecorator):
|
|
395
|
+
impl = CHAR
|
|
396
|
+
cache_ok = True
|
|
397
|
+
|
|
398
|
+
def process_bind_param(self, value: Any, dialect: Any) -> str | None: ...
|
|
399
|
+
|
|
400
|
+
def load_dialect_impl(self, dialect: Any) -> Any: ...
|
|
401
|
+
|
|
402
|
+
def process_result_value(self, value: Any, dialect: Any) -> str | None: ...
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
**使用示例:**
|
|
406
|
+
```python
|
|
407
|
+
from tomskit.sqlalchemy import db, StringUUID
|
|
408
|
+
|
|
409
|
+
class User(db.Model):
|
|
410
|
+
__tablename__ = "users"
|
|
411
|
+
|
|
412
|
+
id = db.Column(StringUUID, primary_key=True, default=uuid_generate_v4)
|
|
413
|
+
name = db.Column(db.String(100))
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
### uuid_generate_v4
|
|
417
|
+
|
|
418
|
+
生成 UUID v4 的十六进制字符串。
|
|
419
|
+
|
|
420
|
+
```python
|
|
421
|
+
def uuid_generate_v4() -> str: ...
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
**使用示例:**
|
|
425
|
+
```python
|
|
426
|
+
from tomskit.sqlalchemy import uuid_generate_v4
|
|
427
|
+
|
|
428
|
+
user_id = uuid_generate_v4()
|
|
429
|
+
# 输出: "550e8400-e29b-41d4-a716-446655440000"
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### cached_async_property
|
|
433
|
+
|
|
434
|
+
异步属性缓存装饰器,用于缓存异步属性的计算结果。
|
|
435
|
+
|
|
436
|
+
```python
|
|
437
|
+
class cached_async_property:
|
|
438
|
+
def __init__(self, func: Callable) -> None: ...
|
|
439
|
+
|
|
440
|
+
def __get__(self, instance: Any, owner: type) -> Awaitable[Any]: ...
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
**使用示例:**
|
|
444
|
+
```python
|
|
445
|
+
from tomskit.sqlalchemy import cached_async_property
|
|
446
|
+
|
|
447
|
+
class User(db.Model):
|
|
448
|
+
__tablename__ = "users"
|
|
449
|
+
|
|
450
|
+
id = db.Column(StringUUID, primary_key=True)
|
|
451
|
+
name = db.Column(db.String(100))
|
|
452
|
+
|
|
453
|
+
@cached_async_property
|
|
454
|
+
async def profile(self):
|
|
455
|
+
# 第一次访问时会执行查询并缓存结果
|
|
456
|
+
return await db.session.get(Profile, self.id)
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
## 完整使用示例
|
|
460
|
+
|
|
461
|
+
### 初始化数据库
|
|
462
|
+
|
|
463
|
+
```python
|
|
464
|
+
from tomskit.sqlalchemy import db, DatabaseConfig
|
|
465
|
+
|
|
466
|
+
# 创建配置
|
|
467
|
+
config = DatabaseConfig(
|
|
468
|
+
DB_USERNAME='user',
|
|
469
|
+
DB_PASSWORD='password',
|
|
470
|
+
DB_HOST='localhost',
|
|
471
|
+
DB_PORT=3306,
|
|
472
|
+
DB_DATABASE='mydb'
|
|
473
|
+
)
|
|
474
|
+
|
|
475
|
+
# 初始化数据库连接池
|
|
476
|
+
db.initialize_session_pool(
|
|
477
|
+
config.SQLALCHEMY_DATABASE_URI,
|
|
478
|
+
config.SQLALCHEMY_ENGINE_OPTIONS
|
|
479
|
+
)
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
### 定义模型
|
|
483
|
+
|
|
484
|
+
```python
|
|
485
|
+
from tomskit.sqlalchemy import db, StringUUID, uuid_generate_v4
|
|
486
|
+
|
|
487
|
+
class User(db.Model):
|
|
488
|
+
__tablename__ = "users"
|
|
489
|
+
|
|
490
|
+
id = db.Column(StringUUID, primary_key=True, default=uuid_generate_v4)
|
|
491
|
+
name = db.Column(db.String(100), nullable=False)
|
|
492
|
+
email = db.Column(db.String(255), unique=True, nullable=False)
|
|
493
|
+
created_at = db.Column(db.DateTime, default=db.func.now())
|
|
494
|
+
updated_at = db.Column(db.DateTime, default=db.func.now(), onupdate=db.func.now())
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
### 数据库操作
|
|
498
|
+
|
|
499
|
+
```python
|
|
500
|
+
from tomskit.sqlalchemy import db
|
|
501
|
+
|
|
502
|
+
# 创建会话
|
|
503
|
+
session = db.create_session()
|
|
504
|
+
|
|
505
|
+
try:
|
|
506
|
+
# 查询单个对象
|
|
507
|
+
user = await session.get(User, user_id)
|
|
508
|
+
|
|
509
|
+
# 查询多个对象
|
|
510
|
+
users = await session.execute(
|
|
511
|
+
db.select(User).where(User.status == "active")
|
|
512
|
+
).scalars().all()
|
|
513
|
+
|
|
514
|
+
# 创建新对象
|
|
515
|
+
new_user = User(name="John", email="john@example.com")
|
|
516
|
+
session.add(new_user)
|
|
517
|
+
await session.commit()
|
|
518
|
+
await session.refresh(new_user)
|
|
519
|
+
|
|
520
|
+
# 更新对象
|
|
521
|
+
user.name = "Jane"
|
|
522
|
+
await session.commit()
|
|
523
|
+
|
|
524
|
+
# 删除对象
|
|
525
|
+
await session.delete(user)
|
|
526
|
+
await session.commit()
|
|
527
|
+
|
|
528
|
+
finally:
|
|
529
|
+
# 关闭会话
|
|
530
|
+
await db.close_session(session)
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
### 分页查询
|
|
534
|
+
|
|
535
|
+
```python
|
|
536
|
+
from tomskit.sqlalchemy import db
|
|
537
|
+
|
|
538
|
+
# 创建查询
|
|
539
|
+
select_stmt = db.select(User).where(User.status == "active")
|
|
540
|
+
|
|
541
|
+
# 执行分页查询
|
|
542
|
+
pagination = await db.paginate(
|
|
543
|
+
select_stmt,
|
|
544
|
+
page=1,
|
|
545
|
+
per_page=20,
|
|
546
|
+
max_per_page=100
|
|
547
|
+
)
|
|
548
|
+
|
|
549
|
+
# 访问结果
|
|
550
|
+
for user in pagination.items:
|
|
551
|
+
print(user.name)
|
|
552
|
+
|
|
553
|
+
# 访问分页信息
|
|
554
|
+
print(f"总记录数: {pagination.total}")
|
|
555
|
+
print(f"总页数: {pagination.pages}")
|
|
556
|
+
print(f"当前页: {pagination.page}")
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
## 环境变量配置
|
|
560
|
+
|
|
561
|
+
数据库模块支持通过环境变量进行配置:
|
|
562
|
+
|
|
563
|
+
- `DB_HOST`: 数据库主机地址
|
|
564
|
+
- `DB_PORT`: 数据库端口
|
|
565
|
+
- `DB_USERNAME`: 数据库用户名
|
|
566
|
+
- `DB_PASSWORD`: 数据库密码
|
|
567
|
+
- `DB_DATABASE`: 数据库名称
|
|
568
|
+
- `DB_CHARSET`: 数据库字符集
|
|
569
|
+
- `DB_EXTRAS`: 数据库额外选项
|
|
570
|
+
- `SQLALCHEMY_DATABASE_URI_SCHEME`: 异步数据库 URI 协议
|
|
571
|
+
- `SQLALCHEMY_DATABASE_SYNC_URI_SCHEME`: 同步数据库 URI 协议
|
|
572
|
+
- `SQLALCHEMY_POOL_SIZE`: 连接池大小
|
|
573
|
+
- `SQLALCHEMY_MAX_OVERFLOW`: 最大溢出连接数
|
|
574
|
+
- `SQLALCHEMY_POOL_RECYCLE`: 连接池回收时间(秒)
|
|
575
|
+
- `SQLALCHEMY_POOL_PRE_PING`: 是否启用连接池预检
|
|
576
|
+
- `SQLALCHEMY_ECHO`: 是否回显 SQL 语句
|
|
577
|
+
- `SQLALCHEMY_POOL_ECHO`: 是否回显连接池调试日志
|
|
578
|
+
|
|
579
|
+
## 注意事项
|
|
580
|
+
|
|
581
|
+
1. **会话管理**:使用 `ContextVar` 管理会话上下文,确保在异步环境中正确工作
|
|
582
|
+
2. **连接池**:默认连接池大小为 300,最大溢出为 10,可根据实际需求调整
|
|
583
|
+
3. **异步操作**:所有数据库操作都是异步的,需要使用 `await` 关键字
|
|
584
|
+
4. **事务管理**:使用 `session.commit()` 提交事务,`session.rollback()` 回滚事务
|
|
585
|
+
5. **资源清理**:使用完毕后务必关闭会话,避免连接泄漏
|
|
586
|
+
|
|
587
|
+
## 相关文档
|
|
588
|
+
|
|
589
|
+
- [Database Guide](../docs/specs/database_guide.md) - 详细的数据库使用指南
|
|
590
|
+
- [SQLAlchemy 官方文档](https://docs.sqlalchemy.org/) - SQLAlchemy 官方文档
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from tomskit.sqlalchemy.sqlalchemy import SQLAlchemy
|
|
2
|
+
from tomskit.sqlalchemy.pagination import Pagination, SelectPagination
|
|
3
|
+
from tomskit.sqlalchemy.database import DatabaseSession, db
|
|
4
|
+
from tomskit.sqlalchemy.config import DatabaseConfig
|
|
5
|
+
from tomskit.sqlalchemy.types import StringUUID, uuid_generate_v4
|
|
6
|
+
from tomskit.sqlalchemy.property import cached_async_property
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
'SQLAlchemy',
|
|
10
|
+
'Pagination',
|
|
11
|
+
'SelectPagination',
|
|
12
|
+
'DatabaseSession',
|
|
13
|
+
'db',
|
|
14
|
+
'DatabaseConfig',
|
|
15
|
+
'StringUUID',
|
|
16
|
+
'uuid_generate_v4',
|
|
17
|
+
'cached_async_property'
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
|