Skip to content

chore: Release v1.0.0.dev12 - #34

Merged
vistart merged 57 commits into
mainfrom
release/v1.0.0.dev12
May 1, 2026
Merged

vistart merged 57 commits into
mainfrom
release/v1.0.0.dev12

Conversation

@vistart

@vistart vistart commented May 1, 2026 •

Copy link
Copy Markdown
Contributor

Description

Release v1.0.0.dev12 for python-activerecord-postgres. This release includes named query/procedure CLI support, schema namespace support, 29 new PostgreSQL extension protocols/mixins, and various bug fixes and refactoring.

Release/Hotfix Details

Related Issues/PRs

Breaking Change

  • No
  • Yes

Testing

  • All CI checks passed on the source branch (release/v1.0.0.dev12).
  • Full test suite executed successfully (on .venv3.8 - .venv3.14).

Test Plan:

  • Executed full test suite with PYTHONPATH=src .venv3.8/bin/pytest tests/ -v --tb=short
  • All tests passed across Python 3.8-3.14

Checklist

Additional Notes

This is a development release (dev12) leading up to v1.0.0.

Commits included since v1.0.0.dev11 (55 commits):

  • Named query/procedure CLI subcommands
  • Schema namespace support
  • 29 new PostgreSQL extension protocols/mixins
  • ConcurrencyAware protocol
  • Various bug fixes and refactoring
  • CI improvements

vistart and others added 30 commits April 27, 2026 12:31
Adds support for executing named queries via CLI using the shared
named_query module from core library.

Features:
- --describe: show function signature
- --dry-run: preview SQL without execution
- --list: list queries in a module
- --param: pass parameters
- --force: allow DML/DDL execution
- Register named-procedure parser and handler
- Add async support for named-query and named-procedure
This adds test coverage for PostgreSQL backend CLI:
- TestCLINamedQueryArgs: 6 tests for named-query args parsing
- TestCLINamedProcedureArgs: 9 tests for named-procedure args parsing

These tests mirror the MySQL CLI tests for consistency.
Provide PostgreSQL-specific connection parameter examples in help text
instead of SQLite's --db-file examples.
- Add PostgresConcurrencyMixin in base.py
- Uses connection pool size as concurrency limit
- Both sync and async backends implement ConcurrencyAware protocol
- Replace pytest_asyncio.mark.asyncio with pytest.mark.asyncio
- This fixes test collection error in pytest-asyncio 1.3.0
- Add CreateExtensionExpression for CREATE EXTENSION SQL generation
- Add DropExtensionExpression for DROP EXTENSION SQL generation
- Update PostgresExtensionSupport protocol with format methods
- Add format_create_extension and format_drop_extension to mixin
- Add comprehensive tests for extension DDL expressions
- Auto-quote extension names containing hyphens or underscores
- Add Dockerfile for PostgreSQL 14-18 with postgis, pgvector, earthdistance
- Add docker-compose.yml for easy deployment
- Add build.sh for multi-version builds
- Add init-extensions.sh for automatic extension creation
- Add comprehensive README documentation

Supports: amd64, arm64, ppc64le, s390x
- Add test_postgres_protocol_conformance.py with tests for:
  - PostgresDialect implements all declared protocols
  - All protocols have at least one member
  - No overlap between protocols
- Skip non-runtime_checkable protocols in isinstance tests
AsyncIntrospectionSupport was removed from python-activerecord,
so the test exclusion is no longer needed.
PostgresBackendMixin now provides threadsafety property (returns 2).
Removed duplicate implementation from sync.py and async_backend.py.
…ests

Refactor handle_info() to use _resolve_postgres_config() instead of
inline named connection logic, ensuring consistency across all
subcommands. Add test suite with PostgreSQL 18 example connections.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
pytest does not allow __init__.py in test directories.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ility status

- Add 'available' field to PostgresExtensionInfo to track installable extensions
- Add is_extension_available() method to protocol and mixin
- Expand KNOWN_EXTENSIONS from 11 to 35+ extensions
- Query pg_available_extensions for complete extension status
- Add 'extensions' introspection command for CLI
- Update info command to display installed vs available extensions
…ions

Previously _detect_extensions() only queried pg_extension for installed
extensions and used hardcoded KNOWN_EXTENSIONS as fallback. This missed
pre-installed extensions that are available but not enabled.

