Skip to content

Commit 5b05ec7

Browse files
vistartclaude
andauthored
feat(dialect): require version adaptation before using Postgres dialect (#37)
* feat(dialect): require version adaptation before using Postgres dialect PostgresDialect now defaults to version=None, requiring introspect_and_adapt() or explicit version before version-dependent features can be used. This prevents silent SQL errors from incorrect version assumptions. - Change PostgresDialect.__init__ default version to None - Remove hardcoded (9, 6, 0) from backend dialect construction - Update tests to use explicit version (13, 0, 0) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * chore: add changelog fragment for PR #37 --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 9f117b5 commit 5b05ec7

6 files changed

Lines changed: 19 additions & 14 deletions

File tree

‎changelog.d/37.changed.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
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.

‎src/rhosocial/activerecord/backend/impl/postgres/backend/async_backend.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,8 @@ def __init__(self, **kwargs):
138138
super().__init__(**kwargs)
139139

140140
# Initialize PostgreSQL-specific components
141-
# Use default version (9.6.0) - actual version detected via introspect_and_adapt()
142-
self._dialect = PostgresDialect((9, 6, 0))
141+
# Version is None until introspect_and_adapt() is called
142+
self._dialect = PostgresDialect()
143143

144144
# Register PostgreSQL-specific type adapters (same as sync backend)
145145
# Note: XML adapter is NOT registered by default due to potential conflicts.

‎src/rhosocial/activerecord/backend/impl/postgres/backend/sync.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,8 @@ def __init__(self, **kwargs):
138138
super().__init__(**kwargs)
139139

140140
# Initialize PostgreSQL-specific components
141-
# Use default version (9.6.0) - actual version detected via introspect_and_adapt()
142-
self._dialect = PostgresDialect((9, 6, 0))
141+
# Version is None until introspect_and_adapt() is called
142+
self._dialect = PostgresDialect()
143143

144144
# Register PostgreSQL-specific type adapters (same as async backend)
145145
# Note: XML adapter is NOT registered by default due to potential conflicts.

‎src/rhosocial/activerecord/backend/impl/postgres/dialect.py‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -427,15 +427,19 @@ class PostgresDialect(
427427
Use introspect_and_adapt() to detect installed extensions automatically.
428428
"""
429429

430-
def __init__(self, version: Tuple[int, int, int] = (13, 0, 0)):
430+
def __init__(self, version: Optional[Tuple[int, int, int]] = None):
431431
"""
432432
Initialize PostgreSQL dialect with specific version.
433433
434434
Args:
435-
version: PostgreSQL version tuple (major, minor, patch)
435+
version: PostgreSQL version tuple (major, minor, patch).
436+
If None, the dialect must be adapted via
437+
backend.introspect_and_adapt() before version-dependent
438+
features can be used.
436439
"""
437-
self.version = version
438440
super().__init__()
441+
if version is not None:
442+
self.version = version
439443

440444
@staticmethod
441445
def _validate_data_type(data_type: str) -> bool:

‎tests/rhosocial/activerecord_postgres_test/feature/backend/test_dialect_function_support.py‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,21 @@ class TestPostgreSQLFunctionSupportBasic:
1515

1616
def test_supports_functions_returns_dict(self):
1717
"""Test that supports_functions returns a dictionary."""
18-
dialect = PostgresDialect()
18+
dialect = PostgresDialect((13, 0, 0))
1919
result = dialect.supports_functions()
2020
assert isinstance(result, dict)
2121
assert len(result) > 0
2222

2323
def test_supports_functions_all_values_are_support_info(self):
2424
"""Test that all values in the returned dict are FunctionSupportInfo."""
25-
dialect = PostgresDialect()
25+
dialect = PostgresDialect((13, 0, 0))
2626
result = dialect.supports_functions()
2727
for func_name, info in result.items():
2828
assert isinstance(info, FunctionSupportInfo), f"Value for {func_name} is not FunctionSupportInfo"
2929

3030
def test_core_functions_always_supported(self):
3131
"""Test that core functions are marked as supported."""
32-
dialect = PostgresDialect()
32+
dialect = PostgresDialect((13, 0, 0))
3333
result = dialect.supports_functions()
3434
core_functions = ["count", "sum_", "avg", "min_", "max_", "coalesce", "nullif"]
3535
for func in core_functions:
@@ -231,7 +231,7 @@ def test_macaddr8_set7bit_requires_pg_10(self):
231231

232232
def test_always_available_functions(self):
233233
"""Test functions that are available in all PostgreSQL versions."""
234-
dialect = PostgresDialect()
234+
dialect = PostgresDialect((13, 0, 0))
235235
result = dialect.supports_functions()
236236

237237
always_available = [
@@ -249,7 +249,7 @@ class TestPostgreSQLFunctionSupportPrivateMethod:
249249

250250
def test_unknown_function_returns_true(self):
251251
"""Test that unknown functions return True (no restriction)."""
252-
dialect = PostgresDialect()
252+
dialect = PostgresDialect((13, 0, 0))
253253
result = dialect._is_postgres_function_supported("unknown_function_xyz")
254254
assert result is True
255255

@@ -277,7 +277,7 @@ class TestPostgreSQLFunctionSupportIntegration:
277277

278278
def test_function_dict_contains_both_core_and_backend_functions(self):
279279
"""Test that the result contains both core and PostgreSQL-specific functions."""
280-
dialect = PostgresDialect()
280+
dialect = PostgresDialect((13, 0, 0))
281281
result = dialect.supports_functions()
282282

283283
assert any(func in result for func in ["count", "sum", "avg"])

‎tests/rhosocial/activerecord_postgres_test/feature/backend/test_postgres_dialect_security.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
@pytest.fixture
2424
def dialect():
2525
"""Create a PostgreSQL test dialect."""
26-
return PostgresDialect()
26+
return PostgresDialect((13, 0, 0))
2727

2828

2929
def test_postgres_escape_sql_string(dialect):

0 commit comments

Comments
 (0)