sqlmodel-ext 0.2.1__tar.gz → 0.3.2__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.
Files changed (167) hide show
  1. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/PKG-INFO +140 -4
  2. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/README.md +136 -3
  3. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/README_zh.md +95 -3
  4. sqlmodel_ext-0.3.2/docs/.vitepress/config.mts +57 -0
  5. sqlmodel_ext-0.3.2/docs/.vitepress/en.mts +88 -0
  6. sqlmodel_ext-0.3.2/docs/.vitepress/theme/index.ts +13 -0
  7. sqlmodel_ext-0.3.2/docs/.vitepress/zh.mts +88 -0
  8. {sqlmodel_ext-0.2.1/docs/en/internals → sqlmodel_ext-0.3.2/docs/en/explanation}/cached-table.md +244 -227
  9. sqlmodel_ext-0.3.2/docs/en/explanation/cascade-delete-semantics.md +153 -0
  10. sqlmodel_ext-0.2.1/docs/en/internals/crud.md → sqlmodel_ext-0.3.2/docs/en/explanation/crud-pipeline.md +288 -283
  11. sqlmodel_ext-0.3.2/docs/en/explanation/index.md +41 -0
  12. {sqlmodel_ext-0.2.1/docs/en/internals → sqlmodel_ext-0.3.2/docs/en/explanation}/metaclass.md +319 -315
  13. {sqlmodel_ext-0.2.1/docs/en/internals → sqlmodel_ext-0.3.2/docs/en/explanation}/optimistic-lock.md +120 -114
  14. sqlmodel_ext-0.2.1/docs/en/internals/polymorphic.md → sqlmodel_ext-0.3.2/docs/en/explanation/polymorphic-internals.md +210 -204
  15. {sqlmodel_ext-0.2.1/docs/en/internals → sqlmodel_ext-0.3.2/docs/en/explanation}/prerequisites.md +158 -154
  16. {sqlmodel_ext-0.2.1/docs/en/internals → sqlmodel_ext-0.3.2/docs/en/explanation}/relation-load-checker.md +116 -108
  17. {sqlmodel_ext-0.2.1/docs/en/internals → sqlmodel_ext-0.3.2/docs/en/explanation}/relation-preload.md +197 -191
  18. sqlmodel_ext-0.3.2/docs/en/guide/cached-table.md +17 -0
  19. sqlmodel_ext-0.3.2/docs/en/guide/crud.md +15 -0
  20. sqlmodel_ext-0.3.2/docs/en/guide/field-types.md +13 -0
  21. sqlmodel_ext-0.3.2/docs/en/guide/index.md +13 -0
  22. sqlmodel_ext-0.3.2/docs/en/guide/optimistic-lock.md +14 -0
  23. sqlmodel_ext-0.3.2/docs/en/guide/pagination.md +14 -0
  24. sqlmodel_ext-0.3.2/docs/en/guide/polymorphic.md +17 -0
  25. sqlmodel_ext-0.3.2/docs/en/guide/relation-load-checker.md +16 -0
  26. sqlmodel_ext-0.3.2/docs/en/guide/relation-preload.md +17 -0
  27. sqlmodel_ext-0.3.2/docs/en/how-to/cache-queries.md +142 -0
  28. sqlmodel_ext-0.3.2/docs/en/how-to/configure-cascade-delete.md +234 -0
  29. sqlmodel_ext-0.3.2/docs/en/how-to/define-jti-models.md +120 -0
  30. sqlmodel_ext-0.3.2/docs/en/how-to/define-sti-models.md +132 -0
  31. sqlmodel_ext-0.3.2/docs/en/how-to/handle-concurrent-updates.md +88 -0
  32. sqlmodel_ext-0.3.2/docs/en/how-to/index.md +41 -0
  33. sqlmodel_ext-0.3.2/docs/en/how-to/integrate-with-fastapi.md +116 -0
  34. sqlmodel_ext-0.3.2/docs/en/how-to/paginate-a-list-endpoint.md +79 -0
  35. sqlmodel_ext-0.3.2/docs/en/how-to/prevent-missing-greenlet.md +162 -0
  36. sqlmodel_ext-0.3.2/docs/en/how-to/release-connection-during-long-io.md +181 -0
  37. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/docs/en/index.md +10 -4
  38. sqlmodel_ext-0.3.2/docs/en/internals/cached-table.md +13 -0
  39. sqlmodel_ext-0.3.2/docs/en/internals/crud.md +15 -0
  40. sqlmodel_ext-0.3.2/docs/en/internals/index.md +13 -0
  41. sqlmodel_ext-0.3.2/docs/en/internals/metaclass.md +13 -0
  42. sqlmodel_ext-0.3.2/docs/en/internals/optimistic-lock.md +13 -0
  43. sqlmodel_ext-0.3.2/docs/en/internals/polymorphic.md +13 -0
  44. sqlmodel_ext-0.3.2/docs/en/internals/prerequisites.md +13 -0
  45. sqlmodel_ext-0.3.2/docs/en/internals/relation-load-checker.md +13 -0
  46. sqlmodel_ext-0.3.2/docs/en/internals/relation-preload.md +13 -0
  47. sqlmodel_ext-0.3.2/docs/en/reference/base-classes.md +121 -0
  48. sqlmodel_ext-0.3.2/docs/en/reference/crud-methods.md +275 -0
  49. sqlmodel_ext-0.3.2/docs/en/reference/decorators.md +162 -0
  50. sqlmodel_ext-0.3.2/docs/en/reference/field-types.md +218 -0
  51. sqlmodel_ext-0.3.2/docs/en/reference/index.md +54 -0
  52. sqlmodel_ext-0.3.2/docs/en/reference/mixins.md +222 -0
  53. sqlmodel_ext-0.3.2/docs/en/reference/pagination-types.md +113 -0
  54. sqlmodel_ext-0.3.2/docs/en/tutorials/01-getting-started.md +174 -0
  55. sqlmodel_ext-0.3.2/docs/en/tutorials/02-building-a-blog-api.md +388 -0
  56. sqlmodel_ext-0.3.2/docs/en/tutorials/03-adding-redis-cache.md +269 -0
  57. sqlmodel_ext-0.3.2/docs/en/tutorials/index.md +32 -0
  58. {sqlmodel_ext-0.2.1/docs/internals → sqlmodel_ext-0.3.2/docs/explanation}/cached-table.md +244 -227
  59. sqlmodel_ext-0.3.2/docs/explanation/cascade-delete-semantics.md +153 -0
  60. sqlmodel_ext-0.2.1/docs/internals/crud.md → sqlmodel_ext-0.3.2/docs/explanation/crud-pipeline.md +288 -283
  61. sqlmodel_ext-0.3.2/docs/explanation/index.md +41 -0
  62. {sqlmodel_ext-0.2.1/docs/internals → sqlmodel_ext-0.3.2/docs/explanation}/metaclass.md +319 -315
  63. {sqlmodel_ext-0.2.1/docs/internals → sqlmodel_ext-0.3.2/docs/explanation}/optimistic-lock.md +120 -114
  64. sqlmodel_ext-0.2.1/docs/internals/polymorphic.md → sqlmodel_ext-0.3.2/docs/explanation/polymorphic-internals.md +210 -204
  65. {sqlmodel_ext-0.2.1/docs/internals → sqlmodel_ext-0.3.2/docs/explanation}/prerequisites.md +158 -154
  66. {sqlmodel_ext-0.2.1/docs/internals → sqlmodel_ext-0.3.2/docs/explanation}/relation-load-checker.md +116 -108
  67. {sqlmodel_ext-0.2.1/docs/internals → sqlmodel_ext-0.3.2/docs/explanation}/relation-preload.md +197 -191
  68. sqlmodel_ext-0.3.2/docs/guide/cached-table.md +17 -0
  69. sqlmodel_ext-0.3.2/docs/guide/crud.md +15 -0
  70. sqlmodel_ext-0.3.2/docs/guide/field-types.md +13 -0
  71. sqlmodel_ext-0.3.2/docs/guide/index.md +13 -0
  72. sqlmodel_ext-0.3.2/docs/guide/optimistic-lock.md +14 -0
  73. sqlmodel_ext-0.3.2/docs/guide/pagination.md +14 -0
  74. sqlmodel_ext-0.3.2/docs/guide/polymorphic.md +17 -0
  75. sqlmodel_ext-0.3.2/docs/guide/relation-load-checker.md +16 -0
  76. sqlmodel_ext-0.3.2/docs/guide/relation-preload.md +17 -0
  77. sqlmodel_ext-0.3.2/docs/how-to/cache-queries.md +142 -0
  78. sqlmodel_ext-0.3.2/docs/how-to/configure-cascade-delete.md +234 -0
  79. sqlmodel_ext-0.3.2/docs/how-to/define-jti-models.md +120 -0
  80. sqlmodel_ext-0.3.2/docs/how-to/define-sti-models.md +132 -0
  81. sqlmodel_ext-0.3.2/docs/how-to/handle-concurrent-updates.md +87 -0
  82. sqlmodel_ext-0.3.2/docs/how-to/index.md +41 -0
  83. sqlmodel_ext-0.3.2/docs/how-to/integrate-with-fastapi.md +116 -0
  84. sqlmodel_ext-0.3.2/docs/how-to/paginate-a-list-endpoint.md +79 -0
  85. sqlmodel_ext-0.3.2/docs/how-to/prevent-missing-greenlet.md +162 -0
  86. sqlmodel_ext-0.3.2/docs/how-to/release-connection-during-long-io.md +181 -0
  87. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/docs/index.md +10 -4
  88. sqlmodel_ext-0.3.2/docs/internals/cached-table.md +13 -0
  89. sqlmodel_ext-0.3.2/docs/internals/crud.md +15 -0
  90. sqlmodel_ext-0.3.2/docs/internals/index.md +13 -0
  91. sqlmodel_ext-0.3.2/docs/internals/metaclass.md +13 -0
  92. sqlmodel_ext-0.3.2/docs/internals/optimistic-lock.md +13 -0
  93. sqlmodel_ext-0.3.2/docs/internals/polymorphic.md +13 -0
  94. sqlmodel_ext-0.3.2/docs/internals/prerequisites.md +13 -0
  95. sqlmodel_ext-0.3.2/docs/internals/relation-load-checker.md +13 -0
  96. sqlmodel_ext-0.3.2/docs/internals/relation-preload.md +13 -0
  97. sqlmodel_ext-0.3.2/docs/reference/base-classes.md +121 -0
  98. sqlmodel_ext-0.3.2/docs/reference/crud-methods.md +275 -0
  99. sqlmodel_ext-0.3.2/docs/reference/decorators.md +162 -0
  100. sqlmodel_ext-0.3.2/docs/reference/field-types.md +218 -0
  101. sqlmodel_ext-0.3.2/docs/reference/index.md +54 -0
  102. sqlmodel_ext-0.3.2/docs/reference/mixins.md +222 -0
  103. sqlmodel_ext-0.3.2/docs/reference/pagination-types.md +113 -0
  104. sqlmodel_ext-0.3.2/docs/tutorials/01-getting-started.md +174 -0
  105. sqlmodel_ext-0.3.2/docs/tutorials/02-building-a-blog-api.md +388 -0
  106. sqlmodel_ext-0.3.2/docs/tutorials/03-adding-redis-cache.md +269 -0
  107. sqlmodel_ext-0.3.2/docs/tutorials/index.md +32 -0
  108. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/package.json +2 -1
  109. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/pnpm-lock.yaml +1096 -390
  110. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/pyproject.toml +2 -1
  111. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/__init__.py +7 -1
  112. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/_compat.py +48 -0
  113. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/base.py +374 -13
  114. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/field_types/__init__.py +33 -4
  115. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/field_types/dialects/postgresql/array.py +119 -113
  116. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/mixins/__init__.py +1 -0
  117. sqlmodel_ext-0.3.2/src/sqlmodel_ext/mixins/cached_table.py +2074 -0
  118. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/mixins/polymorphic.py +50 -17
  119. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/mixins/table.py +16 -0
  120. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/relation_load_checker.py +1161 -175
  121. sqlmodel_ext-0.2.1/docs/.vitepress/config.mts +0 -27
  122. sqlmodel_ext-0.2.1/docs/.vitepress/en.mts +0 -59
  123. sqlmodel_ext-0.2.1/docs/.vitepress/theme/index.ts +0 -6
  124. sqlmodel_ext-0.2.1/docs/.vitepress/zh.mts +0 -59
  125. sqlmodel_ext-0.2.1/docs/en/guide/cached-table.md +0 -156
  126. sqlmodel_ext-0.2.1/docs/en/guide/crud.md +0 -264
  127. sqlmodel_ext-0.2.1/docs/en/guide/field-types.md +0 -120
  128. sqlmodel_ext-0.2.1/docs/en/guide/index.md +0 -175
  129. sqlmodel_ext-0.2.1/docs/en/guide/optimistic-lock.md +0 -102
  130. sqlmodel_ext-0.2.1/docs/en/guide/pagination.md +0 -136
  131. sqlmodel_ext-0.2.1/docs/en/guide/polymorphic.md +0 -141
  132. sqlmodel_ext-0.2.1/docs/en/guide/relation-load-checker.md +0 -105
  133. sqlmodel_ext-0.2.1/docs/en/guide/relation-preload.md +0 -118
  134. sqlmodel_ext-0.2.1/docs/en/internals/index.md +0 -78
  135. sqlmodel_ext-0.2.1/docs/guide/cached-table.md +0 -155
  136. sqlmodel_ext-0.2.1/docs/guide/crud.md +0 -264
  137. sqlmodel_ext-0.2.1/docs/guide/field-types.md +0 -120
  138. sqlmodel_ext-0.2.1/docs/guide/index.md +0 -175
  139. sqlmodel_ext-0.2.1/docs/guide/optimistic-lock.md +0 -102
  140. sqlmodel_ext-0.2.1/docs/guide/pagination.md +0 -136
  141. sqlmodel_ext-0.2.1/docs/guide/polymorphic.md +0 -141
  142. sqlmodel_ext-0.2.1/docs/guide/relation-load-checker.md +0 -105
  143. sqlmodel_ext-0.2.1/docs/guide/relation-preload.md +0 -118
  144. sqlmodel_ext-0.2.1/docs/internals/index.md +0 -78
  145. sqlmodel_ext-0.2.1/src/sqlmodel_ext/mixins/cached_table.py +0 -1707
  146. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/.gitignore +0 -0
  147. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/LICENSE +0 -0
  148. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/docs/.vitepress/theme/style/custom.css +0 -0
  149. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/_exceptions.py +0 -0
  150. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/_sa_type.py +0 -0
  151. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/_utils.py +0 -0
  152. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/field_types/_internal/__init__.py +0 -0
  153. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/field_types/_internal/path.py +0 -0
  154. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/field_types/_ssrf.py +0 -0
  155. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/field_types/dialects/__init__.py +0 -0
  156. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/field_types/dialects/postgresql/__init__.py +0 -0
  157. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/field_types/dialects/postgresql/exceptions.py +0 -0
  158. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/field_types/dialects/postgresql/jsonb_types.py +0 -0
  159. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/field_types/dialects/postgresql/numpy_vector.py +0 -0
  160. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/field_types/ip_address.py +0 -0
  161. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/field_types/mixins/__init__.py +0 -0
  162. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/field_types/mixins/module_name_mixin.py +0 -0
  163. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/field_types/url.py +0 -0
  164. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/mixins/info_response.py +0 -0
  165. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/mixins/optimistic_lock.py +0 -0
  166. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/mixins/relation_preload.py +0 -0
  167. {sqlmodel_ext-0.2.1 → sqlmodel_ext-0.3.2}/src/sqlmodel_ext/pagination.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlmodel-ext