Now the method:
1. Queries pg_extension for installed extensions (installed=True, available=True)
2. Queries pg_available_extensions for all available extensions
3. Marks installed extensions as available
4. Marks not-installed-but-available extensions as available=True
- Sort extensions alphabetically by name
…ions

Implemented support for the following extensions:
- pg_cron: job scheduling
- citext: case-insensitive text
- bloom: bloom filter index
- pg_partman: partition management
- orafce: Oracle compatibility
- pglogical: logical replication
- pgaudit: audit logging
- pg_repack: online rebuild
- hypopg: hypothetical indexes
- address_standardizer: address parsing
- pg_surgery: data repair
- pg_walinspect: WAL inspection
- fuzzystrmatch: fuzzy string matching
- cube: multidimensional cube
- pgcrypto: cryptographic functions
- btree_gin: GIN index for btree types
- btree_gist: GiST index for btree types
- uuid-ossp: UUID generation
- Follow the examples README structure (Setup/Business Logic/Execution/Teardown)
- Use expressions (CreateTableExpression, InsertExpression, QueryExpression)
- Check extension availability before execution
- Auto-create extension if needed
- Use CreateExtensionExpression for extension creation
- Follow examples README structure (Setup/Business Logic/Execution/Teardown)
- Check extension availability before execution
- Use CreateExtensionExpression for extension creation
- Re-detect extensions after creation with introspect_and_adapt()
- Follow examples README structure
- Remove backend_cls parameter requirement from named connection factories
- Update CLI config resolution to use new API
- Add CLI parameter priority tests (5 tests pass)
- Add named-connection subcommand for managing named connections
- Support --list, --show, --describe options
- Allows users to list and inspect named connection configs
Add examples for development and production PostgreSQL connections:
- local_dev(): local development database
- local_dev_no_password(): local database without password
- test_db(): test database
- prod_db(): production database with SSL
- prod_db_ssl(): production with full SSL verification
- prod_replica(): read replica for read-heavy workloads
- Remove erroneous reset_pg_stat_statements() from pg_stat_statements Protocol
  (violates Dialect layer "generate SQL, don't execute" principle)
- Add supports_pg_cron_run capability to pg_cron Protocol/Mixin
- Add format_auto_partition_config to pg_partman Mixin/Protocol
  (aligns with existing supports_pg_partman_auto_partition declaration)
- Add format_pglogical_show_subscription_status and
  format_pglogical_alter_subscription_synchronize to pglogical Mixin/Protocol
  (aligns with existing supports_pglogical_replication declaration)
- Update KNOWN_EXTENSIONS: add 'cancel' and 'run' features for pg_cron
… for 29 extensions

Add missing format_* methods to Mixins where supports_* declared a capability
but no SQL generation method existed:
- hstore: format_hstore_delete_key, format_hstore_each, format_hstore_keys/values
- ltree: format_ltree_concat, format_ltree_lca
- intarray: format_intarray_index_statement
- citext: format_citext_literal
- cube: format_cube_contains, format_cube_distance, format_cube_size
- pgcrypto: format_digest, format_pgp_encrypt, format_pgp_decrypt
- postgis: format_geography_literal, format_st_area/transform/as_geojson/buffer
- pgvector: format_create_hnsw_index_statement, format_vector_l2_distance/inner_product
- fuzzystrmatch: format_difference, format_metaphone
- btree_gin/gist: format_btree_gin/gist_operator_class
- hypopg: format_hypopg_estimate_size
- orafce: format_instr, format_substr

Add format_* method signatures to all 29 Protocol files (previously only
supports_* was declared). Register new Mixins in PostgresDialect inheritance.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…sions

Add requires_extension() and requires_extension_available() decorators
to conftest.py for skipping integration tests when extensions are not
installed on the test database.

Add unit tests for all 20 extensions that previously lacked test coverage:
citext, pgcrypto, fuzzystrmatch, cube, uuid-ossp, bloom, btree_gin,
btree_gist, tablefunc, pg_stat_statements, pg_cron, orafce, pg_partman,
hypopg, pglogical, pgaudit, pg_repack, address_standardizer, pg_surgery,
pg_walinspect.

