sqlmodel-ext 0.4.0__tar.gz → 0.4.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 (173) hide show
  1. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/PKG-INFO +50 -29
  2. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/README.md +42 -27
  3. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/README_zh.md +40 -25
  4. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/explanation/cached-table.md +20 -16
  5. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/explanation/crud-pipeline.md +1 -1
  6. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/explanation/metaclass.md +375 -319
  7. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/explanation/polymorphic-internals.md +24 -0
  8. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/explanation/relation-load-checker.md +33 -1
  9. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/how-to/cache-queries.md +143 -142
  10. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/how-to/define-sti-models.md +132 -132
  11. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/how-to/handle-concurrent-updates.md +94 -88
  12. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/how-to/integrate-with-fastapi.md +10 -7
  13. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/how-to/prevent-missing-greenlet.md +167 -162
  14. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/index.md +4 -4
  15. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/reference/base-classes.md +22 -0
  16. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/reference/crud-methods.md +7 -1
  17. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/reference/field-types.md +4 -0
  18. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/reference/index.md +1 -1
  19. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/reference/mixins.md +35 -0
  20. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/reference/pagination-types.md +1 -1
  21. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/tutorials/01-getting-started.md +6 -5
  22. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/tutorials/02-building-a-blog-api.md +389 -388
  23. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/tutorials/03-adding-redis-cache.md +277 -269
  24. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/explanation/cached-table.md +16 -16
  25. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/explanation/crud-pipeline.md +1 -1
  26. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/explanation/metaclass.md +351 -319
  27. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/explanation/polymorphic-internals.md +13 -0
  28. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/explanation/relation-load-checker.md +21 -1
  29. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/how-to/cache-queries.md +143 -142
  30. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/how-to/define-sti-models.md +132 -132
  31. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/how-to/handle-concurrent-updates.md +93 -87
  32. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/how-to/integrate-with-fastapi.md +10 -7
  33. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/how-to/prevent-missing-greenlet.md +164 -162
  34. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/index.md +4 -4
  35. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/reference/base-classes.md +19 -0
  36. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/reference/crud-methods.md +5 -1
  37. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/reference/field-types.md +4 -0
  38. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/reference/index.md +1 -1
  39. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/reference/mixins.md +30 -0
  40. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/reference/pagination-types.md +1 -1
  41. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/tutorials/01-getting-started.md +6 -5
  42. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/tutorials/02-building-a-blog-api.md +388 -388
  43. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/tutorials/03-adding-redis-cache.md +277 -269
  44. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/examples/consumer_integration/run.py +149 -148
  45. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/pyproject.toml +8 -2
  46. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/__init__.py +1 -1
  47. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/base.py +135 -3
  48. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/field_types/__init__.py +53 -1
  49. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/field_types/_internal/path.py +5 -1
  50. sqlmodel_ext-0.4.2/src/sqlmodel_ext/field_types/dialects/postgresql/array.py +218 -0
  51. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/mixins/table.py +70 -13
  52. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/tests/_models.py +69 -67
  53. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/tests/test_array_explicit_field_sa_type.py +18 -4
  54. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/tests/test_basic_crud.py +71 -61
  55. sqlmodel_ext-0.4.2/tests/test_cached_table.py +513 -0
  56. sqlmodel_ext-0.4.2/tests/test_crud_extended.py +582 -0
  57. sqlmodel_ext-0.4.2/tests/test_field_types_misc.py +189 -0
  58. sqlmodel_ext-0.4.2/tests/test_field_types_str_num.py +400 -0
  59. sqlmodel_ext-0.4.2/tests/test_field_types_url_ssrf.py +267 -0
  60. sqlmodel_ext-0.4.2/tests/test_metaclass_extra.py +194 -0
  61. sqlmodel_ext-0.4.2/tests/test_optimistic_lock.py +190 -0
  62. sqlmodel_ext-0.4.2/tests/test_pagination.py +259 -0
  63. sqlmodel_ext-0.4.2/tests/test_pg_dialect_types.py +427 -0
  64. sqlmodel_ext-0.4.2/tests/test_polymorphic_jti.py +273 -0
  65. sqlmodel_ext-0.4.2/tests/test_polymorphic_sti_query.py +418 -0
  66. sqlmodel_ext-0.4.2/tests/test_relation_load_checker.py +232 -0
  67. sqlmodel_ext-0.4.2/tests/test_relation_preload.py +240 -0
  68. sqlmodel_ext-0.4.2/tests/test_relationship_pep604.py +115 -0
  69. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/uv.lock +2 -2
  70. sqlmodel_ext-0.4.0/src/sqlmodel_ext/field_types/dialects/postgresql/array.py +0 -119
  71. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/.github/workflows/ci.yml +0 -0
  72. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/.gitignore +0 -0
  73. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/LICENSE +0 -0
  74. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/.vitepress/config.mts +0 -0
  75. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/.vitepress/en.mts +0 -0
  76. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/.vitepress/theme/index.ts +0 -0
  77. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/.vitepress/theme/style/custom.css +0 -0
  78. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/.vitepress/zh.mts +0 -0
  79. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/explanation/cascade-delete-semantics.md +0 -0
  80. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/explanation/index.md +0 -0
  81. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/explanation/optimistic-lock.md +0 -0
  82. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/explanation/prerequisites.md +0 -0
  83. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/explanation/relation-preload.md +0 -0
  84. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/guide/cached-table.md +0 -0
  85. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/guide/crud.md +0 -0
  86. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/guide/field-types.md +0 -0
  87. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/guide/index.md +0 -0
  88. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/guide/optimistic-lock.md +0 -0
  89. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/guide/pagination.md +0 -0
  90. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/guide/polymorphic.md +0 -0
  91. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/guide/relation-load-checker.md +0 -0
  92. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/guide/relation-preload.md +0 -0
  93. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/how-to/configure-cascade-delete.md +0 -0
  94. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/how-to/define-jti-models.md +0 -0
  95. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/how-to/index.md +0 -0
  96. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/how-to/paginate-a-list-endpoint.md +0 -0
  97. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/how-to/release-connection-during-long-io.md +0 -0
  98. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/internals/cached-table.md +0 -0
  99. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/internals/crud.md +0 -0
  100. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/internals/index.md +0 -0
  101. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/internals/metaclass.md +0 -0
  102. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/internals/optimistic-lock.md +0 -0
  103. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/internals/polymorphic.md +0 -0
  104. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/internals/prerequisites.md +0 -0
  105. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/internals/relation-load-checker.md +0 -0
  106. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/internals/relation-preload.md +0 -0
  107. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/reference/decorators.md +0 -0
  108. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/en/tutorials/index.md +0 -0
  109. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/explanation/cascade-delete-semantics.md +0 -0
  110. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/explanation/index.md +0 -0
  111. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/explanation/optimistic-lock.md +0 -0
  112. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/explanation/prerequisites.md +0 -0
  113. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/explanation/relation-preload.md +0 -0
  114. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/guide/cached-table.md +0 -0
  115. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/guide/crud.md +0 -0
  116. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/guide/field-types.md +0 -0
  117. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/guide/index.md +0 -0
  118. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/guide/optimistic-lock.md +0 -0
  119. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/guide/pagination.md +0 -0
  120. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/guide/polymorphic.md +0 -0
  121. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/guide/relation-load-checker.md +0 -0
  122. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/guide/relation-preload.md +0 -0
  123. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/how-to/configure-cascade-delete.md +0 -0
  124. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/how-to/define-jti-models.md +0 -0
  125. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/how-to/index.md +0 -0
  126. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/how-to/paginate-a-list-endpoint.md +0 -0
  127. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/how-to/release-connection-during-long-io.md +0 -0
  128. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/internals/cached-table.md +0 -0
  129. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/internals/crud.md +0 -0
  130. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/internals/index.md +0 -0
  131. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/internals/metaclass.md +0 -0
  132. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/internals/optimistic-lock.md +0 -0
  133. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/internals/polymorphic.md +0 -0
  134. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/internals/prerequisites.md +0 -0
  135. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/internals/relation-load-checker.md +0 -0
  136. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/internals/relation-preload.md +0 -0
  137. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/reference/decorators.md +0 -0
  138. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/docs/tutorials/index.md +0 -0
  139. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/package.json +0 -0
  140. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/pnpm-lock.yaml +0 -0
  141. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/_compat.py +0 -0
  142. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/_exceptions.py +0 -0
  143. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/_sa_type.py +0 -0
  144. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/_utils.py +0 -0
  145. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/field_types/_internal/__init__.py +0 -0
  146. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/field_types/_ssrf.py +0 -0
  147. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/field_types/dialects/__init__.py +0 -0
  148. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/field_types/dialects/postgresql/__init__.py +0 -0
  149. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/field_types/dialects/postgresql/exceptions.py +0 -0
  150. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/field_types/dialects/postgresql/jsonb_types.py +0 -0
  151. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/field_types/dialects/postgresql/numpy_vector.py +0 -0
  152. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/field_types/ip_address.py +0 -0
  153. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/field_types/mixins/__init__.py +0 -0
  154. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/field_types/mixins/module_name_mixin.py +0 -0
  155. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/field_types/url.py +0 -0
  156. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/mixins/__init__.py +0 -0
  157. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/mixins/cached_table.py +0 -0
  158. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/mixins/info_response.py +0 -0
  159. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/mixins/optimistic_lock.py +0 -0
  160. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/mixins/polymorphic.py +0 -0
  161. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/mixins/relation_preload.py +0 -0
  162. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/pagination.py +0 -0
  163. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/relation_load_checker.py +0 -0
  164. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/src/sqlmodel_ext/session.py +0 -0
  165. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/tests/__init__.py +0 -0
  166. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/tests/conftest.py +0 -0
  167. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/tests/test_all_fields_optional_constraints.py +0 -0
  168. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/tests/test_annotated_default_factory_inheritance.py +0 -0
  169. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/tests/test_decimal_types.py +0 -0
  170. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/tests/test_deferred_index.py +0 -0
  171. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/tests/test_enhanced_session.py +0 -0
  172. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/tests/test_smoke_imports.py +0 -0
  173. {sqlmodel_ext-0.4.0 → sqlmodel_ext-0.4.2}/tests/test_sti_default_isolation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlmodel-ext
