From 3ce952c2b5e0a40e490c179e26ff1a22b6403fc2 Mon Sep 17 00:00:00 2001 From: Zhao vistart Date: Wed, 11 Nov 2026 20:35:46 +0800 Subject: [PATCH 1/2] feat(fixtures)!: declare models by overriding accessors, not by dunder Breaking, following rhosocial-activerecord: model fixtures now override table_name(), primary_key(), pk_auto_generated(), read_only() and the locator methods instead of assigning __table_name__ and friends, and the composite-key contract tests assert pk_auto_generated() rather than the removed attribute. 534 declarations across 55 files, produced by the core repository\x27s declaration sweep so both sides stay byte-identical in shape. --- .../benchmark/crud/fixtures/models.py | 10 +- .../benchmark/crud/fixtures/models_py310.py | 10 +- .../benchmark/crud/fixtures/models_py311.py | 10 +- .../benchmark/crud/fixtures/models_py312.py | 10 +- .../basic/crud/test_composite_pk_crud.py | 4 +- .../crud/test_composite_pk_crud_async.py | 4 +- .../basic/fields/test_derived_field.py | 10 +- .../basic/fields/test_derived_field_async.py | 10 +- .../basic/fields/test_field_column_mapping.py | 24 +- .../fields/test_field_column_mapping_async.py | 24 +- .../feature/basic/fixtures/models.py | 220 ++++++++++++++---- .../feature/basic/fixtures/models_py310.py | 188 +++++++++++---- .../feature/basic/fixtures/models_py311.py | 188 +++++++++++---- .../feature/basic/fixtures/models_py312.py | 188 +++++++++++---- .../feature/basic/nopk/test_keyless_models.py | 30 ++- .../basic/nopk/test_keyless_models_async.py | 30 ++- .../basic/readonly/test_readonly_models.py | 29 ++- .../readonly/test_readonly_models_async.py | 29 ++- .../test_pydantic_native_validation.py | 126 +++++++--- .../test_pydantic_native_validation_async.py | 126 +++++++--- .../testsuite/feature/cli/fixtures.py | 10 +- .../testsuite/feature/ddl/fixtures/models.py | 58 ++++- .../feature/ddl/test_ddl_source_contract.py | 77 ++++-- .../feature/events/fixtures/models.py | 12 +- .../feature/events/fixtures/models_py310.py | 8 +- .../feature/events/fixtures/models_py311.py | 8 +- .../feature/events/fixtures/models_py312.py | 8 +- .../feature/mixins/fixtures/models.py | 32 ++- .../feature/mixins/fixtures/models_py310.py | 16 +- .../feature/mixins/fixtures/models_py311.py | 16 +- .../feature/mixins/fixtures/models_py312.py | 16 +- .../query/cross_schema/mixed_schema_models.py | 8 +- .../fixtures/annotated_adapter_models.py | 5 +- .../async_annotated_adapter_models.py | 4 +- .../query/fixtures/async_cte_models.py | 4 +- .../query/fixtures/async_extended_models.py | 12 +- .../query/fixtures/async_json_models.py | 4 +- .../feature/query/fixtures/async_models.py | 28 ++- .../feature/query/fixtures/cte_models.py | 4 +- .../feature/query/fixtures/extended_models.py | 12 +- .../feature/query/fixtures/models.py | 64 +++-- .../feature/query/fixtures/models_py310.py | 52 +++-- .../feature/query/fixtures/models_py311.py | 52 +++-- .../feature/query/fixtures/models_py312.py | 52 +++-- .../feature/query/fixtures/schema_models.py | 40 +++- .../query/relations/test_relations_basic.py | 100 ++++++-- .../relations/test_relations_basic_async.py | 100 ++++++-- .../test_column_operations_core.py | 10 +- .../descriptors/test_descriptor_compat.py | 40 +++- .../test_descriptor_compat_async.py | 40 +++- .../descriptors/test_descriptors_async.py | 20 +- .../feature/relation/fixtures/models.py | 72 ++++-- .../feature/relation/fixtures/models_py310.py | 24 +- .../feature/relation/fixtures/models_py311.py | 24 +- .../feature/relation/fixtures/models_py312.py | 24 +- .../relation/validation/test_validator.py | 50 +++- .../validation/test_validator_async.py | 50 +++- 57 files changed, 1888 insertions(+), 538 deletions(-) diff --git a/src/rhosocial/activerecord/testsuite/benchmark/crud/fixtures/models.py b/src/rhosocial/activerecord/testsuite/benchmark/crud/fixtures/models.py index 117dfbc..e8ed6f8 100644 --- a/src/rhosocial/activerecord/testsuite/benchmark/crud/fixtures/models.py +++ b/src/rhosocial/activerecord/testsuite/benchmark/crud/fixtures/models.py @@ -10,7 +10,10 @@ class BenchmarkUser(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): - __table_name__ = "benchmark_users" + @classmethod + def table_name(cls): + return "benchmark_users" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -23,7 +26,10 @@ class BenchmarkUser(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): class AsyncBenchmarkUser(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): - __table_name__ = "benchmark_users" + @classmethod + def table_name(cls): + return "benchmark_users" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None diff --git a/src/rhosocial/activerecord/testsuite/benchmark/crud/fixtures/models_py310.py b/src/rhosocial/activerecord/testsuite/benchmark/crud/fixtures/models_py310.py index 2aa478c..6a7044c 100644 --- a/src/rhosocial/activerecord/testsuite/benchmark/crud/fixtures/models_py310.py +++ b/src/rhosocial/activerecord/testsuite/benchmark/crud/fixtures/models_py310.py @@ -10,7 +10,10 @@ class BenchmarkUser(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): - __table_name__ = "benchmark_users" + @classmethod + def table_name(cls): + return "benchmark_users" + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None @@ -23,7 +26,10 @@ class BenchmarkUser(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): class AsyncBenchmarkUser(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): - __table_name__ = "benchmark_users" + @classmethod + def table_name(cls): + return "benchmark_users" + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None diff --git a/src/rhosocial/activerecord/testsuite/benchmark/crud/fixtures/models_py311.py b/src/rhosocial/activerecord/testsuite/benchmark/crud/fixtures/models_py311.py index 979d2aa..182c0c6 100644 --- a/src/rhosocial/activerecord/testsuite/benchmark/crud/fixtures/models_py311.py +++ b/src/rhosocial/activerecord/testsuite/benchmark/crud/fixtures/models_py311.py @@ -10,7 +10,10 @@ class BenchmarkUser(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): - __table_name__ = "benchmark_users" + @classmethod + def table_name(cls): + return "benchmark_users" + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None @@ -23,7 +26,10 @@ class BenchmarkUser(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): class AsyncBenchmarkUser(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): - __table_name__ = "benchmark_users" + @classmethod + def table_name(cls): + return "benchmark_users" + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None diff --git a/src/rhosocial/activerecord/testsuite/benchmark/crud/fixtures/models_py312.py b/src/rhosocial/activerecord/testsuite/benchmark/crud/fixtures/models_py312.py index a354502..2850440 100644 --- a/src/rhosocial/activerecord/testsuite/benchmark/crud/fixtures/models_py312.py +++ b/src/rhosocial/activerecord/testsuite/benchmark/crud/fixtures/models_py312.py @@ -10,7 +10,10 @@ class BenchmarkUser(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): - __table_name__ = "benchmark_users" + @classmethod + def table_name(cls): + return "benchmark_users" + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None @@ -23,7 +26,10 @@ class BenchmarkUser(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): class AsyncBenchmarkUser(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): - __table_name__ = "benchmark_users" + @classmethod + def table_name(cls): + return "benchmark_users" + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None diff --git a/src/rhosocial/activerecord/testsuite/feature/basic/crud/test_composite_pk_crud.py b/src/rhosocial/activerecord/testsuite/feature/basic/crud/test_composite_pk_crud.py index 851e1f9..2358392 100644 --- a/src/rhosocial/activerecord/testsuite/feature/basic/crud/test_composite_pk_crud.py +++ b/src/rhosocial/activerecord/testsuite/feature/basic/crud/test_composite_pk_crud.py @@ -37,7 +37,7 @@ def test_primary_key_single(self, order_class): def test_pk_auto_generated(self, order_item_class): """Composite keys should not be auto-generated.""" - assert order_item_class.__pk_auto_generated__ is False, \ + assert order_item_class.pk_auto_generated() is False, \ "Expected composite key to not be auto-generated" @@ -273,7 +273,7 @@ def test_meta_primary_key_field(self, mapped_order_item_class): def test_meta_pk_auto_generated(self, mapped_order_item_class): """Mapped composite keys should not be auto-generated.""" - assert mapped_order_item_class.__pk_auto_generated__ is False, \ + assert mapped_order_item_class.pk_auto_generated() is False, \ "Expected the key to not be auto-generated" def test_insert_and_is_new_record(self, mapped_order_item_class): diff --git a/src/rhosocial/activerecord/testsuite/feature/basic/crud/test_composite_pk_crud_async.py b/src/rhosocial/activerecord/testsuite/feature/basic/crud/test_composite_pk_crud_async.py index f356077..a027e42 100644 --- a/src/rhosocial/activerecord/testsuite/feature/basic/crud/test_composite_pk_crud_async.py +++ b/src/rhosocial/activerecord/testsuite/feature/basic/crud/test_composite_pk_crud_async.py @@ -39,7 +39,7 @@ async def test_primary_key_single(self, async_order_class): async def test_pk_auto_generated(self, async_order_item_class): """Composite keys should not be auto-generated.""" - assert async_order_item_class.__pk_auto_generated__ is False, \ + assert async_order_item_class.pk_auto_generated() is False, \ "Expected composite key to not be auto-generated" class TestAsyncCompositePKInsert: @@ -271,7 +271,7 @@ async def test_meta_primary_key_field(self, async_mapped_order_item_class): async def test_meta_pk_auto_generated(self, async_mapped_order_item_class): """Mapped composite keys should not be auto-generated.""" - assert async_mapped_order_item_class.__pk_auto_generated__ is False, \ + assert async_mapped_order_item_class.pk_auto_generated() is False, \ "Expected the key to not be auto-generated" async def test_insert_and_is_new_record(self, async_mapped_order_item_class): diff --git a/src/rhosocial/activerecord/testsuite/feature/basic/fields/test_derived_field.py b/src/rhosocial/activerecord/testsuite/feature/basic/fields/test_derived_field.py index f4684a3..4d00e0a 100644 --- a/src/rhosocial/activerecord/testsuite/feature/basic/fields/test_derived_field.py +++ b/src/rhosocial/activerecord/testsuite/feature/basic/fields/test_derived_field.py @@ -393,7 +393,10 @@ def test_use_column_conflict_raises(self): """UseColumn on derived field must not duplicate a regular field's column name.""" with pytest.raises(TypeError, match="conflicts with a regular field's column name"): class ConflictModel(ActiveRecord): - __table_name__ = "conflict" + @classmethod + def table_name(cls): + return "conflict" + id: Optional[int] = None discount_rate: Annotated[float, UseColumn("disc")] discounted: ClassVar[Annotated[float, DerivedField( @@ -403,7 +406,10 @@ class ConflictModel(ActiveRecord): def test_use_column_no_conflict_different_names(self): """Different column names should not conflict.""" class NoConflict(ActiveRecord): - __table_name__ = "no_conflict" + @classmethod + def table_name(cls): + return "no_conflict" + id: Optional[int] = None discount_rate: Annotated[float, UseColumn("rate")] discounted: ClassVar[Annotated[float, DerivedField( diff --git a/src/rhosocial/activerecord/testsuite/feature/basic/fields/test_derived_field_async.py b/src/rhosocial/activerecord/testsuite/feature/basic/fields/test_derived_field_async.py index 0ff9181..4395024 100644 --- a/src/rhosocial/activerecord/testsuite/feature/basic/fields/test_derived_field_async.py +++ b/src/rhosocial/activerecord/testsuite/feature/basic/fields/test_derived_field_async.py @@ -393,7 +393,10 @@ async def test_use_column_conflict_raises(self): """UseColumn on derived field must not duplicate a regular field's column name.""" with pytest.raises(TypeError, match="conflicts with a regular field's column name"): class ConflictModel(ActiveRecord): - __table_name__ = "conflict" + @classmethod + def table_name(cls): + return "conflict" + id: Optional[int] = None discount_rate: Annotated[float, UseColumn("disc")] discounted: ClassVar[Annotated[float, DerivedField( @@ -403,7 +406,10 @@ class ConflictModel(ActiveRecord): async def test_use_column_no_conflict_different_names(self): """Different column names should not conflict.""" class NoConflict(ActiveRecord): - __table_name__ = "no_conflict" + @classmethod + def table_name(cls): + return "no_conflict" + id: Optional[int] = None discount_rate: Annotated[float, UseColumn("rate")] discounted: ClassVar[Annotated[float, DerivedField( diff --git a/src/rhosocial/activerecord/testsuite/feature/basic/fields/test_field_column_mapping.py b/src/rhosocial/activerecord/testsuite/feature/basic/fields/test_field_column_mapping.py index 8247f94..ca3a64c 100644 --- a/src/rhosocial/activerecord/testsuite/feature/basic/fields/test_field_column_mapping.py +++ b/src/rhosocial/activerecord/testsuite/feature/basic/fields/test_field_column_mapping.py @@ -203,7 +203,10 @@ def test_multiple_use_column_raises_error(self): """Verify that using multiple UseColumn annotations raises an error.""" with pytest.raises(TypeError) as excinfo: class InvalidModel(ActiveRecord): - __table_name__ = "invalid" + @classmethod + def table_name(cls): + return "invalid" + # This field has two UseColumn annotations, which is invalid. name: Annotated[str, UseColumn("col1"), UseColumn("col2")] @@ -218,7 +221,10 @@ def _do_from_database(self, value, **kwargs): return value with pytest.raises(TypeError) as excinfo: class InvalidModel(ActiveRecord): - __table_name__ = "invalid" + @classmethod + def table_name(cls): + return "invalid" + # This field has two UseAdapter annotations, which is invalid. data: Annotated[ str, @@ -233,7 +239,10 @@ def test_use_column_with_invalid_type_raises_error(self): """Verify that UseColumn expects a string argument.""" with pytest.raises(TypeError) as excinfo: class InvalidModel(ActiveRecord): - __table_name__ = "invalid" + @classmethod + def table_name(cls): + return "invalid" + # UseColumn is given an integer, but it expects a string. name: Annotated[str, UseColumn(123)] @@ -247,7 +256,10 @@ class NotAnAdapter: with pytest.raises(TypeError) as excinfo: class InvalidModel(ActiveRecord): - __table_name__ = "invalid" + @classmethod + def table_name(cls): + return "invalid" + # UseAdapter is given an object that is not a BaseSQLTypeAdapter. data: Annotated[str, UseAdapter(NotAnAdapter(), str)] @@ -258,7 +270,9 @@ def test_duplicate_column_name_raises_error(self): """Verify that two fields mapping to the same column raises an error.""" with pytest.raises(ValueError) as excinfo: class InvalidModelWithDuplicates(ActiveRecord): - __table_name__ = "invalid_duplicates" + @classmethod + def table_name(cls): + return "invalid_duplicates" field_a: Annotated[str, UseColumn("shared_column")] field_b: Annotated[int, UseColumn("shared_column")] diff --git a/src/rhosocial/activerecord/testsuite/feature/basic/fields/test_field_column_mapping_async.py b/src/rhosocial/activerecord/testsuite/feature/basic/fields/test_field_column_mapping_async.py index 88751af..0024409 100644 --- a/src/rhosocial/activerecord/testsuite/feature/basic/fields/test_field_column_mapping_async.py +++ b/src/rhosocial/activerecord/testsuite/feature/basic/fields/test_field_column_mapping_async.py @@ -205,7 +205,10 @@ async def test_multiple_use_column_raises_error(self): with pytest.raises(TypeError) as excinfo: class AsyncInvalidModel(AsyncActiveRecord): - __table_name__ = "invalid" + @classmethod + def table_name(cls): + return "invalid" + name: Annotated[str, UseColumn("col1"), UseColumn("col2")] assert "A field can have at most one UseColumn specified" in str(excinfo.value), \ @@ -220,7 +223,10 @@ def _do_from_database(self, value, **kwargs): return value with pytest.raises(TypeError) as excinfo: class AsyncInvalidModel(AsyncActiveRecord): - __table_name__ = "invalid" + @classmethod + def table_name(cls): + return "invalid" + data: Annotated[ str, UseAdapter(DummyAdapter(), str), @@ -236,7 +242,10 @@ async def test_use_column_with_invalid_type_raises_error(self): with pytest.raises(TypeError) as excinfo: class AsyncInvalidModel(AsyncActiveRecord): - __table_name__ = "invalid" + @classmethod + def table_name(cls): + return "invalid" + name: Annotated[str, UseColumn(123)] assert "Invalid type for column_name. Expected str, but received type int." in str(excinfo.value), \ @@ -250,7 +259,10 @@ class NotAnAdapter: with pytest.raises(TypeError) as excinfo: class AsyncInvalidModel(AsyncActiveRecord): - __table_name__ = "invalid" + @classmethod + def table_name(cls): + return "invalid" + data: Annotated[str, UseAdapter(NotAnAdapter(), str)] assert "Invalid type for adapter. Expected an instance of SQLTypeAdapter, but received type NotAnAdapter." in str(excinfo.value), \ @@ -262,7 +274,9 @@ async def test_duplicate_column_name_raises_error(self): with pytest.raises(ValueError) as excinfo: class AsyncInvalidModelWithDuplicates(AsyncActiveRecord): - __table_name__ = "invalid_duplicates" + @classmethod + def table_name(cls): + return "invalid_duplicates" field_a: Annotated[str, UseColumn("shared_column")] field_b: Annotated[int, UseColumn("shared_column")] diff --git a/src/rhosocial/activerecord/testsuite/feature/basic/fixtures/models.py b/src/rhosocial/activerecord/testsuite/feature/basic/fixtures/models.py index e2634bf..382423e 100644 --- a/src/rhosocial/activerecord/testsuite/feature/basic/fixtures/models.py +++ b/src/rhosocial/activerecord/testsuite/feature/basic/fixtures/models.py @@ -31,7 +31,9 @@ class TypeCase(UUIDMixin, ActiveRecord): """A model with a wide variety of data types to test database type handling.""" - __table_name__ = "type_cases" + @classmethod + def table_name(cls): + return "type_cases" username: str email: str @@ -54,7 +56,10 @@ class TypeCase(UUIDMixin, ActiveRecord): class AsyncTypeCase(UUIDMixin, AsyncActiveRecord): """A model with a wide variety of data types to test database type handling.""" - __table_name__ = "type_cases" + @classmethod + def table_name(cls): + return "type_cases" + c: ClassVar[FieldProxy] = FieldProxy() username: str @@ -78,7 +83,9 @@ class AsyncTypeCase(UUIDMixin, AsyncActiveRecord): class TypeTestModel(UUIDMixin, ActiveRecord): """Model class for testing various field types""" - __table_name__ = "type_tests" + @classmethod + def table_name(cls): + return "type_tests" # UUID primary key provided by UUIDMixin string_field: str = Field(default="test string") @@ -92,7 +99,10 @@ class TypeTestModel(UUIDMixin, ActiveRecord): class AsyncTypeTestModel(UUIDMixin, AsyncActiveRecord): """Model class for testing various field types""" - __table_name__ = "type_tests" + @classmethod + def table_name(cls): + return "type_tests" + c: ClassVar[FieldProxy] = FieldProxy() # UUID primary key provided by UUIDMixin @@ -108,7 +118,10 @@ class AsyncTypeTestModel(UUIDMixin, AsyncActiveRecord): class User(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """A standard User model for general CRUD operation testing.""" - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() # The IntegerPKMixin is expected to handle the `id` field. @@ -121,7 +134,10 @@ class User(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): class AsyncUser(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): """A standard User model for general CRUD operation testing.""" - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() # The IntegerPKMixin is expected to handle the `id` field. @@ -137,7 +153,10 @@ class ValidatedFieldUser(IntegerPKMixin, ActiveRecord): A User model with specific, custom field validators to test the framework's validation handling. """ - __table_name__ = "validated_field_users" + @classmethod + def table_name(cls): + return "validated_field_users" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -170,7 +189,10 @@ class AsyncValidatedFieldUser(IntegerPKMixin, AsyncActiveRecord): A User model with specific, custom field validators to test the framework's validation handling. """ - __table_name__ = "validated_field_users" + @classmethod + def table_name(cls): + return "validated_field_users" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -200,7 +222,9 @@ def validate_credit_score(cls, value): class ValidatedUser(IntegerPKMixin, ActiveRecord): """User model for validation testing""" - __table_name__ = "validated_users" + @classmethod + def table_name(cls): + return "validated_users" id: Optional[int] = None username: str = Field(..., min_length=3, max_length=50) @@ -224,7 +248,10 @@ def validate_record(cls, instance: 'ValidatedUser') -> None: class AsyncValidatedUser(IntegerPKMixin, AsyncActiveRecord): """User model for validation testing""" - __table_name__ = "validated_users" + @classmethod + def table_name(cls): + return "validated_users" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -283,14 +310,18 @@ def validate_period(self): class PydanticValidatedModel(PydanticValidatedFieldsMixin, IntegerPKMixin, ActiveRecord): """Model for Pydantic native validation contract tests.""" - __table_name__ = "pydantic_validated_models" + @classmethod + def table_name(cls): + return "pydantic_validated_models" id: Optional[int] = None class AsyncPydanticValidatedModel(PydanticValidatedFieldsMixin, IntegerPKMixin, AsyncActiveRecord): """Async model for Pydantic native validation contract tests.""" - __table_name__ = "pydantic_validated_models" + @classmethod + def table_name(cls): + return "pydantic_validated_models" id: Optional[int] = None @@ -312,7 +343,9 @@ def _do_from_database(self, value: str, target_type: Type, options: Optional[Dic class TypeAdapterTest(ActiveRecord): """Model for testing various type adapter scenarios.""" - __table_name__ = 'type_adapter_tests' + @classmethod + def table_name(cls): + return 'type_adapter_tests' id: Optional[int] = None name: str @@ -329,7 +362,10 @@ class TypeAdapterTest(ActiveRecord): class AsyncTypeAdapterTest(AsyncActiveRecord): """Model for testing various type adapter scenarios.""" - __table_name__ = 'type_adapter_tests' + @classmethod + def table_name(cls): + return 'type_adapter_tests' + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -350,7 +386,9 @@ class AsyncTypeAdapterTest(AsyncActiveRecord): class MappedUser(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """User model with custom column name mappings for testing in basic feature.""" - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" # Python field: user_id, Database column: id user_id: Annotated[Optional[int], UseColumn("id")] = None @@ -368,7 +406,10 @@ class MappedUser(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): class AsyncMappedUser(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): """User model with custom column name mappings for testing in basic feature.""" - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() # Python field: user_id, Database column: id @@ -388,7 +429,9 @@ class AsyncMappedUser(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): class MappedPost(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """Post model with custom column name mappings for testing in basic feature.""" - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" # Python field: post_id, Database column: id post_id: Annotated[Optional[int], UseColumn("id")] = None @@ -411,7 +454,10 @@ class MappedPost(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): class AsyncMappedPost(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): """Post model with custom column name mappings for testing in basic feature.""" - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" + c: ClassVar[FieldProxy] = FieldProxy() # Python field: post_id, Database column: id @@ -436,7 +482,9 @@ class AsyncMappedPost(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): class MappedComment(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """Comment model with custom column name mappings for testing in basic feature.""" - __table_name__ = "comments" + @classmethod + def table_name(cls): + return "comments" # Python field: comment_id, Database column: id comment_id: Annotated[Optional[int], UseColumn("id")] = None @@ -460,7 +508,10 @@ class MappedComment(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): class AsyncMappedComment(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): """Comment model with custom column name mappings for testing in basic feature.""" - __table_name__ = "comments" + @classmethod + def table_name(cls): + return "comments" + c: ClassVar[FieldProxy] = FieldProxy() # Python field: comment_id, Database column: id @@ -504,7 +555,9 @@ class ColumnMappingModel(ActiveRecord): A model demonstrating various valid uses of UseColumn and UseAdapter, including mapping the primary key attribute. """ - __table_name__ = 'column_mapping_items' + @classmethod + def table_name(cls): + return 'column_mapping_items' # Primary key defaults to 'id'. item_id attribute maps to this 'id' column. item_id: Annotated[Optional[int], UseColumn("id")] = Field(default=None) @@ -517,7 +570,10 @@ class AsyncColumnMappingModel(AsyncActiveRecord): A model demonstrating various valid uses of UseColumn and UseAdapter, including mapping the primary key attribute. """ - __table_name__ = 'column_mapping_items' + @classmethod + def table_name(cls): + return 'column_mapping_items' + c: ClassVar[FieldProxy] = FieldProxy() # Primary key defaults to 'id'. item_id attribute maps to this 'id' column. @@ -603,7 +659,9 @@ def _do_from_database(self, value: str, target_type: Type, options: Optional[Dic class MixedAnnotationModel(ActiveRecord): """A model with various combinations of annotations to test field mapping and adapters.""" - __table_name__ = "mixed_annotation_items" + @classmethod + def table_name(cls): + return "mixed_annotation_items" # 1. Standard Python type name: str @@ -626,7 +684,10 @@ class MixedAnnotationModel(ActiveRecord): class AsyncMixedAnnotationModel(AsyncActiveRecord): """A model with various combinations of annotations to test field mapping and adapters.""" - __table_name__ = "mixed_annotation_items" + @classmethod + def table_name(cls): + return "mixed_annotation_items" + c: ClassVar[FieldProxy] = FieldProxy() # 1. Standard Python type @@ -650,7 +711,10 @@ class AsyncMixedAnnotationModel(AsyncActiveRecord): class BulkUser(IntegerPKMixin, ActiveRecord): - __table_name__ = "bulk_users" + @classmethod + def table_name(cls): + return "bulk_users" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -660,7 +724,10 @@ class BulkUser(IntegerPKMixin, ActiveRecord): class AsyncBulkUser(IntegerPKMixin, AsyncActiveRecord): - __table_name__ = "bulk_users" + @classmethod + def table_name(cls): + return "bulk_users" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -675,8 +742,14 @@ class AsyncBulkUser(IntegerPKMixin, AsyncActiveRecord): class OrderItem(CompositePKMixin, ActiveRecord): """Composite PK (order_id, product_id), PK provided by application.""" - __table_name__ = "order_items" - __primary_key__ = ("order_id", "product_id") + @classmethod + def table_name(cls): + return "order_items" + + @classmethod + def primary_key(cls): + return ("order_id", "product_id") + c: ClassVar[FieldProxy] = FieldProxy() order_id: int @@ -687,8 +760,14 @@ class OrderItem(CompositePKMixin, ActiveRecord): class AsyncOrderItem(CompositePKMixin, AsyncActiveRecord): """Async variant of OrderItem.""" - __table_name__ = "order_items" - __primary_key__ = ("order_id", "product_id") + @classmethod + def table_name(cls): + return "order_items" + + @classmethod + def primary_key(cls): + return ("order_id", "product_id") + c: ClassVar[FieldProxy] = FieldProxy() order_id: int @@ -699,8 +778,14 @@ class AsyncOrderItem(CompositePKMixin, AsyncActiveRecord): class StoreInventory(CompositePKMixin, ActiveRecord): """Triple-column composite PK.""" - __table_name__ = "store_inventory" - __primary_key__ = ("store_id", "product_id", "batch_id") + @classmethod + def table_name(cls): + return "store_inventory" + + @classmethod + def primary_key(cls): + return ("store_id", "product_id", "batch_id") + c: ClassVar[FieldProxy] = FieldProxy() store_id: int @@ -711,8 +796,14 @@ class StoreInventory(CompositePKMixin, ActiveRecord): class AsyncStoreInventory(CompositePKMixin, AsyncActiveRecord): """Async variant of StoreInventory.""" - __table_name__ = "store_inventory" - __primary_key__ = ("store_id", "product_id", "batch_id") + @classmethod + def table_name(cls): + return "store_inventory" + + @classmethod + def primary_key(cls): + return ("store_id", "product_id", "batch_id") + c: ClassVar[FieldProxy] = FieldProxy() store_id: int @@ -723,7 +814,10 @@ class AsyncStoreInventory(CompositePKMixin, AsyncActiveRecord): class Order(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """Single-column auto-increment PK — backward compatibility control group.""" - __table_name__ = "orders" + @classmethod + def table_name(cls): + return "orders" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -732,7 +826,10 @@ class Order(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): class AsyncOrder(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): """Async variant of Order.""" - __table_name__ = "orders" + @classmethod + def table_name(cls): + return "orders" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -741,8 +838,13 @@ class AsyncOrder(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): class MappedOrderItem(CompositePKMixin, ActiveRecord): """Composite PK with UseColumn mapping — Python field names differ from DB column names.""" - __table_name__ = "order_items" - __primary_key__ = ("order_id", "product_id") + @classmethod + def table_name(cls): + return "order_items" + + @classmethod + def primary_key(cls): + return ("order_id", "product_id") order_ref: Annotated[int, UseColumn("order_id")] product_ref: Annotated[int, UseColumn("product_id")] @@ -752,8 +854,14 @@ class MappedOrderItem(CompositePKMixin, ActiveRecord): class AsyncMappedOrderItem(CompositePKMixin, AsyncActiveRecord): """Async variant of MappedOrderItem.""" - __table_name__ = "order_items" - __primary_key__ = ("order_id", "product_id") + @classmethod + def table_name(cls): + return "order_items" + + @classmethod + def primary_key(cls): + return ("order_id", "product_id") + c: ClassVar[FieldProxy] = FieldProxy() order_ref: Annotated[int, UseColumn("order_id")] @@ -771,7 +879,9 @@ class AsyncMappedOrderItem(CompositePKMixin, AsyncActiveRecord): class Product(ActiveRecord): - __table_name__ = "product" + @classmethod + def table_name(cls): + return "product" id: Optional[int] = None name: str @@ -788,7 +898,9 @@ class Product(ActiveRecord): class AsyncProduct(AsyncActiveRecord): - __table_name__ = "product" + @classmethod + def table_name(cls): + return "product" id: Optional[int] = None name: str @@ -806,7 +918,9 @@ class AsyncProduct(AsyncActiveRecord): class ProductFormA(ActiveRecord): """Form A declaration: ClassVar[DerivedField] = DerivedField(...).""" - __table_name__ = "product" + @classmethod + def table_name(cls): + return "product" id: Optional[int] = None name: str @@ -823,7 +937,9 @@ class ProductFormA(ActiveRecord): class AsyncProductFormA(AsyncActiveRecord): - __table_name__ = "product" + @classmethod + def table_name(cls): + return "product" id: Optional[int] = None name: str @@ -855,7 +971,9 @@ def supported_types(self) -> Dict[Type, Set[Type]]: class ProductWithProxy(ActiveRecord): """Product model using FieldProxy in DerivedField expressions.""" - __table_name__ = "product" + @classmethod + def table_name(cls): + return "product" c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -873,7 +991,9 @@ class ProductWithProxy(ActiveRecord): class AsyncProductWithProxy(AsyncActiveRecord): - __table_name__ = "product" + @classmethod + def table_name(cls): + return "product" c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -892,7 +1012,9 @@ class AsyncProductWithProxy(AsyncActiveRecord): class ProductWithColumnAndAdapter(ActiveRecord): """Product model with UseColumn and UseAdapter on derived fields.""" - __table_name__ = "product" + @classmethod + def table_name(cls): + return "product" id: Optional[int] = None name: str @@ -909,7 +1031,9 @@ class ProductWithColumnAndAdapter(ActiveRecord): class AsyncProductWithColumnAndAdapter(AsyncActiveRecord): - __table_name__ = "product" + @classmethod + def table_name(cls): + return "product" id: Optional[int] = None name: str diff --git a/src/rhosocial/activerecord/testsuite/feature/basic/fixtures/models_py310.py b/src/rhosocial/activerecord/testsuite/feature/basic/fixtures/models_py310.py index cf882e6..1e5b26d 100644 --- a/src/rhosocial/activerecord/testsuite/feature/basic/fixtures/models_py310.py +++ b/src/rhosocial/activerecord/testsuite/feature/basic/fixtures/models_py310.py @@ -34,7 +34,9 @@ class TypeCase(UUIDMixin, ActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ - __table_name__ = "type_cases" + @classmethod + def table_name(cls): + return "type_cases" username: str email: str @@ -61,7 +63,10 @@ class AsyncTypeCase(UUIDMixin, AsyncActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ - __table_name__ = "type_cases" + @classmethod + def table_name(cls): + return "type_cases" + c: ClassVar[FieldProxy] = FieldProxy() username: str @@ -89,7 +94,9 @@ class TypeTestModel(UUIDMixin, ActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ - __table_name__ = "type_tests" + @classmethod + def table_name(cls): + return "type_tests" # UUID primary key provided by UUIDMixin string_field: str = Field(default="test string") @@ -107,7 +114,10 @@ class AsyncTypeTestModel(UUIDMixin, AsyncActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ - __table_name__ = "type_tests" + @classmethod + def table_name(cls): + return "type_tests" + c: ClassVar[FieldProxy] = FieldProxy() # UUID primary key provided by UUIDMixin @@ -126,7 +136,10 @@ class User(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() # The IntegerPKMixin is expected to handle the `id` field. @@ -143,7 +156,10 @@ class AsyncUser(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() # The IntegerPKMixin is expected to handle the `id` field. @@ -161,7 +177,10 @@ class ValidatedFieldUser(IntegerPKMixin, ActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ - __table_name__ = "validated_field_users" + @classmethod + def table_name(cls): + return "validated_field_users" + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None @@ -194,7 +213,10 @@ class AsyncValidatedFieldUser(IntegerPKMixin, AsyncActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ - __table_name__ = "validated_field_users" + @classmethod + def table_name(cls): + return "validated_field_users" + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None @@ -226,7 +248,9 @@ class ValidatedUser(IntegerPKMixin, ActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ - __table_name__ = "validated_users" + @classmethod + def table_name(cls): + return "validated_users" id: int | None = None username: str = Field(..., min_length=3, max_length=50) @@ -253,7 +277,10 @@ class AsyncValidatedUser(IntegerPKMixin, AsyncActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ - __table_name__ = "validated_users" + @classmethod + def table_name(cls): + return "validated_users" + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None @@ -311,14 +338,18 @@ def validate_period(self): class PydanticValidatedModel(PydanticValidatedFieldsMixin, IntegerPKMixin, ActiveRecord): """Model for Pydantic native validation contract tests.""" - __table_name__ = "pydantic_validated_models" + @classmethod + def table_name(cls): + return "pydantic_validated_models" id: int | None = None class AsyncPydanticValidatedModel(PydanticValidatedFieldsMixin, IntegerPKMixin, AsyncActiveRecord): """Async model for Pydantic native validation contract tests.""" - __table_name__ = "pydantic_validated_models" + @classmethod + def table_name(cls): + return "pydantic_validated_models" id: int | None = None @@ -337,7 +368,9 @@ class TypeAdapterTest(ActiveRecord): Python 3.10+ version using | syntax instead of Optional and Union. """ - __table_name__ = 'type_adapter_tests' + @classmethod + def table_name(cls): + return 'type_adapter_tests' id: int | None = None name: str @@ -358,7 +391,10 @@ class AsyncTypeAdapterTest(AsyncActiveRecord): Python 3.10+ version using | syntax instead of Optional and Union. """ - __table_name__ = 'type_adapter_tests' + @classmethod + def table_name(cls): + return 'type_adapter_tests' + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None @@ -380,7 +416,9 @@ class MappedUser(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" # Python field: user_id, Database column: id user_id: Annotated[int | None, UseColumn("id")] = None @@ -400,7 +438,10 @@ class AsyncMappedUser(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() # Python field: user_id, Database column: id @@ -421,7 +462,9 @@ class MappedPost(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" # Python field: post_id, Database column: id post_id: Annotated[int | None, UseColumn("id")] = None @@ -447,7 +490,10 @@ class AsyncMappedPost(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" + c: ClassVar[FieldProxy] = FieldProxy() # Python field: post_id, Database column: id @@ -474,7 +520,9 @@ class MappedComment(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ - __table_name__ = "comments" + @classmethod + def table_name(cls): + return "comments" # Python field: comment_id, Database column: id comment_id: Annotated[int | None, UseColumn("id")] = None @@ -500,7 +548,10 @@ class AsyncMappedComment(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecor Python 3.10+ version using | syntax instead of Optional. """ - __table_name__ = "comments" + @classmethod + def table_name(cls): + return "comments" + c: ClassVar[FieldProxy] = FieldProxy() # Python field: comment_id, Database column: id @@ -542,7 +593,9 @@ class ColumnMappingModel(ActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ - __table_name__ = 'column_mapping_items' + @classmethod + def table_name(cls): + return 'column_mapping_items' # Primary key defaults to 'id'. item_id attribute maps to this 'id' column. item_id: Annotated[int | None, UseColumn("id")] = Field(default=None) @@ -557,7 +610,10 @@ class AsyncColumnMappingModel(AsyncActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ - __table_name__ = 'column_mapping_items' + @classmethod + def table_name(cls): + return 'column_mapping_items' + c: ClassVar[FieldProxy] = FieldProxy() # Primary key defaults to 'id'. item_id attribute maps to this 'id' column. @@ -636,7 +692,9 @@ class MixedAnnotationModel(ActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ - __table_name__ = "mixed_annotation_items" + @classmethod + def table_name(cls): + return "mixed_annotation_items" # 1. Standard Python type name: str @@ -662,7 +720,10 @@ class AsyncMixedAnnotationModel(AsyncActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ - __table_name__ = "mixed_annotation_items" + @classmethod + def table_name(cls): + return "mixed_annotation_items" + c: ClassVar[FieldProxy] = FieldProxy() # 1. Standard Python type @@ -689,8 +750,14 @@ class AsyncMixedAnnotationModel(AsyncActiveRecord): class OrderItem(CompositePKMixin, ActiveRecord): """Composite PK (order_id, product_id), PK provided by application.""" - __table_name__ = "order_items" - __primary_key__ = ("order_id", "product_id") + @classmethod + def table_name(cls): + return "order_items" + + @classmethod + def primary_key(cls): + return ("order_id", "product_id") + c: ClassVar[FieldProxy] = FieldProxy() order_id: int @@ -701,8 +768,14 @@ class OrderItem(CompositePKMixin, ActiveRecord): class AsyncOrderItem(CompositePKMixin, AsyncActiveRecord): """Async variant of OrderItem.""" - __table_name__ = "order_items" - __primary_key__ = ("order_id", "product_id") + @classmethod + def table_name(cls): + return "order_items" + + @classmethod + def primary_key(cls): + return ("order_id", "product_id") + c: ClassVar[FieldProxy] = FieldProxy() order_id: int @@ -713,8 +786,14 @@ class AsyncOrderItem(CompositePKMixin, AsyncActiveRecord): class StoreInventory(CompositePKMixin, ActiveRecord): """Triple-column composite PK.""" - __table_name__ = "store_inventory" - __primary_key__ = ("store_id", "product_id", "batch_id") + @classmethod + def table_name(cls): + return "store_inventory" + + @classmethod + def primary_key(cls): + return ("store_id", "product_id", "batch_id") + c: ClassVar[FieldProxy] = FieldProxy() store_id: int @@ -725,8 +804,14 @@ class StoreInventory(CompositePKMixin, ActiveRecord): class AsyncStoreInventory(CompositePKMixin, AsyncActiveRecord): """Async variant of StoreInventory.""" - __table_name__ = "store_inventory" - __primary_key__ = ("store_id", "product_id", "batch_id") + @classmethod + def table_name(cls): + return "store_inventory" + + @classmethod + def primary_key(cls): + return ("store_id", "product_id", "batch_id") + c: ClassVar[FieldProxy] = FieldProxy() store_id: int @@ -737,7 +822,10 @@ class AsyncStoreInventory(CompositePKMixin, AsyncActiveRecord): class Order(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """Single-column auto-increment PK -- backward compatibility control group.""" - __table_name__ = "orders" + @classmethod + def table_name(cls): + return "orders" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -746,7 +834,10 @@ class Order(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): class AsyncOrder(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): """Async variant of Order.""" - __table_name__ = "orders" + @classmethod + def table_name(cls): + return "orders" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -755,8 +846,13 @@ class AsyncOrder(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): class MappedOrderItem(CompositePKMixin, ActiveRecord): """Composite PK with UseColumn mapping -- Python field names differ from DB column names.""" - __table_name__ = "order_items" - __primary_key__ = ("order_id", "product_id") + @classmethod + def table_name(cls): + return "order_items" + + @classmethod + def primary_key(cls): + return ("order_id", "product_id") order_ref: Annotated[int, UseColumn("order_id")] product_ref: Annotated[int, UseColumn("product_id")] @@ -766,8 +862,14 @@ class MappedOrderItem(CompositePKMixin, ActiveRecord): class AsyncMappedOrderItem(CompositePKMixin, AsyncActiveRecord): """Async variant of MappedOrderItem.""" - __table_name__ = "order_items" - __primary_key__ = ("order_id", "product_id") + @classmethod + def table_name(cls): + return "order_items" + + @classmethod + def primary_key(cls): + return ("order_id", "product_id") + c: ClassVar[FieldProxy] = FieldProxy() order_ref: Annotated[int, UseColumn("order_id")] @@ -777,7 +879,10 @@ class AsyncMappedOrderItem(CompositePKMixin, AsyncActiveRecord): class BulkUser(IntegerPKMixin, ActiveRecord): - __table_name__ = "bulk_users" + @classmethod + def table_name(cls): + return "bulk_users" + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None @@ -787,7 +892,10 @@ class BulkUser(IntegerPKMixin, ActiveRecord): class AsyncBulkUser(IntegerPKMixin, AsyncActiveRecord): - __table_name__ = "bulk_users" + @classmethod + def table_name(cls): + return "bulk_users" + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None diff --git a/src/rhosocial/activerecord/testsuite/feature/basic/fixtures/models_py311.py b/src/rhosocial/activerecord/testsuite/feature/basic/fixtures/models_py311.py index 063b477..de69fc6 100644 --- a/src/rhosocial/activerecord/testsuite/feature/basic/fixtures/models_py311.py +++ b/src/rhosocial/activerecord/testsuite/feature/basic/fixtures/models_py311.py @@ -38,7 +38,9 @@ class TypeCase(UUIDMixin, ActiveRecord): Python 3.11+ version using | syntax and Self type. """ - __table_name__ = "type_cases" + @classmethod + def table_name(cls): + return "type_cases" username: str email: str @@ -72,7 +74,10 @@ class AsyncTypeCase(UUIDMixin, AsyncActiveRecord): Python 3.11+ version using | syntax and Self type. """ - __table_name__ = "type_cases" + @classmethod + def table_name(cls): + return "type_cases" + c: ClassVar[FieldProxy] = FieldProxy() username: str @@ -107,7 +112,9 @@ class TypeTestModel(UUIDMixin, ActiveRecord): Python 3.11+ version using | syntax and Self type. """ - __table_name__ = "type_tests" + @classmethod + def table_name(cls): + return "type_tests" # UUID primary key provided by UUIDMixin string_field: str = Field(default="test string") @@ -125,7 +132,10 @@ class AsyncTypeTestModel(UUIDMixin, AsyncActiveRecord): Python 3.11+ version using | syntax and Self type. """ - __table_name__ = "type_tests" + @classmethod + def table_name(cls): + return "type_tests" + c: ClassVar[FieldProxy] = FieldProxy() # UUID primary key provided by UUIDMixin @@ -144,7 +154,10 @@ class User(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.11+ version using | syntax and Self type. """ - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None @@ -185,7 +198,10 @@ class AsyncUser(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): Python 3.11+ version using | syntax and Self type. """ - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None @@ -208,7 +224,10 @@ class ValidatedFieldUser(IntegerPKMixin, ActiveRecord): Python 3.11+ version using | syntax and Self type. """ - __table_name__ = "validated_field_users" + @classmethod + def table_name(cls): + return "validated_field_users" + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None @@ -241,7 +260,10 @@ class AsyncValidatedFieldUser(IntegerPKMixin, AsyncActiveRecord): Python 3.11+ version using | syntax and Self type. """ - __table_name__ = "validated_field_users" + @classmethod + def table_name(cls): + return "validated_field_users" + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None @@ -273,7 +295,9 @@ class ValidatedUser(IntegerPKMixin, ActiveRecord): Python 3.11+ version using | syntax and Self type. """ - __table_name__ = "validated_users" + @classmethod + def table_name(cls): + return "validated_users" id: int | None = None username: str = Field(..., min_length=3, max_length=50) @@ -300,7 +324,10 @@ class AsyncValidatedUser(IntegerPKMixin, AsyncActiveRecord): Python 3.11+ version using | syntax and Self type. """ - __table_name__ = "validated_users" + @classmethod + def table_name(cls): + return "validated_users" + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None @@ -358,14 +385,18 @@ def validate_period(self): class PydanticValidatedModel(PydanticValidatedFieldsMixin, IntegerPKMixin, ActiveRecord): """Model for Pydantic native validation contract tests.""" - __table_name__ = "pydantic_validated_models" + @classmethod + def table_name(cls): + return "pydantic_validated_models" id: int | None = None class AsyncPydanticValidatedModel(PydanticValidatedFieldsMixin, IntegerPKMixin, AsyncActiveRecord): """Async model for Pydantic native validation contract tests.""" - __table_name__ = "pydantic_validated_models" + @classmethod + def table_name(cls): + return "pydantic_validated_models" id: int | None = None @@ -384,7 +415,9 @@ class TypeAdapterTest(ActiveRecord): Python 3.11+ version using | syntax. """ - __table_name__ = 'type_adapter_tests' + @classmethod + def table_name(cls): + return 'type_adapter_tests' id: int | None = None name: str @@ -402,7 +435,10 @@ class AsyncTypeAdapterTest(AsyncActiveRecord): Python 3.11+ version using | syntax. """ - __table_name__ = 'type_adapter_tests' + @classmethod + def table_name(cls): + return 'type_adapter_tests' + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None @@ -421,7 +457,9 @@ class MappedUser(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.11+ version using | syntax and Self type. """ - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" user_id: Annotated[int | None, UseColumn("id")] = None user_name: Annotated[str, UseColumn("username")] @@ -439,7 +477,10 @@ class AsyncMappedUser(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): Python 3.11+ version using | syntax. """ - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() user_id: Annotated[int | None, UseColumn("id")] = None @@ -453,7 +494,9 @@ class MappedPost(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.11+ version using | syntax. """ - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" post_id: Annotated[int | None, UseColumn("id")] = None author_id: Annotated[int, UseColumn("author")] @@ -468,7 +511,10 @@ class AsyncMappedPost(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): Python 3.11+ version using | syntax. """ - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" + c: ClassVar[FieldProxy] = FieldProxy() post_id: Annotated[int | None, UseColumn("id")] = None @@ -484,7 +530,9 @@ class MappedComment(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.11+ version using | syntax. """ - __table_name__ = "comments" + @classmethod + def table_name(cls): + return "comments" comment_id: Annotated[int | None, UseColumn("id")] = None post_id: Annotated[int, UseColumn("post_ref")] @@ -499,7 +547,10 @@ class AsyncMappedComment(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecor Python 3.11+ version using | syntax. """ - __table_name__ = "comments" + @classmethod + def table_name(cls): + return "comments" + c: ClassVar[FieldProxy] = FieldProxy() comment_id: Annotated[int | None, UseColumn("id")] = None @@ -529,7 +580,9 @@ class ColumnMappingModel(ActiveRecord): Python 3.11+ version using | syntax. """ - __table_name__ = 'column_mapping_items' + @classmethod + def table_name(cls): + return 'column_mapping_items' item_id: Annotated[int | None, UseColumn("id")] = Field(default=None) name: str @@ -542,7 +595,10 @@ class AsyncColumnMappingModel(AsyncActiveRecord): Python 3.11+ version using | syntax. """ - __table_name__ = 'column_mapping_items' + @classmethod + def table_name(cls): + return 'column_mapping_items' + c: ClassVar[FieldProxy] = FieldProxy() item_id: Annotated[int | None, UseColumn("id")] = Field(default=None) @@ -620,7 +676,9 @@ class MixedAnnotationModel(ActiveRecord): Python 3.11+ version using | syntax. """ - __table_name__ = "mixed_annotation_items" + @classmethod + def table_name(cls): + return "mixed_annotation_items" name: str item_id: Annotated[int, UseColumn("id")] @@ -644,7 +702,10 @@ class AsyncMixedAnnotationModel(AsyncActiveRecord): Python 3.11+ version using | syntax. """ - __table_name__ = "mixed_annotation_items" + @classmethod + def table_name(cls): + return "mixed_annotation_items" + c: ClassVar[FieldProxy] = FieldProxy() name: str @@ -660,8 +721,14 @@ class AsyncMixedAnnotationModel(AsyncActiveRecord): class OrderItem(CompositePKMixin, ActiveRecord): """Composite PK (order_id, product_id), PK provided by application.""" - __table_name__ = "order_items" - __primary_key__ = ("order_id", "product_id") + @classmethod + def table_name(cls): + return "order_items" + + @classmethod + def primary_key(cls): + return ("order_id", "product_id") + c: ClassVar[FieldProxy] = FieldProxy() order_id: int @@ -672,8 +739,14 @@ class OrderItem(CompositePKMixin, ActiveRecord): class AsyncOrderItem(CompositePKMixin, AsyncActiveRecord): """Async variant of OrderItem.""" - __table_name__ = "order_items" - __primary_key__ = ("order_id", "product_id") + @classmethod + def table_name(cls): + return "order_items" + + @classmethod + def primary_key(cls): + return ("order_id", "product_id") + c: ClassVar[FieldProxy] = FieldProxy() order_id: int @@ -684,8 +757,14 @@ class AsyncOrderItem(CompositePKMixin, AsyncActiveRecord): class StoreInventory(CompositePKMixin, ActiveRecord): """Triple-column composite PK.""" - __table_name__ = "store_inventory" - __primary_key__ = ("store_id", "product_id", "batch_id") + @classmethod + def table_name(cls): + return "store_inventory" + + @classmethod + def primary_key(cls): + return ("store_id", "product_id", "batch_id") + c: ClassVar[FieldProxy] = FieldProxy() store_id: int @@ -696,8 +775,14 @@ class StoreInventory(CompositePKMixin, ActiveRecord): class AsyncStoreInventory(CompositePKMixin, AsyncActiveRecord): """Async variant of StoreInventory.""" - __table_name__ = "store_inventory" - __primary_key__ = ("store_id", "product_id", "batch_id") + @classmethod + def table_name(cls): + return "store_inventory" + + @classmethod + def primary_key(cls): + return ("store_id", "product_id", "batch_id") + c: ClassVar[FieldProxy] = FieldProxy() store_id: int @@ -708,7 +793,10 @@ class AsyncStoreInventory(CompositePKMixin, AsyncActiveRecord): class Order(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """Single-column auto-increment PK -- backward compatibility control group.""" - __table_name__ = "orders" + @classmethod + def table_name(cls): + return "orders" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -717,7 +805,10 @@ class Order(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): class AsyncOrder(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): """Async variant of Order.""" - __table_name__ = "orders" + @classmethod + def table_name(cls): + return "orders" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -726,8 +817,13 @@ class AsyncOrder(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): class MappedOrderItem(CompositePKMixin, ActiveRecord): """Composite PK with UseColumn mapping -- Python field names differ from DB column names.""" - __table_name__ = "order_items" - __primary_key__ = ("order_id", "product_id") + @classmethod + def table_name(cls): + return "order_items" + + @classmethod + def primary_key(cls): + return ("order_id", "product_id") order_ref: Annotated[int, UseColumn("order_id")] product_ref: Annotated[int, UseColumn("product_id")] @@ -737,8 +833,14 @@ class MappedOrderItem(CompositePKMixin, ActiveRecord): class AsyncMappedOrderItem(CompositePKMixin, AsyncActiveRecord): """Async variant of MappedOrderItem.""" - __table_name__ = "order_items" - __primary_key__ = ("order_id", "product_id") + @classmethod + def table_name(cls): + return "order_items" + + @classmethod + def primary_key(cls): + return ("order_id", "product_id") + c: ClassVar[FieldProxy] = FieldProxy() order_ref: Annotated[int, UseColumn("order_id")] @@ -748,7 +850,10 @@ class AsyncMappedOrderItem(CompositePKMixin, AsyncActiveRecord): class BulkUser(IntegerPKMixin, ActiveRecord): - __table_name__ = "bulk_users" + @classmethod + def table_name(cls): + return "bulk_users" + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None @@ -758,7 +863,10 @@ class BulkUser(IntegerPKMixin, ActiveRecord): class AsyncBulkUser(IntegerPKMixin, AsyncActiveRecord): - __table_name__ = "bulk_users" + @classmethod + def table_name(cls): + return "bulk_users" + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None diff --git a/src/rhosocial/activerecord/testsuite/feature/basic/fixtures/models_py312.py b/src/rhosocial/activerecord/testsuite/feature/basic/fixtures/models_py312.py index ab14204..b616cb2 100644 --- a/src/rhosocial/activerecord/testsuite/feature/basic/fixtures/models_py312.py +++ b/src/rhosocial/activerecord/testsuite/feature/basic/fixtures/models_py312.py @@ -38,7 +38,9 @@ class TypeCase(UUIDMixin, ActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ - __table_name__ = "type_cases" + @classmethod + def table_name(cls): + return "type_cases" username: str email: str @@ -69,7 +71,10 @@ class AsyncTypeCase(UUIDMixin, AsyncActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ - __table_name__ = "type_cases" + @classmethod + def table_name(cls): + return "type_cases" + c: ClassVar[FieldProxy] = FieldProxy() username: str @@ -101,7 +106,9 @@ class TypeTestModel(UUIDMixin, ActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ - __table_name__ = "type_tests" + @classmethod + def table_name(cls): + return "type_tests" # UUID primary key provided by UUIDMixin string_field: str = Field(default="test string") @@ -119,7 +126,10 @@ class AsyncTypeTestModel(UUIDMixin, AsyncActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ - __table_name__ = "type_tests" + @classmethod + def table_name(cls): + return "type_tests" + c: ClassVar[FieldProxy] = FieldProxy() # UUID primary key provided by UUIDMixin @@ -138,7 +148,10 @@ class User(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None @@ -170,7 +183,10 @@ class AsyncUser(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None @@ -193,7 +209,10 @@ class ValidatedFieldUser(IntegerPKMixin, ActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ - __table_name__ = "validated_field_users" + @classmethod + def table_name(cls): + return "validated_field_users" + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None @@ -226,7 +245,10 @@ class AsyncValidatedFieldUser(IntegerPKMixin, AsyncActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ - __table_name__ = "validated_field_users" + @classmethod + def table_name(cls): + return "validated_field_users" + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None @@ -258,7 +280,9 @@ class ValidatedUser(IntegerPKMixin, ActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ - __table_name__ = "validated_users" + @classmethod + def table_name(cls): + return "validated_users" id: int | None = None username: str = Field(..., min_length=3, max_length=50) @@ -286,7 +310,10 @@ class AsyncValidatedUser(IntegerPKMixin, AsyncActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ - __table_name__ = "validated_users" + @classmethod + def table_name(cls): + return "validated_users" + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None @@ -345,14 +372,18 @@ def validate_period(self): class PydanticValidatedModel(PydanticValidatedFieldsMixin, IntegerPKMixin, ActiveRecord): """Model for Pydantic native validation contract tests.""" - __table_name__ = "pydantic_validated_models" + @classmethod + def table_name(cls): + return "pydantic_validated_models" id: int | None = None class AsyncPydanticValidatedModel(PydanticValidatedFieldsMixin, IntegerPKMixin, AsyncActiveRecord): """Async model for Pydantic native validation contract tests.""" - __table_name__ = "pydantic_validated_models" + @classmethod + def table_name(cls): + return "pydantic_validated_models" id: int | None = None @@ -371,7 +402,9 @@ class TypeAdapterTest(ActiveRecord): Python 3.12+ version using | syntax. """ - __table_name__ = 'type_adapter_tests' + @classmethod + def table_name(cls): + return 'type_adapter_tests' id: int | None = None name: str @@ -389,7 +422,10 @@ class AsyncTypeAdapterTest(AsyncActiveRecord): Python 3.12+ version using | syntax. """ - __table_name__ = 'type_adapter_tests' + @classmethod + def table_name(cls): + return 'type_adapter_tests' + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None @@ -408,7 +444,9 @@ class MappedUser(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" user_id: Annotated[int | None, UseColumn("id")] = None user_name: Annotated[str, UseColumn("username")] @@ -426,7 +464,10 @@ class AsyncMappedUser(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): Python 3.12+ version using | syntax. """ - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() user_id: Annotated[int | None, UseColumn("id")] = None @@ -440,7 +481,9 @@ class MappedPost(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.12+ version using | syntax. """ - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" post_id: Annotated[int | None, UseColumn("id")] = None author_id: Annotated[int, UseColumn("author")] @@ -455,7 +498,10 @@ class AsyncMappedPost(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): Python 3.12+ version using | syntax. """ - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" + c: ClassVar[FieldProxy] = FieldProxy() post_id: Annotated[int | None, UseColumn("id")] = None @@ -471,7 +517,9 @@ class MappedComment(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.12+ version using | syntax. """ - __table_name__ = "comments" + @classmethod + def table_name(cls): + return "comments" comment_id: Annotated[int | None, UseColumn("id")] = None post_id: Annotated[int, UseColumn("post_ref")] @@ -486,7 +534,10 @@ class AsyncMappedComment(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecor Python 3.12+ version using | syntax. """ - __table_name__ = "comments" + @classmethod + def table_name(cls): + return "comments" + c: ClassVar[FieldProxy] = FieldProxy() comment_id: Annotated[int | None, UseColumn("id")] = None @@ -516,7 +567,9 @@ class ColumnMappingModel(ActiveRecord): Python 3.12+ version using | syntax. """ - __table_name__ = 'column_mapping_items' + @classmethod + def table_name(cls): + return 'column_mapping_items' item_id: Annotated[int | None, UseColumn("id")] = Field(default=None) name: str @@ -529,7 +582,10 @@ class AsyncColumnMappingModel(AsyncActiveRecord): Python 3.12+ version using | syntax. """ - __table_name__ = 'column_mapping_items' + @classmethod + def table_name(cls): + return 'column_mapping_items' + c: ClassVar[FieldProxy] = FieldProxy() item_id: Annotated[int | None, UseColumn("id")] = Field(default=None) @@ -607,7 +663,9 @@ class MixedAnnotationModel(ActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ - __table_name__ = "mixed_annotation_items" + @classmethod + def table_name(cls): + return "mixed_annotation_items" name: str item_id: Annotated[int, UseColumn("id")] @@ -628,7 +686,10 @@ class AsyncMixedAnnotationModel(AsyncActiveRecord): Python 3.12+ version using | syntax. """ - __table_name__ = "mixed_annotation_items" + @classmethod + def table_name(cls): + return "mixed_annotation_items" + c: ClassVar[FieldProxy] = FieldProxy() name: str @@ -694,8 +755,14 @@ def unwrap(self) -> T: class OrderItem(CompositePKMixin, ActiveRecord): """Composite PK (order_id, product_id), PK provided by application.""" - __table_name__ = "order_items" - __primary_key__ = ("order_id", "product_id") + @classmethod + def table_name(cls): + return "order_items" + + @classmethod + def primary_key(cls): + return ("order_id", "product_id") + c: ClassVar[FieldProxy] = FieldProxy() order_id: int @@ -706,8 +773,14 @@ class OrderItem(CompositePKMixin, ActiveRecord): class AsyncOrderItem(CompositePKMixin, AsyncActiveRecord): """Async variant of OrderItem.""" - __table_name__ = "order_items" - __primary_key__ = ("order_id", "product_id") + @classmethod + def table_name(cls): + return "order_items" + + @classmethod + def primary_key(cls): + return ("order_id", "product_id") + c: ClassVar[FieldProxy] = FieldProxy() order_id: int @@ -718,8 +791,14 @@ class AsyncOrderItem(CompositePKMixin, AsyncActiveRecord): class StoreInventory(CompositePKMixin, ActiveRecord): """Triple-column composite PK.""" - __table_name__ = "store_inventory" - __primary_key__ = ("store_id", "product_id", "batch_id") + @classmethod + def table_name(cls): + return "store_inventory" + + @classmethod + def primary_key(cls): + return ("store_id", "product_id", "batch_id") + c: ClassVar[FieldProxy] = FieldProxy() store_id: int @@ -730,8 +809,14 @@ class StoreInventory(CompositePKMixin, ActiveRecord): class AsyncStoreInventory(CompositePKMixin, AsyncActiveRecord): """Async variant of StoreInventory.""" - __table_name__ = "store_inventory" - __primary_key__ = ("store_id", "product_id", "batch_id") + @classmethod + def table_name(cls): + return "store_inventory" + + @classmethod + def primary_key(cls): + return ("store_id", "product_id", "batch_id") + c: ClassVar[FieldProxy] = FieldProxy() store_id: int @@ -742,7 +827,10 @@ class AsyncStoreInventory(CompositePKMixin, AsyncActiveRecord): class Order(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """Single-column auto-increment PK -- backward compatibility control group.""" - __table_name__ = "orders" + @classmethod + def table_name(cls): + return "orders" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -751,7 +839,10 @@ class Order(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): class AsyncOrder(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): """Async variant of Order.""" - __table_name__ = "orders" + @classmethod + def table_name(cls): + return "orders" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -760,8 +851,13 @@ class AsyncOrder(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): class MappedOrderItem(CompositePKMixin, ActiveRecord): """Composite PK with UseColumn mapping -- Python field names differ from DB column names.""" - __table_name__ = "order_items" - __primary_key__ = ("order_id", "product_id") + @classmethod + def table_name(cls): + return "order_items" + + @classmethod + def primary_key(cls): + return ("order_id", "product_id") order_ref: Annotated[int, UseColumn("order_id")] product_ref: Annotated[int, UseColumn("product_id")] @@ -771,8 +867,14 @@ class MappedOrderItem(CompositePKMixin, ActiveRecord): class AsyncMappedOrderItem(CompositePKMixin, AsyncActiveRecord): """Async variant of MappedOrderItem.""" - __table_name__ = "order_items" - __primary_key__ = ("order_id", "product_id") + @classmethod + def table_name(cls): + return "order_items" + + @classmethod + def primary_key(cls): + return ("order_id", "product_id") + c: ClassVar[FieldProxy] = FieldProxy() order_ref: Annotated[int, UseColumn("order_id")] @@ -782,7 +884,10 @@ class AsyncMappedOrderItem(CompositePKMixin, AsyncActiveRecord): class BulkUser(IntegerPKMixin, ActiveRecord): - __table_name__ = "bulk_users" + @classmethod + def table_name(cls): + return "bulk_users" + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None @@ -792,7 +897,10 @@ class BulkUser(IntegerPKMixin, ActiveRecord): class AsyncBulkUser(IntegerPKMixin, AsyncActiveRecord): - __table_name__ = "bulk_users" + @classmethod + def table_name(cls): + return "bulk_users" + c: ClassVar[FieldProxy] = FieldProxy() id: int | None = None diff --git a/src/rhosocial/activerecord/testsuite/feature/basic/nopk/test_keyless_models.py b/src/rhosocial/activerecord/testsuite/feature/basic/nopk/test_keyless_models.py index 41f2821..b0b8d5a 100644 --- a/src/rhosocial/activerecord/testsuite/feature/basic/nopk/test_keyless_models.py +++ b/src/rhosocial/activerecord/testsuite/feature/basic/nopk/test_keyless_models.py @@ -24,30 +24,48 @@ class KeylessUser(ActiveRecord): """Mapped onto a keyless projection of the users table.""" - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() - __primary_key__ = None + @classmethod + def primary_key(cls): + return None + id: Optional[int] = None username: str = "" class KeylessReadOnlyUser(ActiveRecord, ReadOnlyMixin): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() - __primary_key__ = None + @classmethod + def primary_key(cls): + return None + id: Optional[int] = None username: str = "" class ReadOnlyWithKeyUser(ActiveRecord, ReadOnlyMixin): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None username: str = "" class NormalUser(ActiveRecord): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None username: str = "" diff --git a/src/rhosocial/activerecord/testsuite/feature/basic/nopk/test_keyless_models_async.py b/src/rhosocial/activerecord/testsuite/feature/basic/nopk/test_keyless_models_async.py index 3837df3..2d82d69 100644 --- a/src/rhosocial/activerecord/testsuite/feature/basic/nopk/test_keyless_models_async.py +++ b/src/rhosocial/activerecord/testsuite/feature/basic/nopk/test_keyless_models_async.py @@ -21,30 +21,48 @@ class AsyncKeylessUser(AsyncActiveRecord): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() - __primary_key__ = None + @classmethod + def primary_key(cls): + return None + id: Optional[int] = None username: str = "" class AsyncKeylessReadOnlyUser(AsyncActiveRecord, ReadOnlyMixin): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() - __primary_key__ = None + @classmethod + def primary_key(cls): + return None + id: Optional[int] = None username: str = "" class AsyncReadOnlyWithKeyUser(AsyncActiveRecord, ReadOnlyMixin): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None username: str = "" class AsyncNormalUser(AsyncActiveRecord): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None username: str = "" diff --git a/src/rhosocial/activerecord/testsuite/feature/basic/readonly/test_readonly_models.py b/src/rhosocial/activerecord/testsuite/feature/basic/readonly/test_readonly_models.py index b9f1b08..e7d34f2 100644 --- a/src/rhosocial/activerecord/testsuite/feature/basic/readonly/test_readonly_models.py +++ b/src/rhosocial/activerecord/testsuite/feature/basic/readonly/test_readonly_models.py @@ -26,29 +26,43 @@ class ReadOnlyUser(ActiveRecord, ReadOnlyMixin): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None username: str = "" class WritableUser(ActiveRecord): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None username: str = "" class OptedOutUser(ActiveRecord, ReadOnlyMixin): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None username: str = "" - __read_only__ = False + @classmethod + def read_only(cls): + return False class ImplementsButWritable(ActiveRecord, IReadOnlyBehavior): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None username: str = "" @@ -57,7 +71,10 @@ class ImplementsButWritable(ActiveRecord, IReadOnlyBehavior): class ReadOnlyView(ActiveRecord, ReadOnlyMixin): """A read-only model that declares it maps a view.""" - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None username: str = "" diff --git a/src/rhosocial/activerecord/testsuite/feature/basic/readonly/test_readonly_models_async.py b/src/rhosocial/activerecord/testsuite/feature/basic/readonly/test_readonly_models_async.py index 2459966..4b6af9d 100644 --- a/src/rhosocial/activerecord/testsuite/feature/basic/readonly/test_readonly_models_async.py +++ b/src/rhosocial/activerecord/testsuite/feature/basic/readonly/test_readonly_models_async.py @@ -19,36 +19,53 @@ class AsyncReadOnlyUser(AsyncActiveRecord, ReadOnlyMixin): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None username: str = "" class AsyncWritableUser(AsyncActiveRecord): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None username: str = "" class AsyncOptedOutUser(AsyncActiveRecord, ReadOnlyMixin): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None username: str = "" - __read_only__ = False + @classmethod + def read_only(cls): + return False class AsyncImplementsButWritable(AsyncActiveRecord, IReadOnlyBehavior): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None username: str = "" class AsyncReadOnlyView(AsyncActiveRecord, ReadOnlyMixin): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None username: str = "" diff --git a/src/rhosocial/activerecord/testsuite/feature/basic/validation/test_pydantic_native_validation.py b/src/rhosocial/activerecord/testsuite/feature/basic/validation/test_pydantic_native_validation.py index d07eb3c..c753fc0 100644 --- a/src/rhosocial/activerecord/testsuite/feature/basic/validation/test_pydantic_native_validation.py +++ b/src/rhosocial/activerecord/testsuite/feature/basic/validation/test_pydantic_native_validation.py @@ -21,7 +21,9 @@ class MutableDefaultModel(ActiveRecord): """Model for Pydantic mutable default isolation tests.""" - __table_name__ = "mutable_default_models" + @classmethod + def table_name(cls): + return "mutable_default_models" tags: List[str] = Field(default_factory=list) metadata: Dict[str, Any] = Field(default_factory=dict) @@ -29,7 +31,9 @@ class MutableDefaultModel(ActiveRecord): class AsyncMutableDefaultModel(AsyncActiveRecord): """Async model for Pydantic mutable default isolation tests.""" - __table_name__ = "mutable_default_models" + @classmethod + def table_name(cls): + return "mutable_default_models" tags: List[str] = Field(default_factory=list) metadata: Dict[str, Any] = Field(default_factory=dict) @@ -37,7 +41,9 @@ class AsyncMutableDefaultModel(AsyncActiveRecord): class LifecycleModel(ActiveRecord): """Model for Pydantic lifecycle and unset/None tests.""" - __table_name__ = "lifecycle_models" + @classmethod + def table_name(cls): + return "lifecycle_models" required_name: str optional_note: Optional[str] = None @@ -60,7 +66,9 @@ def model_post_init(self, __context: object) -> None: class AsyncLifecycleModel(AsyncActiveRecord): """Async model for Pydantic lifecycle and unset/None tests.""" - __table_name__ = "lifecycle_models" + @classmethod + def table_name(cls): + return "lifecycle_models" required_name: str optional_note: Optional[str] = None @@ -83,7 +91,9 @@ def model_post_init(self, __context: object) -> None: class PydanticV2BoundaryModel(ActiveRecord): """Model for Pydantic v2 serialization and Annotated metadata boundary tests.""" - __table_name__ = "pydantic_v2_boundary_models" + @classmethod + def table_name(cls): + return "pydantic_v2_boundary_models" first_name: str last_name: str @@ -102,7 +112,9 @@ def serialize_score(self, value: Decimal) -> str: class AsyncPydanticV2BoundaryModel(AsyncActiveRecord): """Async model for Pydantic v2 serialization and Annotated metadata boundary tests.""" - __table_name__ = "pydantic_v2_boundary_models" + @classmethod + def table_name(cls): + return "pydantic_v2_boundary_models" first_name: str last_name: str @@ -128,17 +140,24 @@ class AliasBoundaryFieldsMixin: class AliasBoundaryModel(AliasBoundaryFieldsMixin, ActiveRecord): """Model for alias and UseColumn boundary tests.""" - __table_name__ = "alias_boundary_models" + @classmethod + def table_name(cls): + return "alias_boundary_models" class AsyncAliasBoundaryModel(AliasBoundaryFieldsMixin, AsyncActiveRecord): """Async model for alias and UseColumn boundary tests.""" - __table_name__ = "alias_boundary_models" + @classmethod + def table_name(cls): + return "alias_boundary_models" class ExtraForbidModel(ActiveRecord): """Model that rejects unknown Pydantic input fields.""" - __table_name__ = "extra_forbid_models" + @classmethod + def table_name(cls): + return "extra_forbid_models" + model_config = ConfigDict(extra="forbid") name: str @@ -146,7 +165,10 @@ class ExtraForbidModel(ActiveRecord): class AsyncExtraForbidModel(AsyncActiveRecord): """Async model that rejects unknown Pydantic input fields.""" - __table_name__ = "extra_forbid_models" + @classmethod + def table_name(cls): + return "extra_forbid_models" + model_config = ConfigDict(extra="forbid") name: str @@ -154,7 +176,10 @@ class AsyncExtraForbidModel(AsyncActiveRecord): class ExtraIgnoreModel(ActiveRecord): """Model that ignores unknown Pydantic input fields.""" - __table_name__ = "extra_ignore_models" + @classmethod + def table_name(cls): + return "extra_ignore_models" + model_config = ConfigDict(extra="ignore") name: str @@ -162,7 +187,10 @@ class ExtraIgnoreModel(ActiveRecord): class AsyncExtraIgnoreModel(AsyncActiveRecord): """Async model that ignores unknown Pydantic input fields.""" - __table_name__ = "extra_ignore_models" + @classmethod + def table_name(cls): + return "extra_ignore_models" + model_config = ConfigDict(extra="ignore") name: str @@ -170,7 +198,10 @@ class AsyncExtraIgnoreModel(AsyncActiveRecord): class ExtraAllowModel(ActiveRecord): """Model that keeps unknown Pydantic input fields as model extras.""" - __table_name__ = "extra_allow_models" + @classmethod + def table_name(cls): + return "extra_allow_models" + model_config = ConfigDict(extra="allow") name: str @@ -178,7 +209,10 @@ class ExtraAllowModel(ActiveRecord): class AsyncExtraAllowModel(AsyncActiveRecord): """Async model that keeps unknown Pydantic input fields as model extras.""" - __table_name__ = "extra_allow_models" + @classmethod + def table_name(cls): + return "extra_allow_models" + model_config = ConfigDict(extra="allow") name: str @@ -190,12 +224,16 @@ class StrictFieldsMixin: class StrictModel(StrictFieldsMixin, ActiveRecord): """Model for strict Pydantic validation tests.""" - __table_name__ = "strict_models" + @classmethod + def table_name(cls): + return "strict_models" class AsyncStrictModel(StrictFieldsMixin, AsyncActiveRecord): """Async model for strict Pydantic validation tests.""" - __table_name__ = "strict_models" + @classmethod + def table_name(cls): + return "strict_models" class ValidateDefaultFieldsMixin: positive_count: int = Field(default=0, gt=0, validate_default=True) @@ -203,12 +241,16 @@ class ValidateDefaultFieldsMixin: class ValidateDefaultModel(ValidateDefaultFieldsMixin, ActiveRecord): """Model for validate_default pipeline tests.""" - __table_name__ = "validate_default_models" + @classmethod + def table_name(cls): + return "validate_default_models" class AsyncValidateDefaultModel(ValidateDefaultFieldsMixin, AsyncActiveRecord): """Async model for validate_default pipeline tests.""" - __table_name__ = "validate_default_models" + @classmethod + def table_name(cls): + return "validate_default_models" class ValidatorModesFieldsMixin: raw_code: str @@ -238,12 +280,16 @@ def wrap_code(cls, value: Any, handler): class ValidatorModesModel(ValidatorModesFieldsMixin, ActiveRecord): """Model for Pydantic validator pipeline mode tests.""" - __table_name__ = "validator_modes_models" + @classmethod + def table_name(cls): + return "validator_modes_models" class AsyncValidatorModesModel(ValidatorModesFieldsMixin, AsyncActiveRecord): """Async model for Pydantic validator pipeline mode tests.""" - __table_name__ = "validator_modes_models" + @classmethod + def table_name(cls): + return "validator_modes_models" class RecordStatus(str, Enum): draft = "draft" @@ -263,12 +309,16 @@ class JsonContainerNestedFieldsMixin: class JsonContainerNestedModel(JsonContainerNestedFieldsMixin, ActiveRecord): """Model for JSON dump, enum, container, and nested model tests.""" - __table_name__ = "json_container_nested_models" + @classmethod + def table_name(cls): + return "json_container_nested_models" class AsyncJsonContainerNestedModel(JsonContainerNestedFieldsMixin, AsyncActiveRecord): """Async model for JSON dump, enum, container, and nested model tests.""" - __table_name__ = "json_container_nested_models" + @classmethod + def table_name(cls): + return "json_container_nested_models" class FromAttributesFieldsMixin: model_config = ConfigDict(from_attributes=True) @@ -279,12 +329,16 @@ class FromAttributesFieldsMixin: class FromAttributesModel(FromAttributesFieldsMixin, ActiveRecord): """Model for from_attributes construction tests.""" - __table_name__ = "from_attributes_models" + @classmethod + def table_name(cls): + return "from_attributes_models" class AsyncFromAttributesModel(FromAttributesFieldsMixin, AsyncActiveRecord): """Async model for from_attributes construction tests.""" - __table_name__ = "from_attributes_models" + @classmethod + def table_name(cls): + return "from_attributes_models" class AnnotatedMetadataOrderFieldsMixin: field_first: Annotated[str, Field(min_length=2), UseColumn("field_first_col")] @@ -293,12 +347,16 @@ class AnnotatedMetadataOrderFieldsMixin: class AnnotatedMetadataOrderModel(AnnotatedMetadataOrderFieldsMixin, ActiveRecord): """Model for Annotated metadata ordering tests.""" - __table_name__ = "annotated_metadata_order_models" + @classmethod + def table_name(cls): + return "annotated_metadata_order_models" class AsyncAnnotatedMetadataOrderModel(AnnotatedMetadataOrderFieldsMixin, AsyncActiveRecord): """Async model for Annotated metadata ordering tests.""" - __table_name__ = "annotated_metadata_order_models" + @classmethod + def table_name(cls): + return "annotated_metadata_order_models" class AliasUseColumnConflictFieldsMixin: model_config = ConfigDict(populate_by_name=True) @@ -310,12 +368,16 @@ class AliasUseColumnConflictFieldsMixin: class AliasUseColumnConflictModel(AliasUseColumnConflictFieldsMixin, ActiveRecord): """Model for alias and UseColumn conflict boundary tests.""" - __table_name__ = "alias_use_column_conflict_models" + @classmethod + def table_name(cls): + return "alias_use_column_conflict_models" class AsyncAliasUseColumnConflictModel(AliasUseColumnConflictFieldsMixin, AsyncActiveRecord): """Async model for alias and UseColumn conflict boundary tests.""" - __table_name__ = "alias_use_column_conflict_models" + @classmethod + def table_name(cls): + return "alias_use_column_conflict_models" class AssignmentValidationFieldsMixin: model_config = ConfigDict(validate_assignment=True) @@ -326,12 +388,16 @@ class AssignmentValidationFieldsMixin: class AssignmentValidationModel(AssignmentValidationFieldsMixin, ActiveRecord): """Model for assignment validation and dirty tracking tests.""" - __table_name__ = "assignment_validation_models" + @classmethod + def table_name(cls): + return "assignment_validation_models" class AsyncAssignmentValidationModel(AssignmentValidationFieldsMixin, AsyncActiveRecord): """Async model for assignment validation and dirty tracking tests.""" - __table_name__ = "assignment_validation_models" + @classmethod + def table_name(cls): + return "assignment_validation_models" def valid_pydantic_data(): diff --git a/src/rhosocial/activerecord/testsuite/feature/basic/validation/test_pydantic_native_validation_async.py b/src/rhosocial/activerecord/testsuite/feature/basic/validation/test_pydantic_native_validation_async.py index 17582cc..7957fc0 100644 --- a/src/rhosocial/activerecord/testsuite/feature/basic/validation/test_pydantic_native_validation_async.py +++ b/src/rhosocial/activerecord/testsuite/feature/basic/validation/test_pydantic_native_validation_async.py @@ -21,7 +21,9 @@ class MutableDefaultModel(ActiveRecord): """Model for Pydantic mutable default isolation tests.""" - __table_name__ = "mutable_default_models" + @classmethod + def table_name(cls): + return "mutable_default_models" tags: List[str] = Field(default_factory=list) metadata: Dict[str, Any] = Field(default_factory=dict) @@ -29,7 +31,9 @@ class MutableDefaultModel(ActiveRecord): class AsyncMutableDefaultModel(AsyncActiveRecord): """Async model for Pydantic mutable default isolation tests.""" - __table_name__ = "mutable_default_models" + @classmethod + def table_name(cls): + return "mutable_default_models" tags: List[str] = Field(default_factory=list) metadata: Dict[str, Any] = Field(default_factory=dict) @@ -37,7 +41,9 @@ class AsyncMutableDefaultModel(AsyncActiveRecord): class LifecycleModel(ActiveRecord): """Model for Pydantic lifecycle and unset/None tests.""" - __table_name__ = "lifecycle_models" + @classmethod + def table_name(cls): + return "lifecycle_models" required_name: str optional_note: Optional[str] = None @@ -60,7 +66,9 @@ def model_post_init(self, __context: object) -> None: class AsyncLifecycleModel(AsyncActiveRecord): """Async model for Pydantic lifecycle and unset/None tests.""" - __table_name__ = "lifecycle_models" + @classmethod + def table_name(cls): + return "lifecycle_models" required_name: str optional_note: Optional[str] = None @@ -83,7 +91,9 @@ def model_post_init(self, __context: object) -> None: class PydanticV2BoundaryModel(ActiveRecord): """Model for Pydantic v2 serialization and Annotated metadata boundary tests.""" - __table_name__ = "pydantic_v2_boundary_models" + @classmethod + def table_name(cls): + return "pydantic_v2_boundary_models" first_name: str last_name: str @@ -102,7 +112,9 @@ def serialize_score(self, value: Decimal) -> str: class AsyncPydanticV2BoundaryModel(AsyncActiveRecord): """Async model for Pydantic v2 serialization and Annotated metadata boundary tests.""" - __table_name__ = "pydantic_v2_boundary_models" + @classmethod + def table_name(cls): + return "pydantic_v2_boundary_models" first_name: str last_name: str @@ -128,17 +140,24 @@ class AliasBoundaryFieldsMixin: class AliasBoundaryModel(AliasBoundaryFieldsMixin, ActiveRecord): """Model for alias and UseColumn boundary tests.""" - __table_name__ = "alias_boundary_models" + @classmethod + def table_name(cls): + return "alias_boundary_models" class AsyncAliasBoundaryModel(AliasBoundaryFieldsMixin, AsyncActiveRecord): """Async model for alias and UseColumn boundary tests.""" - __table_name__ = "alias_boundary_models" + @classmethod + def table_name(cls): + return "alias_boundary_models" class ExtraForbidModel(ActiveRecord): """Model that rejects unknown Pydantic input fields.""" - __table_name__ = "extra_forbid_models" + @classmethod + def table_name(cls): + return "extra_forbid_models" + model_config = ConfigDict(extra="forbid") name: str @@ -146,7 +165,10 @@ class ExtraForbidModel(ActiveRecord): class AsyncExtraForbidModel(AsyncActiveRecord): """Async model that rejects unknown Pydantic input fields.""" - __table_name__ = "extra_forbid_models" + @classmethod + def table_name(cls): + return "extra_forbid_models" + model_config = ConfigDict(extra="forbid") name: str @@ -154,7 +176,10 @@ class AsyncExtraForbidModel(AsyncActiveRecord): class ExtraIgnoreModel(ActiveRecord): """Model that ignores unknown Pydantic input fields.""" - __table_name__ = "extra_ignore_models" + @classmethod + def table_name(cls): + return "extra_ignore_models" + model_config = ConfigDict(extra="ignore") name: str @@ -162,7 +187,10 @@ class ExtraIgnoreModel(ActiveRecord): class AsyncExtraIgnoreModel(AsyncActiveRecord): """Async model that ignores unknown Pydantic input fields.""" - __table_name__ = "extra_ignore_models" + @classmethod + def table_name(cls): + return "extra_ignore_models" + model_config = ConfigDict(extra="ignore") name: str @@ -170,7 +198,10 @@ class AsyncExtraIgnoreModel(AsyncActiveRecord): class ExtraAllowModel(ActiveRecord): """Model that keeps unknown Pydantic input fields as model extras.""" - __table_name__ = "extra_allow_models" + @classmethod + def table_name(cls): + return "extra_allow_models" + model_config = ConfigDict(extra="allow") name: str @@ -178,7 +209,10 @@ class ExtraAllowModel(ActiveRecord): class AsyncExtraAllowModel(AsyncActiveRecord): """Async model that keeps unknown Pydantic input fields as model extras.""" - __table_name__ = "extra_allow_models" + @classmethod + def table_name(cls): + return "extra_allow_models" + model_config = ConfigDict(extra="allow") name: str @@ -190,12 +224,16 @@ class StrictFieldsMixin: class StrictModel(StrictFieldsMixin, ActiveRecord): """Model for strict Pydantic validation tests.""" - __table_name__ = "strict_models" + @classmethod + def table_name(cls): + return "strict_models" class AsyncStrictModel(StrictFieldsMixin, AsyncActiveRecord): """Async model for strict Pydantic validation tests.""" - __table_name__ = "strict_models" + @classmethod + def table_name(cls): + return "strict_models" class ValidateDefaultFieldsMixin: positive_count: int = Field(default=0, gt=0, validate_default=True) @@ -203,12 +241,16 @@ class ValidateDefaultFieldsMixin: class ValidateDefaultModel(ValidateDefaultFieldsMixin, ActiveRecord): """Model for validate_default pipeline tests.""" - __table_name__ = "validate_default_models" + @classmethod + def table_name(cls): + return "validate_default_models" class AsyncValidateDefaultModel(ValidateDefaultFieldsMixin, AsyncActiveRecord): """Async model for validate_default pipeline tests.""" - __table_name__ = "validate_default_models" + @classmethod + def table_name(cls): + return "validate_default_models" class ValidatorModesFieldsMixin: raw_code: str @@ -238,12 +280,16 @@ def wrap_code(cls, value: Any, handler): class ValidatorModesModel(ValidatorModesFieldsMixin, ActiveRecord): """Model for Pydantic validator pipeline mode tests.""" - __table_name__ = "validator_modes_models" + @classmethod + def table_name(cls): + return "validator_modes_models" class AsyncValidatorModesModel(ValidatorModesFieldsMixin, AsyncActiveRecord): """Async model for Pydantic validator pipeline mode tests.""" - __table_name__ = "validator_modes_models" + @classmethod + def table_name(cls): + return "validator_modes_models" class RecordStatus(str, Enum): draft = "draft" @@ -263,12 +309,16 @@ class JsonContainerNestedFieldsMixin: class JsonContainerNestedModel(JsonContainerNestedFieldsMixin, ActiveRecord): """Model for JSON dump, enum, container, and nested model tests.""" - __table_name__ = "json_container_nested_models" + @classmethod + def table_name(cls): + return "json_container_nested_models" class AsyncJsonContainerNestedModel(JsonContainerNestedFieldsMixin, AsyncActiveRecord): """Async model for JSON dump, enum, container, and nested model tests.""" - __table_name__ = "json_container_nested_models" + @classmethod + def table_name(cls): + return "json_container_nested_models" class FromAttributesFieldsMixin: model_config = ConfigDict(from_attributes=True) @@ -279,12 +329,16 @@ class FromAttributesFieldsMixin: class FromAttributesModel(FromAttributesFieldsMixin, ActiveRecord): """Model for from_attributes construction tests.""" - __table_name__ = "from_attributes_models" + @classmethod + def table_name(cls): + return "from_attributes_models" class AsyncFromAttributesModel(FromAttributesFieldsMixin, AsyncActiveRecord): """Async model for from_attributes construction tests.""" - __table_name__ = "from_attributes_models" + @classmethod + def table_name(cls): + return "from_attributes_models" class AnnotatedMetadataOrderFieldsMixin: field_first: Annotated[str, Field(min_length=2), UseColumn("field_first_col")] @@ -293,12 +347,16 @@ class AnnotatedMetadataOrderFieldsMixin: class AnnotatedMetadataOrderModel(AnnotatedMetadataOrderFieldsMixin, ActiveRecord): """Model for Annotated metadata ordering tests.""" - __table_name__ = "annotated_metadata_order_models" + @classmethod + def table_name(cls): + return "annotated_metadata_order_models" class AsyncAnnotatedMetadataOrderModel(AnnotatedMetadataOrderFieldsMixin, AsyncActiveRecord): """Async model for Annotated metadata ordering tests.""" - __table_name__ = "annotated_metadata_order_models" + @classmethod + def table_name(cls): + return "annotated_metadata_order_models" class AliasUseColumnConflictFieldsMixin: model_config = ConfigDict(populate_by_name=True) @@ -310,12 +368,16 @@ class AliasUseColumnConflictFieldsMixin: class AliasUseColumnConflictModel(AliasUseColumnConflictFieldsMixin, ActiveRecord): """Model for alias and UseColumn conflict boundary tests.""" - __table_name__ = "alias_use_column_conflict_models" + @classmethod + def table_name(cls): + return "alias_use_column_conflict_models" class AsyncAliasUseColumnConflictModel(AliasUseColumnConflictFieldsMixin, AsyncActiveRecord): """Async model for alias and UseColumn conflict boundary tests.""" - __table_name__ = "alias_use_column_conflict_models" + @classmethod + def table_name(cls): + return "alias_use_column_conflict_models" class AssignmentValidationFieldsMixin: model_config = ConfigDict(validate_assignment=True) @@ -326,12 +388,16 @@ class AssignmentValidationFieldsMixin: class AssignmentValidationModel(AssignmentValidationFieldsMixin, ActiveRecord): """Model for assignment validation and dirty tracking tests.""" - __table_name__ = "assignment_validation_models" + @classmethod + def table_name(cls): + return "assignment_validation_models" class AsyncAssignmentValidationModel(AssignmentValidationFieldsMixin, AsyncActiveRecord): """Async model for assignment validation and dirty tracking tests.""" - __table_name__ = "assignment_validation_models" + @classmethod + def table_name(cls): + return "assignment_validation_models" def valid_pydantic_data(): start_at = datetime(2024, 1, 1, 10, 0, 0) diff --git a/src/rhosocial/activerecord/testsuite/feature/cli/fixtures.py b/src/rhosocial/activerecord/testsuite/feature/cli/fixtures.py index 2c39b29..da7d504 100644 --- a/src/rhosocial/activerecord/testsuite/feature/cli/fixtures.py +++ b/src/rhosocial/activerecord/testsuite/feature/cli/fixtures.py @@ -10,7 +10,10 @@ class CLIReadOnlyUser(ActiveRecord, ReadOnlyMixin): """Read-only view of the standard ``users`` table.""" - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + id: Optional[int] = None username: str = "" @@ -18,6 +21,9 @@ class CLIReadOnlyUser(ActiveRecord, ReadOnlyMixin): class AsyncCLIReadOnlyUser(AsyncActiveRecord, ReadOnlyMixin): """Async read-only view of the standard ``users`` table.""" - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + id: Optional[int] = None username: str = "" diff --git a/src/rhosocial/activerecord/testsuite/feature/ddl/fixtures/models.py b/src/rhosocial/activerecord/testsuite/feature/ddl/fixtures/models.py index 70bd57c..7f32f95 100644 --- a/src/rhosocial/activerecord/testsuite/feature/ddl/fixtures/models.py +++ b/src/rhosocial/activerecord/testsuite/feature/ddl/fixtures/models.py @@ -39,7 +39,10 @@ class BareItem(ActiveRecord): - __table_name__ = "ddl_bare_items" + @classmethod + def table_name(cls): + return "ddl_bare_items" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -50,7 +53,10 @@ class BareItem(ActiveRecord): class AsyncBareItem(AsyncActiveRecord): - __table_name__ = "ddl_bare_items" + @classmethod + def table_name(cls): + return "ddl_bare_items" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -61,7 +67,10 @@ class AsyncBareItem(AsyncActiveRecord): class SpecOrder(UUIDMixin, ActiveRecord): - __table_name__ = "ddl_spec_orders" + @classmethod + def table_name(cls): + return "ddl_spec_orders" + c: ClassVar[FieldProxy] = FieldProxy() code: Annotated[str, UseSqlType(VarCharType(length=32))] @@ -91,7 +100,10 @@ class SpecOrder(UUIDMixin, ActiveRecord): class AsyncSpecOrder(UUIDMixin, AsyncActiveRecord): - __table_name__ = "ddl_spec_orders" + @classmethod + def table_name(cls): + return "ddl_spec_orders" + c: ClassVar[FieldProxy] = FieldProxy() code: Annotated[str, UseSqlType(VarCharType(length=32))] @@ -121,7 +133,10 @@ class AsyncSpecOrder(UUIDMixin, AsyncActiveRecord): class CapabilityPost(ActiveRecord): - __table_name__ = "ddl_capability_posts" + @classmethod + def table_name(cls): + return "ddl_capability_posts" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -150,7 +165,10 @@ class CapabilityPost(ActiveRecord): class AsyncCapabilityPost(AsyncActiveRecord): - __table_name__ = "ddl_capability_posts" + @classmethod + def table_name(cls): + return "ddl_capability_posts" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -179,11 +197,19 @@ class AsyncCapabilityPost(AsyncActiveRecord): class SpecComment(ActiveRecord): - __table_name__ = "ddl_spec_comments" + @classmethod + def table_name(cls): + return "ddl_spec_comments" + c: ClassVar[FieldProxy] = FieldProxy() - __primary_key__ = "comment_id" - __pk_auto_generated__ = False + @classmethod + def primary_key(cls): + return "comment_id" + + @classmethod + def pk_auto_generated(cls): + return False comment_id: int order_id: UUID @@ -202,11 +228,19 @@ class SpecComment(ActiveRecord): class AsyncSpecComment(AsyncActiveRecord): - __table_name__ = "ddl_spec_comments" + @classmethod + def table_name(cls): + return "ddl_spec_comments" + c: ClassVar[FieldProxy] = FieldProxy() - __primary_key__ = "comment_id" - __pk_auto_generated__ = False + @classmethod + def primary_key(cls): + return "comment_id" + + @classmethod + def pk_auto_generated(cls): + return False comment_id: int order_id: UUID diff --git a/src/rhosocial/activerecord/testsuite/feature/ddl/test_ddl_source_contract.py b/src/rhosocial/activerecord/testsuite/feature/ddl/test_ddl_source_contract.py index 0bbc063..37c24e7 100644 --- a/src/rhosocial/activerecord/testsuite/feature/ddl/test_ddl_source_contract.py +++ b/src/rhosocial/activerecord/testsuite/feature/ddl/test_ddl_source_contract.py @@ -137,9 +137,18 @@ def second_generated(dialect): class ContractDeclarations: - __table_name__ = "ddl_contract_records" - __schema_name__ = "app" - __primary_key__ = "record_id" + @classmethod + def table_name(cls): + return "ddl_contract_records" + + @classmethod + def schema_name(cls): + return "app" + + @classmethod + def primary_key(cls): + return "record_id" + __table_constraints__ = [TABLE_CONSTRAINT] __table_indexes__ = [TABLE_INDEX] _feature_handlers = [DDLAnnotationHandler, BackendOptionHandler] @@ -209,7 +218,9 @@ class AsyncContractModel(ContractDeclarations, AsyncActiveRecord): class DerivedDeclarations: - __table_name__ = "ddl_contract_derived" + @classmethod + def table_name(cls): + return "ddl_contract_derived" id: int value: int @@ -231,8 +242,14 @@ class AsyncDerivedModel(DerivedDeclarations, AsyncActiveRecord): class CompositeDeclarations: - __table_name__ = "ddl_contract_composite" - __primary_key__ = ("left_id", "right_id") + @classmethod + def table_name(cls): + return "ddl_contract_composite" + + @classmethod + def primary_key(cls): + return ("left_id", "right_id") + __table_constraints__ = [COMPOSITE_PRIMARY_KEY] left_id: Annotated[int, UseColumn("left_id")] @@ -254,8 +271,14 @@ class AsyncCompositeModel(CompositeDeclarations, AsyncActiveRecord): class MismatchedCompositeDeclarations: - __table_name__ = "ddl_contract_mismatched_composite" - __primary_key__ = ("left_id", "right_id") + @classmethod + def table_name(cls): + return "ddl_contract_mismatched_composite" + + @classmethod + def primary_key(cls): + return ("left_id", "right_id") + __table_constraints__ = [MISMATCHED_PRIMARY_KEY] left_id: int @@ -267,8 +290,13 @@ class MismatchedCompositeModel(MismatchedCompositeDeclarations, ActiveRecord): class NullablePrimaryKeyDeclarations: - __table_name__ = "ddl_contract_nullable_primary_key" - __primary_key__ = "id" + @classmethod + def table_name(cls): + return "ddl_contract_nullable_primary_key" + + @classmethod + def primary_key(cls): + return "id" id: Annotated[Optional[int], UseConstraint(ColumnNullableConstraint)] = None @@ -278,8 +306,13 @@ class NullablePrimaryKeyModel(NullablePrimaryKeyDeclarations, ActiveRecord): class NotNullPrimaryKeyDeclarations: - __table_name__ = "ddl_contract_not_null_primary_key" - __primary_key__ = "id" + @classmethod + def table_name(cls): + return "ddl_contract_not_null_primary_key" + + @classmethod + def primary_key(cls): + return "id" id: Annotated[int, UseConstraint(ColumnNotNullConstraint)] @@ -289,21 +322,27 @@ class NotNullPrimaryKeyModel(NotNullPrimaryKeyDeclarations, ActiveRecord): class PlainModel(ActiveRecord): - __table_name__ = "ddl_contract_plain" + @classmethod + def table_name(cls): + return "ddl_contract_plain" id: int note: Optional[str] = None class AsyncPlainModel(AsyncActiveRecord): - __table_name__ = "ddl_contract_plain_async" + @classmethod + def table_name(cls): + return "ddl_contract_plain_async" id: int note: Optional[str] = None class ColumnTypeDeclarations: - __table_name__ = "ddl_contract_column_types" + @classmethod + def table_name(cls): + return "ddl_contract_column_types" record_id: Annotated[int, UseColumn("record_id")] payload: Annotated[dict, COLUMN_TYPE_PAYLOAD] @@ -325,7 +364,9 @@ class UnhandledAnnotation(DDLAnnotation): class UnhandledModel(ActiveRecord): - __table_name__ = "ddl_contract_unhandled" + @classmethod + def table_name(cls): + return "ddl_contract_unhandled" id: int value: Annotated[str, UnhandledAnnotation()] @@ -463,7 +504,9 @@ def test_contract_repeated_column_type_declarations_fail_explicitly(): """ class DoubleDeclared: - __table_name__ = "ddl_contract_double_column_types" + @classmethod + def table_name(cls): + return "ddl_contract_double_column_types" record_id: Annotated[int, UseColumn("record_id")] payload: Annotated[dict, UseColumnType(JSONColumn), UseColumnType(ArrayColumn)] diff --git a/src/rhosocial/activerecord/testsuite/feature/events/fixtures/models.py b/src/rhosocial/activerecord/testsuite/feature/events/fixtures/models.py index dac572e..b97b2b1 100644 --- a/src/rhosocial/activerecord/testsuite/feature/events/fixtures/models.py +++ b/src/rhosocial/activerecord/testsuite/feature/events/fixtures/models.py @@ -19,7 +19,9 @@ class EventTestModel(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """A model class for testing event mechanisms""" - __table_name__ = "event_tests" + @classmethod + def table_name(cls): + return "event_tests" id: Optional[int] = None name: str @@ -46,7 +48,9 @@ def clear_event_logs(self): class AsyncEventTestModel(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): """An async model class for testing event mechanisms""" - __table_name__ = "event_tests" + @classmethod + def table_name(cls): + return "event_tests" id: Optional[int] = None name: str @@ -73,7 +77,9 @@ def clear_event_logs(self): class EventTrackingModel(IntegerPKMixin, ActiveRecord): """A model for testing event tracking functionality.""" - __table_name__ = "event_tracking_models" + @classmethod + def table_name(cls): + return "event_tracking_models" title: str content: str diff --git a/src/rhosocial/activerecord/testsuite/feature/events/fixtures/models_py310.py b/src/rhosocial/activerecord/testsuite/feature/events/fixtures/models_py310.py index cdf5e8e..aef0167 100644 --- a/src/rhosocial/activerecord/testsuite/feature/events/fixtures/models_py310.py +++ b/src/rhosocial/activerecord/testsuite/feature/events/fixtures/models_py310.py @@ -27,7 +27,9 @@ class EventTestModel(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ - __table_name__ = "event_tests" + @classmethod + def table_name(cls): + return "event_tests" id: int | None = None name: str @@ -57,7 +59,9 @@ class EventTrackingModel(IntegerPKMixin, ActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ - __table_name__ = "event_tracking_models" + @classmethod + def table_name(cls): + return "event_tracking_models" title: str content: str diff --git a/src/rhosocial/activerecord/testsuite/feature/events/fixtures/models_py311.py b/src/rhosocial/activerecord/testsuite/feature/events/fixtures/models_py311.py index c95a2eb..66d2f42 100644 --- a/src/rhosocial/activerecord/testsuite/feature/events/fixtures/models_py311.py +++ b/src/rhosocial/activerecord/testsuite/feature/events/fixtures/models_py311.py @@ -29,7 +29,9 @@ class EventTestModel(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.11+ version using | syntax and Self type. """ - __table_name__ = "event_tests" + @classmethod + def table_name(cls): + return "event_tests" id: int | None = None name: str @@ -70,7 +72,9 @@ class EventTrackingModel(IntegerPKMixin, ActiveRecord): Python 3.11+ version using | syntax and Self type. """ - __table_name__ = "event_tracking_models" + @classmethod + def table_name(cls): + return "event_tracking_models" title: str content: str diff --git a/src/rhosocial/activerecord/testsuite/feature/events/fixtures/models_py312.py b/src/rhosocial/activerecord/testsuite/feature/events/fixtures/models_py312.py index 69fa115..46e687c 100644 --- a/src/rhosocial/activerecord/testsuite/feature/events/fixtures/models_py312.py +++ b/src/rhosocial/activerecord/testsuite/feature/events/fixtures/models_py312.py @@ -30,7 +30,9 @@ class EventTestModel(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ - __table_name__ = "event_tests" + @classmethod + def table_name(cls): + return "event_tests" id: int | None = None name: str @@ -71,7 +73,9 @@ class EventTrackingModel(IntegerPKMixin, ActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ - __table_name__ = "event_tracking_models" + @classmethod + def table_name(cls): + return "event_tracking_models" title: str content: str diff --git a/src/rhosocial/activerecord/testsuite/feature/mixins/fixtures/models.py b/src/rhosocial/activerecord/testsuite/feature/mixins/fixtures/models.py index 20da7db..6c76541 100644 --- a/src/rhosocial/activerecord/testsuite/feature/mixins/fixtures/models.py +++ b/src/rhosocial/activerecord/testsuite/feature/mixins/fixtures/models.py @@ -18,7 +18,9 @@ class TimestampedPost(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """Blog post model with timestamps""" - __table_name__ = "timestamped_posts" + @classmethod + def table_name(cls): + return "timestamped_posts" id: Optional[int] = None title: str @@ -27,7 +29,9 @@ class TimestampedPost(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): class VersionedProduct(IntegerPKMixin, DefaultOptimisticLockMixin, ActiveRecord): """Product model with optimistic locking""" - __table_name__ = "versioned_products" + @classmethod + def table_name(cls): + return "versioned_products" id: Optional[int] = None name: str @@ -36,7 +40,9 @@ class VersionedProduct(IntegerPKMixin, DefaultOptimisticLockMixin, ActiveRecord) class Task(IntegerPKMixin, DefaultSoftDeleteMixin, ActiveRecord): """Task model supporting soft deletion""" - __table_name__ = "tasks" + @classmethod + def table_name(cls): + return "tasks" id: Optional[int] = None title: str @@ -45,7 +51,9 @@ class Task(IntegerPKMixin, DefaultSoftDeleteMixin, ActiveRecord): class CombinedArticle(IntegerPKMixin, DefaultTimestampMixin, DefaultOptimisticLockMixin, DefaultSoftDeleteMixin, ActiveRecord): """Article model combining all mixins""" - __table_name__ = "combined_articles" + @classmethod + def table_name(cls): + return "combined_articles" id: Optional[int] = None title: str @@ -55,7 +63,9 @@ class CombinedArticle(IntegerPKMixin, DefaultTimestampMixin, DefaultOptimisticLo class AsyncTimestampedPost(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): """Blog post model with timestamps (async version)""" - __table_name__ = "timestamped_posts" + @classmethod + def table_name(cls): + return "timestamped_posts" id: Optional[int] = None title: str @@ -64,7 +74,9 @@ class AsyncTimestampedPost(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRec class AsyncVersionedProduct(IntegerPKMixin, DefaultOptimisticLockMixin, AsyncActiveRecord): """Product model with optimistic locking (async version)""" - __table_name__ = "versioned_products" + @classmethod + def table_name(cls): + return "versioned_products" id: Optional[int] = None name: str @@ -73,7 +85,9 @@ class AsyncVersionedProduct(IntegerPKMixin, DefaultOptimisticLockMixin, AsyncAct class AsyncTask(IntegerPKMixin, DefaultAsyncSoftDeleteMixin, AsyncActiveRecord): """Task model supporting soft deletion (async version)""" - __table_name__ = "tasks" + @classmethod + def table_name(cls): + return "tasks" id: Optional[int] = None title: str @@ -82,7 +96,9 @@ class AsyncTask(IntegerPKMixin, DefaultAsyncSoftDeleteMixin, AsyncActiveRecord): class AsyncCombinedArticle(IntegerPKMixin, DefaultTimestampMixin, DefaultOptimisticLockMixin, DefaultAsyncSoftDeleteMixin, AsyncActiveRecord): """Article model combining all mixins (async version)""" - __table_name__ = "combined_articles" + @classmethod + def table_name(cls): + return "combined_articles" id: Optional[int] = None title: str diff --git a/src/rhosocial/activerecord/testsuite/feature/mixins/fixtures/models_py310.py b/src/rhosocial/activerecord/testsuite/feature/mixins/fixtures/models_py310.py index ea669a3..c5a6f8a 100644 --- a/src/rhosocial/activerecord/testsuite/feature/mixins/fixtures/models_py310.py +++ b/src/rhosocial/activerecord/testsuite/feature/mixins/fixtures/models_py310.py @@ -25,7 +25,9 @@ class TimestampedPost(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ - __table_name__ = "timestamped_posts" + @classmethod + def table_name(cls): + return "timestamped_posts" id: int | None = None title: str @@ -37,7 +39,9 @@ class VersionedProduct(IntegerPKMixin, DefaultOptimisticLockMixin, ActiveRecord) Python 3.10+ version using | syntax instead of Optional. """ - __table_name__ = "versioned_products" + @classmethod + def table_name(cls): + return "versioned_products" id: int | None = None name: str @@ -49,7 +53,9 @@ class Task(IntegerPKMixin, DefaultSoftDeleteMixin, ActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ - __table_name__ = "tasks" + @classmethod + def table_name(cls): + return "tasks" id: int | None = None title: str @@ -61,7 +67,9 @@ class CombinedArticle(IntegerPKMixin, DefaultTimestampMixin, DefaultOptimisticLo Python 3.10+ version using | syntax instead of Optional. """ - __table_name__ = "combined_articles" + @classmethod + def table_name(cls): + return "combined_articles" id: int | None = None title: str diff --git a/src/rhosocial/activerecord/testsuite/feature/mixins/fixtures/models_py311.py b/src/rhosocial/activerecord/testsuite/feature/mixins/fixtures/models_py311.py index 3942dd2..f9cf7e6 100644 --- a/src/rhosocial/activerecord/testsuite/feature/mixins/fixtures/models_py311.py +++ b/src/rhosocial/activerecord/testsuite/feature/mixins/fixtures/models_py311.py @@ -28,7 +28,9 @@ class TimestampedPost(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.11+ version using | syntax and Self type. """ - __table_name__ = "timestamped_posts" + @classmethod + def table_name(cls): + return "timestamped_posts" id: int | None = None title: str @@ -45,7 +47,9 @@ class VersionedProduct(IntegerPKMixin, DefaultOptimisticLockMixin, ActiveRecord) Python 3.11+ version using | syntax and Self type. """ - __table_name__ = "versioned_products" + @classmethod + def table_name(cls): + return "versioned_products" id: int | None = None name: str @@ -62,7 +66,9 @@ class Task(IntegerPKMixin, DefaultSoftDeleteMixin, ActiveRecord): Python 3.11+ version using | syntax and Self type. """ - __table_name__ = "tasks" + @classmethod + def table_name(cls): + return "tasks" id: int | None = None title: str @@ -84,7 +90,9 @@ class CombinedArticle(IntegerPKMixin, DefaultTimestampMixin, DefaultOptimisticLo Python 3.11+ version using | syntax and Self type. """ - __table_name__ = "combined_articles" + @classmethod + def table_name(cls): + return "combined_articles" id: int | None = None title: str diff --git a/src/rhosocial/activerecord/testsuite/feature/mixins/fixtures/models_py312.py b/src/rhosocial/activerecord/testsuite/feature/mixins/fixtures/models_py312.py index 5eefd20..716056d 100644 --- a/src/rhosocial/activerecord/testsuite/feature/mixins/fixtures/models_py312.py +++ b/src/rhosocial/activerecord/testsuite/feature/mixins/fixtures/models_py312.py @@ -29,7 +29,9 @@ class TimestampedPost(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ - __table_name__ = "timestamped_posts" + @classmethod + def table_name(cls): + return "timestamped_posts" id: int | None = None title: str @@ -52,7 +54,9 @@ class VersionedProduct(IntegerPKMixin, DefaultOptimisticLockMixin, ActiveRecord) Python 3.12+ version using | syntax, Self type, and @override. """ - __table_name__ = "versioned_products" + @classmethod + def table_name(cls): + return "versioned_products" id: int | None = None name: str @@ -75,7 +79,9 @@ class Task(IntegerPKMixin, DefaultSoftDeleteMixin, ActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ - __table_name__ = "tasks" + @classmethod + def table_name(cls): + return "tasks" id: int | None = None title: str @@ -103,7 +109,9 @@ class CombinedArticle(IntegerPKMixin, DefaultTimestampMixin, DefaultOptimisticLo Python 3.12+ version using | syntax, Self type, and @override. """ - __table_name__ = "combined_articles" + @classmethod + def table_name(cls): + return "combined_articles" id: int | None = None title: str diff --git a/src/rhosocial/activerecord/testsuite/feature/query/cross_schema/mixed_schema_models.py b/src/rhosocial/activerecord/testsuite/feature/query/cross_schema/mixed_schema_models.py index 765a746..1ac0c19 100644 --- a/src/rhosocial/activerecord/testsuite/feature/query/cross_schema/mixed_schema_models.py +++ b/src/rhosocial/activerecord/testsuite/feature/query/cross_schema/mixed_schema_models.py @@ -16,10 +16,14 @@ class MixedSchemaOrder(Order): """Base ``orders`` fixture living in a non-default schema.""" - __schema_name__ = SCHEMA_A + @classmethod + def schema_name(cls): + return SCHEMA_A class AsyncMixedSchemaOrder(AsyncOrder): """Async variant of ``MixedSchemaOrder``.""" - __schema_name__ = SCHEMA_A + @classmethod + def schema_name(cls): + return SCHEMA_A diff --git a/src/rhosocial/activerecord/testsuite/feature/query/fixtures/annotated_adapter_models.py b/src/rhosocial/activerecord/testsuite/feature/query/fixtures/annotated_adapter_models.py index dd67f2a..4b9f348 100644 --- a/src/rhosocial/activerecord/testsuite/feature/query/fixtures/annotated_adapter_models.py +++ b/src/rhosocial/activerecord/testsuite/feature/query/fixtures/annotated_adapter_models.py @@ -58,7 +58,10 @@ def supported_types(self) -> Dict[Type, Set[Type]]: class SearchableItem(IntegerPKMixin, ActiveRecord): """Model for testing Annotated Type Adapters.""" c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = 'searchable_items' + @classmethod + def table_name(cls): + return 'searchable_items' + id: Optional[int] = None name: str tags: Annotated[Optional[List[str]], UseAdapter(ListToStringAdapter(), str)] = None diff --git a/src/rhosocial/activerecord/testsuite/feature/query/fixtures/async_annotated_adapter_models.py b/src/rhosocial/activerecord/testsuite/feature/query/fixtures/async_annotated_adapter_models.py index 811147a..b169816 100644 --- a/src/rhosocial/activerecord/testsuite/feature/query/fixtures/async_annotated_adapter_models.py +++ b/src/rhosocial/activerecord/testsuite/feature/query/fixtures/async_annotated_adapter_models.py @@ -26,7 +26,9 @@ class AsyncSearchableItem(IntegerPKMixin, AsyncActiveRecord): """Async SearchableItem model for testing Annotated type adapters in queries.""" c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "searchable_items" + @classmethod + def table_name(cls): + return "searchable_items" id: Optional[int] = None name: str = "" diff --git a/src/rhosocial/activerecord/testsuite/feature/query/fixtures/async_cte_models.py b/src/rhosocial/activerecord/testsuite/feature/query/fixtures/async_cte_models.py index dc2cf6a..679bf9c 100644 --- a/src/rhosocial/activerecord/testsuite/feature/query/fixtures/async_cte_models.py +++ b/src/rhosocial/activerecord/testsuite/feature/query/fixtures/async_cte_models.py @@ -15,7 +15,9 @@ class AsyncNode(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): """Async Node model for tree structure tests (recursive CTEs).""" c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "nodes" + @classmethod + def table_name(cls): + return "nodes" id: Optional[int] = None name: str diff --git a/src/rhosocial/activerecord/testsuite/feature/query/fixtures/async_extended_models.py b/src/rhosocial/activerecord/testsuite/feature/query/fixtures/async_extended_models.py index 7a17f61..819f51e 100644 --- a/src/rhosocial/activerecord/testsuite/feature/query/fixtures/async_extended_models.py +++ b/src/rhosocial/activerecord/testsuite/feature/query/fixtures/async_extended_models.py @@ -15,7 +15,9 @@ class AsyncUser(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): """Async User model with basic relations.""" c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" id: Optional[int] = None username: str @@ -30,7 +32,9 @@ class AsyncUser(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): class AsyncExtendedOrder(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): """Async ExtendedOrder model with basic relations.""" c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "extended_orders" + @classmethod + def table_name(cls): + return "extended_orders" id: Optional[int] = None user_id: int @@ -52,7 +56,9 @@ class AsyncExtendedOrder(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecor class AsyncExtendedOrderItem(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): """Async ExtendedOrderItem model with basic relations.""" c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "extended_order_items" + @classmethod + def table_name(cls): + return "extended_order_items" id: Optional[int] = None order_id: int diff --git a/src/rhosocial/activerecord/testsuite/feature/query/fixtures/async_json_models.py b/src/rhosocial/activerecord/testsuite/feature/query/fixtures/async_json_models.py index 9ff7e08..aa5d822 100644 --- a/src/rhosocial/activerecord/testsuite/feature/query/fixtures/async_json_models.py +++ b/src/rhosocial/activerecord/testsuite/feature/query/fixtures/async_json_models.py @@ -13,7 +13,9 @@ class AsyncJsonUser(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): """Async User model specialized for JSON testing.""" c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "json_users" + @classmethod + def table_name(cls): + return "json_users" id: Optional[int] = None username: str diff --git a/src/rhosocial/activerecord/testsuite/feature/query/fixtures/async_models.py b/src/rhosocial/activerecord/testsuite/feature/query/fixtures/async_models.py index 6fc36fb..1f5a4bc 100644 --- a/src/rhosocial/activerecord/testsuite/feature/query/fixtures/async_models.py +++ b/src/rhosocial/activerecord/testsuite/feature/query/fixtures/async_models.py @@ -14,7 +14,10 @@ class AsyncUser(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): """Async User model with basic relations.""" - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -36,7 +39,10 @@ class AsyncUser(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): class AsyncOrder(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): """Async Order model with basic relations.""" - __table_name__ = "orders" + @classmethod + def table_name(cls): + return "orders" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -51,7 +57,10 @@ class AsyncOrder(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): class AsyncOrderItem(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): """Async Order item model with basic relations.""" - __table_name__ = "order_items" + @classmethod + def table_name(cls): + return "order_items" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -70,7 +79,10 @@ class AsyncProfile(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): Mirrors sync Profile for sync/async parity. Used for testing HasOne batch loading via with_(). """ - __table_name__ = "profiles" + @classmethod + def table_name(cls): + return "profiles" + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -87,7 +99,9 @@ class AsyncProfile(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): class AsyncPost(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): """Async Post model with basic relations.""" c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" id: Optional[int] = None user_id: int @@ -102,7 +116,9 @@ class AsyncPost(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): class AsyncComment(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): """Async Comment model with basic relations.""" c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "comments" + @classmethod + def table_name(cls): + return "comments" id: Optional[int] = None user_id: int diff --git a/src/rhosocial/activerecord/testsuite/feature/query/fixtures/cte_models.py b/src/rhosocial/activerecord/testsuite/feature/query/fixtures/cte_models.py index ce15495..6ba694a 100644 --- a/src/rhosocial/activerecord/testsuite/feature/query/fixtures/cte_models.py +++ b/src/rhosocial/activerecord/testsuite/feature/query/fixtures/cte_models.py @@ -15,7 +15,9 @@ class Node(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """Node model for tree structure tests (recursive CTEs).""" c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "nodes" + @classmethod + def table_name(cls): + return "nodes" id: Optional[int] = None name: str diff --git a/src/rhosocial/activerecord/testsuite/feature/query/fixtures/extended_models.py b/src/rhosocial/activerecord/testsuite/feature/query/fixtures/extended_models.py index 5b8739d..54e9c3e 100644 --- a/src/rhosocial/activerecord/testsuite/feature/query/fixtures/extended_models.py +++ b/src/rhosocial/activerecord/testsuite/feature/query/fixtures/extended_models.py @@ -15,7 +15,9 @@ class User(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """User model with basic relations.""" c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" id: Optional[int] = None username: str @@ -30,7 +32,9 @@ class User(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): class ExtendedOrder(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """Extended Order model with additional fields for advanced grouping tests.""" c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "extended_orders" + @classmethod + def table_name(cls): + return "extended_orders" id: Optional[int] = None user_id: int @@ -54,7 +58,9 @@ class ExtendedOrder(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): class ExtendedOrderItem(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """Extended Order item model with basic relations.""" c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "extended_order_items" + @classmethod + def table_name(cls): + return "extended_order_items" id: Optional[int] = None order_id: int diff --git a/src/rhosocial/activerecord/testsuite/feature/query/fixtures/models.py b/src/rhosocial/activerecord/testsuite/feature/query/fixtures/models.py index 41eb5ba..a4bd470 100644 --- a/src/rhosocial/activerecord/testsuite/feature/query/fixtures/models.py +++ b/src/rhosocial/activerecord/testsuite/feature/query/fixtures/models.py @@ -24,7 +24,9 @@ class User(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """User model with basic relations.""" c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" id: Optional[int] = None # Primary key, null for new records username: str # Required field @@ -52,7 +54,9 @@ class User(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): class JsonUser(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """User model specialized for JSON testing.""" c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "json_users" + @classmethod + def table_name(cls): + return "json_users" id: Optional[int] = None username: str @@ -72,7 +76,9 @@ class JsonUser(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): class Order(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """Order model with basic relations.""" c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "orders" + @classmethod + def table_name(cls): + return "orders" id: Optional[int] = None user_id: int @@ -87,7 +93,9 @@ class Order(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): class OrderItem(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """Order item model with basic relations.""" c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "order_items" + @classmethod + def table_name(cls): + return "order_items" id: Optional[int] = None order_id: int @@ -101,7 +109,9 @@ class OrderItem(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): class OrderWithCustomCache(Order): """Order model with custom TTL cache configuration.""" - __table_name__ = "orders" + @classmethod + def table_name(cls): + return "orders" user: ClassVar[BelongsTo['User']] = BelongsTo( foreign_key='user_id', @@ -111,7 +121,9 @@ class OrderWithCustomCache(Order): class OrderWithLimitedCache(Order): """Order model with limited cache size configuration.""" - __table_name__ = "orders" + @classmethod + def table_name(cls): + return "orders" user: ClassVar[BelongsTo['User']] = BelongsTo( foreign_key='user_id', @@ -121,7 +133,9 @@ class OrderWithLimitedCache(Order): class OrderWithComplexCache(Order): """Order model with complex cache configuration.""" - __table_name__ = "orders" + @classmethod + def table_name(cls): + return "orders" user: ClassVar[BelongsTo['User']] = BelongsTo( foreign_key='user_id', @@ -137,7 +151,9 @@ class OrderWithComplexCache(Order): class Post(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """Post model with user and comments relations.""" c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" id: Optional[int] = None user_id: int @@ -158,7 +174,9 @@ class Post(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): class Comment(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """Comment model with user and post relations.""" c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "comments" + @classmethod + def table_name(cls): + return "comments" id: Optional[int] = None user_id: int @@ -182,7 +200,9 @@ class Profile(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Used for testing HasOne batch loading via with_(). """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "profiles" + @classmethod + def table_name(cls): + return "profiles" id: Optional[int] = None user_id: int @@ -201,7 +221,9 @@ class MappedUser(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """User model with custom column name mappings for testing in query feature.""" c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" user_id: Annotated[Optional[int], UseColumn("id")] = None user_name: Annotated[str, UseColumn("username")] @@ -222,7 +244,9 @@ class MappedPost(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """Post model with custom column name mappings for testing in query feature.""" c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" post_id: Annotated[Optional[int], UseColumn("id")] = None author_id: Annotated[int, UseColumn("author")] @@ -245,7 +269,9 @@ class MappedComment(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """Comment model with custom column name mappings for testing in query feature.""" c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "comments" + @classmethod + def table_name(cls): + return "comments" comment_id: Annotated[Optional[int], UseColumn("id")] = None post_id: Annotated[int, UseColumn("post_ref")] @@ -272,7 +298,9 @@ class AsyncMappedUser(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" user_id: Annotated[Optional[int], UseColumn("id")] = None user_name: Annotated[str, UseColumn("username")] @@ -293,7 +321,9 @@ class AsyncMappedPost(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecord): """Async Post model with custom column name mappings for testing in query feature.""" c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" post_id: Annotated[Optional[int], UseColumn("id")] = None author_id: Annotated[int, UseColumn("author")] @@ -316,7 +346,9 @@ class AsyncMappedComment(IntegerPKMixin, DefaultTimestampMixin, AsyncActiveRecor """Async Comment model with custom column name mappings for testing in query feature.""" c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "comments" + @classmethod + def table_name(cls): + return "comments" comment_id: Annotated[Optional[int], UseColumn("id")] = None post_id: Annotated[int, UseColumn("post_ref")] diff --git a/src/rhosocial/activerecord/testsuite/feature/query/fixtures/models_py310.py b/src/rhosocial/activerecord/testsuite/feature/query/fixtures/models_py310.py index 4f037be..0a3186c 100644 --- a/src/rhosocial/activerecord/testsuite/feature/query/fixtures/models_py310.py +++ b/src/rhosocial/activerecord/testsuite/feature/query/fixtures/models_py310.py @@ -31,7 +31,9 @@ class User(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" id: int | None = None # Primary key, null for new records username: str # Required field @@ -62,7 +64,9 @@ class Profile(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "profiles" + @classmethod + def table_name(cls): + return "profiles" id: int | None = None user_id: int @@ -81,7 +85,9 @@ class JsonUser(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "json_users" + @classmethod + def table_name(cls): + return "json_users" id: int | None = None username: str @@ -104,7 +110,9 @@ class Order(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "orders" + @classmethod + def table_name(cls): + return "orders" id: int | None = None user_id: int @@ -122,7 +130,9 @@ class OrderItem(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "order_items" + @classmethod + def table_name(cls): + return "order_items" id: int | None = None order_id: int @@ -136,7 +146,9 @@ class OrderItem(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): class OrderWithCustomCache(Order): """Order model with custom TTL cache configuration.""" - __table_name__ = "orders" + @classmethod + def table_name(cls): + return "orders" user: ClassVar[BelongsTo['User']] = BelongsTo( foreign_key='user_id', @@ -146,7 +158,9 @@ class OrderWithCustomCache(Order): class OrderWithLimitedCache(Order): """Order model with limited cache size configuration.""" - __table_name__ = "orders" + @classmethod + def table_name(cls): + return "orders" user: ClassVar[BelongsTo['User']] = BelongsTo( foreign_key='user_id', @@ -156,7 +170,9 @@ class OrderWithLimitedCache(Order): class OrderWithComplexCache(Order): """Order model with complex cache configuration.""" - __table_name__ = "orders" + @classmethod + def table_name(cls): + return "orders" user: ClassVar[BelongsTo['User']] = BelongsTo( foreign_key='user_id', @@ -175,7 +191,9 @@ class Post(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" id: int | None = None user_id: int @@ -199,7 +217,9 @@ class Comment(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.10+ version using | syntax instead of Optional. """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "comments" + @classmethod + def table_name(cls): + return "comments" id: int | None = None user_id: int @@ -226,7 +246,9 @@ class MappedUser(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" user_id: Annotated[int | None, UseColumn("id")] = None user_name: Annotated[str, UseColumn("username")] @@ -250,7 +272,9 @@ class MappedPost(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" post_id: Annotated[int | None, UseColumn("id")] = None author_id: Annotated[int, UseColumn("author")] @@ -276,7 +300,9 @@ class MappedComment(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "comments" + @classmethod + def table_name(cls): + return "comments" comment_id: Annotated[int | None, UseColumn("id")] = None post_id: Annotated[int, UseColumn("post_ref")] diff --git a/src/rhosocial/activerecord/testsuite/feature/query/fixtures/models_py311.py b/src/rhosocial/activerecord/testsuite/feature/query/fixtures/models_py311.py index e12b058..2c6fda7 100644 --- a/src/rhosocial/activerecord/testsuite/feature/query/fixtures/models_py311.py +++ b/src/rhosocial/activerecord/testsuite/feature/query/fixtures/models_py311.py @@ -34,7 +34,9 @@ class User(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.11+ version using | syntax and Self type. """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" id: int | None = None # Primary key, null for new records username: str # Required field @@ -81,7 +83,9 @@ class Profile(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.11+ version using | syntax and Self type. """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "profiles" + @classmethod + def table_name(cls): + return "profiles" id: int | None = None user_id: int @@ -100,7 +104,9 @@ class JsonUser(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.11+ version using | syntax and Self type. """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "json_users" + @classmethod + def table_name(cls): + return "json_users" id: int | None = None username: str @@ -123,7 +129,9 @@ class Order(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.11+ version using | syntax and Self type. """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "orders" + @classmethod + def table_name(cls): + return "orders" id: int | None = None user_id: int @@ -146,7 +154,9 @@ class OrderItem(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.11+ version using | syntax and Self type. """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "order_items" + @classmethod + def table_name(cls): + return "order_items" id: int | None = None order_id: int @@ -160,7 +170,9 @@ class OrderItem(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): class OrderWithCustomCache(Order): """Order model with custom TTL cache configuration.""" - __table_name__ = "orders" + @classmethod + def table_name(cls): + return "orders" user: ClassVar[BelongsTo['User']] = BelongsTo( foreign_key='user_id', @@ -170,7 +182,9 @@ class OrderWithCustomCache(Order): class OrderWithLimitedCache(Order): """Order model with limited cache size configuration.""" - __table_name__ = "orders" + @classmethod + def table_name(cls): + return "orders" user: ClassVar[BelongsTo['User']] = BelongsTo( foreign_key='user_id', @@ -180,7 +194,9 @@ class OrderWithLimitedCache(Order): class OrderWithComplexCache(Order): """Order model with complex cache configuration.""" - __table_name__ = "orders" + @classmethod + def table_name(cls): + return "orders" user: ClassVar[BelongsTo['User']] = BelongsTo( foreign_key='user_id', @@ -199,7 +215,9 @@ class Post(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.11+ version using | syntax and Self type. """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" id: int | None = None user_id: int @@ -228,7 +246,9 @@ class Comment(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.11+ version using | syntax and Self type. """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "comments" + @classmethod + def table_name(cls): + return "comments" id: int | None = None user_id: int @@ -265,7 +285,9 @@ class MappedUser(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" user_id: Annotated[int | None, UseColumn("id")] = None user_name: Annotated[str, UseColumn("username")] @@ -289,7 +311,9 @@ class MappedPost(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" post_id: Annotated[int | None, UseColumn("id")] = None author_id: Annotated[int, UseColumn("author")] @@ -315,7 +339,9 @@ class MappedComment(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "comments" + @classmethod + def table_name(cls): + return "comments" comment_id: Annotated[int | None, UseColumn("id")] = None post_id: Annotated[int, UseColumn("post_ref")] diff --git a/src/rhosocial/activerecord/testsuite/feature/query/fixtures/models_py312.py b/src/rhosocial/activerecord/testsuite/feature/query/fixtures/models_py312.py index 619ceca..f685166 100644 --- a/src/rhosocial/activerecord/testsuite/feature/query/fixtures/models_py312.py +++ b/src/rhosocial/activerecord/testsuite/feature/query/fixtures/models_py312.py @@ -36,7 +36,9 @@ class User(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" id: int | None = None # Primary key, null for new records username: str # Required field @@ -89,7 +91,9 @@ class Profile(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "profiles" + @classmethod + def table_name(cls): + return "profiles" id: int | None = None user_id: int @@ -108,7 +112,9 @@ class JsonUser(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "json_users" + @classmethod + def table_name(cls): + return "json_users" id: int | None = None username: str @@ -131,7 +137,9 @@ class Order(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "orders" + @classmethod + def table_name(cls): + return "orders" id: int | None = None user_id: int @@ -154,7 +162,9 @@ class OrderItem(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "order_items" + @classmethod + def table_name(cls): + return "order_items" id: int | None = None order_id: int @@ -168,7 +178,9 @@ class OrderItem(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): class OrderWithCustomCache(Order): """Order model with custom TTL cache configuration.""" - __table_name__ = "orders" + @classmethod + def table_name(cls): + return "orders" user: ClassVar[BelongsTo['User']] = BelongsTo( foreign_key='user_id', @@ -178,7 +190,9 @@ class OrderWithCustomCache(Order): class OrderWithLimitedCache(Order): """Order model with limited cache size configuration.""" - __table_name__ = "orders" + @classmethod + def table_name(cls): + return "orders" user: ClassVar[BelongsTo['User']] = BelongsTo( foreign_key='user_id', @@ -188,7 +202,9 @@ class OrderWithLimitedCache(Order): class OrderWithComplexCache(Order): """Order model with complex cache configuration.""" - __table_name__ = "orders" + @classmethod + def table_name(cls): + return "orders" user: ClassVar[BelongsTo['User']] = BelongsTo( foreign_key='user_id', @@ -207,7 +223,9 @@ class Post(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" id: int | None = None user_id: int @@ -236,7 +254,9 @@ class Comment(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "comments" + @classmethod + def table_name(cls): + return "comments" id: int | None = None user_id: int @@ -273,7 +293,9 @@ class MappedUser(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" user_id: Annotated[int | None, UseColumn("id")] = None user_name: Annotated[str, UseColumn("username")] @@ -297,7 +319,9 @@ class MappedPost(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" post_id: Annotated[int | None, UseColumn("id")] = None author_id: Annotated[int, UseColumn("author")] @@ -323,7 +347,9 @@ class MappedComment(IntegerPKMixin, DefaultTimestampMixin, ActiveRecord): """ c: ClassVar[FieldProxy] = FieldProxy() - __table_name__ = "comments" + @classmethod + def table_name(cls): + return "comments" comment_id: Annotated[int | None, UseColumn("id")] = None post_id: Annotated[int, UseColumn("post_ref")] diff --git a/src/rhosocial/activerecord/testsuite/feature/query/fixtures/schema_models.py b/src/rhosocial/activerecord/testsuite/feature/query/fixtures/schema_models.py index 5c4f14b..ac1a65d 100644 --- a/src/rhosocial/activerecord/testsuite/feature/query/fixtures/schema_models.py +++ b/src/rhosocial/activerecord/testsuite/feature/query/fixtures/schema_models.py @@ -20,8 +20,14 @@ class SchemaCustomer(ActiveRecord): - __table_name__ = "customers" - __schema_name__ = SCHEMA_A + @classmethod + def table_name(cls): + return "customers" + + @classmethod + def schema_name(cls): + return SCHEMA_A + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -29,8 +35,14 @@ class SchemaCustomer(ActiveRecord): class SchemaOrder(ActiveRecord): - __table_name__ = "orders" - __schema_name__ = SCHEMA_B + @classmethod + def table_name(cls): + return "orders" + + @classmethod + def schema_name(cls): + return SCHEMA_B + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -39,8 +51,14 @@ class SchemaOrder(ActiveRecord): class AsyncSchemaCustomer(AsyncActiveRecord): - __table_name__ = "customers" - __schema_name__ = SCHEMA_A + @classmethod + def table_name(cls): + return "customers" + + @classmethod + def schema_name(cls): + return SCHEMA_A + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -48,8 +66,14 @@ class AsyncSchemaCustomer(AsyncActiveRecord): class AsyncSchemaOrder(AsyncActiveRecord): - __table_name__ = "orders" - __schema_name__ = SCHEMA_B + @classmethod + def table_name(cls): + return "orders" + + @classmethod + def schema_name(cls): + return SCHEMA_B + c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None diff --git a/src/rhosocial/activerecord/testsuite/feature/query/relations/test_relations_basic.py b/src/rhosocial/activerecord/testsuite/feature/query/relations/test_relations_basic.py index 586279e..4610eb2 100644 --- a/src/rhosocial/activerecord/testsuite/feature/query/relations/test_relations_basic.py +++ b/src/rhosocial/activerecord/testsuite/feature/query/relations/test_relations_basic.py @@ -53,7 +53,10 @@ def test_relation_inheritance(order_fixtures): # Define base class with relation class BaseOrder(ActiveRecord): - __table_name__ = 'orders' + @classmethod + def table_name(cls): + return 'orders' + __backend__ = Order.__backend__ user: ClassVar[BelongsTo['User']] = BelongsTo( foreign_key='user_id' @@ -88,13 +91,19 @@ def test_relation_registration(): """Test basic relation registration functionality.""" class User(ActiveRecord): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + id: Optional[int] = None username: str email: EmailStr class Post(ActiveRecord): - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" + id: Optional[int] = None user_id: int title: str @@ -111,13 +120,19 @@ def test_relation_cache_management(): """Test relation cache management.""" class User(ActiveRecord): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + id: Optional[int] = None username: str email: EmailStr class Post(ActiveRecord): - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" + id: Optional[int] = None user_id: int title: str @@ -143,13 +158,19 @@ def test_relation_descriptor_initialization(): """Test RelationDescriptor initialization and configuration.""" class User(ActiveRecord): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + id: Optional[int] = None username: str email: EmailStr class Post(ActiveRecord): - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" + id: Optional[int] = None user_id: int title: str @@ -171,13 +192,19 @@ def test_belongs_to_relation(): """Test BelongsTo relation functionality.""" class User(ActiveRecord): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + id: Optional[int] = None username: str email: EmailStr class Post(ActiveRecord): - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" + id: Optional[int] = None user_id: int title: str @@ -193,13 +220,19 @@ def test_has_many_relation(): """Test HasMany relation functionality.""" class Comment(ActiveRecord): - __table_name__ = "comments" + @classmethod + def table_name(cls): + return "comments" + id: Optional[int] = None post_id: int content: str class Post(ActiveRecord): - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" + id: Optional[int] = None title: str @@ -214,13 +247,19 @@ def test_has_one_relation(): """Test HasOne relation functionality.""" class Profile(ActiveRecord): - __table_name__ = "profiles" + @classmethod + def table_name(cls): + return "profiles" + id: Optional[int] = None user_id: int bio: str class User(ActiveRecord): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + id: Optional[int] = None username: str @@ -235,18 +274,27 @@ def test_multiple_relations_on_model(): """Test multiple relations on a single model.""" class User(ActiveRecord): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + id: Optional[int] = None username: str class Comment(ActiveRecord): - __table_name__ = "comments" + @classmethod + def table_name(cls): + return "comments" + id: Optional[int] = None post_id: int content: str class Post(ActiveRecord): - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" + id: Optional[int] = None user_id: int title: str @@ -266,7 +314,10 @@ def test_relation_inverse_of(): """Test inverse_of relation configuration.""" class User(ActiveRecord): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + id: Optional[int] = None username: str @@ -276,7 +327,10 @@ class User(ActiveRecord): ) class Post(ActiveRecord): - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" + id: Optional[int] = None user_id: int title: str @@ -297,12 +351,18 @@ def test_relation_query_method(): """Test relation query method generation.""" class User(ActiveRecord): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + id: Optional[int] = None username: str class Post(ActiveRecord): - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" + id: Optional[int] = None user_id: int title: str diff --git a/src/rhosocial/activerecord/testsuite/feature/query/relations/test_relations_basic_async.py b/src/rhosocial/activerecord/testsuite/feature/query/relations/test_relations_basic_async.py index df9a903..6b10143 100644 --- a/src/rhosocial/activerecord/testsuite/feature/query/relations/test_relations_basic_async.py +++ b/src/rhosocial/activerecord/testsuite/feature/query/relations/test_relations_basic_async.py @@ -53,7 +53,10 @@ async def test_relation_inheritance(async_order_fixtures): # Define base class with relation class BaseOrder(ActiveRecord): - __table_name__ = 'orders' + @classmethod + def table_name(cls): + return 'orders' + __backend__ = AsyncOrder.__backend__ user: ClassVar[BelongsTo['AsyncUser']] = BelongsTo( foreign_key='user_id' @@ -88,13 +91,19 @@ async def test_relation_registration(): """Test basic relation registration functionality.""" class AsyncUser(ActiveRecord): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + id: Optional[int] = None username: str email: EmailStr class AsyncPost(ActiveRecord): - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" + id: Optional[int] = None user_id: int title: str @@ -111,13 +120,19 @@ async def test_relation_cache_management(): """Test relation cache management.""" class AsyncUser(ActiveRecord): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + id: Optional[int] = None username: str email: EmailStr class AsyncPost(ActiveRecord): - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" + id: Optional[int] = None user_id: int title: str @@ -143,13 +158,19 @@ async def test_relation_descriptor_initialization(): """Test RelationDescriptor initialization and configuration.""" class AsyncUser(ActiveRecord): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + id: Optional[int] = None username: str email: EmailStr class AsyncPost(ActiveRecord): - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" + id: Optional[int] = None user_id: int title: str @@ -171,13 +192,19 @@ async def test_belongs_to_relation(): """Test BelongsTo relation functionality.""" class AsyncUser(ActiveRecord): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + id: Optional[int] = None username: str email: EmailStr class AsyncPost(ActiveRecord): - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" + id: Optional[int] = None user_id: int title: str @@ -193,13 +220,19 @@ async def test_has_many_relation(): """Test HasMany relation functionality.""" class AsyncComment(ActiveRecord): - __table_name__ = "comments" + @classmethod + def table_name(cls): + return "comments" + id: Optional[int] = None post_id: int content: str class AsyncPost(ActiveRecord): - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" + id: Optional[int] = None title: str @@ -214,13 +247,19 @@ async def test_has_one_relation(): """Test HasOne relation functionality.""" class AsyncProfile(ActiveRecord): - __table_name__ = "profiles" + @classmethod + def table_name(cls): + return "profiles" + id: Optional[int] = None user_id: int bio: str class AsyncUser(ActiveRecord): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + id: Optional[int] = None username: str @@ -235,18 +274,27 @@ async def test_multiple_relations_on_model(): """Test multiple relations on a single model.""" class AsyncUser(ActiveRecord): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + id: Optional[int] = None username: str class AsyncComment(ActiveRecord): - __table_name__ = "comments" + @classmethod + def table_name(cls): + return "comments" + id: Optional[int] = None post_id: int content: str class AsyncPost(ActiveRecord): - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" + id: Optional[int] = None user_id: int title: str @@ -266,7 +314,10 @@ async def test_relation_inverse_of(): """Test inverse_of relation configuration.""" class AsyncUser(ActiveRecord): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + id: Optional[int] = None username: str @@ -276,7 +327,10 @@ class AsyncUser(ActiveRecord): ) class AsyncPost(ActiveRecord): - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" + id: Optional[int] = None user_id: int title: str @@ -297,12 +351,18 @@ async def test_relation_query_method(): """Test relation query method generation.""" class AsyncUser(ActiveRecord): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" + id: Optional[int] = None username: str class AsyncPost(ActiveRecord): - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" + id: Optional[int] = None user_id: int title: str diff --git a/src/rhosocial/activerecord/testsuite/feature/query/typed_column/test_column_operations_core.py b/src/rhosocial/activerecord/testsuite/feature/query/typed_column/test_column_operations_core.py index 19976e3..9e0f93d 100644 --- a/src/rhosocial/activerecord/testsuite/feature/query/typed_column/test_column_operations_core.py +++ b/src/rhosocial/activerecord/testsuite/feature/query/typed_column/test_column_operations_core.py @@ -41,8 +41,14 @@ def model(dialect): """ class Operations(ActiveRecord): - __table_name__ = "core_column_operations" - __primary_key__: ClassVar[str] = "id" + @classmethod + def table_name(cls): + return "core_column_operations" + + @classmethod + def primary_key(cls): + return "id" + c: ClassVar[FieldProxy] = FieldProxy() id: int diff --git a/src/rhosocial/activerecord/testsuite/feature/relation/descriptors/test_descriptor_compat.py b/src/rhosocial/activerecord/testsuite/feature/relation/descriptors/test_descriptor_compat.py index 59d66ad..db201e5 100644 --- a/src/rhosocial/activerecord/testsuite/feature/relation/descriptors/test_descriptor_compat.py +++ b/src/rhosocial/activerecord/testsuite/feature/relation/descriptors/test_descriptor_compat.py @@ -21,7 +21,10 @@ def test_sync_belongs_to_on_async_model_raises(self): with pytest.raises(TypeError, match="Sync relation descriptor.*async model"): class AsyncB(AsyncActiveRecord): - __table_name__ = "compat_b" + @classmethod + def table_name(cls): + return "compat_b" + id: Optional[int] = None ref_id: int a: ClassVar[BelongsTo["AsyncA"]] = BelongsTo( @@ -35,7 +38,10 @@ def test_sync_has_many_on_async_model_raises(self): with pytest.raises(TypeError, match="Sync relation descriptor.*async model"): class AsyncP(AsyncActiveRecord): - __table_name__ = "compat_p" + @classmethod + def table_name(cls): + return "compat_p" + id: Optional[int] = None items: ClassVar[HasMany["AsyncC"]] = HasMany( foreign_key="parent_id", inverse_of=None @@ -48,7 +54,10 @@ def test_sync_has_one_on_async_model_raises(self): with pytest.raises(TypeError, match="Sync relation descriptor.*async model"): class AsyncU(AsyncActiveRecord): - __table_name__ = "compat_u" + @classmethod + def table_name(cls): + return "compat_u" + id: Optional[int] = None profile: ClassVar[HasOne["AsyncPr"]] = HasOne( foreign_key="user_id", inverse_of=None @@ -65,7 +74,10 @@ def test_async_belongs_to_on_sync_model_raises(self): with pytest.raises(TypeError, match="Async relation descriptor.*sync model"): class SyncB(ActiveRecord): - __table_name__ = "compat_sb" + @classmethod + def table_name(cls): + return "compat_sb" + id: Optional[int] = None ref_id: int a: ClassVar[AsyncBelongsTo["SyncA"]] = AsyncBelongsTo( @@ -79,7 +91,10 @@ def test_async_has_many_on_sync_model_raises(self): with pytest.raises(TypeError, match="Async relation descriptor.*sync model"): class SyncP(ActiveRecord): - __table_name__ = "compat_sp" + @classmethod + def table_name(cls): + return "compat_sp" + id: Optional[int] = None items: ClassVar[AsyncHasMany["SyncC"]] = AsyncHasMany( foreign_key="parent_id", inverse_of=None @@ -92,7 +107,10 @@ def test_async_has_one_on_sync_model_raises(self): with pytest.raises(TypeError, match="Async relation descriptor.*sync model"): class SyncU(ActiveRecord): - __table_name__ = "compat_su" + @classmethod + def table_name(cls): + return "compat_su" + id: Optional[int] = None profile: ClassVar[AsyncHasOne["SyncPr"]] = AsyncHasOne( foreign_key="user_id", inverse_of=None @@ -108,7 +126,10 @@ def test_sync_descriptor_on_sync_model_ok(self): from rhosocial.activerecord.relation.descriptors import BelongsTo class SyncB(ActiveRecord): - __table_name__ = "compat_nw_sb" + @classmethod + def table_name(cls): + return "compat_nw_sb" + id: Optional[int] = None ref_id: int a: ClassVar[BelongsTo["SyncA"]] = BelongsTo( @@ -121,7 +142,10 @@ def test_async_descriptor_on_async_model_ok(self): from rhosocial.activerecord.relation.async_descriptors import AsyncBelongsTo class AsyncB(AsyncActiveRecord): - __table_name__ = "compat_nw_ab" + @classmethod + def table_name(cls): + return "compat_nw_ab" + id: Optional[int] = None ref_id: int a: ClassVar[AsyncBelongsTo["AsyncA"]] = AsyncBelongsTo( diff --git a/src/rhosocial/activerecord/testsuite/feature/relation/descriptors/test_descriptor_compat_async.py b/src/rhosocial/activerecord/testsuite/feature/relation/descriptors/test_descriptor_compat_async.py index bfef108..5b7f481 100644 --- a/src/rhosocial/activerecord/testsuite/feature/relation/descriptors/test_descriptor_compat_async.py +++ b/src/rhosocial/activerecord/testsuite/feature/relation/descriptors/test_descriptor_compat_async.py @@ -21,7 +21,10 @@ async def test_sync_belongs_to_on_async_model_raises(self): with pytest.raises(TypeError, match="Sync relation descriptor.*async model"): class AsyncB(AsyncActiveRecord): - __table_name__ = "compat_b" + @classmethod + def table_name(cls): + return "compat_b" + id: Optional[int] = None ref_id: int a: ClassVar[BelongsTo["AsyncA"]] = BelongsTo( @@ -35,7 +38,10 @@ async def test_sync_has_many_on_async_model_raises(self): with pytest.raises(TypeError, match="Sync relation descriptor.*async model"): class AsyncP(AsyncActiveRecord): - __table_name__ = "compat_p" + @classmethod + def table_name(cls): + return "compat_p" + id: Optional[int] = None items: ClassVar[HasMany["AsyncC"]] = HasMany( foreign_key="parent_id", inverse_of=None @@ -48,7 +54,10 @@ async def test_sync_has_one_on_async_model_raises(self): with pytest.raises(TypeError, match="Sync relation descriptor.*async model"): class AsyncU(AsyncActiveRecord): - __table_name__ = "compat_u" + @classmethod + def table_name(cls): + return "compat_u" + id: Optional[int] = None profile: ClassVar[HasOne["AsyncPr"]] = HasOne( foreign_key="user_id", inverse_of=None @@ -65,7 +74,10 @@ async def test_async_belongs_to_on_sync_model_raises(self): with pytest.raises(TypeError, match="Async relation descriptor.*sync model"): class SyncB(ActiveRecord): - __table_name__ = "compat_sb" + @classmethod + def table_name(cls): + return "compat_sb" + id: Optional[int] = None ref_id: int a: ClassVar[AsyncBelongsTo["SyncA"]] = AsyncBelongsTo( @@ -79,7 +91,10 @@ async def test_async_has_many_on_sync_model_raises(self): with pytest.raises(TypeError, match="Async relation descriptor.*sync model"): class SyncP(ActiveRecord): - __table_name__ = "compat_sp" + @classmethod + def table_name(cls): + return "compat_sp" + id: Optional[int] = None items: ClassVar[AsyncHasMany["SyncC"]] = AsyncHasMany( foreign_key="parent_id", inverse_of=None @@ -92,7 +107,10 @@ async def test_async_has_one_on_sync_model_raises(self): with pytest.raises(TypeError, match="Async relation descriptor.*sync model"): class SyncU(ActiveRecord): - __table_name__ = "compat_su" + @classmethod + def table_name(cls): + return "compat_su" + id: Optional[int] = None profile: ClassVar[AsyncHasOne["SyncPr"]] = AsyncHasOne( foreign_key="user_id", inverse_of=None @@ -108,7 +126,10 @@ async def test_sync_descriptor_on_sync_model_ok(self): from rhosocial.activerecord.relation.descriptors import BelongsTo class SyncB(ActiveRecord): - __table_name__ = "compat_nw_sb" + @classmethod + def table_name(cls): + return "compat_nw_sb" + id: Optional[int] = None ref_id: int a: ClassVar[BelongsTo["SyncA"]] = BelongsTo( @@ -121,7 +142,10 @@ async def test_async_descriptor_on_async_model_ok(self): from rhosocial.activerecord.relation.async_descriptors import AsyncBelongsTo class AsyncB(AsyncActiveRecord): - __table_name__ = "compat_nw_ab" + @classmethod + def table_name(cls): + return "compat_nw_ab" + id: Optional[int] = None ref_id: int a: ClassVar[AsyncBelongsTo["AsyncA"]] = AsyncBelongsTo( diff --git a/src/rhosocial/activerecord/testsuite/feature/relation/descriptors/test_descriptors_async.py b/src/rhosocial/activerecord/testsuite/feature/relation/descriptors/test_descriptors_async.py index c8773dd..c59d261 100644 --- a/src/rhosocial/activerecord/testsuite/feature/relation/descriptors/test_descriptors_async.py +++ b/src/rhosocial/activerecord/testsuite/feature/relation/descriptors/test_descriptors_async.py @@ -56,7 +56,10 @@ async def test_belongs_to_on_model(self): from rhosocial.activerecord.model import AsyncActiveRecord class AsyncPost(AsyncActiveRecord): - __table_name__ = "desc_ab_post" + @classmethod + def table_name(cls): + return "desc_ab_post" + id: Optional[int] = None user_id: int user: ClassVar[AsyncBelongsTo["AsyncUser"]] = AsyncBelongsTo( @@ -72,7 +75,10 @@ async def test_has_many_on_model(self): from rhosocial.activerecord.model import AsyncActiveRecord class AsyncUser(AsyncActiveRecord): - __table_name__ = "desc_hm_user" + @classmethod + def table_name(cls): + return "desc_hm_user" + id: Optional[int] = None posts: ClassVar[AsyncHasMany["AsyncPost"]] = AsyncHasMany( foreign_key="user_id", inverse_of=None @@ -87,7 +93,10 @@ async def test_has_one_on_model(self): from rhosocial.activerecord.model import AsyncActiveRecord class AsyncUser(AsyncActiveRecord): - __table_name__ = "desc_ho_user" + @classmethod + def table_name(cls): + return "desc_ho_user" + id: Optional[int] = None profile: ClassVar[AsyncHasOne["AsyncProfile"]] = AsyncHasOne( foreign_key="user_id", inverse_of=None @@ -102,7 +111,10 @@ async def test_query_method_created(self): from rhosocial.activerecord.model import AsyncActiveRecord class AsyncUser(AsyncActiveRecord): - __table_name__ = "desc_qm_user" + @classmethod + def table_name(cls): + return "desc_qm_user" + id: Optional[int] = None posts: ClassVar[AsyncHasMany["AsyncPost"]] = AsyncHasMany( foreign_key="user_id", inverse_of=None diff --git a/src/rhosocial/activerecord/testsuite/feature/relation/fixtures/models.py b/src/rhosocial/activerecord/testsuite/feature/relation/fixtures/models.py index 955cab2..d6c64b8 100644 --- a/src/rhosocial/activerecord/testsuite/feature/relation/fixtures/models.py +++ b/src/rhosocial/activerecord/testsuite/feature/relation/fixtures/models.py @@ -24,7 +24,9 @@ # ── Basic Relation Models ──────────────────────────────── class Employee(ActiveRecord): - __table_name__ = "employees" + @classmethod + def table_name(cls): + return "employees" id: Optional[int] = None username: str @@ -37,7 +39,9 @@ class Employee(ActiveRecord): class Department(ActiveRecord): - __table_name__ = "departments" + @classmethod + def table_name(cls): + return "departments" id: Optional[int] = None name: str @@ -50,7 +54,9 @@ class Department(ActiveRecord): class Author(ActiveRecord): - __table_name__ = "authors" + @classmethod + def table_name(cls): + return "authors" id: Optional[int] = None name: str @@ -66,7 +72,9 @@ class Author(ActiveRecord): class Book(ActiveRecord): - __table_name__ = "books" + @classmethod + def table_name(cls): + return "books" id: Optional[int] = None title: str @@ -83,7 +91,9 @@ class Book(ActiveRecord): class Chapter(ActiveRecord): - __table_name__ = "chapters" + @classmethod + def table_name(cls): + return "chapters" id: Optional[int] = None title: str @@ -96,7 +106,9 @@ class Chapter(ActiveRecord): class Profile(ActiveRecord): - __table_name__ = "profiles" + @classmethod + def table_name(cls): + return "profiles" id: Optional[int] = None bio: str @@ -111,7 +123,9 @@ class Profile(ActiveRecord): # ── Advanced Relation Models (with FieldProxy, DerivedField, JSON) ── class User(ActiveRecord): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -142,7 +156,9 @@ class User(ActiveRecord): class Post(ActiveRecord): - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -184,7 +200,9 @@ class Post(ActiveRecord): class Comment(ActiveRecord): - __table_name__ = "comments" + @classmethod + def table_name(cls): + return "comments" c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -212,7 +230,9 @@ class Comment(ActiveRecord): # ── Async Models ───────────────────────────────────────── class AsyncUser(AsyncActiveRecord): - __table_name__ = "users" + @classmethod + def table_name(cls): + return "users" c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -239,7 +259,9 @@ class AsyncUser(AsyncActiveRecord): class AsyncPost(AsyncActiveRecord): - __table_name__ = "posts" + @classmethod + def table_name(cls): + return "posts" c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -276,7 +298,9 @@ class AsyncPost(AsyncActiveRecord): class AsyncComment(AsyncActiveRecord): - __table_name__ = "comments" + @classmethod + def table_name(cls): + return "comments" c: ClassVar[FieldProxy] = FieldProxy() id: Optional[int] = None @@ -301,7 +325,9 @@ class AsyncComment(AsyncActiveRecord): # ── Relation Boundary Models ────────────────────────────── class BoundaryOwner(ActiveRecord): - __table_name__ = "relation_boundary_owners" + @classmethod + def table_name(cls): + return "relation_boundary_owners" id: Optional[int] = None name: str @@ -317,7 +343,9 @@ class BoundaryOwner(ActiveRecord): class BoundaryProfile(ActiveRecord): - __table_name__ = "relation_boundary_profiles" + @classmethod + def table_name(cls): + return "relation_boundary_profiles" id: Optional[int] = None bio: str @@ -330,7 +358,9 @@ class BoundaryProfile(ActiveRecord): class BoundaryPost(ActiveRecord): - __table_name__ = "relation_boundary_posts" + @classmethod + def table_name(cls): + return "relation_boundary_posts" id: Optional[int] = None title: str @@ -343,7 +373,9 @@ class BoundaryPost(ActiveRecord): class AsyncBoundaryOwner(AsyncActiveRecord): - __table_name__ = "relation_boundary_owners" + @classmethod + def table_name(cls): + return "relation_boundary_owners" id: Optional[int] = None name: str @@ -359,7 +391,9 @@ class AsyncBoundaryOwner(AsyncActiveRecord): class AsyncBoundaryProfile(AsyncActiveRecord): - __table_name__ = "relation_boundary_profiles" + @classmethod + def table_name(cls): + return "relation_boundary_profiles" id: Optional[int] = None bio: str @@ -372,7 +406,9 @@ class AsyncBoundaryProfile(AsyncActiveRecord): class AsyncBoundaryPost(AsyncActiveRecord): - __table_name__ = "relation_boundary_posts" + @classmethod + def table_name(cls): + return "relation_boundary_posts" id: Optional[int] = None title: str diff --git a/src/rhosocial/activerecord/testsuite/feature/relation/fixtures/models_py310.py b/src/rhosocial/activerecord/testsuite/feature/relation/fixtures/models_py310.py index 20e1016..e91bf2c 100644 --- a/src/rhosocial/activerecord/testsuite/feature/relation/fixtures/models_py310.py +++ b/src/rhosocial/activerecord/testsuite/feature/relation/fixtures/models_py310.py @@ -22,7 +22,9 @@ class Employee(ActiveRecord): Python 3.10+ version. """ - __table_name__ = "employees" + @classmethod + def table_name(cls): + return "employees" id: int | None = None username: str @@ -40,7 +42,9 @@ class Department(ActiveRecord): Python 3.10+ version. """ - __table_name__ = "departments" + @classmethod + def table_name(cls): + return "departments" id: int | None = None name: str @@ -58,7 +62,9 @@ class Author(ActiveRecord): Python 3.10+ version. """ - __table_name__ = "authors" + @classmethod + def table_name(cls): + return "authors" id: int | None = None name: str @@ -79,7 +85,9 @@ class Book(ActiveRecord): Python 3.10+ version. """ - __table_name__ = "books" + @classmethod + def table_name(cls): + return "books" id: int | None = None title: str @@ -101,7 +109,9 @@ class Chapter(ActiveRecord): Python 3.10+ version. """ - __table_name__ = "chapters" + @classmethod + def table_name(cls): + return "chapters" id: int | None = None title: str @@ -119,7 +129,9 @@ class Profile(ActiveRecord): Python 3.10+ version. """ - __table_name__ = "profiles" + @classmethod + def table_name(cls): + return "profiles" id: int | None = None bio: str diff --git a/src/rhosocial/activerecord/testsuite/feature/relation/fixtures/models_py311.py b/src/rhosocial/activerecord/testsuite/feature/relation/fixtures/models_py311.py index a6835c3..ea692f3 100644 --- a/src/rhosocial/activerecord/testsuite/feature/relation/fixtures/models_py311.py +++ b/src/rhosocial/activerecord/testsuite/feature/relation/fixtures/models_py311.py @@ -25,7 +25,9 @@ class Employee(ActiveRecord): Python 3.11+ version using | syntax and Self type. """ - __table_name__ = "employees" + @classmethod + def table_name(cls): + return "employees" id: int | None = None username: str @@ -48,7 +50,9 @@ class Department(ActiveRecord): Python 3.11+ version using | syntax and Self type. """ - __table_name__ = "departments" + @classmethod + def table_name(cls): + return "departments" id: int | None = None name: str @@ -71,7 +75,9 @@ class Author(ActiveRecord): Python 3.11+ version using | syntax and Self type. """ - __table_name__ = "authors" + @classmethod + def table_name(cls): + return "authors" id: int | None = None name: str @@ -97,7 +103,9 @@ class Book(ActiveRecord): Python 3.11+ version using | syntax and Self type. """ - __table_name__ = "books" + @classmethod + def table_name(cls): + return "books" id: int | None = None title: str @@ -124,7 +132,9 @@ class Chapter(ActiveRecord): Python 3.11+ version using | syntax and Self type. """ - __table_name__ = "chapters" + @classmethod + def table_name(cls): + return "chapters" id: int | None = None title: str @@ -147,7 +157,9 @@ class Profile(ActiveRecord): Python 3.11+ version using | syntax and Self type. """ - __table_name__ = "profiles" + @classmethod + def table_name(cls): + return "profiles" id: int | None = None bio: str diff --git a/src/rhosocial/activerecord/testsuite/feature/relation/fixtures/models_py312.py b/src/rhosocial/activerecord/testsuite/feature/relation/fixtures/models_py312.py index 84ce68c..75a3906 100644 --- a/src/rhosocial/activerecord/testsuite/feature/relation/fixtures/models_py312.py +++ b/src/rhosocial/activerecord/testsuite/feature/relation/fixtures/models_py312.py @@ -26,7 +26,9 @@ class Employee(ActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ - __table_name__ = "employees" + @classmethod + def table_name(cls): + return "employees" id: int | None = None username: str @@ -55,7 +57,9 @@ class Department(ActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ - __table_name__ = "departments" + @classmethod + def table_name(cls): + return "departments" id: int | None = None name: str @@ -84,7 +88,9 @@ class Author(ActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ - __table_name__ = "authors" + @classmethod + def table_name(cls): + return "authors" id: int | None = None name: str @@ -116,7 +122,9 @@ class Book(ActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ - __table_name__ = "books" + @classmethod + def table_name(cls): + return "books" id: int | None = None title: str @@ -149,7 +157,9 @@ class Chapter(ActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ - __table_name__ = "chapters" + @classmethod + def table_name(cls): + return "chapters" id: int | None = None title: str @@ -178,7 +188,9 @@ class Profile(ActiveRecord): Python 3.12+ version using | syntax, Self type, and @override. """ - __table_name__ = "profiles" + @classmethod + def table_name(cls): + return "profiles" id: int | None = None bio: str diff --git a/src/rhosocial/activerecord/testsuite/feature/relation/validation/test_validator.py b/src/rhosocial/activerecord/testsuite/feature/relation/validation/test_validator.py index 21f09b5..6fa1c40 100644 --- a/src/rhosocial/activerecord/testsuite/feature/relation/validation/test_validator.py +++ b/src/rhosocial/activerecord/testsuite/feature/relation/validation/test_validator.py @@ -133,7 +133,10 @@ def test_async_belongs_to_has_many_valid(self): from rhosocial.activerecord.model import AsyncActiveRecord class AsyncRelated(AsyncActiveRecord): - __table_name__ = "v_abhm_rel" + @classmethod + def table_name(cls): + return "v_abhm_rel" + id: Optional[int] = None owner_id: int owner: ClassVar[AsyncBelongsTo["AsyncOwner"]] = AsyncBelongsTo( @@ -141,7 +144,10 @@ class AsyncRelated(AsyncActiveRecord): ) class AsyncOwner(AsyncActiveRecord): - __table_name__ = "v_abhm_own" + @classmethod + def table_name(cls): + return "v_abhm_own" + id: Optional[int] = None items: ClassVar[AsyncHasMany["AsyncRelated"]] = AsyncHasMany( foreign_key="owner_id", inverse_of="owner" @@ -156,7 +162,10 @@ def test_async_belongs_to_has_one_valid(self): from rhosocial.activerecord.model import AsyncActiveRecord class AsyncProfile(AsyncActiveRecord): - __table_name__ = "v_abho_pro" + @classmethod + def table_name(cls): + return "v_abho_pro" + id: Optional[int] = None user_id: int user: ClassVar[AsyncBelongsTo["AsyncUser"]] = AsyncBelongsTo( @@ -164,7 +173,10 @@ class AsyncProfile(AsyncActiveRecord): ) class AsyncUser(AsyncActiveRecord): - __table_name__ = "v_abho_usr" + @classmethod + def table_name(cls): + return "v_abho_usr" + id: Optional[int] = None profile: ClassVar[AsyncHasOne["AsyncProfile"]] = AsyncHasOne( foreign_key="user_id", inverse_of="user" @@ -179,7 +191,10 @@ def test_async_invalid_pair_raises(self): from rhosocial.activerecord.model import AsyncActiveRecord class AsyncOther(AsyncActiveRecord): - __table_name__ = "v_ip_oth" + @classmethod + def table_name(cls): + return "v_ip_oth" + id: Optional[int] = None ref_id: int item: ClassVar[AsyncBelongsTo["AsyncItem"]] = AsyncBelongsTo( @@ -187,7 +202,10 @@ class AsyncOther(AsyncActiveRecord): ) class AsyncItem(AsyncActiveRecord): - __table_name__ = "v_ip_itm" + @classmethod + def table_name(cls): + return "v_ip_itm" + id: Optional[int] = None other_id: int other: ClassVar[AsyncBelongsTo["AsyncOther"]] = AsyncBelongsTo( @@ -203,12 +221,18 @@ def test_async_missing_inverse_raises(self): from rhosocial.activerecord.model import AsyncActiveRecord class AsyncRelated(AsyncActiveRecord): - __table_name__ = "v_mi_rel" + @classmethod + def table_name(cls): + return "v_mi_rel" + id: Optional[int] = None owner_id: int class AsyncOwner(AsyncActiveRecord): - __table_name__ = "v_mi_own" + @classmethod + def table_name(cls): + return "v_mi_own" + id: Optional[int] = None items: ClassVar[AsyncHasMany["AsyncRelated"]] = AsyncHasMany( foreign_key="owner_id", inverse_of="nonexistent" @@ -223,7 +247,10 @@ def test_async_auto_set_inverse_of(self): from rhosocial.activerecord.model import AsyncActiveRecord class AsyncRelated(AsyncActiveRecord): - __table_name__ = "v_asi_rel" + @classmethod + def table_name(cls): + return "v_asi_rel" + id: Optional[int] = None owner_id: int owner: ClassVar[AsyncBelongsTo["AsyncOwner"]] = AsyncBelongsTo( @@ -231,7 +258,10 @@ class AsyncRelated(AsyncActiveRecord): ) class AsyncOwner(AsyncActiveRecord): - __table_name__ = "v_asi_own" + @classmethod + def table_name(cls): + return "v_asi_own" + id: Optional[int] = None items: ClassVar[AsyncHasMany["AsyncRelated"]] = AsyncHasMany( foreign_key="owner_id", inverse_of="owner" diff --git a/src/rhosocial/activerecord/testsuite/feature/relation/validation/test_validator_async.py b/src/rhosocial/activerecord/testsuite/feature/relation/validation/test_validator_async.py index 5fa91be..b01fbb5 100644 --- a/src/rhosocial/activerecord/testsuite/feature/relation/validation/test_validator_async.py +++ b/src/rhosocial/activerecord/testsuite/feature/relation/validation/test_validator_async.py @@ -139,7 +139,10 @@ async def test_async_belongs_to_has_many_valid(self): from rhosocial.activerecord.model import AsyncActiveRecord class AsyncRelated(AsyncActiveRecord): - __table_name__ = "v_abhm_rel" + @classmethod + def table_name(cls): + return "v_abhm_rel" + id: Optional[int] = None owner_id: int owner: ClassVar[AsyncBelongsTo["AsyncOwner"]] = AsyncBelongsTo( @@ -147,7 +150,10 @@ class AsyncRelated(AsyncActiveRecord): ) class AsyncOwner(AsyncActiveRecord): - __table_name__ = "v_abhm_own" + @classmethod + def table_name(cls): + return "v_abhm_own" + id: Optional[int] = None items: ClassVar[AsyncHasMany["AsyncRelated"]] = AsyncHasMany( foreign_key="owner_id", inverse_of="owner" @@ -163,7 +169,10 @@ async def test_async_belongs_to_has_one_valid(self): from rhosocial.activerecord.model import AsyncActiveRecord class AsyncProfile(AsyncActiveRecord): - __table_name__ = "v_abho_pro" + @classmethod + def table_name(cls): + return "v_abho_pro" + id: Optional[int] = None user_id: int user: ClassVar[AsyncBelongsTo["AsyncUser"]] = AsyncBelongsTo( @@ -171,7 +180,10 @@ class AsyncProfile(AsyncActiveRecord): ) class AsyncUser(AsyncActiveRecord): - __table_name__ = "v_abho_usr" + @classmethod + def table_name(cls): + return "v_abho_usr" + id: Optional[int] = None profile: ClassVar[AsyncHasOne["AsyncProfile"]] = AsyncHasOne( foreign_key="user_id", inverse_of="user" @@ -187,7 +199,10 @@ async def test_async_invalid_pair_raises(self): from rhosocial.activerecord.model import AsyncActiveRecord class AsyncOther(AsyncActiveRecord): - __table_name__ = "v_ip_oth" + @classmethod + def table_name(cls): + return "v_ip_oth" + id: Optional[int] = None ref_id: int item: ClassVar[AsyncBelongsTo["AsyncItem"]] = AsyncBelongsTo( @@ -195,7 +210,10 @@ class AsyncOther(AsyncActiveRecord): ) class AsyncItem(AsyncActiveRecord): - __table_name__ = "v_ip_itm" + @classmethod + def table_name(cls): + return "v_ip_itm" + id: Optional[int] = None other_id: int other: ClassVar[AsyncBelongsTo["AsyncOther"]] = AsyncBelongsTo( @@ -212,12 +230,18 @@ async def test_async_missing_inverse_raises(self): from rhosocial.activerecord.model import AsyncActiveRecord class AsyncRelated(AsyncActiveRecord): - __table_name__ = "v_mi_rel" + @classmethod + def table_name(cls): + return "v_mi_rel" + id: Optional[int] = None owner_id: int class AsyncOwner(AsyncActiveRecord): - __table_name__ = "v_mi_own" + @classmethod + def table_name(cls): + return "v_mi_own" + id: Optional[int] = None items: ClassVar[AsyncHasMany["AsyncRelated"]] = AsyncHasMany( foreign_key="owner_id", inverse_of="nonexistent" @@ -233,7 +257,10 @@ async def test_async_auto_set_inverse_of(self): from rhosocial.activerecord.model import AsyncActiveRecord class AsyncRelated(AsyncActiveRecord): - __table_name__ = "v_asi_rel" + @classmethod + def table_name(cls): + return "v_asi_rel" + id: Optional[int] = None owner_id: int owner: ClassVar[AsyncBelongsTo["AsyncOwner"]] = AsyncBelongsTo( @@ -241,7 +268,10 @@ class AsyncRelated(AsyncActiveRecord): ) class AsyncOwner(AsyncActiveRecord): - __table_name__ = "v_asi_own" + @classmethod + def table_name(cls): + return "v_asi_own" + id: Optional[int] = None items: ClassVar[AsyncHasMany["AsyncRelated"]] = AsyncHasMany( foreign_key="owner_id", inverse_of="owner" From 533ded8cc86404e4dc40530a2650f9c6662f19a8 Mon Sep 17 00:00:00 2001 From: Zhao vistart Date: Thu, 12 Nov 2026 14:48:27 +0800 Subject: [PATCH 2/2] chore: add changelog fragment for PR #32 --- changelog.d/32.removed.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/32.removed.md diff --git a/changelog.d/32.removed.md b/changelog.d/32.removed.md new file mode 100644 index 0000000..baa7ef2 --- /dev/null +++ b/changelog.d/32.removed.md @@ -0,0 +1 @@ +**Breaking:** the fixtures declare models by overriding accessors, following rhosocial-activerecord#140. `__table_name__`, `__primary_key__`, `__pk_auto_generated__` and the locator dunders are no longer read by the core release, so every fixture, provider model and embedded model source now overrides `table_name()`, `primary_key()`, `pk_auto_generated()` or the matching locator method instead; the composite-key contract tests assert `pk_auto_generated()` rather than the removed attribute. 534 declarations across 55 files. A backend that provides models of its own must follow the same shape: a model with no `table_name()` override fails with `NotImplementedError` at the first read.