All tests are pure in-memory (no database connection required).
Integration tests that connect to real PostgreSQL database:
- hstore: CRUD, operators (@>/?/||), functions (each/akeys/avals)
- pg_trgm: similarity, % operator, GIN index, show_trgm
- uuid-ossp: uuid_generate_v1/v4, UUID column default
- citext: case-insensitive comparison, unique constraint, LIKE, JOIN
- ltree: path operators (@>/<@/~), ancestor/descendant, GiST index
- pgcrypto: crypt+gen_salt, digest, hmac, pgp_sym_encrypt/decrypt
- intarray: @>/&&/<@ operators, idx() function, GIN index
- fuzzystrmatch: levenshtein, soundex, difference, metaphone/dmetaphone

All tests use requires_extension() guard to skip when not installed.
- postgis: spatial data (geometry), ST_Distance/Contains, GIST index
- pgvector: vector column, cosine similarity search, HNSW index
- ltree: hierarchical paths, ancestor/descendant queries, GiST index
- pgcrypto: crypt+gen_salt password hashing, digest, hmac
- pg_trgm: similarity fuzzy search, % operator, GIN index
- intarray: @>/&& operators, idx/sort/uniq functions
- earthdistance: earth_distance calculation, range queries
- cube: @> contains, <-> distance, nearest-neighbor search

All examples follow Setup → Business Logic → Execution → Teardown
structure with CreateExtensionExpression and introspect_and_adapt().
…date KNOWN_EXTENSIONS

- Add PostgresPostgisRasterSupport protocol and PostgresPostgisRasterMixin
  for PostGIS raster type operations (ST_AsRaster, ST_RastFromText, etc.)
- Add PostgresPgRoutingSupport protocol and PostgresPgRoutingMixin
  for pgRouting path finding operations (pgr_dijkstra, pgr_astar, etc.)
- Update KNOWN_EXTENSIONS: add raster_type feature for postgis_raster,
  dijkstra feature for pgrouting, cancel/run features for pg_cron
- Mark 8 extensions as requires_dialect: False that don't need
  Protocol/Mixin adaptation (postgis_topology, postgis_sfcgal,
  postgis_tiger_geocoder, amcheck, pageinspect, pgtap,
  pg_logicalinspect, address_standardizer_data_us)
vistart and others added 23 commits April 27, 2026 12:31
…/ subpackage

Split the 1779-line __main__.py into a thin entry point and 9 focused
modules under cli/, following the same pattern as SQLite and MySQL:
- __init__.py: subcommand registration and dynamic dispatch
- output.py: provider factory and RICH_AVAILABLE
- connection.py: connection args, config resolution, backend creation
- info.py: info subcommand with protocol display (26 Postgres Protocols)
- query.py: query subcommand (sync + async)
- introspect.py: introspect subcommand with 'extensions' type
- status.py: status subcommand with WAL/Replication/Archive/Security sections
- named_query.py: named-query adapter using closures
- named_procedure.py: named-procedure adapter using closures
- named_connection.py: named-connection adapter with empty parent parser

Key changes:
- Remove global _default_backend variable, use closure-based approach
- Move -v/--verbose from main parser to info/status subcommands only
- Each subcommand independently decides its own arguments
- Rename test_cli.py to test_named_connection_cli.py for clarity
- Update mock paths from __main__ to cli.connection module
…YTHONPATH, and enable autocommit

1. Remove `tests.` prefix from module paths in integration tests.
   The `tests.rhosocial...` import paths only worked with `python -m
   pytest` (CWD in sys.path makes `tests` an implicit namespace package).
   Direct `pytest` does not add CWD to sys.path, causing ModuleNotFoundError.
   Fix by using `rhosocial.xxx` paths that work via PYTHONPATH entry.

2. Add `tests` to PYTHONPATH in CI to ensure `tests/rhosocial/` is
   searched as part of the namespace package path.

3. Enable autocommit on psycopg connections to prevent psycopg 3 from
   auto-managing transactions (which conflicts with manual BEGIN/COMMIT
   statements in the ActiveRecord layer).
…rinciples

- Derive 5 PG protocols from generic counterparts:
  PostgresTableSupport(TableSupport),
  PostgresIndexSupport(IndexSupport),
  PostgresLockingSupport(LockingSupport),
  PostgresTriggerSupport(TriggerSupport),
  PostgresConstraintSupport(ConstraintSupport)