3
- Version: 0.2.1
3
+ Version: 0.3.2
4
4
  Summary: Extended SQLModel infrastructure: smart metaclass, async CRUD mixins, polymorphic inheritance, optimistic locking, relation preloading, and reusable field types.
5
5
  Project-URL: Homepage, https://github.com/Foxerine/sqlmodel-ext
6
6
  Project-URL: Repository, https://github.com/Foxerine/sqlmodel-ext
@@ -25,6 +25,9 @@ Requires-Python: >=3.12
25
25
  Requires-Dist: pydantic>=2.0
26
26
  Requires-Dist: sqlalchemy>=2.0
27
27
  Requires-Dist: sqlmodel>=0.0.22
28
+ Provides-Extra: cache
29
+ Requires-Dist: orjson>=3.0; extra == 'cache'
30
+ Requires-Dist: redis>=5.0; extra == 'cache'
28
31
  Provides-Extra: dev
29
32
  Requires-Dist: aiosqlite>=0.20; extra == 'dev'
30
33
  Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
@@ -58,8 +61,9 @@ Extended SQLModel infrastructure: smart metaclass, async CRUD mixins, polymorphi
58
61
 
59
62
  | Feature | Description |
60
63
  |---------|-------------|
61
- | **SQLModelBase** | Smart metaclass with automatic `table=True`, `mapper_args` merging, and Python 3.14 (PEP 649) compatibility |
64
+ | **SQLModelBase** | Smart metaclass with automatic `table=True`, `mapper_args` merging, `all_fields_optional` for UpdateRequest DTOs, attribute docstring inheritance, and Python 3.14 (PEP 649) compatibility |
62
65
  | **TableBaseMixin / UUIDTableBaseMixin** | Full async CRUD: `add()`, `save()`, `update()`, `delete()`, `get()`, `count()`, `get_with_count()`, `get_exist_one()` |