3
- Version: 0.4.0
3
+ Version: 0.4.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
@@ -24,14 +24,20 @@ Classifier: Typing :: Typed
24
24
  Requires-Python: >=3.12
25
25
  Requires-Dist: pydantic>=2.0
26
26
  Requires-Dist: sqlalchemy>=2.0
27
- Requires-Dist: sqlmodel>=0.0.22
27
+ Requires-Dist: sqlmodel>=0.0.32
28
28
  Provides-Extra: cache
29
29
  Requires-Dist: orjson>=3.0; extra == 'cache'
30
30
  Requires-Dist: redis>=5.0; extra == 'cache'
31
31
  Provides-Extra: dev
32
32
  Requires-Dist: aiosqlite>=0.20; extra == 'dev'
33
+ Requires-Dist: fakeredis>=2.20; extra == 'dev'
34
+ Requires-Dist: fastapi>=0.100.0; extra == 'dev'
35
+ Requires-Dist: numpy>=1.24; extra == 'dev'
36
+ Requires-Dist: orjson>=3.0; extra == 'dev'
37
+ Requires-Dist: pgvector>=0.3; extra == 'dev'
33
38
  Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
34
39
  Requires-Dist: pytest>=8.0; extra == 'dev'
40
+ Requires-Dist: redis>=5.0; extra == 'dev'
35
41
  Requires-Dist: ruff>=0.4; extra == 'dev'