- Remove 4 duplicate generic protocols from PostgresDialect base class list
- Rename 22 PG expression classes with Postgres prefix:
  AdvisoryLockExpression → PostgresAdvisoryLockExpression,
  RefreshMaterializedViewPgExpression → PostgresRefreshMaterializedViewExpression,
  CreateEnumTypeExpression → PostgresCreateEnumTypeExpression, etc.
- Fix Expression-Dialect separation for 3 expression classes:
  PostgresAlterEnumTypeAddValueExpression,
  PostgresAlterEnumTypeRenameValueExpression,
  PostgresCreateRangeTypeExpression
- Make PostgresRefreshMaterializedViewExpression derive from
  RefreshMaterializedViewExpression with schema/name/concurrently aliases
- Rename format_postgres_for_update_clause → format_for_update_clause
  in PostgresLockingMixin and PostgresLockingSupport protocol
- Add TestPostgresProtocolDerivation and TestPostgresExpressionDialectSeparation
  test classes for protocol coverage validation
- Update test_postgres_protocol_conformance.py excluded_overlaps

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…2 format

The third segment of UUID v1 was incorrectly matched with {3} hex chars
instead of {4}, causing test_uuid_generate_v1 to always fail.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PostgresIndexSupport, PostgresTableSupport, and PostgresConstraintSupport
now derive from their generic counterparts, so method overlap is expected.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… and PostgresMultirangeSupport

These two protocols were missing the decorator, causing them to be
skipped in protocol conformance isinstance() checks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…l_and_params

ActiveQuery layer uses ? as parameter placeholders (e.g. where("name = ?",
params)), but psycopg v3 requires %s format. Previously the conversion
was not performed, causing "the query has N placeholders but M parameters
were passed" errors for any query using RawSQLPredicate/RawSQLExpression.

The new _convert_qmark_to_format() method handles the conversion while
preserving PostgreSQL's hstore/jsonb operators (?, ?|, ?&) by:
- Keeping ? followed by | or & as-is (operator context)
- Keeping ? preceded by alphanumeric/underscore as-is (identifier context)
- Replacing all other ? with %s (parameter placeholder context)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…greSQL backend

Placeholder conversion is now handled by the ActiveRecord layer via
convert_qmark_placeholder(). The backend no longer needs to do any
? → %s conversion in _prepare_sql_and_params.

Remove _convert_qmark_to_format static method and _prepare_sql_and_params
override, restoring base class pass-through behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…in format_for_update_clause

PostgreSQL dialect's format_for_update_clause assumed clause.strength
always exists, but the base ForUpdateClause class (used by
Query.for_update()) does not have this attribute — only
PostgresForUpdateClause does. Use getattr() with a default of
LockStrength.UPDATE for compatibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Switch from PyPI package to git+https source for
rhosocial-activerecord-testsuite to track the new dev12 branch.
…nsaction_manager access

Replace direct `_transaction_manager.is_active` checks with the
`in_transaction` property in both sync and async backends. The property
already handles the None case for `_transaction_manager`, making the
code simpler and consistent with the project's abstraction conventions.
Add a second PostgreSQL service using vistart/postgres-exts image
alongside the official postgres container, allowing tests against
databases with additional extensions installed.

- postgres service: port 5432 (official image)
- postgres-exts service: port 5433 (vistart/postgres-exts image)
- Both use same version tag from matrix, same credentials
- Added postgres_exts scenario to CI config
- Wait step now checks both services are ready

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…c/async parity

Move identical non-I/O methods from sync and async implementations into
shared mixin classes to enforce proper sync/async parity:

- PostgresBackendMixin: log, _register_postgres_adapters,
  _is_connection_error, _is_connection_error_message,
  _parse_explain_result, CONNECTION_ERROR_SQLSTATES
- PostgresTransactionMixin (new): _ISOLATION_LEVELS, _build_begin_sql,
  set_deferrable, get_deferred_constraints, get_active_savepoint

Also fix AsyncPostgresTransactionManager.set_deferrable being incorrectly
marked async (no I/O in method body), and fix member order inconsistency
in async_backend.py.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…atibility

Changes:
- Fix MRO ordering: PostgresBackendMixin must come before ExplainBackendMixin
  to ensure _parse_explain_result returns PostgresExplainResult instead of
  BaseExplainResult
- Add WindowsSelectorEventLoopPolicy setup in tests/conftest.py for Windows
  compatibility with async tests
