Repository navigation
feat(postgres): expression-based formatters, DDL improvements, protocol compliance - #57
Merged
Merged
Conversation
… format_method - Backend types carry postgres_-prefixed generic names; dispatch by naming convention (format_data_type_<name>); @DDLTypeMixin.handles registration removed. - Formatting functions take (self, expr); the ::type cast syntax is the CastExpression formatter. - Ownership of the expression source tree moves to the core library. - CI installs rhosocial-activerecord and the testsuite from their active branches.
…format_grouping_clause - Updated imports and usage in recursive_cte_graph_traversal.py (src + tests) - Updated import in test_property_graph_query_scenarios.py - Updated protocol conformance exclusion string in test_postgres_protocol_conformance.py
…ion contracts - 5 type classes declare dialect_options explicitly; unified _type_params based equality/hash (hand-written eq/hash retired) - PostgresEnumType remains BaseExpression (DDL expression, not DataType); format_data_type_postgres_enum/supports pair added for future DataType subclasses - 70+ supports_data_type_* added (1:1 with format family); supports_data_types() updated to check supports() before including types - suggested_data_types() returns empty dict (PG handles all core types natively; no honest cross-backend suggestion warranted) - Precision validation: decimal 1-1000/0-precision, float 1-53, fractional-seconds 0-6 for time/timestamp types - parse_type() constructor calls converted to keyword arguments for dialect-first signatures; PostgresArrayType/CustomType calls fixed - New test_postgres_type_protocol.py (24 tests)
- ArrayType(IntegerType(...), dialect=...) → ArrayType(element_type=..., dialect=...) - DecimalType(10, 2, dialect=...) → DecimalType(precision=10, scale=2, dialect=...) - TimestampType(6, dialect=...) → TimestampType(fsp=6, dialect=...) - Hash tests updated: hash(X) == hash(X._type_params())
…ataType convention Update ColumnDefinition and DataType subclass constructors to use dialect-first signatures throughout examples: - ColumnDefinition(dialect, name, type, ...) - PostgresSerialType(dialect), ArrayType(dialect, ...), IntegerType(dialect), etc. Aligns with parameter-inline refactor in core library.
- Complete POSTGRES_PROTOCOLS base list with 5 previously-omitted generic protocols (AlterTableModifierSupport, DDLTypeSupport, GraphTableSupport, ILIKESupport, TriggerSupport). - Add POSTGRES_NOT_IMPLEMENTED (intentional: generic FunctionSupport [Postgres uses PostgresRoutineSupport]; known gaps: AutoIncrementSupport, GeneratedColumnSupport — see TODO comments). - Add negative isinstance test + partition completeness test. - Whitelist AlterTableModifierSupport/PostgresConstraintSupport and ILIKESupport/PostgresILIKESupport overlaps.
Postgres supports SERIAL/IDENTITY and (12+) STORED generated columns but never declared the generic protocols. Add the missing methods and promote both protocols from POSTGRES_NOT_IMPLEMENTED to the positive list.
…ion-based signature Core protocol changed from scatter args to (self, expr). Update backend overrides and tests to construct expression objects.
- Add backend reserved words and wire format_identifier(need_quote=...) through SQLDialectBase, warning when a reserved word is left unquoted - Rename supports_table_like_syntax to supports_create_table_like - Add identifier quoting tests
Delete format_identifier, format_commit/rollback_transaction, format_savepoint/release_savepoint, format_drop_view_statement, format_drop_materialized_view_statement, supports_generated_columns, format_truncate_statement, format_refresh_materialized_view_statement, format_explain_statement — all equivalent to implementations provided by SQLDialectBase, TransactionControlMixin, ViewMixin, TruncateMixin, PostgresFeaturesMixin, and ExplainMixin respectively. dialect.py: 1877 → 1866 (-11)
The dialect methods were removed without moving the behavior into PostgresExplainMixin/PostgresTruncateMixin, so the generic core formatters won: EXPLAIN options rendered invalid SQL (COSTS/FORMAT) and TRUNCATE ignored the 8.4 restart-identity gate. Restore both.
The reverse-coverage conformance test requires the mixin formatters to be declared on PostgresExplainSupport/PostgresTruncateSupport.
Move 30 methods from dialect.py into 17 mixin files: - datetime.py, collation.py, dql.py, json.py, generated_column.py, expression.py, function.py (new) - Extended: ilike.py, upsert.py, view.py, materialized_view.py, ddl/column.py, ddl/index.py, table.py, ddl/constraint.py, dml/locking.py, transaction.py dialect.py: 1657 → 645 lines (retains __init__, _validate_data_type, get_parameter_placeholder, get_server_version, create_schema_differ).
…ange expressions - Add ILikeExpression for format_ilike_expression - Add EnumTypeNameExpression, EnumValuesExpression - Add CreateEnumTypeRawExpression, DropEnumTypeRawExpression, AlterEnumAddValueRawExpression - Add CreateMultirangeTypeStatementExpression, MultirangeAggFunctionExpression - Update format methods to accept expressions - Add 16 new tests
Add the reverse-coverage declarations (constraint/index/locking/ materialized-view/transaction/upsert/view) and align the ILIKESupport format_ilike_expression signature.
The dialect dispatches expression formatters as formatter(expr); a formatter referenced by format_method must therefore accept exactly (self, expr). Drop the raw/str hybrid signature on PostgresILIKEMixin.format_ilike_expression and read column/pattern/ negate from the ILIKEExpression node instead. Align the PostgresILIKESupport declaration and update the ILIKE tests to build an ILIKEExpression; exempt the generic ILIKESupport protocol from the signature-conformance test since its named-parameter declaration is a pre-existing core signature.
expr.column is an expression node; render it via to_sql().
Drop the raw-string test helper; construct ILIKEExpression with a Column and dispatch via to_sql().
Route DDL/extension formatter tests through their expression nodes and to_sql() instead of calling dialect.format_*() with raw values or pre-built expressions. Convert bloom/btree_gin/btree_gist unit tests to CreateIndexExpression, enum name/values to EnumTypeNameExpression / EnumValuesExpression, and inline PartitionValue construction (dropping the test-local _format_partition_value helper).
The ILIKEExpression constructor requires an expression column; pass Column(...) instead of a raw string so to_sql() exercises the real expression/formatter path.
Replace hard-coded %s bind markers in SQL builders with the dialect's single source of truth: self.p() for dialect mixins and self.dialect.p()/self._backend.dialect.p() for non-dialect helpers.
…pr type hints - Mixin methods: return type 'tuple' -> 'Tuple[str, tuple]' for format_on_conflict_clause, format_create_view_statement, format_create_materialized_view_statement, format_truncate_statement, format_explain_statement, format_datetime_diff_expression - ENUM raw methods: return type 'str' -> 'Tuple[str, tuple]' for format_enum_type_name, format_enum_values, format_create_enum_type_raw, format_drop_enum_type_raw, format_alter_enum_add_value_raw; convenience methods (create/drop/alter_enum_*) extract SQL from tuple - Protocol layer: add 'Any' type hint to all expr parameters - Mixin layer: add concrete type hints for expr parameters (OnConflictClause, CreateViewExpression, etc.) and rename explain_expr -> expr in format_explain_statement - Eliminate isinstance(Column) in format_on_conflict_clause by using getattr(expr_val, 'table', None) == 'EXCLUDED' and unified to_sql() for conflict_target
…re change format_storage_options now accepts StorageOptionsExpression and returns Tuple[str, tuple] instead of dict and str.
…ssion
- remove the dialect_options['like_table'] block from
format_create_table_statement and delete the format_create_table_like
delegate
- add PostgreSQL's format_create_table_like_statement rendering the
column-list clause form CREATE TABLE t (LIKE src [INCLUDING ...])
with support for dict/list like_options; space-separated options
(the old comma-separated form was invalid PostgreSQL)
- protocols + docs + tests updated to CreateTableLikeExpression
BREAKING CHANGE: CREATE TABLE ... LIKE is no longer expressed through
CreateTableExpression(dialect_options={'like_table': ...}); use
CreateTableLikeExpression(dialect, table, like_table, like_options=...).
- remove the dialect_options['unlogged_table'] post-processing; the generic renderer now emits CREATE UNLOGGED TABLE gated on supports_unlogged_table() - explicitly reject UNLOGGED combined with TEMPORARY (mutually exclusive) - tests use CreateTableOptions(unlogged=True) BREAKING CHANGE: request UNLOGGED via CreateTableOptions(unlogged=True); the dialect_options key is ignored.
PostgreSQL format_column_definition now reads identity from the typed ColumnDefinition.identity field, falling back to dialect_options["identity"] for backward compatibility.
- Add PostgresDatabaseMixin for CREATE/DROP/ALTER DATABASE support - Add PostgresViewMixin with capability gating (OR REPLACE, IF EXISTS, CASCADE, MATERIALIZED) - Add test_postgres_ddl_improvements.py with 11 tests - Rename view.py -> ddl_view.py
… on PG < 8.4 - PostgreSQL truncate mixin: raise UnsupportedFeatureError when RESTART IDENTITY is requested on versions < 8.4 (was silently skipping before) - Updated test to expect UnsupportedFeatureError instead of silent skip
- PostgresReturningMixin.supports_returning_old_new() returns True on 17+ - Add tests for OLD/NEW validation and capability defaults
- PostgresReturningSupport: add supports_returning_old_new - PostgresViewSupport: add supports_create_or_replace_view / supports_if_not_exists_view - Classify DatabaseSupport in protocol conformance
…core; nulls ordering - Remove PG LockStrength; use core LockStrength via clause.strength (no dialect_options) - Remove supports_fetch_with_ties (now core default = PG 13+) - Add supports_nulls_first_last - Update examples/tests
…LMixin/ExpressionMixin)
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## release/v1.0.0.dev17 #57 +/- ##
========================================================
+ Coverage 77.15% 77.31% +0.15%
========================================================
Files 306 314 +8
Lines 12530 12884 +354
Branches 2033 2042 +9
========================================================
+ Hits 9668 9961 +293
- Misses 2171 2212 +41
- Partials 691 711 +20
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
vistart
added a commit
that referenced
this pull request
Sep 24, 2026
…ol compliance (#57) * feat(postgres): adapt to node-based expression system and declarative format_method - Backend types carry postgres_-prefixed generic names; dispatch by naming convention (format_data_type_<name>); @DDLTypeMixin.handles registration removed. - Formatting functions take (self, expr); the ::type cast syntax is the CastExpression formatter. - Ownership of the expression source tree moves to the core library. - CI installs rhosocial-activerecord and the testsuite from their active branches. * ci: test against Python 3.15.0-rc.2 * fix: Rename JoinExpression→JoinClause and format_grouping_expression→format_grouping_clause - Updated imports and usage in recursive_cte_graph_traversal.py (src + tests) - Updated import in test_property_graph_query_scenarios.py - Updated protocol conformance exclusion string in test_postgres_protocol_conformance.py * feat(dialect-protocol): formalize PostgreSQL type support and suggestion contracts - 5 type classes declare dialect_options explicitly; unified _type_params based equality/hash (hand-written eq/hash retired) - PostgresEnumType remains BaseExpression (DDL expression, not DataType); format_data_type_postgres_enum/supports pair added for future DataType subclasses - 70+ supports_data_type_* added (1:1 with format family); supports_data_types() updated to check supports() before including types - suggested_data_types() returns empty dict (PG handles all core types natively; no honest cross-backend suggestion warranted) - Precision validation: decimal 1-1000/0-precision, float 1-53, fractional-seconds 0-6 for time/timestamp types - parse_type() constructor calls converted to keyword arguments for dialect-first signatures; PostgresArrayType/CustomType calls fixed - New test_postgres_type_protocol.py (24 tests) * fix(test): VarCharType dialect-first call sites in fixtures and examples * fix(test): ArrayType/DecimalType/TimestampType dialect-first call sites - ArrayType(IntegerType(...), dialect=...) → ArrayType(element_type=..., dialect=...) - DecimalType(10, 2, dialect=...) → DecimalType(precision=10, scale=2, dialect=...) - TimestampType(6, dialect=...) → TimestampType(fsp=6, dialect=...) - Hash tests updated: hash(X) == hash(X._type_params()) * fix(test): TimestampType precision keyword, ArrayType element_type keyword * fix(test): hash tests use (type, _type_params) tuple * fix(test): ArrayType dimensions keyword in test_core_type_mappings * fix(examples): adapt example code to dialect-first ColumnDefinition/DataType convention Update ColumnDefinition and DataType subclass constructors to use dialect-first signatures throughout examples: - ColumnDefinition(dialect, name, type, ...) - PostgresSerialType(dialect), ArrayType(dialect, ...), IntegerType(dialect), etc. Aligns with parameter-inline refactor in core library. * test(protocol): add negative protocol list + partition completeness - Complete POSTGRES_PROTOCOLS base list with 5 previously-omitted generic protocols (AlterTableModifierSupport, DDLTypeSupport, GraphTableSupport, ILIKESupport, TriggerSupport). - Add POSTGRES_NOT_IMPLEMENTED (intentional: generic FunctionSupport [Postgres uses PostgresRoutineSupport]; known gaps: AutoIncrementSupport, GeneratedColumnSupport — see TODO comments). - Add negative isinstance test + partition completeness test. - Whitelist AlterTableModifierSupport/PostgresConstraintSupport and ILIKESupport/PostgresILIKESupport overlaps. * feat(dialect): declare AutoIncrement + GeneratedColumn protocol support Postgres supports SERIAL/IDENTITY and (12+) STORED generated columns but never declared the generic protocols. Add the missing methods and promote both protocols from POSTGRES_NOT_IMPLEMENTED to the positive list. * fix(dialect): adapt format_fulltext_match/array_expression to expression-based signature Core protocol changed from scatter args to (self, expr). Update backend overrides and tests to construct expression objects. * feat(identifier): add reserved words and opt-out identifier quoting - Add backend reserved words and wire format_identifier(need_quote=...) through SQLDialectBase, warning when a reserved word is left unquoted - Rename supports_table_like_syntax to supports_create_table_like - Add identifier quoting tests * refactor(identifier): remove IdentifierMixin and fix format_column with _need_quote * refactor(postgres): remove 11 duplicate dialect methods Delete format_identifier, format_commit/rollback_transaction, format_savepoint/release_savepoint, format_drop_view_statement, format_drop_materialized_view_statement, supports_generated_columns, format_truncate_statement, format_refresh_materialized_view_statement, format_explain_statement — all equivalent to implementations provided by SQLDialectBase, TransactionControlMixin, ViewMixin, TruncateMixin, PostgresFeaturesMixin, and ExplainMixin respectively. dialect.py: 1877 → 1866 (-11) * fix(mixins): restore Postgres EXPLAIN and TRUNCATE formatters The dialect methods were removed without moving the behavior into PostgresExplainMixin/PostgresTruncateMixin, so the generic core formatters won: EXPLAIN options rendered invalid SQL (COSTS/FORMAT) and TRUNCATE ignored the 8.4 restart-identity gate. Restore both. * fix(protocols): declare Postgres EXPLAIN/TRUNCATE formatters The reverse-coverage conformance test requires the mixin formatters to be declared on PostgresExplainSupport/PostgresTruncateSupport. * refactor(postgres): split dialect methods into feature mixins Move 30 methods from dialect.py into 17 mixin files: - datetime.py, collation.py, dql.py, json.py, generated_column.py, expression.py, function.py (new) - Extended: ilike.py, upsert.py, view.py, materialized_view.py, ddl/column.py, ddl/index.py, table.py, ddl/constraint.py, dml/locking.py, transaction.py dialect.py: 1657 → 645 lines (retains __init__, _validate_data_type, get_parameter_placeholder, get_server_version, create_schema_differ). * feat(postgres): format_* signature compliance - ILIKE + Enum + Multirange expressions - Add ILikeExpression for format_ilike_expression - Add EnumTypeNameExpression, EnumValuesExpression - Add CreateEnumTypeRawExpression, DropEnumTypeRawExpression, AlterEnumAddValueRawExpression - Add CreateMultirangeTypeStatementExpression, MultirangeAggFunctionExpression - Update format methods to accept expressions - Add 16 new tests * chore: resolve merge conflict in expression types * fix(postgres): restore types.py accidentally emptied during conflict resolution * fix(postgres): fix expression format_method to match mixin method names * fix(postgres): fix format_method for EnumTypeNameExpression and EnumValuesExpression * fix(postgres): add missing methods to protocols for expression compliance * fix(postgres): declare mixin formatters on protocols Add the reverse-coverage declarations (constraint/index/locking/ materialized-view/transaction/upsert/view) and align the ILIKESupport format_ilike_expression signature. * fix(postgres): convert format_ilike_expression to (self, expr) The dialect dispatches expression formatters as formatter(expr); a formatter referenced by format_method must therefore accept exactly (self, expr). Drop the raw/str hybrid signature on PostgresILIKEMixin.format_ilike_expression and read column/pattern/ negate from the ILIKEExpression node instead. Align the PostgresILIKESupport declaration and update the ILIKE tests to build an ILIKEExpression; exempt the generic ILIKESupport protocol from the signature-conformance test since its named-parameter declaration is a pre-existing core signature. * refactor(postgres): drop str fallback in ILIKE column expr.column is an expression node; render it via to_sql(). * test(postgres): build ILIKE expressions with Column nodes Drop the raw-string test helper; construct ILIKEExpression with a Column and dispatch via to_sql(). * test(postgres): exercise formatter tests via expression to_sql() Route DDL/extension formatter tests through their expression nodes and to_sql() instead of calling dialect.format_*() with raw values or pre-built expressions. Convert bloom/btree_gin/btree_gist unit tests to CreateIndexExpression, enum name/values to EnumTypeNameExpression / EnumValuesExpression, and inline PartitionValue construction (dropping the test-local _format_partition_value helper). * test(postgres): build ILIKE expression tests with Column nodes The ILIKEExpression constructor requires an expression column; pass Column(...) instead of a raw string so to_sql() exercises the real expression/formatter path. * refactor(postgres): emit bind markers via dialect placeholder Replace hard-coded %s bind markers in SQL builders with the dialect's single source of truth: self.p() for dialect mixins and self.dialect.p()/self._backend.dialect.p() for non-dialect helpers. * refactor: unify format_* return types to Tuple[str, tuple] and add expr type hints - Mixin methods: return type 'tuple' -> 'Tuple[str, tuple]' for format_on_conflict_clause, format_create_view_statement, format_create_materialized_view_statement, format_truncate_statement, format_explain_statement, format_datetime_diff_expression - ENUM raw methods: return type 'str' -> 'Tuple[str, tuple]' for format_enum_type_name, format_enum_values, format_create_enum_type_raw, format_drop_enum_type_raw, format_alter_enum_add_value_raw; convenience methods (create/drop/alter_enum_*) extract SQL from tuple - Protocol layer: add 'Any' type hint to all expr parameters - Mixin layer: add concrete type hints for expr parameters (OnConflictClause, CreateViewExpression, etc.) and rename explain_expr -> expr in format_explain_statement - Eliminate isinstance(Column) in format_on_conflict_clause by using getattr(expr_val, 'table', None) == 'EXCLUDED' and unified to_sql() for conflict_target * chore: fix .gitignore for .claude/plan*/ * fix: update storage_options test for StorageOptionsExpression signature change format_storage_options now accepts StorageOptionsExpression and returns Tuple[str, tuple] instead of dict and str. * refactor(ddl)!: migrate CREATE TABLE ... LIKE to CreateTableLikeExpression - remove the dialect_options['like_table'] block from format_create_table_statement and delete the format_create_table_like delegate - add PostgreSQL's format_create_table_like_statement rendering the column-list clause form CREATE TABLE t (LIKE src [INCLUDING ...]) with support for dict/list like_options; space-separated options (the old comma-separated form was invalid PostgreSQL) - protocols + docs + tests updated to CreateTableLikeExpression BREAKING CHANGE: CREATE TABLE ... LIKE is no longer expressed through CreateTableExpression(dialect_options={'like_table': ...}); use CreateTableLikeExpression(dialect, table, like_table, like_options=...). * refactor(ddl)!: UNLOGGED via typed CreateTableOptions - remove the dialect_options['unlogged_table'] post-processing; the generic renderer now emits CREATE UNLOGGED TABLE gated on supports_unlogged_table() - explicitly reject UNLOGGED combined with TEMPORARY (mutually exclusive) - tests use CreateTableOptions(unlogged=True) BREAKING CHANGE: request UNLOGGED via CreateTableOptions(unlogged=True); the dialect_options key is ignored. * feat(ddl): prefer typed identity field over dialect_options PostgreSQL format_column_definition now reads identity from the typed ColumnDefinition.identity field, falling back to dialect_options["identity"] for backward compatibility. * refactor(ddl): rename table.py → ddl_table.py in mixins * feat: add PostgreSQL DDL improvements with capability gating - Add PostgresDatabaseMixin for CREATE/DROP/ALTER DATABASE support - Add PostgresViewMixin with capability gating (OR REPLACE, IF EXISTS, CASCADE, MATERIALIZED) - Add test_postgres_ddl_improvements.py with 11 tests - Rename view.py -> ddl_view.py * fix: B01 TRUNCATE RESTART IDENTITY now raises UnsupportedFeatureError on PG < 8.4 - PostgreSQL truncate mixin: raise UnsupportedFeatureError when RESTART IDENTITY is requested on versions < 8.4 (was silently skipping before) - Updated test to expect UnsupportedFeatureError instead of silent skip * refactor: remove ReturningMixin import (merged into DMLMixin in core) * feat: add supports_returning_old_new for PostgreSQL 17+ OLD/NEW refs - PostgresReturningMixin.supports_returning_old_new() returns True on 17+ - Add tests for OLD/NEW validation and capability defaults * fix: declare new RETURNING/view capability methods in Postgres protocols - PostgresReturningSupport: add supports_returning_old_new - PostgresViewSupport: add supports_create_or_replace_view / supports_if_not_exists_view - Classify DatabaseSupport in protocol conformance * refactor(dql): typed lock strength; lift supports_fetch_with_ties to core; nulls ordering - Remove PG LockStrength; use core LockStrength via clause.strength (no dialect_options) - Remove supports_fetch_with_ties (now core default = PG 13+) - Add supports_nulls_first_last - Update examples/tests * refactor: remove core DQL/Expression mixin references (merged into DQLMixin/ExpressionMixin) * feat(ddl): render generated columns via core GeneratedColumnExpression * chore: add scripts/preflight.sh and optional git hook installer * chore(ci): update rhosocial-activerecord install source to release/v1.0.0.dev30 * chore: add changelog fragment for PR #57
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Description
Comprehensive PostgreSQL backend overhaul: expression-based formatter system, DDL improvements, protocol compliance, and identifier quoting.
This PR modernizes the PostgreSQL backend to align with the rhosocial-activerecord core's node-based expression system. Key changes include:
format_*methods now accept expression objects instead of raw parameters, following the standardized formatter signature contractCreateTableLikeExpression, UNLOGGED via typedCreateTableOptions, dialect method renames, removal of duplicate/mixed-in dialect methodsAdds rhosocial-activerecord
>=1.0.0.dev29dependency for expression system.Type of change
feat: A new featuredocs: Documentation only changesperf: A code change that improves performancetest: Adding missing tests or correcting existing testschore: Changes to the build process or auxiliary toolsci: Changes to our CI configuration files and scriptsbuild: Changes that affect the build system or external dependenciesrevert: Reverts a previous commitBreaking Change
Impact:
CreateTableLikeExpressionreplaces rawCREATE TABLE ... LIKEstring formatting. UNLOGGED tables now use typedCreateTableOptions. Dialect methods renamed to Postgres-prefixed convention. Some mixin methods removed (merged into core DQLMixin/ExpressionMixin).Migration path: Update any direct calls to renamed/removed dialect methods. Use
CreateTableLikeExpressionfor CREATE TABLE ... LIKE. UseCreateTableOptions(unlogged=True)for UNLOGGED tables.Applicable
rhosocial-activerecordVersion Range:>=1.0.0.dev29Related Repositories/Packages
rhosocial-activerecord(core): Requires>=1.0.0.dev29for expression system changesrhosocial-activerecord-testsuite: No coordinated changes requiredTesting
Test Plan:
Tests were skipped locally. CI/CD will validate against PostgreSQL across Python 3.8–3.14.
Checklist
Additional Notes