36
42
  Provides-Extra: fastapi
37
43
  Requires-Dist: fastapi>=0.100.0; extra == 'fastapi'
@@ -70,7 +76,7 @@ Extended SQLModel infrastructure: smart metaclass, async CRUD mixins, polymorphi
70
76
  | **RelationPreloadMixin** | Decorator-based automatic relationship preloading (prevents `MissingGreenlet` errors) |
71
77
  | **ListResponse[T]** | Generic paginated response model for list endpoints |
72
78
  | **Field Types** | Reusable constrained types: `Str64`, `Port`, `IPAddress`, `HttpUrl`, `SafeHttpUrl`, and more |
73
- | **PostgreSQL Types** | `Array[T]` for native ARRAY, `JSON100K`/`JSONList100K` for size-limited JSONB, `NumpyVector` for pgvector+NumPy |
79
+ | **PostgreSQL Types** | `Array[T]` for native ARRAY (read-tolerant for enum arrays during rolling-deploy version skew), `JSON100K`/`JSONList100K` for size-limited JSONB, `NumpyVector` for pgvector+NumPy |
74
80
  | **Info Response DTOs** | Pre-built mixins for API response models with id/timestamp fields |
75
81
 
76
82
  ## Installation
@@ -108,12 +114,13 @@ pip install sqlmodel-ext[pgvector]
108
114
  ### Define Models
109
115
 
110
116
  ```python
111
- from sqlmodel_ext import SQLModelBase, UUIDTableBaseMixin, Str64
117
+ from pydantic import EmailStr # requires: pip install 'pydantic[email]'
118
+ from sqlmodel_ext import SQLModelBase, UUIDTableBaseMixin, NonEmptyStrippedStr64
112
119
 
113
120
  # Base class -- fields only, no database table
114
121
  class UserBase(SQLModelBase):
115
- name: Str64
116
- email: str
122
+ name: NonEmptyStrippedStr64 # user-visible name: rejects "" and whitespace-only
123
+ email: EmailStr
117
124
 
118
125
  # Table class -- inherits fields + gains async CRUD + UUID primary key
119
126
  class User(UserBase, UUIDTableBaseMixin, table=True):
@@ -438,17 +445,19 @@ async def delete_article(session: SessionDep, article_id: UUID) -> None:
438
445
 
439
446
  ```python