- Fix test: set_deferrable() is sync, not async (PostgresTransactionManager)
- Updated PostgreSQL CLI to match new runner.run(backend) signature
- Removed execute_query, get_dialect parameters from handle_named_procedure
- Updated docs examples to use new API
- Add F401 fixes to __all__ in named_connections/__init__.py, mixins/__init__.py, protocols/__init__.py
- Fix unused imports in various files (from ruff --fix)
- Update extension examples to use 4-section format consistently
)

* test(schema): add schema namespace tests for PostgresBackend

Add test_schema_namespace.py covering:
- Dialect layer: schema capability declarations, Column/TableExpression/
  WildcardExpression with schema_name, CreateSchemaExpression/
  DropSchemaExpression SQL generation (including IF NOT EXISTS/IF EXISTS
  CASCADE)
- Backend layer: get_default_schema(), CREATE/DROP schema, CRUD in
  custom schema, information_schema introspection with schema
- Async Backend layer: async equivalents of backend operations

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(schema): add get_default_schema() and schema config to PostgresBackend

- PostgresBackendMixin.get_default_schema(): returns configured
  default_schema or 'public' as PostgreSQL standard default
- PostgresConnectionConfig: add search_path and default_schema fields
- Pass search_path to psycopg connection params

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(postgres): add UUID type adapter and gen_random_uuid function factory

Add PostgresUUIDAdapter for bidirectional conversion between Python
UUID objects and database values. Add gen_random_uuid() and
uuid-ossp extension function factories that return Expression objects.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(postgres): add pgvector type, adapter, and function factories

Add PostgresVector dataclass, PostgresVectorAdapter, and pgvector
function factories (l2_distance, cosine_distance, inner_product,
cosine_similarity, literal) that return Expression objects.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(postgres): add PostGIS type, adapter, and function factories

Add PostgresGeometry dataclass, PostgresGeometryAdapter, and PostGIS
function factories (ST_MakePoint, ST_Contains, ST_Distance, etc.)
that return Expression objects.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(postgres): rewrite hstore module with Expression/Dialect architecture

Replace raw string returns with Expression objects (FunctionCall,
BinaryExpression) in hstore function factories. Add PostgresHstore
dataclass, PostgresHstoreAdapter, and simplify hstore extension mixin
to only keep supports_*() methods.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(postgres): add extension-aware function version system

Replace flat _POSTGRES_FUNCTION_VERSIONS dict with categorized
FunctionVersionRequirement definitions in function_versions.py.
Functions from extensions (hstore, uuid-ossp, pgvector, PostGIS) now
require extension installation check via introspect_and_adapt().

Key changes:
- FunctionVersionRequirement: structured version req with extension awareness
- FunctionSupportInfo: detailed support status with reason for unavailability
- supports_functions() returns Dict[str, FunctionSupportInfo]
- Extension functions return False when _extensions not probed (no guessing)
- _POSTGRES_FUNCTION_VERSIONS moved to function_versions.py, 15 categories

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(tests): move transaction tests into transaction/ subdirectory

Reorganize transaction-related test files into a dedicated transaction/
subdirectory under feature/backend/ for better test structure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(postgres): align Expression-Dialect architecture across all function modules

Implement all 6 phases of the expression-dialect alignment plan:

Phase 1: Rewrite core native type function factories (geometric, bit_string,
enum, array, json, text_search, xml, network) to return Expression objects
instead of raw SQL strings.

Phase 2-3: Create new function factory modules for all extension types
(pgcrypto, ltree, pg_trgm, fuzzystrmatch, earthdistance, intarray, cube,
citext, pg_stat_statements, postgis_raster, pglogical, pgrouting, tablefunc,
pg_cron, pgaudit, hypopg, pg_surgery, pg_walinspect, address_standardizer,
pg_partman, pg_repack, orafce) and add data_type function factories
(xid8_literal, array_literal).

Phase 4: Migrate multirange/data_type format_* methods from mixins to
function factories, retaining only supports_* and DDL methods in mixins.

Phase 5: Update all tests to use Expression-based assertions (to_sql(),
isinstance checks) instead of raw string comparison.

Phase 6: Add 4 new protocol definitions (PostgresFullTextSearchSupport,
PostgresRangeTypeSupport, PostgresJSONBEnhancedSupport,
PostgresArrayEnhancedSupport) with corresponding supports_* methods in
PostgresDialect.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test(backend): add protocol implementation completeness tests for PostgreSQL

