sqlmodel-ext 0.4.2__tar.gz → 0.5.0__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.
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/.github/workflows/ci.yml +145 -100
- sqlmodel_ext-0.5.0/CHANGELOG.md +181 -0
- sqlmodel_ext-0.5.0/PKG-INFO +1933 -0
- sqlmodel_ext-0.5.0/README.md +1877 -0
- sqlmodel_ext-0.5.0/README_zh.md +1877 -0
- sqlmodel_ext-0.5.0/ai-rules/AGENTS.md +282 -0
- sqlmodel_ext-0.5.0/ai-rules/CLAUDE.md +6 -0
- sqlmodel_ext-0.5.0/ai-rules/README.md +58 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/.vitepress/en.mts +126 -88
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/.vitepress/zh.mts +126 -88
- sqlmodel_ext-0.5.0/docs/en/explanation/cached-table.md +189 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/explanation/cascade-delete-semantics.md +155 -153
- sqlmodel_ext-0.5.0/docs/en/explanation/crud-pipeline.md +279 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/explanation/index.md +48 -41
- sqlmodel_ext-0.5.0/docs/en/explanation/metaclass.md +358 -0
- sqlmodel_ext-0.5.0/docs/en/explanation/optimistic-lock.md +160 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/explanation/polymorphic-internals.md +242 -234
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/explanation/prerequisites.md +187 -158
- sqlmodel_ext-0.5.0/docs/en/explanation/relation-load-checker.md +184 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/explanation/relation-preload.md +224 -197
- sqlmodel_ext-0.5.0/docs/en/explanation/single-source-of-truth.md +138 -0
- sqlmodel_ext-0.5.0/docs/en/explanation/transactional-cache-transparency.md +146 -0
- sqlmodel_ext-0.5.0/docs/en/explanation/unset-three-state.md +317 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/guide/cached-table.md +17 -17
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/guide/crud.md +15 -15
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/guide/field-types.md +13 -13
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/guide/index.md +13 -13
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/guide/optimistic-lock.md +14 -14
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/guide/pagination.md +14 -14
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/guide/polymorphic.md +17 -17
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/guide/relation-load-checker.md +16 -16
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/guide/relation-preload.md +17 -17
- sqlmodel_ext-0.5.0/docs/en/how-to/aggregate-queries.md +133 -0
- sqlmodel_ext-0.5.0/docs/en/how-to/cache-queries.md +177 -0
- sqlmodel_ext-0.5.0/docs/en/how-to/check-partial-dtos.md +175 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/how-to/configure-cascade-delete.md +234 -234
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/how-to/define-jti-models.md +122 -120
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/how-to/define-sti-models.md +15 -4
- sqlmodel_ext-0.5.0/docs/en/how-to/enforce-locking-and-isolation.md +227 -0
- sqlmodel_ext-0.5.0/docs/en/how-to/extra-mixins.md +255 -0
- sqlmodel_ext-0.5.0/docs/en/how-to/handle-concurrent-updates.md +123 -0
- sqlmodel_ext-0.5.0/docs/en/how-to/handle-referenced-deletes.md +86 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/how-to/index.md +57 -41
- sqlmodel_ext-0.5.0/docs/en/how-to/integrate-with-fastapi.md +186 -0
- sqlmodel_ext-0.5.0/docs/en/how-to/keyset-pagination.md +102 -0
- sqlmodel_ext-0.5.0/docs/en/how-to/migrate-to-0-5.md +319 -0
- sqlmodel_ext-0.5.0/docs/en/how-to/paginate-a-list-endpoint.md +107 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/how-to/prevent-missing-greenlet.md +45 -2
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/how-to/release-connection-during-long-io.md +183 -181
- sqlmodel_ext-0.5.0/docs/en/how-to/type-check-with-basedpyright.md +258 -0
- sqlmodel_ext-0.5.0/docs/en/how-to/use-with-ai-assistants.md +102 -0
- sqlmodel_ext-0.5.0/docs/en/how-to/write-patch-endpoints.md +223 -0
- sqlmodel_ext-0.5.0/docs/en/index.md +76 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/internals/cached-table.md +13 -13
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/internals/crud.md +15 -15
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/internals/index.md +13 -13
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/internals/metaclass.md +13 -13
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/internals/optimistic-lock.md +13 -13
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/internals/polymorphic.md +13 -13
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/internals/prerequisites.md +13 -13
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/internals/relation-load-checker.md +13 -13
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/internals/relation-preload.md +13 -13
- sqlmodel_ext-0.5.0/docs/en/reference/base-classes.md +225 -0
- sqlmodel_ext-0.5.0/docs/en/reference/crud-methods.md +392 -0
- sqlmodel_ext-0.5.0/docs/en/reference/decorators.md +260 -0
- sqlmodel_ext-0.5.0/docs/en/reference/field-types.md +410 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/reference/index.md +54 -54
- sqlmodel_ext-0.5.0/docs/en/reference/mixins.md +404 -0
- sqlmodel_ext-0.5.0/docs/en/reference/pagination-types.md +157 -0
- sqlmodel_ext-0.5.0/docs/en/tutorials/01-getting-started.md +263 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/tutorials/02-building-a-blog-api.md +42 -12
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/tutorials/03-adding-redis-cache.md +22 -11
- sqlmodel_ext-0.5.0/docs/explanation/cached-table.md +189 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/explanation/cascade-delete-semantics.md +155 -153
- sqlmodel_ext-0.5.0/docs/explanation/crud-pipeline.md +279 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/explanation/index.md +48 -41
- sqlmodel_ext-0.5.0/docs/explanation/metaclass.md +358 -0
- sqlmodel_ext-0.5.0/docs/explanation/optimistic-lock.md +160 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/explanation/polymorphic-internals.md +231 -223
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/explanation/prerequisites.md +187 -158
- sqlmodel_ext-0.5.0/docs/explanation/relation-load-checker.md +184 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/explanation/relation-preload.md +224 -197
- sqlmodel_ext-0.5.0/docs/explanation/single-source-of-truth.md +138 -0
- sqlmodel_ext-0.5.0/docs/explanation/transactional-cache-transparency.md +146 -0
- sqlmodel_ext-0.5.0/docs/explanation/unset-three-state.md +317 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/guide/cached-table.md +17 -17
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/guide/crud.md +15 -15
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/guide/field-types.md +13 -13
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/guide/index.md +13 -13
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/guide/optimistic-lock.md +14 -14
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/guide/pagination.md +14 -14
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/guide/polymorphic.md +17 -17
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/guide/relation-load-checker.md +16 -16
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/guide/relation-preload.md +17 -17
- sqlmodel_ext-0.5.0/docs/how-to/aggregate-queries.md +133 -0
- sqlmodel_ext-0.5.0/docs/how-to/cache-queries.md +177 -0
- sqlmodel_ext-0.5.0/docs/how-to/check-partial-dtos.md +175 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/how-to/configure-cascade-delete.md +234 -234
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/how-to/define-jti-models.md +122 -120
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/how-to/define-sti-models.md +15 -4
- sqlmodel_ext-0.5.0/docs/how-to/enforce-locking-and-isolation.md +227 -0
- sqlmodel_ext-0.5.0/docs/how-to/extra-mixins.md +255 -0
- sqlmodel_ext-0.5.0/docs/how-to/handle-concurrent-updates.md +123 -0
- sqlmodel_ext-0.5.0/docs/how-to/handle-referenced-deletes.md +86 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/how-to/index.md +57 -41
- sqlmodel_ext-0.5.0/docs/how-to/integrate-with-fastapi.md +186 -0
- sqlmodel_ext-0.5.0/docs/how-to/keyset-pagination.md +102 -0
- sqlmodel_ext-0.5.0/docs/how-to/migrate-to-0-5.md +319 -0
- sqlmodel_ext-0.5.0/docs/how-to/paginate-a-list-endpoint.md +107 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/how-to/prevent-missing-greenlet.md +45 -2
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/how-to/release-connection-during-long-io.md +183 -181
- sqlmodel_ext-0.5.0/docs/how-to/type-check-with-basedpyright.md +258 -0
- sqlmodel_ext-0.5.0/docs/how-to/use-with-ai-assistants.md +102 -0
- sqlmodel_ext-0.5.0/docs/how-to/write-patch-endpoints.md +223 -0
- sqlmodel_ext-0.5.0/docs/index.md +76 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/internals/cached-table.md +13 -13
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/internals/crud.md +15 -15
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/internals/index.md +13 -13
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/internals/metaclass.md +13 -13
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/internals/optimistic-lock.md +13 -13
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/internals/polymorphic.md +13 -13
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/internals/prerequisites.md +13 -13
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/internals/relation-load-checker.md +13 -13
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/internals/relation-preload.md +13 -13
- sqlmodel_ext-0.5.0/docs/reference/base-classes.md +224 -0
- sqlmodel_ext-0.5.0/docs/reference/crud-methods.md +392 -0
- sqlmodel_ext-0.5.0/docs/reference/decorators.md +260 -0
- sqlmodel_ext-0.5.0/docs/reference/field-types.md +410 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/reference/index.md +54 -54
- sqlmodel_ext-0.5.0/docs/reference/mixins.md +404 -0
- sqlmodel_ext-0.5.0/docs/reference/pagination-types.md +157 -0
- sqlmodel_ext-0.5.0/docs/tutorials/01-getting-started.md +263 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/tutorials/02-building-a-blog-api.md +42 -11
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/tutorials/03-adding-redis-cache.md +22 -11
- sqlmodel_ext-0.5.0/examples/01_unset_patch.py +195 -0
- sqlmodel_ext-0.5.0/examples/02_single_source_types.py +104 -0
- sqlmodel_ext-0.5.0/examples/03_keyset_pagination.py +96 -0
- sqlmodel_ext-0.5.0/examples/04_locking_and_isolation.py +155 -0
- sqlmodel_ext-0.5.0/examples/05_aggregates.py +91 -0
- sqlmodel_ext-0.5.0/examples/06_referenced_delete.py +118 -0
- sqlmodel_ext-0.5.0/examples/07_transactional_cache.py +108 -0
- sqlmodel_ext-0.5.0/examples/08_optimistic_lock.py +98 -0
- sqlmodel_ext-0.5.0/examples/09_relation_preload_bulk.py +117 -0
- sqlmodel_ext-0.5.0/examples/10_typed_select.py +103 -0
- sqlmodel_ext-0.5.0/examples/11_type_errors_caught_by_basedpyright.py +80 -0
- sqlmodel_ext-0.5.0/examples/README.md +154 -0
- sqlmodel_ext-0.5.0/examples/check_derived_demo/pyrightconfig.json +4 -0
- sqlmodel_ext-0.5.0/examples/check_derived_demo/shop/__init__.py +7 -0
- sqlmodel_ext-0.5.0/examples/check_derived_demo/shop/handlers.py +16 -0
- sqlmodel_ext-0.5.0/examples/check_derived_demo/shop/models.py +29 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/examples/consumer_integration/run.py +29 -13
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/pyproject.toml +18 -3
- sqlmodel_ext-0.5.0/pyrightconfig.json +48 -0
- sqlmodel_ext-0.5.0/src/sqlmodel_ext/__init__.py +251 -0
- sqlmodel_ext-0.5.0/src/sqlmodel_ext/_type_unwrap.py +109 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/src/sqlmodel_ext/base.py +750 -248
- sqlmodel_ext-0.5.0/src/sqlmodel_ext/check_derived.py +565 -0
- sqlmodel_ext-0.5.0/src/sqlmodel_ext/constants.py +76 -0
- sqlmodel_ext-0.5.0/src/sqlmodel_ext/derived_decls.py +818 -0
- sqlmodel_ext-0.5.0/src/sqlmodel_ext/field_types/__init__.py +1009 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/src/sqlmodel_ext/field_types/_internal/path.py +2 -2
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/src/sqlmodel_ext/field_types/dialects/postgresql/__init__.py +16 -7
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/src/sqlmodel_ext/field_types/dialects/postgresql/array.py +218 -218
- sqlmodel_ext-0.5.0/src/sqlmodel_ext/field_types/dialects/postgresql/jsonb_types.py +267 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/src/sqlmodel_ext/field_types/dialects/postgresql/numpy_vector.py +6 -6
- sqlmodel_ext-0.5.0/src/sqlmodel_ext/field_types/ip_address.py +86 -0
- sqlmodel_ext-0.5.0/src/sqlmodel_ext/field_types/mixins/__init__.py +1 -0
- sqlmodel_ext-0.5.0/src/sqlmodel_ext/mixins/__init__.py +79 -0
- sqlmodel_ext-0.5.0/src/sqlmodel_ext/mixins/_uuid.py +69 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/src/sqlmodel_ext/mixins/cached_table.py +750 -145
- sqlmodel_ext-0.5.0/src/sqlmodel_ext/mixins/constants.py +17 -0
- sqlmodel_ext-0.5.0/src/sqlmodel_ext/mixins/exceptions.py +84 -0
- sqlmodel_ext-0.5.0/src/sqlmodel_ext/mixins/migration_cache_invalidation.py +243 -0
- sqlmodel_ext-0.5.0/src/sqlmodel_ext/mixins/mixin_table_scan.py +96 -0
- sqlmodel_ext-0.5.0/src/sqlmodel_ext/mixins/optimistic_lock.py +161 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/src/sqlmodel_ext/mixins/polymorphic.py +48 -15
- sqlmodel_ext-0.5.0/src/sqlmodel_ext/mixins/relation_preload.py +916 -0
- sqlmodel_ext-0.5.0/src/sqlmodel_ext/mixins/resource_quota.py +315 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/src/sqlmodel_ext/mixins/table.py +836 -148
- sqlmodel_ext-0.5.0/src/sqlmodel_ext/mixins/trgm_searchable.py +230 -0
- sqlmodel_ext-0.5.0/src/sqlmodel_ext/pagination.py +258 -0
- sqlmodel_ext-0.5.0/src/sqlmodel_ext/relation_load_checker.py +6361 -0
- sqlmodel_ext-0.5.0/src/sqlmodel_ext/select.py +466 -0
- sqlmodel_ext-0.5.0/src/sqlmodel_ext/session.py +606 -0
- sqlmodel_ext-0.5.0/src/sqlmodel_ext/unset.py +191 -0
- sqlmodel_ext-0.5.0/tests/__init__.py +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/tests/conftest.py +58 -58
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/tests/test_annotated_default_factory_inheritance.py +307 -194
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/tests/test_cached_table.py +239 -7
- sqlmodel_ext-0.5.0/tests/test_check_derived.py +239 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/tests/test_crud_extended.py +244 -4
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/tests/test_decimal_types.py +431 -256
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/tests/test_deferred_index.py +50 -50
- sqlmodel_ext-0.5.0/tests/test_derived_decls.py +159 -0
- sqlmodel_ext-0.5.0/tests/test_enhanced_session.py +523 -0
- sqlmodel_ext-0.5.0/tests/test_examples.py +52 -0
- sqlmodel_ext-0.5.0/tests/test_field_types_aliases_extra.py +292 -0
- sqlmodel_ext-0.5.0/tests/test_field_types_jsonb_limits.py +186 -0
- sqlmodel_ext-0.5.0/tests/test_final_check_derived_review2.py +91 -0
- sqlmodel_ext-0.5.0/tests/test_final_check_derived_temp_root.py +40 -0
- sqlmodel_ext-0.5.0/tests/test_final_nested_duplicate_names.py +38 -0
- sqlmodel_ext-0.5.0/tests/test_final_omitted_sentinel_alias_modes.py +38 -0
- sqlmodel_ext-0.5.0/tests/test_final_partial_alias_generator.py +20 -0
- sqlmodel_ext-0.5.0/tests/test_final_partial_annotated_field_warnings.py +28 -0
- sqlmodel_ext-0.5.0/tests/test_final_partial_discriminator.py +42 -0
- sqlmodel_ext-0.5.0/tests/test_final_partial_frozen_field.py +21 -0
- sqlmodel_ext-0.5.0/tests/test_final_partial_rhs_field_metadata.py +36 -0
- sqlmodel_ext-0.5.0/tests/test_final_review4_followup.py +109 -0
- sqlmodel_ext-0.5.0/tests/test_final_review5.py +145 -0
- sqlmodel_ext-0.5.0/tests/test_metaclass_extra.py +396 -0
- sqlmodel_ext-0.5.0/tests/test_mixins_extra.py +323 -0
- sqlmodel_ext-0.5.0/tests/test_optimistic_lock.py +243 -0
- sqlmodel_ext-0.5.0/tests/test_pagination.py +469 -0
- sqlmodel_ext-0.5.0/tests/test_partial.py +326 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/tests/test_pg_dialect_types.py +17 -12
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/tests/test_polymorphic_jti.py +38 -2
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/tests/test_polymorphic_sti_query.py +54 -0
- sqlmodel_ext-0.5.0/tests/test_relation_load_checker_load_resolution.py +1555 -0
- sqlmodel_ext-0.5.0/tests/test_relation_load_checker_sessions.py +563 -0
- sqlmodel_ext-0.5.0/tests/test_relation_preload.py +499 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/tests/test_relationship_pep604.py +115 -115
- sqlmodel_ext-0.5.0/tests/test_review_mixed_version_cache.py +59 -0
- sqlmodel_ext-0.5.0/tests/test_review_raw_insert_cache.py +50 -0
- sqlmodel_ext-0.5.0/tests/test_review_raw_insert_edges.py +68 -0
- sqlmodel_ext-0.5.0/tests/test_review_raw_insert_late_model.py +29 -0
- sqlmodel_ext-0.5.0/tests/test_review_raw_insert_sti.py +56 -0
- sqlmodel_ext-0.5.0/tests/test_select.py +156 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/tests/test_smoke_imports.py +263 -157
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/tests/test_sti_default_isolation.py +132 -132
- sqlmodel_ext-0.5.0/tests/test_unset.py +241 -0
- sqlmodel_ext-0.4.2/PKG-INFO +0 -1518
- sqlmodel_ext-0.4.2/README.md +0 -1467
- sqlmodel_ext-0.4.2/README_zh.md +0 -1383
- sqlmodel_ext-0.4.2/docs/en/explanation/cached-table.md +0 -248
- sqlmodel_ext-0.4.2/docs/en/explanation/crud-pipeline.md +0 -288
- sqlmodel_ext-0.4.2/docs/en/explanation/metaclass.md +0 -375
- sqlmodel_ext-0.4.2/docs/en/explanation/optimistic-lock.md +0 -120
- sqlmodel_ext-0.4.2/docs/en/explanation/relation-load-checker.md +0 -148
- sqlmodel_ext-0.4.2/docs/en/how-to/cache-queries.md +0 -143
- sqlmodel_ext-0.4.2/docs/en/how-to/handle-concurrent-updates.md +0 -94
- sqlmodel_ext-0.4.2/docs/en/how-to/integrate-with-fastapi.md +0 -119
- sqlmodel_ext-0.4.2/docs/en/how-to/paginate-a-list-endpoint.md +0 -79
- sqlmodel_ext-0.4.2/docs/en/index.md +0 -45
- sqlmodel_ext-0.4.2/docs/en/reference/base-classes.md +0 -143
- sqlmodel_ext-0.4.2/docs/en/reference/crud-methods.md +0 -281
- sqlmodel_ext-0.4.2/docs/en/reference/decorators.md +0 -164
- sqlmodel_ext-0.4.2/docs/en/reference/field-types.md +0 -279
- sqlmodel_ext-0.4.2/docs/en/reference/mixins.md +0 -257
- sqlmodel_ext-0.4.2/docs/en/reference/pagination-types.md +0 -113
- sqlmodel_ext-0.4.2/docs/en/tutorials/01-getting-started.md +0 -175
- sqlmodel_ext-0.4.2/docs/explanation/cached-table.md +0 -244
- sqlmodel_ext-0.4.2/docs/explanation/crud-pipeline.md +0 -288
- sqlmodel_ext-0.4.2/docs/explanation/metaclass.md +0 -351
- sqlmodel_ext-0.4.2/docs/explanation/optimistic-lock.md +0 -120
- sqlmodel_ext-0.4.2/docs/explanation/relation-load-checker.md +0 -136
- sqlmodel_ext-0.4.2/docs/how-to/cache-queries.md +0 -143
- sqlmodel_ext-0.4.2/docs/how-to/handle-concurrent-updates.md +0 -93
- sqlmodel_ext-0.4.2/docs/how-to/integrate-with-fastapi.md +0 -119
- sqlmodel_ext-0.4.2/docs/how-to/paginate-a-list-endpoint.md +0 -79
- sqlmodel_ext-0.4.2/docs/index.md +0 -45
- sqlmodel_ext-0.4.2/docs/reference/base-classes.md +0 -140
- sqlmodel_ext-0.4.2/docs/reference/crud-methods.md +0 -279
- sqlmodel_ext-0.4.2/docs/reference/decorators.md +0 -164
- sqlmodel_ext-0.4.2/docs/reference/field-types.md +0 -279
- sqlmodel_ext-0.4.2/docs/reference/mixins.md +0 -252
- sqlmodel_ext-0.4.2/docs/reference/pagination-types.md +0 -113
- sqlmodel_ext-0.4.2/docs/tutorials/01-getting-started.md +0 -175
- sqlmodel_ext-0.4.2/src/sqlmodel_ext/__init__.py +0 -173
- sqlmodel_ext-0.4.2/src/sqlmodel_ext/field_types/__init__.py +0 -560
- sqlmodel_ext-0.4.2/src/sqlmodel_ext/field_types/dialects/postgresql/jsonb_types.py +0 -178
- sqlmodel_ext-0.4.2/src/sqlmodel_ext/field_types/ip_address.py +0 -50
- sqlmodel_ext-0.4.2/src/sqlmodel_ext/field_types/mixins/__init__.py +0 -1
- sqlmodel_ext-0.4.2/src/sqlmodel_ext/mixins/__init__.py +0 -39
- sqlmodel_ext-0.4.2/src/sqlmodel_ext/mixins/optimistic_lock.py +0 -85
- sqlmodel_ext-0.4.2/src/sqlmodel_ext/mixins/relation_preload.py +0 -436
- sqlmodel_ext-0.4.2/src/sqlmodel_ext/pagination.py +0 -127
- sqlmodel_ext-0.4.2/src/sqlmodel_ext/relation_load_checker.py +0 -3825
- sqlmodel_ext-0.4.2/src/sqlmodel_ext/session.py +0 -105
- sqlmodel_ext-0.4.2/tests/test_all_fields_optional_constraints.py +0 -76
- sqlmodel_ext-0.4.2/tests/test_enhanced_session.py +0 -87
- sqlmodel_ext-0.4.2/tests/test_metaclass_extra.py +0 -194
- sqlmodel_ext-0.4.2/tests/test_optimistic_lock.py +0 -190
- sqlmodel_ext-0.4.2/tests/test_pagination.py +0 -259
- sqlmodel_ext-0.4.2/tests/test_relation_preload.py +0 -240
- sqlmodel_ext-0.4.2/uv.lock +0 -585
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/.gitignore +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/LICENSE +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/.vitepress/config.mts +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/.vitepress/theme/index.ts +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/.vitepress/theme/style/custom.css +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/en/tutorials/index.md +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/docs/tutorials/index.md +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/package.json +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/pnpm-lock.yaml +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/src/sqlmodel_ext/_compat.py +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/src/sqlmodel_ext/_exceptions.py +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/src/sqlmodel_ext/_sa_type.py +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/src/sqlmodel_ext/_utils.py +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/src/sqlmodel_ext/field_types/_internal/__init__.py +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/src/sqlmodel_ext/field_types/_ssrf.py +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/src/sqlmodel_ext/field_types/dialects/__init__.py +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/src/sqlmodel_ext/field_types/dialects/postgresql/exceptions.py +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/src/sqlmodel_ext/field_types/mixins/module_name_mixin.py +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/src/sqlmodel_ext/field_types/url.py +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/src/sqlmodel_ext/mixins/info_response.py +0 -0
- /sqlmodel_ext-0.4.2/tests/__init__.py → /sqlmodel_ext-0.5.0/src/sqlmodel_ext/py.typed +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/tests/_models.py +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/tests/test_array_explicit_field_sa_type.py +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/tests/test_basic_crud.py +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/tests/test_field_types_misc.py +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/tests/test_field_types_str_num.py +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/tests/test_field_types_url_ssrf.py +0 -0
- {sqlmodel_ext-0.4.2 → sqlmodel_ext-0.5.0}/tests/test_relation_load_checker.py +0 -0
|
@@ -1,100 +1,145 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [master]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: [master]
|
|
8
|
-
workflow_dispatch:
|
|
9
|
-
|
|
10
|
-
permissions:
|
|
11
|
-
contents: read
|
|
12
|
-
|
|
13
|
-
concurrency:
|
|
14
|
-
group: ci-${{ github.ref }}
|
|
15
|
-
cancel-in-progress: true
|
|
16
|
-
|
|
17
|
-
jobs:
|
|
18
|
-
# -------------------------------------------------------------------
|
|
19
|
-
# Job 1: source-tree tests across supported Python versions.
|
|
20
|
-
# Uses uv sync so the lockfile is honoured and runs are reproducible.
|
|
21
|
-
# -------------------------------------------------------------------
|
|
22
|
-
test:
|
|
23
|
-
name: test (py${{ matrix.python-version }})
|
|
24
|
-
runs-on: ubuntu-latest
|
|
25
|
-
strategy:
|
|
26
|
-
fail-fast: false
|
|
27
|
-
matrix:
|
|
28
|
-
python-version: ["3.12", "3.13", "3.14"]
|
|
29
|
-
steps:
|
|
30
|
-
- name: Checkout
|
|
31
|
-
uses: actions/checkout@v4
|
|
32
|
-
|
|
33
|
-
- name: Install uv
|
|
34
|
-
uses: astral-sh/setup-uv@v5
|
|
35
|
-
with:
|
|
36
|
-
enable-cache: true
|
|
37
|
-
cache-dependency-glob: "uv.lock"
|
|
38
|
-
|
|
39
|
-
- name: Set up Python ${{ matrix.python-version }}
|
|
40
|
-
run: uv python install ${{ matrix.python-version }}
|
|
41
|
-
|
|
42
|
-
- name: Create venv and install project with dev extras
|
|
43
|
-
# Dev extras: pytest, pytest-asyncio, aiosqlite, ruff. Editable install
|
|
44
|
-
# keeps the wheel build separate for the consumer-integration job.
|
|
45
|
-
run: |
|
|
46
|
-
uv venv --python ${{ matrix.python-version }} .venv
|
|
47
|
-
uv pip install --python .venv/bin/python -e ".[dev]"
|
|
48
|
-
|
|
49
|
-
- name: Run pytest
|
|
50
|
-
run: .venv/bin/python -m pytest tests/ -v
|
|
51
|
-
|
|
52
|
-
# -------------------------------------------------------------------
|
|
53
|
-
# Job
|
|
54
|
-
#
|
|
55
|
-
#
|
|
56
|
-
#
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
- name: Set up Python
|
|
75
|
-
run: uv python install
|
|
76
|
-
|
|
77
|
-
- name:
|
|
78
|
-
run:
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
run:
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [master]
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: ci-${{ github.ref }}
|
|
15
|
+
cancel-in-progress: true
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
# -------------------------------------------------------------------
|
|
19
|
+
# Job 1: source-tree tests across supported Python versions.
|
|
20
|
+
# Uses uv sync so the lockfile is honoured and runs are reproducible.
|
|
21
|
+
# -------------------------------------------------------------------
|
|
22
|
+
test:
|
|
23
|
+
name: test (py${{ matrix.python-version }})
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
strategy:
|
|
26
|
+
fail-fast: false
|
|
27
|
+
matrix:
|
|
28
|
+
python-version: ["3.12", "3.13", "3.14"]
|
|
29
|
+
steps:
|
|
30
|
+
- name: Checkout
|
|
31
|
+
uses: actions/checkout@v4
|
|
32
|
+
|
|
33
|
+
- name: Install uv
|
|
34
|
+
uses: astral-sh/setup-uv@v5
|
|
35
|
+
with:
|
|
36
|
+
enable-cache: true
|
|
37
|
+
cache-dependency-glob: "uv.lock"
|
|
38
|
+
|
|
39
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
40
|
+
run: uv python install ${{ matrix.python-version }}
|
|
41
|
+
|
|
42
|
+
- name: Create venv and install project with dev extras
|
|
43
|
+
# Dev extras: pytest, pytest-asyncio, aiosqlite, ruff. Editable install
|
|
44
|
+
# keeps the wheel build separate for the consumer-integration job.
|
|
45
|
+
run: |
|
|
46
|
+
uv venv --python ${{ matrix.python-version }} .venv
|
|
47
|
+
uv pip install --python .venv/bin/python -e ".[dev]"
|
|
48
|
+
|
|
49
|
+
- name: Run pytest
|
|
50
|
+
run: .venv/bin/python -m pytest tests/ -v
|
|
51
|
+
|
|
52
|
+
# -------------------------------------------------------------------
|
|
53
|
+
# Job 1b: static type check. basedpyright reads pyrightconfig.json from
|
|
54
|
+
# the repository root (src only, pythonVersion 3.12 = lowest supported).
|
|
55
|
+
# The gate is 0 errors; warnings are printed but do not fail the job.
|
|
56
|
+
# The alembic extra is installed so the optional-import module
|
|
57
|
+
# `mixins/migration_cache_invalidation.py` resolves its imports.
|
|
58
|
+
# "0 errors" is also what an empty scan prints, so the job additionally
|
|
59
|
+
# fails when the verbose log does not report a non-zero source-file count.
|
|
60
|
+
# -------------------------------------------------------------------
|
|
61
|
+
typecheck:
|
|
62
|
+
name: basedpyright (py3.12)
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
steps:
|
|
65
|
+
- name: Checkout
|
|
66
|
+
uses: actions/checkout@v4
|
|
67
|
+
|
|
68
|
+
- name: Install uv
|
|
69
|
+
uses: astral-sh/setup-uv@v5
|
|
70
|
+
with:
|
|
71
|
+
enable-cache: true
|
|
72
|
+
cache-dependency-glob: "uv.lock"
|
|
73
|
+
|
|
74
|
+
- name: Set up Python 3.12
|
|
75
|
+
run: uv python install 3.12
|
|
76
|
+
|
|
77
|
+
- name: Create venv and install project with dev extras
|
|
78
|
+
run: |
|
|
79
|
+
uv venv --python 3.12 .venv
|
|
80
|
+
uv pip install --python .venv/bin/python -e ".[dev,alembic]"
|
|
81
|
+
|
|
82
|
+
- name: Run basedpyright
|
|
83
|
+
# Activate the venv so basedpyright resolves imports against it.
|
|
84
|
+
run: |
|
|
85
|
+
source .venv/bin/activate
|
|
86
|
+
status=0
|
|
87
|
+
basedpyright --verbose > basedpyright.log 2>&1 || status=$?
|
|
88
|
+
grep -E " - (error|warning)" basedpyright.log || true
|
|
89
|
+
grep -E "^[0-9]+ errors?, [0-9]+ warnings?" basedpyright.log
|
|
90
|
+
grep -E "^Found [0-9]+ source files" basedpyright.log
|
|
91
|
+
if ! grep -qE "^Found [1-9][0-9]* source files" basedpyright.log; then
|
|
92
|
+
echo "::error::basedpyright scanned no source files (check pyrightconfig.json include/exclude)"
|
|
93
|
+
exit 1
|
|
94
|
+
fi
|
|
95
|
+
exit $status
|
|
96
|
+
|
|
97
|
+
# -------------------------------------------------------------------
|
|
98
|
+
# Job 2: build wheel + sdist, then install the wheel into a clean
|
|
99
|
+
# virtualenv with zero dev deps and run the consumer integration
|
|
100
|
+
# script. This simulates an external PyPI consumer.
|
|
101
|
+
# -------------------------------------------------------------------
|
|
102
|
+
consumer-integration:
|
|
103
|
+
name: consumer integration (py${{ matrix.python-version }})
|
|
104
|
+
runs-on: ubuntu-latest
|
|
105
|
+
needs: test
|
|
106
|
+
strategy:
|
|
107
|
+
fail-fast: false
|
|
108
|
+
matrix:
|
|
109
|
+
python-version: ["3.12", "3.13", "3.14"]
|
|
110
|
+
steps:
|
|
111
|
+
- name: Checkout
|
|
112
|
+
uses: actions/checkout@v4
|
|
113
|
+
|
|
114
|
+
- name: Install uv
|
|
115
|
+
uses: astral-sh/setup-uv@v5
|
|
116
|
+
with:
|
|
117
|
+
enable-cache: true
|
|
118
|
+
|
|
119
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
120
|
+
run: uv python install ${{ matrix.python-version }}
|
|
121
|
+
|
|
122
|
+
- name: Build wheel and sdist
|
|
123
|
+
run: uv tool run --from build python -m build
|
|
124
|
+
|
|
125
|
+
- name: Create isolated consumer venv
|
|
126
|
+
run: uv venv --python ${{ matrix.python-version }} /tmp/consumer-env
|
|
127
|
+
|
|
128
|
+
- name: Install built wheel (no dev deps, only the wheel + aiosqlite driver)
|
|
129
|
+
run: uv pip install --python /tmp/consumer-env/bin/python dist/*.whl aiosqlite
|
|
130
|
+
|
|
131
|
+
- name: Confirm installed version matches wheel
|
|
132
|
+
run: |
|
|
133
|
+
/tmp/consumer-env/bin/python -c "import sqlmodel_ext; print('installed:', sqlmodel_ext.__version__ if hasattr(sqlmodel_ext, '__version__') else '(no __version__)')"
|
|
134
|
+
|
|
135
|
+
- name: Run consumer integration scenario
|
|
136
|
+
run: /tmp/consumer-env/bin/python examples/consumer_integration/run.py
|
|
137
|
+
|
|
138
|
+
- name: Upload distribution artifacts
|
|
139
|
+
if: matrix.python-version == '3.12'
|
|
140
|
+
uses: actions/upload-artifact@v4
|
|
141
|
+
with:
|
|
142
|
+
name: dist
|
|
143
|
+
path: dist/
|
|
144
|
+
if-no-files-found: error
|
|
145
|
+
retention-days: 14
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
5
|
+
|
|
6
|
+
> **The project is still WIP / alpha.** Any release may contain breaking changes;
|
|
7
|
+
> there is no stability or backward-compatibility guarantee between versions, and
|
|
8
|
+
> you use it at your own risk. Pin the exact version you depend on.
|
|
9
|
+
|
|
10
|
+
## [0.5.0]
|
|
11
|
+
|
|
12
|
+
Upgrade guide: [Migrate from 0.4.x to 0.5.0](docs/en/how-to/migrate-to-0-5.md)
|
|
13
|
+
([中文](docs/how-to/migrate-to-0-5.md)).
|
|
14
|
+
|
|
15
|
+
### Breaking
|
|
16
|
+
|
|
17
|
+
- **`all_fields_optional=True` removed; use `partial=True`.** The old keyword raises
|
|
18
|
+
`TypeError` at class creation. `partial=True` turns inherited fields into
|
|
19
|
+
`Unset | T = Unset` (`Unset | T | None` when the base field is nullable): omitted
|
|
20
|
+
fields are `Unset` and never appear in `model_dump()` (no `exclude_unset=True`
|
|
21
|
+
needed); explicit `null` is only accepted where the base field allows `None`.
|
|
22
|
+
Replace `is None` / `is not None` "was it sent" checks with `is Unset` /
|
|
23
|
+
`is not Unset`. `partial=True` cannot be combined with `table=True`.
|
|
24
|
+
- **Optimistic-lock column renamed `version` → `oplock_version`**, now `BIGINT`
|
|
25
|
+
(bounded by `JS_MAX_SAFE_INTEGER`) with `server_default 0`, and excluded from
|
|
26
|
+
`model_dump()`. Requires a database migration (see the upgrade guide). The
|
|
27
|
+
rename is **not rolling-compatible**: 0.4.x and 0.5.0 instances cannot run
|
|
28
|
+
against the same table at once, so switch all instances together. If you
|
|
29
|
+
use `CachedTableBaseMixin`, also clear the Redis cache at the switch: cache
|
|
30
|
+
keys are unchanged and a 0.4.x entry can validate under 0.5.0 with a
|
|
31
|
+
different meaning.
|
|
32
|
+
- **`oplock_version` is a reserved name**: declaring it in the class body of any
|
|
33
|
+
`SQLModelBase` subclass raises `TypeError`.
|
|
34
|
+
- **`OptimisticLockMixin` retries conflicts 3 times by default**
|
|
35
|
+
(`__optimistic_retry_default__`); `optimistic_retry_count` now defaults to `None`
|
|
36
|
+
("use the model policy"). Pass `optimistic_retry_count=0` to fail immediately.
|
|
37
|
+
- **`delete()` normalizes errors**: an optimistic-lock conflict raises
|
|
38
|
+
`OptimisticLockError` (previously a raw `StaleDataError`); deleting a row that is
|
|
39
|
+
still referenced through a foreign key raises `ResourceReferencedError`
|
|
40
|
+
(`status_code = 409`; previously a raw `IntegrityError`).
|
|
41
|
+
- **Default primary keys are UUIDv7** (`UUIDTableBaseMixin.id` and
|
|
42
|
+
`create_subclass_id_mixin()`), previously UUIDv4. Existing rows need no migration.
|
|
43
|
+
- **`TimeFilterRequest` bounds are `AwareDatetime`**: naive datetimes are rejected.
|
|
44
|
+
`PaginationRequest.offset` is now bounded by `MAX_TABLE_VIEW_OFFSET`.
|
|
45
|
+
- **`@requires_for_update` fails closed**: it raises `RuntimeError` when it cannot
|
|
46
|
+
find an `AsyncSession` in the call arguments (previously the check was skipped).
|
|
47
|
+
- **Renamed / removed internals**: `RelationPreloadMixin._ensure_relations_loaded` →
|
|
48
|
+
`ensure_relations_loaded`; `CachedTableBaseMixin._warn_raw_dml_on_cached` →
|
|
49
|
+
`register_raw_dml_write`; `CachedTableBaseMixin._refresh_via_cache` and
|
|
50
|
+
`_has_pending_invalidation` removed.
|
|
51
|
+
- **`AsyncSession.refresh()` always reads the database** (no longer routed through
|
|
52
|
+
the Redis cache).
|
|
53
|
+
- **`get(with_for_update=True)` always implies `populate_existing`** (no opt-out).
|
|
54
|
+
- **`JSON100K` / `JSONList100K` serialize as objects / arrays** in every dump mode
|
|
55
|
+
(previously a JSON string). Dict / list input is now subject to the 100K-character
|
|
56
|
+
and nesting-depth limits as well; table models are checked at construction.
|
|
57
|
+
Subclasses overriding `model_post_init` must call `super().model_post_init(context)`.
|
|
58
|
+
- **`PositiveFloat` / `NonNegativeFloat` reject `inf` and `nan`.**
|
|
59
|
+
- **Decimal aliases enforce integer digits** (previously only total digits and
|
|
60
|
+
decimal places were validated, e.g. `SignedDecimal20_10` accepted a 15-digit integer).
|
|
61
|
+
- **Dependencies**: `pydantic>=2.12` (was `>=2.0`) and `typing-extensions>=4.14.1`.
|
|
62
|
+
- **RelationLoadChecker** (experimental) reports more findings (RLC014, session
|
|
63
|
+
subclasses) and honors `# noqa: RLCxxx` on every public entry point; endpoint
|
|
64
|
+
`noqa` comments must be on the first decorator line.
|
|
65
|
+
|
|
66
|
+
### Added
|
|
67
|
+
|
|
68
|
+
- **Tri-state fields**: `Unset` (Pydantic's `MISSING` sentinel), `partial=True`,
|
|
69
|
+
`SQLModelBase.annotation_is_omissible()` / `field_is_omissible()` /
|
|
70
|
+
`submitted_fields_among()`, `sqlmodel_ext.base.optional_dto_registry`.
|
|
71
|
+
- **Wire sentinel for callers that cannot omit keys**: `SQLModelExtConfig(omitted_sentinel=True)`
|
|
72
|
+
and `OMITTED_SENTINEL` (`'__omitted__'`).
|
|
73
|
+
- `EXCLUDE_IF_NONE` field marker (the key is dropped from every dump while the value is `None`).
|
|
74
|
+
- `sqlmodel_ext.select`: typed `select()` overloads for 5–9 column projections
|
|
75
|
+
(same object as `sqlmodel.select` at runtime). For 1–4 columns the overload set is
|
|
76
|
+
exactly upstream's, so bare attributes (`select(User.id, User.name)` →
|
|
77
|
+
`Select[tuple[UUID, str]]`) type-check; bare attributes also work for 5–9 columns,
|
|
78
|
+
and only a 5+ projection that mixes in a SQL function expression (`func.count()`)
|
|
79
|
+
should wrap every column in `col()` to keep the precise type.
|
|
80
|
+
- **Experimental `check_derived`**: `python -m sqlmodel_ext.check_derived <package>`
|
|
81
|
+
(console script `sqlmodel-ext-check-derived`) expands `partial=True` DTOs and their
|
|
82
|
+
inherited methods in a throwaway copy and runs basedpyright there, reporting only the
|
|
83
|
+
errors the expansion introduced. See
|
|
84
|
+
[Check partial DTOs for misuse](docs/en/how-to/check-partial-dtos.md).
|
|
85
|
+
- **AI rule pack** in [`ai-rules/`](ai-rules/) (`AGENTS.md` plus a `CLAUDE.md` entry
|
|
86
|
+
point) so AI coding assistants use the library the intended way. See
|
|
87
|
+
[Use with AI coding assistants](docs/en/how-to/use-with-ai-assistants.md).
|
|
88
|
+
- **`py.typed`**: the package is now PEP 561 typed, so type checkers read its inline
|
|
89
|
+
annotations.
|
|
90
|
+
- `pyrightconfig.json` and a basedpyright CI gate (the job fails on errors and when no
|
|
91
|
+
source files are scanned). See
|
|
92
|
+
[Type-check with basedpyright](docs/en/how-to/type-check-with-basedpyright.md).
|
|
93
|
+
- Runnable [`examples/`](examples/) for the new features, executed by
|
|
94
|
+
`tests/test_examples.py`.
|
|
95
|
+
- `AsyncSession`: `commit_count`, `add_post_commit_callback()`, `set_local_timeouts()`,
|
|
96
|
+
`enter_repeatable_read()`, `commit(fail_soft_when_observed=...)`,
|
|
97
|
+
`rollback(best_effort_budget_seconds=...)`, a `begin()` that routes through the
|
|
98
|
+
enhanced commit / rollback, raw-DML registration on `execute` / `exec` / `scalar` /
|
|
99
|
+
`stream` / `stream_scalars`.
|
|
100
|
+
- `sqlmodel_ext.session.SessionFactory.run_in_repeatable_read()` (whole-session retry on
|
|
101
|
+
SQLSTATE 40001), `RepeatableReadSnapshotConflictError`, `SerializationRetryExhaustedError`.
|
|
102
|
+
- CRUD: `get(skip_locked=..., authoritative=...)`, `get_one(authoritative=...)`,
|
|
103
|
+
`get_exist_one(with_for_update=...)`, `count(distinct_column=...)`, `distinct_column()`,
|
|
104
|
+
`group_sum()` / `GroupSumRow`.
|
|
105
|
+
- Keyset pagination: `PaginationRequest.after_id`, `order="id"`, `PageWindowRequest`,
|
|
106
|
+
`KeysetCursorError` / `KeysetCursorInvalidError` / `KeysetCursorUnsupportedError`.
|
|
107
|
+
- `ResourceReferencedError`, `FK_DELETE_RESTRICT_FALLBACK_MESSAGE`,
|
|
108
|
+
`TableBaseMixin.register_fk_delete_restrict_message()`.
|
|
109
|
+
- `sqlmodel_ext.mixins.uuid7` (standard-library `uuid.uuid7` on Python 3.14+).
|
|
110
|
+
- Transaction contracts: `requires_locked_param`, `requires_read_committed`,
|
|
111
|
+
`requires_repeatable_read`, `validate_locked_instances`, `SESSION_REPEATABLE_READ_KEY`.
|
|
112
|
+
- Relation preloading: `ensure_relations_loaded_bulk()`, `bulk_preload_unsupported_reason()`.
|
|
113
|
+
- Cache: `CachedTableBaseMixin.invalidate_on_commit()`, `invalidate_all(strict=...)`,
|
|
114
|
+
`register_raw_dml_write()`; `CACHE_TTL_HOT` / `CACHE_TTL_WARM` / `CACHE_TTL_COLD`;
|
|
115
|
+
`collect_migration_invalidation_tasks()` / `run_pending_migration_cache_invalidations()`
|
|
116
|
+
(new optional extra `alembic`).
|
|
117
|
+
- New mixins: `ResourceQuotaMixin` (with `QuotaExceededError`, `QuotaOwnerNotFoundError`,
|
|
118
|
+
`CallerDidNotCommitError`), `TrgmSearchableMixin` / `TrgmSearchRequest` /
|
|
119
|
+
`BIGRAM_FUNCTION_SQL`, `MixinTableScanMixin`.
|
|
120
|
+
- Field types: `max_length_of()`, `Str1`, `Text3072`, `Text4K`, `NonEmptyStrippedStr32`,
|
|
121
|
+
`SingleLineStr64`, `SearchQueryStr64`, `HttpHeaderName`, `SignedBigInt`, `INT32_MIN`,
|
|
122
|
+
`ClientIPAddress`, `OptionalSignedDecimal38_18`, `NullableNonNegativeDecimal20_10`,
|
|
123
|
+
write/sum Decimal pairs (`SignedWriteDecimal38_18`, `NonNegativeWriteDecimal38_18`,
|
|
124
|
+
`PositiveWriteDecimal38_18`, `OptionalNonNegativeWriteDecimal38_18`,
|
|
125
|
+
`OptionalSignedWriteDecimal38_18`, `SignedSumDecimal38_18`) and
|
|
126
|
+
`DECIMAL_38_18_COLUMN_DIGITS` / `DECIMAL_38_18_WRITE_DIGITS` / `DECIMAL_38_18_PLACES`;
|
|
127
|
+
`ensure_json_within_limits()` in `sqlmodel_ext.field_types.dialects.postgresql`.
|
|
128
|
+
- RelationLoadChecker: RLC014 and module-level `conditional_commit_methods` /
|
|
129
|
+
`explicit_commit_methods` / `dependency_commit_methods`.
|
|
130
|
+
|
|
131
|
+
### Fixed
|
|
132
|
+
|
|
133
|
+
- A raw `insert(...)` into a cached table executed through the enhanced
|
|
134
|
+
`AsyncSession` left cached query results stale after commit (until TTL). It
|
|
135
|
+
now registers a query-level invalidation that the enhanced `commit()` runs.
|
|
136
|
+
`text()` writes and writes nested in a `SELECT` (writable CTEs) are still not
|
|
137
|
+
invalidated after commit -- register `invalidate_on_commit` or call
|
|
138
|
+
`invalidate_all` yourself.
|
|
139
|
+
- An explicit `default=None` inside merged `Field` metadata was dropped, silently making
|
|
140
|
+
the field required.
|
|
141
|
+
- On sqlmodel ≥ 0.0.32, `id: NonNegativeInt = Field(primary_key=True)` lost its primary key.
|
|
142
|
+
- Cached-model serialization dropped `exclude=True` columns.
|
|
143
|
+
- The cache could serve stale reads or publish data that was not yet committed.
|
|
144
|
+
- Read-modify-write after `with_for_update=True` could lose an update through a stale
|
|
145
|
+
identity-map object.
|
|
146
|
+
- A joined-table-inheritance update that touched only child-table columns did not
|
|
147
|
+
advance `updated_at`.
|
|
148
|
+
- `ExtraIgnoreModelBase` warned about keys accepted through `AliasChoices`.
|
|
149
|
+
- `model_json_schema()` did not inject the sentinel branch into self-referencing models.
|
|
150
|
+
- `AsyncSession.execute()` / `exec()` / `scalar()` / `stream()` / `stream_scalars()`
|
|
151
|
+
no longer degrade their return type to `Any`: they keep upstream SQLModel's
|
|
152
|
+
signatures (`await session.exec(select(User))` is `ScalarResult[User]`).
|
|
153
|
+
- Optimistic-lock models no longer emit Pydantic's "Field name ... shadows an
|
|
154
|
+
attribute in parent" `UserWarning` for the version column.
|
|
155
|
+
|
|
156
|
+
### Changed
|
|
157
|
+
|
|
158
|
+
- Documentation rewritten around the single-source-of-truth design, with new pages for
|
|
159
|
+
`Unset`, PATCH endpoints, basedpyright and this migration.
|
|
160
|
+
|
|
161
|
+
### Known limitations
|
|
162
|
+
|
|
163
|
+
- A Redis failure during post-commit cache invalidation is logged, not raised (the
|
|
164
|
+
database has already committed): the affected cache entries keep serving
|
|
165
|
+
pre-commit data until their TTL expires. Use `no_cache=True` for reads that must
|
|
166
|
+
not rely on the cache.
|
|
167
|
+
- Every commit of a cached model through the enhanced `AsyncSession` logs a spurious
|
|
168
|
+
`WARNING` "fallback compensation triggered: ..." (pre-existing in 0.4.x). The only
|
|
169
|
+
effect is one redundant cache invalidation; correctness is unaffected.
|
|
170
|
+
- When `TableViewRequest` is used as a `Depends()` dependency, a cross-field validation
|
|
171
|
+
failure (e.g. `after_id` with a non-zero `offset`) surfaces as a 500 instead of a 422,
|
|
172
|
+
because FastAPI constructs the object outside its per-parameter validation. Register
|
|
173
|
+
the `ValidationError` → 422 handler shown in
|
|
174
|
+
[Paginate a list endpoint](docs/en/how-to/paginate-a-list-endpoint.md).
|
|
175
|
+
- On Python 3.12, `JSON100K | None` as a `table=True` field raises
|
|
176
|
+
`has no matching SQLAlchemy type`; declare the column explicitly with
|
|
177
|
+
`Field(default=None, sa_type=JSONB)` (pre-existing).
|
|
178
|
+
|
|
179
|
+
## 0.4.2 and earlier
|
|
180
|
+
|
|
181
|
+
Not recorded in this file; see the git history (tags `v0.4.0` and earlier).
|