440
447
  from abc import ABC, abstractmethod
448
+ from pydantic import EmailStr
441
449
  from sqlmodel_ext import (
442
450
  SQLModelBase, UUIDTableBaseMixin, PolymorphicBaseMixin,
443
451
  AutoPolymorphicIdentityMixin, create_subclass_id_mixin,
444
452
  ListResponse, TableViewRequest,
453
+ Str512, Text1K,
445
454
  )
446
455
 
447
456
  # ── Polymorphic models ────────────────────────────────────────────
448
457
 
449
458
  class NotificationBase(SQLModelBase):
450
459
  user_id: UUID = Field(foreign_key='user.id')
451
- message: str
460
+ message: Text1K
452
461
 
453
462
  class Notification(NotificationBase, UUIDTableBaseMixin, PolymorphicBaseMixin, ABC):
454
463
  @abstractmethod
@@ -457,13 +466,13 @@ class Notification(NotificationBase, UUIDTableBaseMixin, PolymorphicBaseMixin, A
457
466
  NotifSubclassId = create_subclass_id_mixin('notification')
458
467
 
459
468
  class EmailNotification(NotifSubclassId, Notification, AutoPolymorphicIdentityMixin, table=True):
460
- email_to: str
469
+ email_to: EmailStr
461
470
 
462
471
  def summary(self) -> str:
463
472
  return f"Email to {self.email_to}: {self.message}"
464
473
 
465
474
  class PushNotification(NotifSubclassId, Notification, AutoPolymorphicIdentityMixin, table=True):
466
- device_token: str
475
+ device_token: Str512
467
476
 
468
477
  def summary(self) -> str:
469
478
  return f"Push to {self.device_token}: {self.message}"
@@ -493,15 +502,15 @@ These mixins provide the async CRUD interface. `TableBaseMixin` uses an auto-inc
493
502
  Both mixins automatically add `id`, `created_at`, and `updated_at` fields.
494
503
 
495
504
  ```python
496
- from sqlmodel_ext import SQLModelBase, TableBaseMixin, UUIDTableBaseMixin
505
+ from sqlmodel_ext import SQLModelBase, TableBaseMixin, UUIDTableBaseMixin, NonEmptyStrippedStr64, Text1K
497
506
 
498
507
  # Integer primary key
499
508
  class LogEntry(SQLModelBase, TableBaseMixin, table=True):
500
- message: str
509
+ message: Text1K
501
510
 
502
511
  # UUID primary key (recommended for most use cases)
503
512
  class Project(SQLModelBase, UUIDTableBaseMixin, table=True):
504
- name: str
513
+ name: NonEmptyStrippedStr64
505
514
  ```
506
515
 
507
516
  #### `add()` -- Batch Insert
@@ -529,7 +538,9 @@ user = await User.add(session, User(name="Alice", email="a@x.com"))
529
538
  user = await user.save(session)
530
539
 
531
540
  # Save with relationship preloading
532
- user = await user.save(session, load=User.profile)
541
+ # (rel() casts the Relationship field for type checkers, which would
542
+ # otherwise infer User.profile as Profile instead of a loadable attribute)
543
+ user = await user.save(session, load=rel(User.profile))
533
544
 
534
545
  # Save with optimistic lock retry
535
546
  user = await user.save(session, optimistic_retry_count=3)
@@ -562,9 +573,10 @@ user3 = await user3.save(session) # commits all three
562
573
  #### `update()` -- Partial Update from a Model
563
574
 
564
575
  ```python
565
- class UserUpdate(SQLModelBase):
566
- name: str | None = None
567
- email: str | None = None
576
+ # all_fields_optional auto-converts every inherited field to ``T | None = None``
577
+ # while preserving constraints -- no hand-written Optional boilerplate
578
+ class UserUpdate(UserBase, all_fields_optional=True):
579
+ pass
568
580
 
569
581
  # Only updates fields that were explicitly set
570
582
  user = await user.update(session, UserUpdate(name="Charlie"))
@@ -643,7 +655,7 @@ users = await User.get(session, fetch_mode="all")
643
655
  user = await User.get(
644
656
  session,
645
657
  User.id == user_id,
646
- load=[User.profile, User.orders],
658
+ load=[rel(User.profile), rel(User.orders)],
647
659
  )
648
660
 
649
661
  # With JOIN
@@ -767,11 +779,12 @@ from sqlmodel_ext import (
767
779
  SQLModelBase, UUIDTableBaseMixin,
768
780
  PolymorphicBaseMixin, AutoPolymorphicIdentityMixin,
769
781
  create_subclass_id_mixin,
782
+ HttpUrl, NonEmptyStrippedStr64, NonNegativeInt,
770
783
  )
771
784
 
772
785
  # 1. Base class (fields only, no table)
773
786
  class ToolBase(SQLModelBase):
774
- name: str
787
+ name: NonEmptyStrippedStr64
775
788
 
776
789
  # 2. Abstract parent (creates the parent table)
777
790
  class Tool(ToolBase, UUIDTableBaseMixin, PolymorphicBaseMixin, ABC):
@@ -783,13 +796,13 @@ ToolSubclassIdMixin = create_subclass_id_mixin('tool')
783
796
 
784
797
  # 4. Concrete subclasses (each gets its own table)
785
798
  class WebSearchTool(ToolSubclassIdMixin, Tool, AutoPolymorphicIdentityMixin, table=True):
786
- search_url: str
799
+ search_url: HttpUrl
787
800
 
788
801
  async def execute(self) -> str:
789
802
  return f"Searching {self.search_url}"
790
803
 
791
804
  class CalculatorTool(ToolSubclassIdMixin, Tool, AutoPolymorphicIdentityMixin, table=True):
792
- precision: int = 2
805
+ precision: NonNegativeInt = 2
793
806
 
794
807
  async def execute(self) -> str:
795
808
  return "Calculating..."
@@ -823,16 +836,17 @@ from sqlmodel_ext import (
823
836
  PolymorphicBaseMixin, AutoPolymorphicIdentityMixin,
824
837
  register_sti_columns_for_all_subclasses,
825
838
  register_sti_column_properties_for_all_subclasses,
839
+ NonNegativeBigInt, Str256,
826
840
  )
827
841
 
828
842
  class UserFile(SQLModelBase, UUIDTableBaseMixin, PolymorphicBaseMixin, table=True):
829
- filename: str
843
+ filename: Str256
830
844
 
831
845
  class PendingFile(UserFile, AutoPolymorphicIdentityMixin, table=True):
832
846
  upload_deadline: datetime | None = None # Added to userfile table as nullable
833
847
 
834
848
  class CompletedFile(UserFile, AutoPolymorphicIdentityMixin, table=True):
835
- file_size: int | None = None # Added to userfile table as nullable
849
+ file_size: NonNegativeBigInt | None = None # Added to userfile table as nullable
836
850
 
837
851
  # After all models are defined, before configure_mappers():
838
852
  register_sti_columns_for_all_subclasses()
@@ -858,7 +872,7 @@ class ToolSet(SQLModelBase, UUIDTableBaseMixin, table=True):
858
872
  tool_set = await ToolSet.get(
859
873
  session,
860
874
  ToolSet.id == ts_id,
861
- load=ToolSet.tools,
875
+ load=rel(ToolSet.tools),
862
876
  jti_subclasses='all', # Loads all subclass-specific columns
863
877
  )
864
878
  ```
@@ -885,15 +899,22 @@ Tool._is_joined_table_inheritance() # True for JTI, False for STI
885
899
  Prevents lost updates in concurrent environments using SQLAlchemy's `version_id_col` mechanism.
886
900
 
887
901
  ```python
902
+ from enum import StrEnum
903
+
888
904
  from sqlmodel_ext import (
889
905
  SQLModelBase, UUIDTableBaseMixin,
890
906
  OptimisticLockMixin, OptimisticLockError,
907
+ NonNegativeDecimal38_18,
891
908
  )
892
909
 
910
+ class OrderStatusEnum(StrEnum):
911
+ pending = 'pending'
912
+ paid = 'paid'
913
+
893
914
  # OptimisticLockMixin MUST come before TableBaseMixin in MRO
894
915
  class Order(OptimisticLockMixin, UUIDTableBaseMixin, table=True):
895
- status: str
896
- amount: int
916
+ status: OrderStatusEnum = OrderStatusEnum.pending
917
+ amount: NonNegativeDecimal38_18
897
918
  ```
898
919
 
899
920
  The mixin adds a `version` integer field (starting at 0). Every `UPDATE` generates SQL like:
@@ -945,11 +966,11 @@ The `RelationPreloadMixin` and `@requires_relations` decorator automatically loa
945
966
 
946
967
  ```python
947
968
  from sqlmodel import Relationship
948
- from sqlmodel_ext import UUIDTableBaseMixin, SQLModelBase
969
+ from sqlmodel_ext import UUIDTableBaseMixin, SQLModelBase, NonNegativeDecimal38_18
949
970
  from sqlmodel_ext.mixins import RelationPreloadMixin, requires_relations
950
971
 
951
972
  class GeneratorConfig(SQLModelBase, UUIDTableBaseMixin, table=True):
952
- price: int
973
+ price: NonNegativeDecimal38_18
953
974
 
954
975
  class Generator(SQLModelBase, UUIDTableBaseMixin, table=True):
955
976
  config: GeneratorConfig = Relationship()
@@ -1391,12 +1412,12 @@ When using Pydantic's `use_attribute_docstrings=True` (enabled by default in `SQ
1391
1412
 
1392
1413
  ```python
1393
1414
  class UserBase(SQLModelBase):
1394
- name: str
1415
+ name: NonEmptyStrippedStr64
1395
1416
  """User display name""" # ← parsed by Pydantic
1396
1417
 
1397
1418
  class UserUpdateRequest(UserBase, all_fields_optional=True):
1398
1419
  pass
1399
- # name: str | None = None — description "User display name" is automatically inherited
1420
+ # name: NonEmptyStrippedStr64 | None = None — description "User display name" is inherited
1400
1421
  # Shows up correctly in OpenAPI/Swagger docs
1401
1422
  ```
1402
1423
 
@@ -25,7 +25,7 @@ Extended SQLModel infrastructure: smart metaclass, async CRUD mixins, polymorphi
25
25
  | **RelationPreloadMixin** | Decorator-based automatic relationship preloading (prevents `MissingGreenlet` errors) |
26
26
  | **ListResponse[T]** | Generic paginated response model for list endpoints |
27
27
  | **Field Types** | Reusable constrained types: `Str64`, `Port`, `IPAddress`, `HttpUrl`, `SafeHttpUrl`, and more |
28
- | **PostgreSQL Types** | `Array[T]` for native ARRAY, `JSON100K`/`JSONList100K` for size-limited JSONB, `NumpyVector` for pgvector+NumPy |
28
+ | **PostgreSQL Types** | `Array[T]` for native ARRAY (read-tolerant for enum arrays during rolling-deploy version skew), `JSON100K`/`JSONList100K` for size-limited JSONB, `NumpyVector` for pgvector+NumPy |
29
29
  | **Info Response DTOs** | Pre-built mixins for API response models with id/timestamp fields |
30
30
 
31
31
  ## Installation
@@ -63,12 +63,13 @@ pip install sqlmodel-ext[pgvector]
63
63
  ### Define Models
64
64
 
65
65
  ```python
66
- from sqlmodel_ext import SQLModelBase, UUIDTableBaseMixin, Str64
66
+ from pydantic import EmailStr # requires: pip install 'pydantic[email]'
67
+ from sqlmodel_ext import SQLModelBase, UUIDTableBaseMixin, NonEmptyStrippedStr64
67
68
 
68
69
  # Base class -- fields only, no database table
69
70
  class UserBase(SQLModelBase):
70
- name: Str64
71
- email: str
71
+ name: NonEmptyStrippedStr64 # user-visible name: rejects "" and whitespace-only
72
+ email: EmailStr
72
73
 
73
74
  # Table class -- inherits fields + gains async CRUD + UUID primary key
74
75
  class User(UserBase, UUIDTableBaseMixin, table=True):
@@ -393,17 +394,19 @@ async def delete_article(session: SessionDep, article_id: UUID) -> None:
393
394
 
394
395
  ```python
395
396
  from abc import ABC, abstractmethod
397
+ from pydantic import EmailStr
396
398
  from sqlmodel_ext import (
397
399
  SQLModelBase, UUIDTableBaseMixin, PolymorphicBaseMixin,
398
400
  AutoPolymorphicIdentityMixin, create_subclass_id_mixin,
399
401
  ListResponse, TableViewRequest,
402
+ Str512, Text1K,
400
403
  )
401
404
 
402
405
  # ── Polymorphic models ────────────────────────────────────────────
403
406
 
404
407
  class NotificationBase(SQLModelBase):
405
408
  user_id: UUID = Field(foreign_key='user.id')
406
- message: str
409
+ message: Text1K
407
410
 
408
411
  class Notification(NotificationBase, UUIDTableBaseMixin, PolymorphicBaseMixin, ABC):
409
412
  @abstractmethod
@@ -412,13 +415,13 @@ class Notification(NotificationBase, UUIDTableBaseMixin, PolymorphicBaseMixin, A
412
415
  NotifSubclassId = create_subclass_id_mixin('notification')
413
416
 
414
417
  class EmailNotification(NotifSubclassId, Notification, AutoPolymorphicIdentityMixin, table=True):
415
- email_to: str
418
+ email_to: EmailStr
416
419
 
417
420
  def summary(self) -> str:
418
421
  return f"Email to {self.email_to}: {self.message}"
419
422
 
420
423
  class PushNotification(NotifSubclassId, Notification, AutoPolymorphicIdentityMixin, table=True):
421
- device_token: str
424
+ device_token: Str512
422
425
 
423
426
  def summary(self) -> str:
424
427
  return f"Push to {self.device_token}: {self.message}"
@@ -448,15 +451,15 @@ These mixins provide the async CRUD interface. `TableBaseMixin` uses an auto-inc
448
451
  Both mixins automatically add `id`, `created_at`, and `updated_at` fields.
449
452
 
450
453
  ```python
451
- from sqlmodel_ext import SQLModelBase, TableBaseMixin, UUIDTableBaseMixin
454
+ from sqlmodel_ext import SQLModelBase, TableBaseMixin, UUIDTableBaseMixin, NonEmptyStrippedStr64, Text1K
452
455
 
453
456
  # Integer primary key
454
457
  class LogEntry(SQLModelBase, TableBaseMixin, table=True):
455
- message: str
458
+ message: Text1K
456
459
 
457
460
  # UUID primary key (recommended for most use cases)
458
461
  class Project(SQLModelBase, UUIDTableBaseMixin, table=True):
459
- name: str
462
+ name: NonEmptyStrippedStr64
460
463
  ```
461
464
 
462
465
  #### `add()` -- Batch Insert
@@ -484,7 +487,9 @@ user = await User.add(session, User(name="Alice", email="a@x.com"))
484
487
  user = await user.save(session)
485
488
 
486
489
  # Save with relationship preloading
487
- user = await user.save(session, load=User.profile)
490
+ # (rel() casts the Relationship field for type checkers, which would
491
+ # otherwise infer User.profile as Profile instead of a loadable attribute)
492
+ user = await user.save(session, load=rel(User.profile))
488
493
 
489
494
  # Save with optimistic lock retry
490
495
  user = await user.save(session, optimistic_retry_count=3)
@@ -517,9 +522,10 @@ user3 = await user3.save(session) # commits all three
517
522
  #### `update()` -- Partial Update from a Model
518
523
 
519
524
  ```python
520
- class UserUpdate(SQLModelBase):
521
- name: str | None = None
522
- email: str | None = None
525
+ # all_fields_optional auto-converts every inherited field to ``T | None = None``
526
+ # while preserving constraints -- no hand-written Optional boilerplate
527
+ class UserUpdate(UserBase, all_fields_optional=True):
528
+ pass
523
529
 
524
530
  # Only updates fields that were explicitly set
525
531
  user = await user.update(session, UserUpdate(name="Charlie"))
@@ -598,7 +604,7 @@ users = await User.get(session, fetch_mode="all")
598
604
  user = await User.get(
599
605
  session,
600
606
  User.id == user_id,
601
- load=[User.profile, User.orders],
607
+ load=[rel(User.profile), rel(User.orders)],
602
608
  )
603
609
 
604
610
  # With JOIN
@@ -722,11 +728,12 @@ from sqlmodel_ext import (
722
728
  SQLModelBase, UUIDTableBaseMixin,
723
729
  PolymorphicBaseMixin, AutoPolymorphicIdentityMixin,
724
730
  create_subclass_id_mixin,
731
+ HttpUrl, NonEmptyStrippedStr64, NonNegativeInt,
725
732
  )
726
733
 
727
734
  # 1. Base class (fields only, no table)
728
735
  class ToolBase(SQLModelBase):
729
- name: str
736
+ name: NonEmptyStrippedStr64
730
737
 
731
738
  # 2. Abstract parent (creates the parent table)
732
739
  class Tool(ToolBase, UUIDTableBaseMixin, PolymorphicBaseMixin, ABC):
@@ -738,13 +745,13 @@ ToolSubclassIdMixin = create_subclass_id_mixin('tool')
738
745
 
739
746
  # 4. Concrete subclasses (each gets its own table)
740
747
  class WebSearchTool(ToolSubclassIdMixin, Tool, AutoPolymorphicIdentityMixin, table=True):
741
- search_url: str
748
+ search_url: HttpUrl
742
749
 
743
750
  async def execute(self) -> str:
744
751
  return f"Searching {self.search_url}"
745
752
 
746
753
  class CalculatorTool(ToolSubclassIdMixin, Tool, AutoPolymorphicIdentityMixin, table=True):
747
- precision: int = 2
754
+ precision: NonNegativeInt = 2
748
755
 
749
756
  async def execute(self) -> str:
750
757
  return "Calculating..."
@@ -778,16 +785,17 @@ from sqlmodel_ext import (
778
785
  PolymorphicBaseMixin, AutoPolymorphicIdentityMixin,
779
786
  register_sti_columns_for_all_subclasses,
780
787
  register_sti_column_properties_for_all_subclasses,
788
+ NonNegativeBigInt, Str256,
781
789
  )
782
790
 
783
791
  class UserFile(SQLModelBase, UUIDTableBaseMixin, PolymorphicBaseMixin, table=True):
784
- filename: str
792
+ filename: Str256
785
793
 
786
794
  class PendingFile(UserFile, AutoPolymorphicIdentityMixin, table=True):
787
795
  upload_deadline: datetime | None = None # Added to userfile table as nullable
788
796
 
789
797
  class CompletedFile(UserFile, AutoPolymorphicIdentityMixin, table=True):
790
- file_size: int | None = None # Added to userfile table as nullable
798
+ file_size: NonNegativeBigInt | None = None # Added to userfile table as nullable
791
799
 
792
800
  # After all models are defined, before configure_mappers():
793
801
  register_sti_columns_for_all_subclasses()
@@ -813,7 +821,7 @@ class ToolSet(SQLModelBase, UUIDTableBaseMixin, table=True):
813
821
  tool_set = await ToolSet.get(
814
822
  session,
815
823
  ToolSet.id == ts_id,
816
- load=ToolSet.tools,
824
+ load=rel(ToolSet.tools),
817
825
  jti_subclasses='all', # Loads all subclass-specific columns
818
826
  )
819
827
  ```
@@ -840,15 +848,22 @@ Tool._is_joined_table_inheritance() # True for JTI, False for STI
840
848
  Prevents lost updates in concurrent environments using SQLAlchemy's `version_id_col` mechanism.
841
849
 
842
850
  ```python
851
+ from enum import StrEnum
852
+
843
853
  from sqlmodel_ext import (
844
854
  SQLModelBase, UUIDTableBaseMixin,
845
855
  OptimisticLockMixin, OptimisticLockError,
856
+ NonNegativeDecimal38_18,
846
857
  )
847
858
 
859
+ class OrderStatusEnum(StrEnum):
860
+ pending = 'pending'
861
+ paid = 'paid'
862
+
848
863
  # OptimisticLockMixin MUST come before TableBaseMixin in MRO
849
864
  class Order(OptimisticLockMixin, UUIDTableBaseMixin, table=True):
850
- status: str
851
- amount: int
865
+ status: OrderStatusEnum = OrderStatusEnum.pending
866
+ amount: NonNegativeDecimal38_18
852
867
  ```
853
868
 
854
869
  The mixin adds a `version` integer field (starting at 0). Every `UPDATE` generates SQL like:
@@ -900,11 +915,11 @@ The `RelationPreloadMixin` and `@requires_relations` decorator automatically loa
900
915
 
901
916
  ```python
902
917
  from sqlmodel import Relationship
903
- from sqlmodel_ext import UUIDTableBaseMixin, SQLModelBase
918
+ from sqlmodel_ext import UUIDTableBaseMixin, SQLModelBase, NonNegativeDecimal38_18
904
919
  from sqlmodel_ext.mixins import RelationPreloadMixin, requires_relations
905
920
 
906
921
  class GeneratorConfig(SQLModelBase, UUIDTableBaseMixin, table=True):
907
- price: int
922
+ price: NonNegativeDecimal38_18
908
923
 
909
924
  class Generator(SQLModelBase, UUIDTableBaseMixin, table=True):
910
925
  config: GeneratorConfig = Relationship()
@@ -1346,12 +1361,12 @@ When using Pydantic's `use_attribute_docstrings=True` (enabled by default in `SQ
1346
1361
 
1347
1362
  ```python
1348
1363
  class UserBase(SQLModelBase):
1349
- name: str
1364
+ name: NonEmptyStrippedStr64
1350
1365
  """User display name""" # ← parsed by Pydantic
1351
1366
 
1352
1367
  class UserUpdateRequest(UserBase, all_fields_optional=True):
1353
1368
  pass
1354
- # name: str | None = None — description "User display name" is automatically inherited
1369
+ # name: NonEmptyStrippedStr64 | None = None — description "User display name" is inherited
1355
1370
  # Shows up correctly in OpenAPI/Swagger docs
1356
1371
  ```
1357
1372