Add three test classes to verify bidirectional consistency between
Protocol declarations and Mixin/Dialect implementations:

- TestProtocolMethodSignatureConformance: verifies method signatures
  on PostgresDialect match Protocol declarations
- TestProtocolMixinForwardCoverage: verifies Protocol-declared methods
  exist in corresponding Mixins (42 Protocol-Mixin pairs)
- TestProtocolMixinReverseCoverage: verifies Mixin-implemented methods
  are declared in corresponding Protocols

Also fix protocol implementation gaps discovered by the tests:

New Mixins (5):
- PostgresFullTextSearchMixin: 4 methods migrated from Dialect
- PostgresRangeTypeMixin: 4 methods migrated from Dialect
- PostgresJSONBEnhancedMixin: 5 methods migrated + 1 new
  (supports_jsonb_subscript)
- PostgresArrayEnhancedMixin: 5 methods migrated + 1 new
  (supports_domain_arrays)
- PostgresParallelQueryMixin: 6 new methods (all previously missing)

Protocol declarations completed (8):
- PostgresExtensionSupport: +2 methods
- PostgresPartitionSupport: +1 method
- PostgresIndexSupport: +6 methods
- PostgresDataTypeSupport: +1 method
- PostgresMultirangeSupport: +2 methods
- PostgresEnumTypeSupport: +10 methods
- PostgresQueryOptimizationSupport: +6 methods
- PostgresSQLSyntaxSupport: +9 methods

Upgrade get_all_protocol_methods() to walk MRO for Python < 3.12,
and add get_own_protocol_methods() for forward coverage testing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: resolve all ruff lint errors across postgres backend

- Rename PostgresGeometryAdapter (postgis) to PostgresPostGISAdapter
  to avoid name collision with geometric adapter (F811)
- Rename orafce trunc/round to orafce_trunc/orafce_round to avoid
  collision with math_enhanced module (F811)
- Add TYPE_CHECKING imports for FunctionSupportInfo and
  FunctionVersionRequirement in dialect.py (F821)
- Remove unused imports: List, Optional, Dict, re, field (F401)
- Remove unused variable assignment for provider in cli/info.py (F841)
- Add `from None` to raise inside except in types/postgis.py (B904)
- Fix f-string without placeholders in examples/types/uuid.py (F541)
- Break long lines across adapters, cli, introspection, functions,
  mixins, and protocols modules (E501)
- Configure ruff per-file-ignores for examples/ (E402, E501) and
  migrate select/ignore to [tool.ruff.lint] section

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: restore quoted type annotations and update test references

- Add quotes back around FunctionSupportInfo and
  FunctionVersionRequirement in dialect.py type annotations,
  since they are imported under TYPE_CHECKING and not available
  at runtime (Python 3.8+ evaluates annotations eagerly)
- Update test_postgis_types.py to use PostgresPostGISAdapter
  instead of the old PostgresGeometryAdapter name

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(tests): update function support tests for FunctionSupportInfo return type

supports_functions() returns Dict[str, FunctionSupportInfo] (not bool),
so tests must check .supported attribute instead of using `is True`/`is False`.

- Replace `result[func] is True` with `result[func].supported`
- Replace `result[func] is False` with `not result[func].supported`
- Update hstore extension tests: without database connection,
  extension functions return extension_not_probed instead of True
- Add FunctionSupportInfo import and type check test

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(postgres): override format_column() with alias-aware schema handling

PostgreSQL rejects three-segment column references (schema.table.column)
when the table has an alias in the FROM/JOIN clause. Override
format_column() to implement PostgreSQL-specific rules:
- When table has an alias, use alias.column (ignore schema_name)
- When table has no alias but has schema, use schema.table.column
- Otherwise use standard table.column or column form

This fixes the JOIN bug where ON conditions generated
"public"."users"."id" instead of "users"."id" when tables had aliases.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(postgres): add async integration tests and expression-based fixtures for all 29 extensions

Add async integration tests matching existing sync tests for all 29
extension test files, including async fixtures using
async_postgres_backend_single. Convert raw SQL strings in fixtures and
test methods to expression objects (CreateTableExpression,
InsertExpression, QueryExpression, FunctionCall, etc.).

Key changes:
- Add async_ensure_extension_installed to test utils
- Add async_postgres_backend_single fixture to conftest
- Add 29 async test classes with _async table suffix convention
- Replace raw SQL with expression objects across all integration tests
- Use Literal.cast("type") for PostgreSQL type casts (cube, hstore,
  ltree, vector, uuid, integer[], geography) instead of RawSQLExpression
- Use Subquery wrapper for ComparisonPredicate aliasing
- Use specific exception types (IntegrityError, DatabaseError) instead
  of bare Exception in pytest.raises
- Fix earth_distance() assertion (returns meters, not miles)
- Fix hypopg_estimate_size assertion (maps to hypopg_relation_size)

Remaining RawSQLExpression usage (with TODO comments):
- COUNT(*) where Literal("*") gets parameterized
- PostgreSQL operators with aliases where ComparisonPredicate lacks .as_()
- Index opclass specifications (no structural expression support)

All 316 tests pass, 13 skipped (extensions not available/permissions).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(tests): skip pg_stat_statements and pg_walinspect tests on CI env constraints

- pg_stat_statements: skip when extension requires shared_preload_libraries
- pg_walinspect: skip when LSN is rejected as future start LSN (Postgres 15)

Both failures are environment configuration issues, not code bugs.

* chore: add changelog fragment for PR #33

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Add comprehensive SQL injection protection for the PostgreSQL backend:

- Add validation for EXCLUDE constraint index methods (using allowlist)
- Add validation for EXCLUDE constraint operators (using allowlist)
- Add _escape_sql_string() for DEFAULT constraint values
- Add _validate_data_type() for column data types
- Add security unit tests for constraint validation
- Add integration tests with real PostgreSQL database execution

Security fixes prevent SQL injection through:
- Index method allowlist validation (gist, btree, spgist, etc.)
- Operator allowlist validation (&&, =, @>, etc.)
- String escaping for DEFAULT values
- Type validation for column definitions

Fixes: #sql-injection-audit-remediation
@vistart vistart added the release label May 1, 2026
@vistart vistart self-assigned this May 1, 2026
PostgreSQL array types like TEXT[] and INTEGER[] were rejected because
the base dialect's allowlist pattern didn't include brackets [].

Override _validate_data_type in PostgresDialect to support array types,
with a note that this can be removed once rhosocial-activerecord base
dialect includes this change in a future release.
@codecov

codecov Bot commented May 1, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 43.43818% with 1043 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.66%. Comparing base (79ec719) to head (032ce6e).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...l/activerecord/backend/impl/postgres/cli/status.py 7.47% 334 Missing ⚠️
...tiverecord/backend/impl/postgres/cli/introspect.py 12.56% 181 Missing ⚠️
...ial/activerecord/backend/impl/postgres/cli/info.py 16.50% 167 Missing ⚠️
...al/activerecord/backend/impl/postgres/cli/query.py 20.00% 84 Missing ⚠️
...iverecord/backend/impl/postgres/cli/named_query.py 21.42% 33 Missing ⚠️
...activerecord/backend/impl/postgres/backend/base.py 60.27% 25 Missing and 4 partials ⚠️
...tiverecord/backend/impl/postgres/functions/enum.py 26.31% 28 Missing ⚠️
...ecord/backend/impl/postgres/cli/named_procedure.py 26.47% 25 Missing ⚠️
...ecord/backend/impl/postgres/functions/data_type.py 20.83% 18 Missing and 1 partial ⚠️
...ecord/backend/impl/postgres/functions/geometric.py 48.64% 19 Missing ⚠️
... and 19 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #34      +/-   ##
==========================================
- Coverage   73.12%   68.66%   -4.47%     
==========================================
  Files         136      230      +94     
  Lines        7365    10049    +2684     
  Branches     1218     1598     +380     
==========================================
+ Hits         5386     6900    +1514     
- Misses       1546     2628    +1082     
- Partials      433      521      +88     
Flag Coverage Δ
postgres-18 68.66% <43.43%> (-4.47%) ⬇️
python-3.14 68.66% <43.43%> (-4.47%) ⬇️
unittests 68.66% <43.43%> (-4.47%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@sonarqubecloud

sonarqubecloud Bot commented May 1, 2026

Copy link
Copy Markdown

@vistart
vistart merged commit 15e5823 into main May 1, 2026
22 of 24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant