Skip to content

chore: Release v1.0.0.dev16 - #54

Merged
vistart merged 21 commits into
mainfrom
release/v1.0.0.dev16
Aug 15, 2026
Merged

vistart merged 21 commits into
mainfrom
release/v1.0.0.dev16

Conversation

@vistart

@vistart vistart commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Description

This PR merges the release/v1.0.0.dev16 branch into main, finalizing version v1.0.0.dev16 of python-activerecord-postgres.

Key highlights in this release:

Release/Hotfix Details

  • Target Version: v1.0.0.dev16
  • Type: Minor Release (dev)
  • Key Changes:
    • New Features (if applicable)
    • Bug Fixes (if applicable)
    • Breaking Changes (if applicable, with migration path)
    • Security Fixes (if applicable, with CVE)

Related Issues/PRs

Commits included (from origin/main..HEAD):

e4b5ea4 ci(test): install testsuite 1.0.0.dev16 from PyPI
bb42ab7 ci(test): install core 1.0.0.dev29 from PyPI
1eaedb6 docs: remove GEMINI.md
3087163 chore(changelog): remove redundant scenario/schema-differ fragments
fcedfc3 feat(backend): override create_schema_differ() to supply PostgresSchemaDiffer
6d43947 chore(postgres): support TESTSUITE_ACTIVE_SCENARIOS filtering and raise core dependency
acf620e feat(backend): add PostgreSQL DDL coverage-completion expressions and CREATE UNLOGGED TABLE (#53)
226867d feat(backend): add PostgreSQL Row-Level Security POLICY DDL expressions (#52)
5b83d05 feat(backend): render ALTER TABLE IF [NOT] EXISTS qualifiers for PostgreSQL (#51)
5c9fae4 test(postgres): sync testsuite mirroring - add 9 missing test files + rename worker test + add 4 relation fixtures + remove empty composite_pk dir
8c48c78 feat: PGQ enhancement - fulltext search, cursor pollution fix, and PG 19 compatibility (#49)
ab3be40 fix(backend): defensively consume cursor results in get_server_version()
aca738b test(postgres): rewrite fulltext tests to reflect tsvector search capability
e45fc79 feat(postgres): fulltext_search capability, benchmark markers, composite_pk mapped provider, partition explain test
e691dc4 feat(cli): add named-migration subcommand for PostgreSQL backend (#47)
fb975d5 feat(schema): implement schema-diff support and DataType refactoring for PostgreSQL backend (#46)
63ed8d1 fix: install testsuite from git release/v1.0.0.dev16 instead of PyPI dev15
bd72d65 ci: update activerecord dependency to release/v1.0.0.dev29
717b988 chore: bump version to 1.0.0.dev16

Breaking Change

  • Yes
  • No
    (If Yes, please describe the impact and migration path below):

Applicable rhosocial-activerecord Version Range:
>=1.0.0.dev29

Testing

  • All CI checks passed on the source branch (e.g., release/vX.Y.Z or hotfix/ar-XXX).
  • Specific tests for this hotfix have been run and passed.

Test Plan:
CI on the release/v1.0.0.dev16 branch covers the full test suite (local tests skipped per user instruction).

Checklist

  • My changes follow the project's version control guidelines (especially for release and hotfix procedures).
  • I have updated the CHANGELOG.md using towncrier build (for releases).
  • All necessary documentation (e.g., release notes, migration guides) has been prepared or updated.
  • I have confirmed all CI checks have passed on the target branch after merging (post-merge verification).

Additional Notes

Changelog fragments 46/47/49/51/52/53 verified against merged PRs. CI status is being verified via gh pr checks.

vistart and others added 19 commits June 16, 2026 14:12
…dev15

PyPI rhosocial-activerecord-testsuite==1.0.0.dev15 does not include
the composite_pk module added in testsuite v1.0.0.dev16.
Install from the release branch directly to resolve ModuleNotFoundError.
…for PostgreSQL backend (#46)

* feat(types): implement PostgreSQL DataType subclasses and type support mixin

- Add ~45 PostgreSQL-specific DataType subclasses in expression/types.py
- Add PostgresTypeFormatSupportMixin with TypeFormattingSupport + TypeParsingSupport
- Integrate type support into PostgresDialect
- Update exports in __init__.py, expression/__init__.py, mixins/__init__.py, mixins/types/__init__.py

* refactor(types): add __eq__/__hash__, remove synonyms, add CharacterVaryingType

- Replace _type_params() with __eq__/__hash__ in PostgresBitType,
  PostgresVarBitType, PostgresVectorType
- Remove synonyms() from PostgresSmallSerialType, PostgresSerialType,
  PostgresBigSerialType
- Add PostgresCharacterVaryingType(VarCharType) for CHARACTER VARYING(n)
- Register new type in data_type_formatting mixin
- Clean up unused imports (ClassVar, Set, Tuple)

* feat(schema): add parsed_data_type to PostgreSQL _parse_columns

Call DataType.parse_data_type_str(dialect, data_type) when
constructing ColumnInfo so that introspection results carry
structured DataType instances for schema comparison.

* feat(types): add synonyms to PostgreSQL types

- PostgresSerialType ↔ IntegerType/SerialType
- PostgresSmallSerialType ↔ SmallIntType/SmallSerialType
- PostgresBigSerialType ↔ BigIntType/BigSerialType
- PostgresCharacterVaryingType ↔ VarCharType

* feat(types): add synonyms to PostgresByteaType

PostgresByteaType ↔ BlobType for cross-backend schema comparison.

* refactor(types): inherit DDLTypeMixin in Postgres type formatting

* refactor(types): update to DDLTypeSupport protocol

* refactor(types): use @DDLTypeMixin.handles, remove format_data_type override

- Add @DDLTypeMixin.handles decorators to all 56 formatter methods
- Remove custom format_data_type() dispatch and supports_data_types() list
- Move Postgres type imports from TYPE_CHECKING to runtime

* fix(types): rewrite Postgres core type formatters, fix missing PostgresTypeFormatSupportMixin base

- Replace _default_sql() calls with explicit PostgreSQL SQL strings
  for all 18 core type handlers (SmallIntType→SMALLINT, etc.)
- Add PostgresTypeFormatSupportMixin as base of PostgresDialect
  (was imported but never used as base, causing format_data_type
  to resolve to protocol stub and return None)
- Create test_core_type_mappings.py with 15 tests for core type→SQL
  rendering via PostgreSQL dialect

* feat(postgres): implement array type support

- Add PostgresArrayType parameterised container type (element_type, dimensions)
- Add format_data_type_array handler that recursively formats element types
- Update parse_type to detect ARRAY keyword and [] suffix before standard dispatch
- Add 25 tests covering core type mappings and array rendering/parsing

* refactor(postgres): use core ArrayType, keep PostgresArrayType as alias

- PostgresArrayType is now just 'PostgresArrayType = ArrayType'
- Update handler registration to use core ArrayType
- Update parse_type to return ArrayType directly
- Add test for is_element_type_equivalent

* feat(postgres): add element type validation and PostgresArrayType subclass

- format_data_type_array validates element_type is in _type_formatters
- PostgresArrayType is now a proper subclass with is_equivalent ignoring
  dimensions (PG normalises multi-dim arrays to 1-D internally)
- parse_type always creates PostgresArrayType with dimensions=1
- Update tests for new PostgresArrayType subclass and PG array semantics

* feat(schema): add PostgresSchemaDiffer

Column order has no semantic meaning in PostgreSQL; array dimension
equivalence is handled by PostgresArrayType.is_equivalent().

* feat(schema): add schema-diff examples and refactor for PostgreSQL backend

- Add 6 schema-diff example scripts: table_changes, column_order_irrelevant, postgres10_identity, array_type_diff, index_type_diff, serialization_roundtrip
- All DDL uses expression objects, call introspect_and_adapt() after connect
- Refactor format_column_definition to use col_def.data_type.to_sql() and add identity dialect_options support
- Update existing DDL examples to use expression API (table param, QueryExpression for verification)

* refactor(types): remove _default_sql(), make format_data_type return Tuple[str, tuple]

- Delete all _default_sql() methods from Postgres expression types
- Change all PostgresTypeFormatSupportMixin formatters to return Tuple[str, tuple]
- Inline _default_sql() logic directly into each format_data_type_* method
- Unpack format_data_type() call in array formatter

* style(types): add complete type annotations to all format_data_type_* methods

* feat(examples): strengthen serialization roundtrip with table data assertions

* fix(tests): replace string data_type with DataType instances across 22 test files

ColumnDefinition now validates that data_type must be a DataType
instance. Replace all string data_type values (SERIAL, TEXT, INTEGER,
etc.) with proper instance references.

Also add PostgresCitextType, PostgresCubeType, PostgresLtreeType,
PostgresRasterType missing extension DataType subclasses.

Update security injection tests to verify TypeError at construction
time instead of ValueError at format time.

* docs: add changelog fragment for PR #46

* fix(tests): replace positional string data_type with DataType instances in 6 more files

* fix(types): register PostgresCitextType, PostgresCubeType, PostgresLtreeType, PostgresRasterType formatters

* fix: restore PostgresCidrType import accidentally removed in type formatter registration
* feat(cli): add named-migration subcommand (PostgreSQL adapter)

Registers the 'named-migration' CLI subcommand for the PostgreSQL backend.
Delegates to the shared implementation in
rhosocial.activerecord.backend.migration.cli.

- cli/named_migration.py: parser + handler adapter
- cli/__init__.py: register in COMMAND_NAMES and register_commands()

* feat(migration): add --async support, example migrations, and demo scripts for PostgreSQL

- Extend named_migration.py adapter with --async support (AsyncPostgresBackend)
- Add extensive CLI epilog with 12 scenario examples and demo script references
- Create examples/named_migrations/ with migrations.py, expressions.py, run_basic.py, run_chain.py
- Add demo_basic.sh, demo_chain.sh, demo_all.sh end-to-end shell scripts
- expressions.py uses PostgresSerialType and PostgresCharacterVaryingType

* chore: add changelog fragment for PR #47

* chore: add parameterized migration, async, incompatible, and single-transaction demo scripts for PostgreSQL

* fix(postgres): use positional arg instead of keyword 'size' for PostgresCharacterVaryingType

* ci: trigger rebuild
…ite_pk mapped provider, partition explain test

- mixins/ddl/index: implement supports_fulltext_search() (tsvector/tsquery
  via GIN), supports_fulltext_boolean_mode() (tsquery boolean operators),
  and refine docstrings distinguishing DDL (CREATE FULLTEXT INDEX, False)
  from query capability (True).
- pyproject: register benchmark* pytest markers.
- tests/providers/composite_pk: add MappedOrderItem/Async setup helpers.
- Add tests/.../feature/backend/test_partition_explain.py covering
  partition EXPLAIN plan introspection.
…ability

The TestFulltextNotSupported class previously assumed PostgreSQL
opposes ALL fulltext features and that the format_* helpers raise
UnsupportedFeatureError. That contract is stale: PostgresIndexMixin
overrides supports_fulltext_search/supports_fulltext_boolean_mode to
return True (queried via tsvector @@ tsquery), and
format_fulltext_match / format_create_fulltext_index_statement /
format_drop_fulltext_index_statement return working SQL
(plainto_tsquery / to_tsquery / CREATE INDEX USING GIN / DROP INDEX).

- Rename to TestFulltextDdlNotSupportedSearchSupported to express the
  decoupled DDL-vs-query contract introduced by core PR #110.
- Keep the still-unsupported DDL flags (supports_fulltext_index,
  supports_fulltext_parser, supports_fulltext_query_expansion) as False.
- Add positive coverage for supports_fulltext_search,
  supports_fulltext_boolean_mode.
- Add tsvector/tsquery SQL-shape assertions for natural-language mode,
  boolean mode, and multi-column variants.
- Add CREATE INDEX ... USING GIN / DROP INDEX shape assertions
  (with and without IF [NOT] EXISTS), constructing
  CreateFulltextIndexExpression / DropFulltextIndexExpression with a
  dialect instance as required by BaseExpression.
get_server_version() called fetchone() on SELECT version() but did not
consume any remaining results before closing the cursor.  Some database
drivers can leave stale result-set metadata on the connection, causing
the next cursor opened on the same connection to read a polluted
cursor.description.

This mirrors the same fix applied to the core SQLite backend and the
MySQL backend.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… 19 compatibility (#49)

* feat(pgq): gate quantified path and comma-separated patterns as unsupported on PG 19

PostgreSQL 19 does not support:
- Variable-length (quantified) path patterns (+/*/{n,m})
- Comma-separated multiple patterns in a single MATCH clause

Add capability overrides returning False, document known limitations,
and add tests for the new gating methods.

* fix: use correct fixture names 'postgres_backend' / 'async_postgres_backend' in cursor pollution tests

The cursor pollution tests referenced 'pg_backend' and 'async_pg_backend'
which do not exist as pytest fixtures. The correct names are
'postgres_backend' and 'async_postgres_backend', matching the actual
fixture definitions used by the rest of the test suite.

* feat: sync bridge files with testsuite rename and add 4 async relation bridges

- Update bridge files to match testsuite rename: test_sync_queries -> test_queries
- Add 4 new async relation bridge files (test_base_async, test_cache_async,
  test_interfaces_async, test_nested_relationship_access_async)
- Include pgq/ example directory

* feat: add bridge files for derived_field, interface feature tests and relation benchmark

- derived_field/conftest.py + test_derived_field_testsuite.py
- interface/test_threadsafe_dict.py (sync + async combined)
- benchmark/relation/conftest.py + test_cache_comparison.py

* perf(backend): remove redundant fetchall() in get_server_version()

execute() is atomic per DB-API 2.0 — the extra fetchall() after
fetchone() is unnecessary and adds a round-trip for no benefit.

Follow-up to commit ab3be40 which introduced these defensive calls.

* refactor(postgres): merge composite_pk/derived_field, switch to expression-based DDL

- Delete composite_pk/derived_field bridge files, schema SQL, and providers
- Create tests/providers/fixtures/ with TABLE_EXPRESSIONS (basic, query, mixins, events)
- Replace _load_postgres_schema with CreateTableExpression/DropTableExpression DDL
- Update all query/relation bridge imports to new subdirectory paths
- Fix _setup_model_async -> _setup_async_model typo in query provider

* fix(postgres): move bridge files to subdirectories, add missing conftest, fix composite_pk setup

- Move 70 bridge files from flat paths to testsuite-matching subdirectories
- Create 6 missing bridge files (composite_pk crud/query/cte/set_operations, derived_field_basic, example_basic_fixtures)
- Add missing basic/worker, query/worker, interface conftest bridge files
- Rename test_worker_transaction_isolation -> test_transaction_isolation
- Fix setup_order_item_model to use basic TABLE_EXPRESSIONS for composite PK order_items table

* fix(postgres): fix PROVIDER_KEY_ASYNC and method names in relation conftest

- Use PROVIDER_KEY_ASYNC instead of undefined PROVIDER_KEY
- Fix method call names: setup_async_user_model -> setup_user_model (await)
- Fix cleanup_after_test_async -> cleanup_after_test (await)
- Align method calls with testsuite IRelationAsyncProvider interface

* fix(postgres): remove non-existent _ensure_user_post_comment_async_schema call from relation conftest

RelationAsyncProvider._setup_user_post_comment_async() already handles
all three tables in a single call.

* fix(postgres): extend cleanup_after_test table lists to ensure no cross-test contamination

Add missing tables to PostgreSQL provider cleanup lists so all tables
created during a test are reliably removed afterwards:

- basic provider (sync + async): bulk_users
- query provider (sync + async): profiles

These were created by setup methods (setup_bulk_user_model,
setup_profile_fixtures) but absent from the cleanup drop list, leading
to orphaned tables across sequential test runs and cross-scenario
contamination.

* fix(postgres): add DROP TABLE to relation/connection/benchmark cleanup, fix bare excepts

- RelationSyncProvider/RelationAsyncProvider cleanup_after_test now
  drops all 12 created tables (employees, departments, authors, books,
  chapters, profiles, users, posts, comments, boundary_*) with CASCADE
  before disconnect.
- BasicConnectionProvider/QueryConnectionProvider cleanup now drops
  test_users table.
- CrudBenchmarkProvider cleanup now drops benchmark_users table.
- All 8 bare 'except:' -> 'except Exception:' across basic.py, query.py,
  mixins.py, events.py providers.

* refactor(test): add missing _async bridge files (61), fix naming

- Generate 61 _async.py bridge files for sync/async pairing compliance
- Rename test_eager_loading_scenarios_sync.py -> test_eager_loading_scenarios.py
- Rename test_relations_with_sync.py -> test_relations_with.py
- Split test_derived_field_basic.py into sync-only + test_derived_field_basic_async.py
- Add missing bridge files for basic/fields/ subcategories
- Fix testsuite module path in relation/derived/test_derived_field.py

* fix(test): remove conflicting test_derived_field bridges from basic/fields/

Same fix as python-activerecord-mysql: identical leaf filename
test_derived_field.py from two different testsuite modules collide under
pytest's import model. Drop the basic/fields duplicates to keep only
the relation/derived/ bridges, matching SQLite.

* fix(test): restore __init__.py under tests/benchmark/packages

Same fix as python-activerecord-mysql: the four __init__.py markers
under tests/benchmark/{,backend,activerecord_bulk,relation} were
removed in commit f146d54, breaking pytest collection on tests that
use relative imports (e.g. 'from .workloads import ...' in
tests/benchmark/backend/test_execute_crud_*.py).

Restore them so pytest treats those directories as packages and the
relative imports resolve.

* fix(test): resolve cursor pollution, DataType errors, and import-file-mismatch

- Move cursor.description assertions before cursor.close() in all
  8 cursor pollution tests (both sync and async) to fix assert None
- Replace string type names ('INTEGER', 'VARCHAR', 'NUMERIC') with
  proper DataType instances (IntegerType, VarCharType, DecimalType)
  in test_recursive_cte_graph_traversal.py to fix TypeError
- Rename test_transaction_isolation.py → test_worker_transaction_isolation.py
  to avoid import-file-mismatch collision with backend/transaction/

* fix(ci): update benchmark test file names to match testsuite (remove _sync suffix)

* fix(test): replace FunctionCall('+') with infix BinaryArithmeticExpression for depth+1 in CTE tests

PostgreSQL does not support prefix function-call syntax for arithmetic
operators (+(a, b)). Use the overloaded + operator (creates
BinaryArithmeticExpression) which generates correct infix a + b SQL.

* fix(test): add GROUP BY to fund_trace_aggregation, fix pre-existing assertion bugs in CTE tests

- Add GroupByHavingClause to fix column 'fund_trace.depth' must appear in GROUP BY
- Fix depth 3 expected sum to 800000 (500000 Diana + 300000 Eve)
- Fix social network assertions: Charlie at depth 2 (not 1), no Diana in results
- These bugs were pre-existing: tests were never runnable before DataType fix

* fix(test): track created tables per provider to eliminate xdist race condition in cleanup_after_test

Instead of hardcoding tables_to_drop list in cleanup_after_test (which
drops ALL tables including those used by concurrent xdist workers),
track only tables that were actually created by _setup_{model,multiple}
calls in each provider instance. Since each test fixture creates a fresh
provider, this naturally isolates table cleanup to just the tables the
current test created, eliminating the race where one test's teardown
drops users/type_adapter_tests/pydantic_validated_models tables that
another concurrent worker is still using.

* feat(postgres): set supports_json_arrow_operators=True

* feat(postgres): add ON CONFLICT capability switches

PostgreSQL supports only a single ON CONFLICT clause per INSERT.
Explicitly declare supports_on_conflict_clause=True and
supports_multiple_on_conflict_clauses=False to enable the generic
gate in DMLMixin.format_on_conflict_clauses. Add targeted tests for
the capability switches and single-clause rendering (incl. EXCLUDED).

* test(postgres): add DROP TABLE CASCADE/RESTRICT rendering test

Confirm PostgreSQL inherits the correct optimistic True/True defaults from
the core TableMixin and emits standard CASCADE/RESTRICT tokens. No code
change required on the PostgreSQL backend.

* fix(postgres): add missing supports_on_conflict_clause and supports_multiple_on_conflict_clauses to PostgresUpsertSupport protocol

* fix(postgres): remove sync savepoint test import, only async tests apply

* fix(postgres): pass scenario name to type_adapter_fixtures provider to avoid cross-scenario table conflicts

* fix(postgres): import all testsuite basic fixtures in conftest while overriding type_adapter_fixtures

* fix(postgres): revert conftest override, restore import * to avoid breaking other fixtures

* fix(postgres): pass scenario name to sync type_adapter_fixtures to avoid cross-scenario table collisions

* fix(postgres): remove test bridge files accidentally added in protocol fix

* fix(postgres): remove shadowing fixture import from type_adapter bridge file

The bridge file imported type_adapter_fixtures directly from the testsuite
conftest into the test module namespace. pytest registered that fixture with
the test module as its most specific baseid, shadowing the conftest override
(feature/basic/conftest.py) that passes the scenario name to the provider.

As a result, the sync [postgres_exts] type_adapter tests connected to the
default scenario database (5432) instead of postgres_exts (5433), colliding
with async [postgres_default] tests on the same type_adapter_tests table and
causing 'relation does not exist' failures under xdist concurrency.

Remove the import so pytest resolves the conftest override, which correctly
passes the scenario name.

* test(postgres): add unit tests for data type formatting and parsing

- Fix relative imports in parse_type (..expression.types -> ...expression.types)
  that crashed serial/binary/jsonpath/uuid/net/geom/range/oid/ts/vector
  parsing with ModuleNotFoundError.
- Fix DATETIME mis-parsed as DATE (dispatch order), and CHARACTER/
  CHARACTER VARYING/TIMESTAMPTZ/TIMETZ falling back to CustomType due to
  \b boundary regex.
- Add test_data_type_formatting.py covering all PostgreSQL type format
  and parse branches (data_type_formatting.py coverage 55.67% -> 98%).
- Add test_expression_types.py covering synonyms/equality/hash/array
  equivalence (expression/types.py coverage 76.19% -> 100%).
- Cover index fulltext PHRASE mode + multi-column, and upsert capability
  switches (index.py and upsert.py -> 100%).

* chore: add changelog fragment for PR #49
… rename worker test + add 4 relation fixtures + remove empty composite_pk dir
…greSQL (#51)

* feat(backend): render ALTER TABLE IF [NOT] EXISTS qualifiers for PostgreSQL

Add PostgresAlterColumnModifierMixin so PostgreSQL emits the vendor
qualifiers supported since 9.6: ADD COLUMN IF NOT EXISTS, DROP COLUMN
IF EXISTS, and DROP CONSTRAINT IF EXISTS, opt-in via if_not_exists /
if_exists on AddColumn / DropColumn / DropTableConstraint. Wire the mixin
into PostgresDialect ahead of TableMixin/ConstraintMixin and add the
supports_drop_constraint_if_exists capability to PostgresConstraintSupport
and PostgresConstraintMixin. Add unit tests covering qualifier and plain
forms.

* chore(changelog): rename fragment 50 to new PR #51

* ci: update Python 3.15 beta-2 to rc.1 in test matrix

* test: add feature/basic/ddl mirror with provider get_dialect for postgres

* test: rename basic/ddl mirror basename to avoid pytest import collision with backend dialect test
…ns (#52)

* feat(backend): add PostgreSQL Row-Level Security POLICY DDL expressions

Add PostgresCreatePolicyExpression, PostgresAlterPolicyExpression, and
PostgresDropPolicyExpression (plus PolicyType/PolicyCommand/AlterPolicyMode
enums) so RLS policies can be administered through the Expression-Dialect
pipeline. The new PostgresPolicyMixin provides version-gated formatters
(PG 9.5+ for basic CREATE/ALTER/DROP, 10+ for AS RESTRICTIVE and explicit
AS PERMISSIVE, 15+ for the CURRENT_ROLE role keyword) and capability
switches; PostgresPolicySupport is the matching @runtime_checkable Protocol.

POLICY is a PostgreSQL extension, not SQL-standard, so it is implemented in
the postgres backend package only; the core library is untouched.

Note: changelog.d/0.added.md is a placeholder fragment — rename it to the
actual PR number once assigned before merging.

* ci: bump postgres 19 job from 19beta1 to 19beta2 (PGQ)

* chore: add changelog fragment for PR #52
… CREATE UNLOGGED TABLE (#53)

* feat(backend): add coverage-gap DDL expressions for PostgreSQL

Add expression/mixin/protocol triads covering the remaining PostgreSQL DDL
coverage gaps, each version-gated and exposed through a @runtime_checkable
Protocol:

- RLS table configuration (ENABLE/DISABLE/ALWAYS/FORCE) — PG 9.5+
- ALTER TABLE SET LOGGED/UNLOGGED (9.6+) and SET ACCESS METHOD (15+)
- CLUSTER (index re-cluster) — 9.6+
- CREATE/ALTER/DROP DOMAIN (9.6+; ALTER supports SET DEFAULT/RENAME NOT NULL)
- CREATE/DROP COLLATION objects (9.6+)
- CREATE/DROP FOREIGN TABLE (9.6+)
- CREATE/DROP FUNCTION and CREATE/DROP AGGREGATE (9.6+)
- CREATE/DROP PUBLICATION / SUBSCRIPTION (10+)

PostgresAlterColumnModifierMixin.format_alter_column_action now renders the
ALTER COLUMN ... SET DATA TYPE ... USING (expr) conversion (opt-in via
dialect_options['using']), raising ValueError when used on non-type ops.

PostgreSQL extensions only — core rhosocial-activerecord untouched. Adds
pure-SQL unit tests (no DB) for capability switches, protocol conformance,
and SQL generation. Closes the plan at .claude/plan/2026-08-07
postgres-coverage-gap-analysis.md.

* docs(backend): add JSONExpression type hints to enhanced JSONB mixin and protocol

* feat(backend): complete DDL coverage gaps RENAME and CREATE UNLOGGED TABLE

Plan 4.6/4.7 closure:
- CREATE UNLOGGED TABLE via dialect_options={'unlogged_table': True} on
  CreateTableExpression, version-gated at 9.5+, rendering through
  PostgresTableMixin.format_create_table_statement; TEMPORARY wins over
  UNLOGGED. Exposes supports_unlogged_table on PostgresTableSupport.
- RENAME COLUMN / RENAME TABLE verified through core actions and covered
  by tests (already supported by core DDL; no new mixin needed).

Tests:
- Extend test_alter_table_if_exists.py with ALTER COLUMN SET DATA TYPE
  [USING] and RENAME subclause coverage plus CREATE UNLOGGED TABLE.
- Add plan §6.3 version-baseline sweep at PG 9.6/10/11/14/15/17/19 with
  UnsupportedFeatureError gates.

* test(backend): split DDL expression tests and close DDL mixin coverage gaps

* chore(backend): clean up unused imports and long-line style in DDL code paths

Static-check pass over source and tests touched by the DDL coverage work:
- src: drop unused imports (types, ddl/__init__, named_expressions/partition),
  fix E501 in examples, restore noqa where intentional
- tests: remove unused imports, add E402 noqa to late imports, drop unused
  backend binding var

No behavioral change.; src and changed tests pass ruff.
…se core dependency

- Scenario filtering reads generic TESTSUITE_ACTIVE_SCENARIOS env var
  (fallback from backend-local POSTGRES_ACTIVE_SCENARIOS) so --scenarios
  works when running tests from either the testsuite dir or this repo
- Raise rhosocial-activerecord dependency floor to >=1.0.0.dev0
- Fix relation/derived bridge imports to correctly named testsuite modules
- Add changelog fragment
…maDiffer

The core migrated schema-diff resolution to the dependency-inversion hook
SQLDialectBase.create_schema_differ() and no longer imports concrete
backend differs. Override the hook so PostgreSQL keeps its specialized
schema comparison in migration snapshot diffs.

- Implement PostgresDialect.create_schema_differ() returning PostgresSchemaDiffer
- Add changelog fragment
@vistart vistart self-assigned this Aug 15, 2026
@codecov

codecov Bot commented Aug 15, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.63780% with 160 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.67%. Comparing base (39b2169) to head (f5ea77a).

Files with missing lines Patch % Lines
...ecord/backend/impl/postgres/cli/named_migration.py 28.57% 25 Missing ⚠️
...cord/backend/impl/postgres/protocols/ddl/policy.py 52.00% 11 Missing and 1 partial ⚠️
...activerecord/backend/impl/postgres/mixins/table.py 64.28% 7 Missing and 3 partials ⚠️
...impl/postgres/mixins/types/data_type_formatting.py 97.77% 4 Missing and 6 partials ⚠️
...backend/impl/postgres/protocols/ddl/publication.py 52.94% 7 Missing and 1 partial ⚠️
...ord/backend/impl/postgres/protocols/ddl/routine.py 52.94% 7 Missing and 1 partial ⚠️
.../backend/impl/postgres/protocols/ddl/rls_config.py 53.33% 6 Missing and 1 partial ⚠️
...erecord/backend/impl/postgres/mixins/ddl/policy.py 95.62% 3 Missing and 3 partials ⚠️
...cord/backend/impl/postgres/protocols/ddl/domain.py 53.84% 5 Missing and 1 partial ⚠️
...d/backend/impl/postgres/protocols/ddl/collation.py 54.54% 4 Missing and 1 partial ⚠️
... and 27 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #54      +/-   ##
==========================================
+ Coverage   71.66%   74.67%   +3.01%     
==========================================
  Files         274      305      +31     
  Lines       10687    12380    +1693     
  Branches     1743     2001     +258     
==========================================
+ Hits         7659     9245    +1586     
- Misses       2438     2502      +64     
- Partials      590      633      +43     
Flag Coverage Δ
postgres-18 74.67% <90.63%> (+3.01%) ⬆️
python-3.14 74.67% <90.63%> (+3.01%) ⬆️
unittests 74.67% <90.63%> (+3.01%) ⬆️

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

☔ View full report in Codecov by Harness.
📢 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

Copy link
Copy Markdown

@vistart
vistart marked this pull request as ready for review August 15, 2026 11:39
@vistart
vistart merged commit be414c7 into main Aug 15, 2026
30 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