Skip to content

refactor: implement phase 3 ORM hardening#25

Merged
davebarnwell merged 2 commits intomainfrom
feature/phase-3-quality-portability
Mar 8, 2026
Merged

refactor: implement phase 3 ORM hardening#25
davebarnwell merged 2 commits intomainfrom
feature/phase-3-quality-portability

Conversation

@davebarnwell
Copy link
Owner

Summary

Implements Phase 3 of the roadmap around quality, portability, and maintenance for the ORM core.

This change tightens behavior that was already mostly present in the library but not consistently expressed across drivers. In practice, it makes metadata refresh explicit, normalizes no-op update handling, and broadens integration coverage for cases that were under-tested.

User impact

Consumers can now refresh cached table metadata without reconnecting by calling YourModel::refreshTableMetadata(). That matters when schemas change during long-lived processes or test runs.

Update behavior is also less sensitive to driver-specific rowCount() semantics. A no-op update on an existing row is now treated as a successful update instead of looking like a failure simply because the database reported zero changed rows.

The documentation now makes UTC timestamp behavior explicit and calls out support for PostgreSQL schema-qualified tables.

Root cause

A few driver-facing behaviors depended on incidental implementation details rather than explicit library rules.

Table metadata was cached per model class with no direct way to invalidate it short of reconnecting. Update success also relied too directly on raw PDO affected-row behavior, which varies across drivers for no-op writes. Several edge cases were effectively supported but not protected by integration coverage.

Fix

The model now exposes refreshTableMetadata() to clear cached column metadata for the current model class. Timestamp generation was centralized through currentTimestamp() so the UTC formatting behavior is explicit.

The update path now uses an updateSucceeded() check that treats an update as successful when the target row still exists, even if the driver reports zero changed rows. That keeps behavior consistent for no-op updates without loosening failure handling for missing rows.

The test suite was expanded with cross-driver coverage for inherited connections, custom primary keys, schema refresh behavior, timestamp opt-out behavior, timestamp-less tables, PostgreSQL schema-qualified tables, and no-op update handling.

Validation

  • vendor/bin/phpunit -c phpunit.xml.dist
  • vendor/bin/phpstan analyse -c phpstan.neon
  • vendor/bin/php-cs-fixer fix --dry-run --diff

@davebarnwell davebarnwell marked this pull request as ready for review March 8, 2026 09:28
Copilot AI review requested due to automatic review settings March 8, 2026 09:28
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements Phase 3 ORM “hardening” by making table-metadata cache invalidation explicit, normalizing update success semantics across PDO drivers, and expanding cross-driver integration coverage.

Changes:

  • Add Model::refreshTableMetadata() to invalidate cached column metadata per model class.
  • Centralize automatic timestamp generation via currentTimestamp() and document UTC behavior.
  • Treat no-op updates as successful when the target row still exists; expand integration tests for schema refresh, custom PKs, schema-qualified PG tables, timestamp opt-out, and no-op updates.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/Model/Model.php Adds metadata refresh API, centralizes timestamp formatting, and changes update success logic to be driver-consistent.
tests/Model/CategoryTest.php Extends cross-driver integration coverage for new Phase 3 behaviors and edge cases.
test-src/Model/CodedCategory.php Test model for custom primary key support across drivers.
test-src/Model/MetadataRefreshCategory.php Test model for validating metadata refresh behavior after schema changes.
test-src/Model/SchemaQualifiedCategory.php Test model for PostgreSQL schema-qualified table name support.
test-src/Model/UntimedCategory.php Test model for tables without timestamp columns.
README.md Documents UTC timestamp formatting, metadata refresh usage, and PostgreSQL schema-qualified table support.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@davebarnwell davebarnwell merged commit 1f604d8 into main Mar 8, 2026
7 checks passed
@davebarnwell davebarnwell deleted the feature/phase-3-quality-portability branch March 8, 2026 09:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants