Skip to content

feat(schema): implement schema-diff support and DataType refactoring for PostgreSQL backend - #46

Merged
vistart merged 22 commits into
release/v1.0.0.dev16from
feature/schema-snapshot-diff
Jun 24, 2026
Merged

vistart merged 22 commits into
release/v1.0.0.dev16from
feature/schema-snapshot-diff

Conversation

@vistart

@vistart vistart commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Description

This PR implements the schema-diff subsystem for PostgreSQL backend, along with DataType system refactoring to match the core python-activerecord changes.

Schema Diff

  • Add PostgresSchemaDiffer
  • Add schema-diff examples for PostgreSQL backend
  • Add serialization roundtrip test with table data assertions

DataType System Refactoring

  • Implement PostgreSQL-specific DataType subclasses and type support mixin
  • Add __eq__/__hash__ to all PostgreSQL parameterized types
  • Add parsed_data_type to PostgreSQL _parse_columns
  • Add synonyms to PostgreSQL types
  • Update to DDLTypeSupport protocol (format_data_type returns Tuple[str, tuple])
  • Use @DDLTypeMixin.handles decorator
  • Remove _default_sql(), delegate to format_data_type()

Type Annotations

  • Add complete type annotations to all format_data_type_* methods
  • Return Tuple[str, tuple] from all type formatting methods

Type of change

  • feat: A new feature
  • refactor: A code change that neither fixes a bug nor adds a feature
  • style: Changes that do not affect the meaning of the code (type annotations)
  • test: Adding missing tests or correcting existing tests

Breaking Change

  • Yes
  • No

Related Repositories/Packages

This is a coordinated update with python-activerecord core (PR #108). The PostgreSQL backend implements the updated DDLTypeSupport protocol and DDLTypeMixin from the core refactoring.

Testing

  • I have added new tests to cover my changes.
  • I have updated existing tests to reflect my changes.
  • All existing tests pass.
  • This change has been tested on PostgreSQL backend.

Test Plan:
Requires PostgreSQL database for full integration tests.

Checklist

  • My code follows the project's code style guidelines.
  • I have performed a self-review of my own code.
  • My changes generate no new warnings.
  • I have added a Changelog fragment (changelog.d/<issue_number>.<type>.md).
  • I have verified that my changes do not introduce SQL injection vulnerabilities.

vistart and others added 17 commits June 19, 2026 23:24
…t 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
…aryingType

- 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)
Call DataType.parse_data_type_str(dialect, data_type) when
constructing ColumnInfo so that introspection results carry
structured DataType instances for schema comparison.
- PostgresSerialType ↔ IntegerType/SerialType
- PostgresSmallSerialType ↔ SmallIntType/SmallSerialType
- PostgresBigSerialType ↔ BigIntType/BigSerialType
- PostgresCharacterVaryingType ↔ VarCharType
PostgresByteaType ↔ BlobType for cross-backend schema comparison.
…verride

- 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
…esTypeFormatSupportMixin 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
- 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
- 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
…class

- 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
Column order has no semantic meaning in PostgreSQL; array dimension
equivalence is handled by PostgresArrayType.is_equivalent().
…ckend

- 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)
…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
@vistart vistart self-assigned this Jun 24, 2026
vistart added 5 commits June 24, 2026 10:22
…2 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.
@codecov

codecov Bot commented Jun 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 59.05097% with 233 lines in your changes missing coverage. Please review.
✅ Project coverage is 71.02%. Comparing base (63ed8d1) to head (bfa91de).

Files with missing lines Patch % Lines
...impl/postgres/mixins/types/data_type_formatting.py 54.78% 178 Missing and 25 partials ⚠️
...verecord/backend/impl/postgres/expression/types.py 76.19% 24 Missing and 1 partial ⚠️
...activerecord/backend/impl/postgres/mixins/table.py 44.44% 3 Missing and 2 partials ⚠️
Additional details and impacted files
@@                   Coverage Diff                    @@
##           release/v1.0.0.dev16      #46      +/-   ##
========================================================
- Coverage                 71.68%   71.02%   -0.66%     
========================================================
  Files                       274      276       +2     
  Lines                     10687    11253     +566     
  Branches                   1743     1825      +82     
========================================================
+ Hits                       7661     7993     +332     
- Misses                     2437     2643     +206     
- Partials                    589      617      +28     
Flag Coverage Δ
postgres-18 71.02% <59.05%> (-0.66%) ⬇️
python-3.14 71.02% <59.05%> (-0.66%) ⬇️
unittests 71.02% <59.05%> (-0.66%) ⬇️

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.

@vistart
vistart merged commit fb975d5 into release/v1.0.0.dev16 Jun 24, 2026
15 of 17 checks passed
@sonarqubecloud

Copy link
Copy Markdown

@vistart vistart mentioned this pull request Aug 15, 2026
8 of 12 tasks
vistart added a commit that referenced this pull request Aug 15, 2026
…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
@vistart
vistart deleted the feature/schema-snapshot-diff branch October 1, 2026 03:52
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