66
+ | **CachedTableBaseMixin** | Two-tier Redis cache (ID + query) with version-based invalidation, STI-aware cascade, and optional metrics callbacks |
63
67
  | **PolymorphicBaseMixin** | Simplified Joined Table Inheritance (JTI) and Single Table Inheritance (STI) |
64
68
  | **AutoPolymorphicIdentityMixin** | Auto-generated `polymorphic_identity` from class names |
65
69
  | **OptimisticLockMixin** | Version-based optimistic locking with automatic retry |
@@ -87,6 +91,12 @@ With PostgreSQL ARRAY and JSONB types (requires `orjson`):
87
91
  pip install sqlmodel-ext[postgresql]
88
92
  ```
89
93
 
94
+ With Redis caching support (enables `CachedTableBaseMixin`):
95
+
96
+ ```bash
97
+ pip install sqlmodel-ext[cache]
98
+ ```
99
+
90
100
  With pgvector + NumPy vector support (includes `[postgresql]`):
91
101
 
92
102
  ```bash
@@ -1251,6 +1261,130 @@ These mixins define the fields as **required** (non-optional), because in API re
1251
1261
 
1252
1262
  ---
1253
1263
 
1264
+ ### Redis Caching (CachedTableBaseMixin)
1265
+
1266
+ Add a two-tier Redis cache to any table model. Queries go through Redis first; cache misses fall through to the database.
1267
+
1268
+ ```bash
1269
+ pip install sqlmodel-ext[cache] # installs redis + orjson
1270
+ ```
1271
+
1272
+ **Setup (once at application startup):**
1273
+
1274
+ ```python
1275
+ from redis.asyncio import Redis
1276
+ from sqlmodel_ext import CachedTableBaseMixin
1277
+
1278
+ redis = Redis.from_url("redis://localhost:6379/0", decode_responses=False)
1279
+ CachedTableBaseMixin.configure_redis(redis)
1280
+ ```
1281
+
1282
+ **Define a cached model:**
1283
+
1284
+ ```python
1285
+ class Character(CachedTableBaseMixin, CharacterBase, UUIDTableBaseMixin, table=True, cache_ttl=1800):
1286
+ pass # 30-minute cache TTL
1287
+ ```
1288
+
1289
+ That's it. All `get()` calls now check Redis first. Cache invalidation is automatic on `save()`, `update()`, and `delete()`.
1290
+
1291
+ **Cache architecture:**
1292
+
1293
+ | Layer | Key format | Invalidation |
1294
+ |-------|-----------|--------------|
1295
+ | ID cache | `id:{Model}:{id}` | Row-level DEL on save/update/delete |
1296
+ | Query cache | `query:{Model}:v{version}:{hash}` | Version bump (O(1) INCR) makes old keys unreachable |
1297
+ | Version | `ver:{Model}` | INCR on any write; STI subclass changes bump all ancestor versions |
1298
+
1299
+ **Optional metrics callbacks:**
1300
+
1301
+ ```python
1302
+ CachedTableBaseMixin.on_cache_hit = lambda name: print(f"HIT: {name}")
1303
+ CachedTableBaseMixin.on_cache_miss = lambda name: print(f"MISS: {name}")
1304
+ ```
1305
+
1306
+ **Cache skip conditions** (automatically detected):
1307
+ - `no_cache=True` (explicit bypass)
1308
+ - `with_for_update=True` (pessimistic lock needs latest)
1309
+ - `join` is set (join target changes don't trigger invalidation)
1310
+ - `options` is set (custom loading options)
1311
+
1312
+ **No Redis? No problem.** If you don't call `configure_redis()` and don't inherit `CachedTableBaseMixin`, there is zero Redis dependency. The caching layer is entirely opt-in.
1313
+
1314
+ ---
1315
+
1316
+ ### all_fields_optional
1317
+
1318
+ Automatically convert all inherited fields to optional for PATCH/UpdateRequest DTOs:
1319
+
1320
+ ```python
1321
+ class ArticleBase(SQLModelBase):
1322
+ title: Str64
1323
+ """Article title"""
1324
+ body: Text10K
1325
+ """Article body"""
1326
+ is_published: bool = False
1327
+ """Publication status"""
1328
+
1329
+ class ArticleUpdateRequest(ArticleBase, all_fields_optional=True):
1330
+ pass
1331
+ # All fields become: title: Str64 | None = None, body: Text10K | None = None, etc.
1332
+ # Annotated constraints (max_length, ge, le) are preserved
1333
+ # Attribute docstrings are inherited from ArticleBase
1334
+ ```
1335
+
1336
+ **What it does:**
1337
+ - Converts `T` to `T | None = None` for all inherited fields
1338
+ - Preserves `Annotated` metadata (e.g. `Field(ge=0)` constraints stay intact)
1339
+ - Skips `Literal` fields (discriminator fields must remain required)
1340
+ - Replaces `default_factory` with `default=None`
1341
+
1342
+ **No more manual overrides** like this:
1343
+
1344
+ ```python
1345
+ # Before: tedious and error-prone
1346
+ class ArticleUpdateRequest(ArticleBase):
1347
+ title: Str64 | None = None # Must manually repeat type + optional
1348
+ body: Text10K | None = None # Easy to forget constraints
1349
+ is_published: bool | None = None
1350
+ ```
1351
+
1352
+ ---
1353
+
1354
+ ### Attribute Docstring Inheritance
1355
+
1356
+ When using Pydantic's `use_attribute_docstrings=True` (enabled by default in `SQLModelBase`), field descriptions appear in OpenAPI schemas. However, Pydantic's AST-based docstring parser doesn't inherit descriptions when subclasses override fields.
1357
+
1358
+ **sqlmodel-ext fixes this automatically.** The metaclass inherits missing descriptions from parent classes via MRO traversal, and `__get_pydantic_json_schema__` patches bare `$ref` properties to include descriptions.
1359
+
1360
+ ```python
1361
+ class UserBase(SQLModelBase):
1362
+ name: str
1363
+ """User display name""" # ← parsed by Pydantic
1364
+
1365
+ class UserUpdateRequest(UserBase, all_fields_optional=True):
1366
+ pass
1367
+ # name: str | None = None — description "User display name" is automatically inherited
1368
+ # Shows up correctly in OpenAPI/Swagger docs
1369
+ ```
1370
+
1371
+ ---
1372
+
1373
+ ### safe_reset
1374
+
1375
+ Safely reset an async session, clearing both the DB connection and FOR UPDATE lock tracking:
1376
+
1377
+ ```python
1378
+ from sqlmodel_ext import safe_reset
1379
+
1380
+ # In long-lived tasks (e.g. background workers) between operations:
1381
+ await safe_reset(session)
1382
+ ```
1383
+
1384
+ This prevents stale `FOR UPDATE` lock tracking in `session.info` when Python reuses object IDs across `reset()` cycles.
1385
+
1386
+ ---
1387
+
1254
1388
  ## Architecture
1255
1389
 
1256
1390
  ```
@@ -1264,7 +1398,8 @@ sqlmodel_ext/
1264
1398
  pagination.py # ListResponse, TimeFilterRequest, PaginationRequest, TableViewRequest
1265
1399
  mixins/
1266
1400
  __init__.py # Mixin re-exports
1267
- table.py # TableBaseMixin, UUIDTableBaseMixin (async CRUD)
1401
+ table.py # TableBaseMixin, UUIDTableBaseMixin, safe_reset (async CRUD)
1402
+ cached_table.py # CachedTableBaseMixin (two-tier Redis cache with version invalidation)
1268
1403
  polymorphic.py # PolymorphicBaseMixin, AutoPolymorphicIdentityMixin, create_subclass_id_mixin
1269
1404
  optimistic_lock.py # OptimisticLockMixin, OptimisticLockError
1270
1405
  relation_preload.py # RelationPreloadMixin, @requires_relations
@@ -1292,7 +1427,8 @@ sqlmodel_ext/
1292
1427
  - **pydantic** >= 2.0
1293
1428
  - **sqlalchemy** >= 2.0
1294
1429
  - (optional) **fastapi** >= 0.100.0
1295
- - (optional) **orjson** >= 3.0 -- for `JSON100K` / `JSONList100K`
1430
+ - (optional) **redis** >= 5.0 -- for `CachedTableBaseMixin`
1431
+ - (optional) **orjson** >= 3.0 -- for `CachedTableBaseMixin` and `JSON100K` / `JSONList100K`
1296
1432
  - (optional) **numpy** >= 1.24 -- for `NumpyVector`
1297
1433
  - (optional) **pgvector** >= 0.3 -- for `NumpyVector`
1298
1434
 
@@ -16,8 +16,9 @@ Extended SQLModel infrastructure: smart metaclass, async CRUD mixins, polymorphi
16
16
 
17
17
  | Feature | Description |
18
18
  |---------|-------------|
19
- | **SQLModelBase** | Smart metaclass with automatic `table=True`, `mapper_args` merging, and Python 3.14 (PEP 649) compatibility |
19
+ | **SQLModelBase** | Smart metaclass with automatic `table=True`, `mapper_args` merging, `all_fields_optional` for UpdateRequest DTOs, attribute docstring inheritance, and Python 3.14 (PEP 649) compatibility |
20
20
  | **TableBaseMixin / UUIDTableBaseMixin** | Full async CRUD: `add()`, `save()`, `update()`, `delete()`, `get()`, `count()`, `get_with_count()`, `get_exist_one()` |
21
+ | **CachedTableBaseMixin** | Two-tier Redis cache (ID + query) with version-based invalidation, STI-aware cascade, and optional metrics callbacks |
21
22
  | **PolymorphicBaseMixin** | Simplified Joined Table Inheritance (JTI) and Single Table Inheritance (STI) |
22
23
  | **AutoPolymorphicIdentityMixin** | Auto-generated `polymorphic_identity` from class names |
23
24
  | **OptimisticLockMixin** | Version-based optimistic locking with automatic retry |
@@ -45,6 +46,12 @@ With PostgreSQL ARRAY and JSONB types (requires `orjson`):
45
46
  pip install sqlmodel-ext[postgresql]
46
47
  ```
47
48
 
49
+ With Redis caching support (enables `CachedTableBaseMixin`):
50
+
51
+ ```bash
52
+ pip install sqlmodel-ext[cache]
53
+ ```
54
+
48
55
  With pgvector + NumPy vector support (includes `[postgresql]`):
49
56
 
50
57
  ```bash
@@ -1209,6 +1216,130 @@ These mixins define the fields as **required** (non-optional), because in API re
1209
1216
 
1210
1217
  ---
1211
1218
 
1219
+ ### Redis Caching (CachedTableBaseMixin)
1220
+
1221
+ Add a two-tier Redis cache to any table model. Queries go through Redis first; cache misses fall through to the database.
1222
+
1223
+ ```bash
1224
+ pip install sqlmodel-ext[cache] # installs redis + orjson
1225
+ ```
1226
+
1227
+ **Setup (once at application startup):**
1228
+
1229
+ ```python
1230
+ from redis.asyncio import Redis
1231
+ from sqlmodel_ext import CachedTableBaseMixin
1232
+
1233
+ redis = Redis.from_url("redis://localhost:6379/0", decode_responses=False)
1234
+ CachedTableBaseMixin.configure_redis(redis)
1235
+ ```
1236
+
1237
+ **Define a cached model:**
1238
+
1239
+ ```python
1240
+ class Character(CachedTableBaseMixin, CharacterBase, UUIDTableBaseMixin, table=True, cache_ttl=1800):
1241
+ pass # 30-minute cache TTL
1242
+ ```
1243
+
1244
+ That's it. All `get()` calls now check Redis first. Cache invalidation is automatic on `save()`, `update()`, and `delete()`.
1245
+
1246
+ **Cache architecture:**
1247
+
1248
+ | Layer | Key format | Invalidation |
1249
+ |-------|-----------|--------------|
1250
+ | ID cache | `id:{Model}:{id}` | Row-level DEL on save/update/delete |
1251
+ | Query cache | `query:{Model}:v{version}:{hash}` | Version bump (O(1) INCR) makes old keys unreachable |
1252
+ | Version | `ver:{Model}` | INCR on any write; STI subclass changes bump all ancestor versions |
1253
+
1254
+ **Optional metrics callbacks:**
1255
+
1256
+ ```python
1257
+ CachedTableBaseMixin.on_cache_hit = lambda name: print(f"HIT: {name}")
1258
+ CachedTableBaseMixin.on_cache_miss = lambda name: print(f"MISS: {name}")
1259
+ ```
1260
+
1261
+ **Cache skip conditions** (automatically detected):
1262
+ - `no_cache=True` (explicit bypass)
1263
+ - `with_for_update=True` (pessimistic lock needs latest)
1264
+ - `join` is set (join target changes don't trigger invalidation)
1265
+ - `options` is set (custom loading options)
1266
+
1267
+ **No Redis? No problem.** If you don't call `configure_redis()` and don't inherit `CachedTableBaseMixin`, there is zero Redis dependency. The caching layer is entirely opt-in.
1268
+
1269
+ ---
1270
+
1271
+ ### all_fields_optional
1272
+
1273
+ Automatically convert all inherited fields to optional for PATCH/UpdateRequest DTOs:
1274
+
1275
+ ```python
1276
+ class ArticleBase(SQLModelBase):
1277
+ title: Str64
1278
+ """Article title"""
1279
+ body: Text10K
1280
+ """Article body"""
1281
+ is_published: bool = False
1282
+ """Publication status"""
1283
+
1284
+ class ArticleUpdateRequest(ArticleBase, all_fields_optional=True):
1285
+ pass
1286
+ # All fields become: title: Str64 | None = None, body: Text10K | None = None, etc.
1287
+ # Annotated constraints (max_length, ge, le) are preserved
1288
+ # Attribute docstrings are inherited from ArticleBase
1289
+ ```
1290
+
1291
+ **What it does:**
1292
+ - Converts `T` to `T | None = None` for all inherited fields
1293
+ - Preserves `Annotated` metadata (e.g. `Field(ge=0)` constraints stay intact)
1294
+ - Skips `Literal` fields (discriminator fields must remain required)
1295
+ - Replaces `default_factory` with `default=None`
1296
+
1297
+ **No more manual overrides** like this:
1298
+
1299
+ ```python
1300
+ # Before: tedious and error-prone
1301
+ class ArticleUpdateRequest(ArticleBase):
1302
+ title: Str64 | None = None # Must manually repeat type + optional
1303
+ body: Text10K | None = None # Easy to forget constraints
1304
+ is_published: bool | None = None
1305
+ ```
1306
+
1307
+ ---
1308
+
1309
+ ### Attribute Docstring Inheritance
1310
+
1311
+ When using Pydantic's `use_attribute_docstrings=True` (enabled by default in `SQLModelBase`), field descriptions appear in OpenAPI schemas. However, Pydantic's AST-based docstring parser doesn't inherit descriptions when subclasses override fields.
1312
+
1313
+ **sqlmodel-ext fixes this automatically.** The metaclass inherits missing descriptions from parent classes via MRO traversal, and `__get_pydantic_json_schema__` patches bare `$ref` properties to include descriptions.
1314
+
1315
+ ```python
1316
+ class UserBase(SQLModelBase):
1317
+ name: str
1318
+ """User display name""" # ← parsed by Pydantic
1319
+
1320
+ class UserUpdateRequest(UserBase, all_fields_optional=True):
1321
+ pass
1322
+ # name: str | None = None — description "User display name" is automatically inherited
1323
+ # Shows up correctly in OpenAPI/Swagger docs
1324
+ ```
1325
+
1326
+ ---
1327
+
1328
+ ### safe_reset
1329
+
1330
+ Safely reset an async session, clearing both the DB connection and FOR UPDATE lock tracking:
1331
+
1332
+ ```python
1333
+ from sqlmodel_ext import safe_reset
1334
+
1335
+ # In long-lived tasks (e.g. background workers) between operations:
1336
+ await safe_reset(session)
1337
+ ```
1338
+
1339
+ This prevents stale `FOR UPDATE` lock tracking in `session.info` when Python reuses object IDs across `reset()` cycles.
1340
+
1341
+ ---
1342
+
1212
1343
  ## Architecture
1213
1344
 
1214
1345
  ```
@@ -1222,7 +1353,8 @@ sqlmodel_ext/
1222
1353
  pagination.py # ListResponse, TimeFilterRequest, PaginationRequest, TableViewRequest
1223
1354
  mixins/
1224
1355
  __init__.py # Mixin re-exports
1225
- table.py # TableBaseMixin, UUIDTableBaseMixin (async CRUD)
1356
+ table.py # TableBaseMixin, UUIDTableBaseMixin, safe_reset (async CRUD)
1357
+ cached_table.py # CachedTableBaseMixin (two-tier Redis cache with version invalidation)
1226
1358
  polymorphic.py # PolymorphicBaseMixin, AutoPolymorphicIdentityMixin, create_subclass_id_mixin
1227
1359
  optimistic_lock.py # OptimisticLockMixin, OptimisticLockError
1228
1360
  relation_preload.py # RelationPreloadMixin, @requires_relations
@@ -1250,7 +1382,8 @@ sqlmodel_ext/
1250
1382
  - **pydantic** >= 2.0
1251
1383
  - **sqlalchemy** >= 2.0
1252
1384
  - (optional) **fastapi** >= 0.100.0
1253
- - (optional) **orjson** >= 3.0 -- for `JSON100K` / `JSONList100K`
1385
+ - (optional) **redis** >= 5.0 -- for `CachedTableBaseMixin`
1386
+ - (optional) **orjson** >= 3.0 -- for `CachedTableBaseMixin` and `JSON100K` / `JSONList100K`
1254
1387
  - (optional) **numpy** >= 1.24 -- for `NumpyVector`
1255
1388
  - (optional) **pgvector** >= 0.3 -- for `NumpyVector`
1256
1389
 
@@ -16,8 +16,9 @@ SQLModel 增强基础设施:智能元类、异步 CRUD Mixin、多态继承、
16
16
 
17
17
  | 特性 | 说明 |
18
18
  |------|------|
19
- | **SQLModelBase** | 智能元类,自动设置 `table=True`、合并 `mapper_args`,兼容 Python 3.14 (PEP 649) |
19
+ | **SQLModelBase** | 智能元类,自动 `table=True`、合并 `mapper_args`、`all_fields_optional` UpdateRequest DTO、属性 docstring 继承、兼容 Python 3.14 (PEP 649) |
20
20
  | **TableBaseMixin / UUIDTableBaseMixin** | 完整异步 CRUD:`add()`、`save()`、`update()`、`delete()`、`get()`、`count()`、`get_with_count()`、`get_exist_one()` |
21
+ | **CachedTableBaseMixin** | 双层 Redis 缓存(ID + 查询),版本号失效、STI 级联感知、可选 metrics 回调 |
21
22
  | **PolymorphicBaseMixin** | 简化联表继承 (JTI) 和单表继承 (STI) 配置 |
22
23
  | **AutoPolymorphicIdentityMixin** | 根据类名自动生成 `polymorphic_identity` |
23
24
  | **OptimisticLockMixin** | 基于版本号的乐观锁,支持自动重试 |
@@ -45,6 +46,12 @@ pip install sqlmodel-ext[fastapi]
45
46
  pip install sqlmodel-ext[postgresql]
46
47
  ```
47
48
 
49
+ 使用 Redis 缓存(启用 `CachedTableBaseMixin`):
50
+
51
+ ```bash
52
+ pip install sqlmodel-ext[cache]
53
+ ```
54
+
48
55
  使用 pgvector + NumPy 向量支持(包含 `[postgresql]`):
49
56
 
50
57
  ```bash
@@ -1209,6 +1216,89 @@ class UserResponse(UserBase, UUIDIdDatetimeInfoMixin):
1209
1216
 
1210
1217
  ---
1211
1218
 
1219
+ ### Redis 缓存 (CachedTableBaseMixin)
1220
+
1221
+ 为任何表模型添加双层 Redis 缓存。查询先走 Redis,未命中再查数据库。
1222
+
1223
+ ```bash
1224
+ pip install sqlmodel-ext[cache] # 安装 redis + orjson
1225
+ ```
1226
+
1227
+ **启动配置(一次性):**
1228
+
1229
+ ```python
1230
+ from redis.asyncio import Redis
1231
+ from sqlmodel_ext import CachedTableBaseMixin
1232
+
1233
+ redis = Redis.from_url("redis://localhost:6379/0", decode_responses=False)
1234
+ CachedTableBaseMixin.configure_redis(redis)
1235
+ ```
1236
+
1237
+ **定义缓存模型:**
1238
+
1239
+ ```python
1240
+ class Character(CachedTableBaseMixin, CharacterBase, UUIDTableBaseMixin, table=True, cache_ttl=1800):
1241
+ pass # 30 分钟缓存 TTL
1242
+ ```
1243
+
1244
+ 所有 `get()` 调用自动先查 Redis。`save()`、`update()`、`delete()` 时自动失效缓存。
1245
+
1246
+ **缓存架构:**
1247
+
1248
+ | 层 | Key 格式 | 失效方式 |
1249
+ |----|---------|---------|
1250
+ | ID 缓存 | `id:{Model}:{id}` | 行级 DEL |
1251
+ | 查询缓存 | `query:{Model}:v{version}:{hash}` | 版本号 INCR(O(1))使旧 key 不可达 |
1252
+ | 版本号 | `ver:{Model}` | 写入时 INCR;STI 子类变更级联 bump 所有祖先 |
1253
+
1254
+ **可选 metrics 回调:**
1255
+
1256
+ ```python
1257
+ CachedTableBaseMixin.on_cache_hit = lambda name: print(f"命中: {name}")
1258
+ CachedTableBaseMixin.on_cache_miss = lambda name: print(f"未命中: {name}")
1259
+ ```
1260
+
1261
+ **不用 Redis?** 不调用 `configure_redis()`、不继承 `CachedTableBaseMixin`,则零 Redis 依赖。缓存层完全可选。
1262
+
1263
+ ---
1264
+
1265
+ ### all_fields_optional
1266
+
1267
+ 自动将所有继承字段转为可选,用于 PATCH/UpdateRequest DTO:
1268
+
1269
+ ```python
1270
+ class ArticleBase(SQLModelBase):
1271
+ title: Str64
1272
+ """文章标题"""
1273
+ body: Text10K
1274
+ """文章内容"""
1275
+
1276
+ class ArticleUpdateRequest(ArticleBase, all_fields_optional=True):
1277
+ pass
1278
+ # 所有字段变为: title: Str64 | None = None, body: Text10K | None = None, ...
1279
+ # Annotated 约束(max_length, ge, le)保留
1280
+ # 属性 docstring 从 ArticleBase 继承
1281
+ ```
1282
+
1283
+ ---
1284
+
1285
+ ### 属性 Docstring 继承
1286
+
1287
+ `SQLModelBase` 默认启用 Pydantic 的 `use_attribute_docstrings=True`,字段后的 docstring 自动出现在 OpenAPI Schema 中。当子类覆盖字段时,Pydantic 不会继承父类的 description——**sqlmodel-ext 在元类中自动修复此问题**。
1288
+
1289
+ ---
1290
+
1291
+ ### safe_reset
1292
+
1293
+ 安全重置异步会话,同时清理 FOR UPDATE 锁跟踪:
1294
+
1295
+ ```python
1296
+ from sqlmodel_ext import safe_reset
1297
+ await safe_reset(session)
1298
+ ```
1299
+
1300
+ ---
1301
+
1212
1302
  ## 架构
1213
1303
 
1214
1304
  ```
@@ -1222,7 +1312,8 @@ sqlmodel_ext/
1222
1312
  pagination.py # ListResponse、TimeFilterRequest、PaginationRequest、TableViewRequest
1223
1313
  mixins/
1224
1314
  __init__.py # Mixin 重导出
1225
- table.py # TableBaseMixin、UUIDTableBaseMixin(异步 CRUD)
1315
+ table.py # TableBaseMixin、UUIDTableBaseMixin、safe_reset(异步 CRUD)
1316
+ cached_table.py # CachedTableBaseMixin(双层 Redis 缓存 + 版本号失效)
1226
1317
  polymorphic.py # PolymorphicBaseMixin、AutoPolymorphicIdentityMixin、create_subclass_id_mixin
1227
1318
  optimistic_lock.py # OptimisticLockMixin、OptimisticLockError
1228
1319
  relation_preload.py # RelationPreloadMixin、@requires_relations
@@ -1250,7 +1341,8 @@ sqlmodel_ext/
1250
1341
  - **pydantic** >= 2.0
1251
1342
  - **sqlalchemy** >= 2.0
1252
1343
  - (可选)**fastapi** >= 0.100.0
1253
- - (可选)**orjson** >= 3.0 -- 用于 `JSON100K` / `JSONList100K`
1344
+ - (可选)**redis** >= 5.0 -- 用于 `CachedTableBaseMixin`
1345
+ - (可选)**orjson** >= 3.0 -- 用于 `CachedTableBaseMixin` 和 `JSON100K` / `JSONList100K`
1254
1346
  - (可选)**numpy** >= 1.24 -- 用于 `NumpyVector`
1255
1347
  - (可选)**pgvector** >= 0.3 -- 用于 `NumpyVector`
1256
1348
 
@@ -0,0 +1,57 @@
1
+ import { withMermaid } from 'vitepress-plugin-mermaid'
2
+ import llmstxt from 'vitepress-plugin-llms'
3
+ import { copyOrDownloadAsMarkdownButtons } from 'vitepress-plugin-llms'
4
+ import { zh } from './zh.mts'
5
+ import { en } from './en.mts'
6
+
7
+ export default withMermaid({
8
+ title: 'sqlmodel-ext',
9
+
10
+ vite: {
11
+ plugins: [
12
+ llmstxt({
13
+ // Exclude legacy redirect placeholders. The old guide/internals trees were
14
+ // migrated to tutorials/how-to/reference/explanation under Diátaxis;
15
+ // the placeholders only carry meta-refresh stubs and would pollute llms-full.txt.
16
+ ignoreFiles: [
17
+ 'guide/*',
18
+ 'internals/*',
19
+ 'en/guide/*',
20
+ 'en/internals/*',
21
+ ],
22
+ }),
23
+ ],
24
+ optimizeDeps: {
25
+ include: ['mermaid', 'dayjs'],
26
+ },
27
+ ssr: {
28
+ noExternal: ['vitepress-plugin-mermaid', 'mermaid'],
29
+ },
30
+ },
31
+
32
+ markdown: {
33
+ config(md) {
34
+ md.use(copyOrDownloadAsMarkdownButtons)
35
+ },
36
+ },
37
+
38
+ locales: {
39
+ root: {
40
+ label: '简体中文',
41
+ ...zh,
42
+ },
43
+ en: {
44
+ label: 'English',
45
+ ...en,
46
+ },
47
+ },
48
+
49
+ themeConfig: {
50
+ socialLinks: [
51
+ { icon: 'github', link: 'https://github.com/Foxerine/sqlmodel-ext' },
52
+ ],
53
+ search: {
54
+ provider: 'local',
55
+ },
56
+ },
57
+ })
@@ -0,0 +1,88 @@
1
+ import type { DefaultTheme } from 'vitepress'
2
+
3
+ export const en = {
4
+ lang: 'en',
5
+ description: 'SQLModel Enhancement Library — Tutorials, How-to, Reference, Explanation',
6
+
7
+ themeConfig: {
8
+ nav: [
9
+ { text: 'Home', link: '/en/' },
10
+ { text: 'Tutorials', link: '/en/tutorials/' },
11
+ { text: 'How-to', link: '/en/how-to/' },
12
+ { text: 'Reference', link: '/en/reference/' },
13
+ { text: 'Explanation', link: '/en/explanation/' },
14
+ ],
15
+
16
+ sidebar: {
17
+ '/en/tutorials/': [
18
+ {
19
+ text: 'Tutorials',
20
+ items: [
21
+ { text: 'Overview', link: '/en/tutorials/' },
22
+ { text: '01 · Getting started', link: '/en/tutorials/01-getting-started' },
23
+ { text: '02 · Building a blog API', link: '/en/tutorials/02-building-a-blog-api' },
24
+ { text: '03 · Adding Redis caching', link: '/en/tutorials/03-adding-redis-cache' },
25
+ ],
26
+ },
27
+ ],
28
+ '/en/how-to/': [
29
+ {
30
+ text: 'How-to guides',
31
+ items: [
32
+ { text: 'Overview', link: '/en/how-to/' },
33
+ { text: 'Integrate with FastAPI', link: '/en/how-to/integrate-with-fastapi' },
34
+ { text: 'Paginate a list endpoint', link: '/en/how-to/paginate-a-list-endpoint' },
35
+ { text: 'Define JTI models', link: '/en/how-to/define-jti-models' },
36
+ { text: 'Define STI models', link: '/en/how-to/define-sti-models' },
37
+ { text: 'Handle concurrent updates', link: '/en/how-to/handle-concurrent-updates' },
38
+ { text: 'Prevent MissingGreenlet errors', link: '/en/how-to/prevent-missing-greenlet' },
39
+ { text: 'Release the DB connection during long I/O', link: '/en/how-to/release-connection-during-long-io' },
40
+ { text: 'Configure cascade delete', link: '/en/how-to/configure-cascade-delete' },
41
+ { text: 'Cache queries with Redis', link: '/en/how-to/cache-queries' },
42
+ ],
43
+ },
44
+ ],
45
+ '/en/reference/': [
46
+ {
47
+ text: 'Reference',
48
+ items: [
49
+ { text: 'Overview', link: '/en/reference/' },
50
+ { text: 'Base classes', link: '/en/reference/base-classes' },
51
+ { text: 'CRUD methods', link: '/en/reference/crud-methods' },
52
+ { text: 'Field types', link: '/en/reference/field-types' },
53
+ { text: 'Mixins', link: '/en/reference/mixins' },
54
+ { text: 'Decorators & helpers', link: '/en/reference/decorators' },
55
+ { text: 'Pagination types', link: '/en/reference/pagination-types' },
56
+ ],
57
+ },
58
+ ],
59
+ '/en/explanation/': [
60
+ {
61
+ text: 'Explanation',
62
+ items: [
63
+ { text: 'Overview', link: '/en/explanation/' },
64
+ { text: 'Prerequisites', link: '/en/explanation/prerequisites' },
65
+ { text: 'Metaclass & SQLModelBase', link: '/en/explanation/metaclass' },
66
+ { text: 'CRUD pipeline', link: '/en/explanation/crud-pipeline' },
67
+ { text: 'Polymorphic internals', link: '/en/explanation/polymorphic-internals' },
68
+ { text: 'Optimistic locking', link: '/en/explanation/optimistic-lock' },
69
+ { text: 'Relation preloading', link: '/en/explanation/relation-preload' },
70
+ { text: 'Cascade delete semantics', link: '/en/explanation/cascade-delete-semantics' },
71
+ { text: 'Redis caching', link: '/en/explanation/cached-table' },
72
+ { text: 'Static analyzer', link: '/en/explanation/relation-load-checker' },
73
+ ],
74
+ },
75
+ ],
76
+ },
77
+
78
+ outline: {
79
+ level: [2, 3],
80
+ label: 'On this page',
81
+ },
82
+
83
+ docFooter: {
84
+ prev: 'Previous',
85
+ next: 'Next',
86
+ },
87
+ } satisfies DefaultTheme.Config,
88
+ }
@@ -0,0 +1,13 @@
1
+ // .vitepress/theme/index.ts
2
+ import DefaultTheme from 'vitepress/theme'
3
+ import type { Theme } from 'vitepress'
4
+ import CopyOrDownloadAsMarkdownButtons from 'vitepress-plugin-llms/vitepress-components/CopyOrDownloadAsMarkdownButtons.vue'
5
+ import '@fontsource/maple-mono';
6
+ import './style/custom.css'
7
+
8
+ export default {
9
+ extends: DefaultTheme,
10
+ enhanceApp({ app }) {
11
+ app.component('CopyOrDownloadAsMarkdownButtons', CopyOrDownloadAsMarkdownButtons)
12
+ },
13
+ } satisfies Theme