diff --git a/changelog.d/37.changed.md b/changelog.d/37.changed.md new file mode 100644 index 00000000..357f3fd9 --- /dev/null +++ b/changelog.d/37.changed.md @@ -0,0 +1 @@ +Changed PostgresDialect to default to version=None instead of fixed version, requiring introspect_and_adapt() or explicit version before version-dependent features can be used. \ No newline at end of file diff --git a/src/rhosocial/activerecord/backend/impl/postgres/backend/async_backend.py b/src/rhosocial/activerecord/backend/impl/postgres/backend/async_backend.py index a3e8cc38..beca6fbc 100644 --- a/src/rhosocial/activerecord/backend/impl/postgres/backend/async_backend.py +++ b/src/rhosocial/activerecord/backend/impl/postgres/backend/async_backend.py @@ -138,8 +138,8 @@ def __init__(self, **kwargs): super().__init__(**kwargs) # Initialize PostgreSQL-specific components - # Use default version (9.6.0) - actual version detected via introspect_and_adapt() - self._dialect = PostgresDialect((9, 6, 0)) + # Version is None until introspect_and_adapt() is called + self._dialect = PostgresDialect() # Register PostgreSQL-specific type adapters (same as sync backend) # Note: XML adapter is NOT registered by default due to potential conflicts. diff --git a/src/rhosocial/activerecord/backend/impl/postgres/backend/sync.py b/src/rhosocial/activerecord/backend/impl/postgres/backend/sync.py index cf9b6d61..1c8eae2d 100644 --- a/src/rhosocial/activerecord/backend/impl/postgres/backend/sync.py +++ b/src/rhosocial/activerecord/backend/impl/postgres/backend/sync.py @@ -138,8 +138,8 @@ def __init__(self, **kwargs): super().__init__(**kwargs) # Initialize PostgreSQL-specific components - # Use default version (9.6.0) - actual version detected via introspect_and_adapt() - self._dialect = PostgresDialect((9, 6, 0)) + # Version is None until introspect_and_adapt() is called + self._dialect = PostgresDialect() # Register PostgreSQL-specific type adapters (same as async backend) # Note: XML adapter is NOT registered by default due to potential conflicts. diff --git a/src/rhosocial/activerecord/backend/impl/postgres/dialect.py b/src/rhosocial/activerecord/backend/impl/postgres/dialect.py index 2cd1804f..2e5a24f5 100644 --- a/src/rhosocial/activerecord/backend/impl/postgres/dialect.py +++ b/src/rhosocial/activerecord/backend/impl/postgres/dialect.py @@ -427,15 +427,19 @@ class PostgresDialect( Use introspect_and_adapt() to detect installed extensions automatically. """ - def __init__(self, version: Tuple[int, int, int] = (13, 0, 0)): + def __init__(self, version: Optional[Tuple[int, int, int]] = None): """ Initialize PostgreSQL dialect with specific version. Args: - version: PostgreSQL version tuple (major, minor, patch) + version: PostgreSQL version tuple (major, minor, patch). + If None, the dialect must be adapted via + backend.introspect_and_adapt() before version-dependent + features can be used. """ - self.version = version super().__init__() + if version is not None: + self.version = version @staticmethod def _validate_data_type(data_type: str) -> bool: diff --git a/tests/rhosocial/activerecord_postgres_test/feature/backend/test_dialect_function_support.py b/tests/rhosocial/activerecord_postgres_test/feature/backend/test_dialect_function_support.py index da6d08ea..84813be1 100644 --- a/tests/rhosocial/activerecord_postgres_test/feature/backend/test_dialect_function_support.py +++ b/tests/rhosocial/activerecord_postgres_test/feature/backend/test_dialect_function_support.py @@ -15,21 +15,21 @@ class TestPostgreSQLFunctionSupportBasic: def test_supports_functions_returns_dict(self): """Test that supports_functions returns a dictionary.""" - dialect = PostgresDialect() + dialect = PostgresDialect((13, 0, 0)) result = dialect.supports_functions() assert isinstance(result, dict) assert len(result) > 0 def test_supports_functions_all_values_are_support_info(self): """Test that all values in the returned dict are FunctionSupportInfo.""" - dialect = PostgresDialect() + dialect = PostgresDialect((13, 0, 0)) result = dialect.supports_functions() for func_name, info in result.items(): assert isinstance(info, FunctionSupportInfo), f"Value for {func_name} is not FunctionSupportInfo" def test_core_functions_always_supported(self): """Test that core functions are marked as supported.""" - dialect = PostgresDialect() + dialect = PostgresDialect((13, 0, 0)) result = dialect.supports_functions() core_functions = ["count", "sum_", "avg", "min_", "max_", "coalesce", "nullif"] for func in core_functions: @@ -231,7 +231,7 @@ def test_macaddr8_set7bit_requires_pg_10(self): def test_always_available_functions(self): """Test functions that are available in all PostgreSQL versions.""" - dialect = PostgresDialect() + dialect = PostgresDialect((13, 0, 0)) result = dialect.supports_functions() always_available = [ @@ -249,7 +249,7 @@ class TestPostgreSQLFunctionSupportPrivateMethod: def test_unknown_function_returns_true(self): """Test that unknown functions return True (no restriction).""" - dialect = PostgresDialect() + dialect = PostgresDialect((13, 0, 0)) result = dialect._is_postgres_function_supported("unknown_function_xyz") assert result is True @@ -277,7 +277,7 @@ class TestPostgreSQLFunctionSupportIntegration: def test_function_dict_contains_both_core_and_backend_functions(self): """Test that the result contains both core and PostgreSQL-specific functions.""" - dialect = PostgresDialect() + dialect = PostgresDialect((13, 0, 0)) result = dialect.supports_functions() assert any(func in result for func in ["count", "sum", "avg"]) diff --git a/tests/rhosocial/activerecord_postgres_test/feature/backend/test_postgres_dialect_security.py b/tests/rhosocial/activerecord_postgres_test/feature/backend/test_postgres_dialect_security.py index d4d6fab9..a5e7e836 100644 --- a/tests/rhosocial/activerecord_postgres_test/feature/backend/test_postgres_dialect_security.py +++ b/tests/rhosocial/activerecord_postgres_test/feature/backend/test_postgres_dialect_security.py @@ -23,7 +23,7 @@ @pytest.fixture def dialect(): """Create a PostgreSQL test dialect.""" - return PostgresDialect() + return PostgresDialect((13, 0, 0)) def test_postgres_escape_sql_string(dialect):