Skip to content

7.0: Executor observers, Journal (record/restore DML), remove deprecated driver query methods - #36

Open
byjg wants to merge 3 commits into
masterfrom
7.0
Open

7.0: Executor observers, Journal (record/restore DML), remove deprecated driver query methods#36
byjg wants to merge 3 commits into
masterfrom
7.0

Conversation

@byjg

@byjg byjg commented Jul 12, 2026

Copy link
Copy Markdown
Owner

Summary

Major release completing the refactoring started in 6.0. See CHANGELOG-7.0.md for the full changelog.

Breaking changes

  • Removed the query methods deprecated since 6.0 (getIterator, getScalar, getAllFields, execute, executeAndGetId) from DbDriverInterface, the PDO/OCI8 drivers and DatabaseRouter. DatabaseExecutor is now the single API for queries and commands. Docs updated accordingly (docs/deprecated-features.md is now the migration guide).

Executor Observers

  • New DatabaseEventObserverInterface, attachable with DatabaseExecutor::addObserver() / removeObserver()
  • Events: BEFORE_QUERY, AFTER_QUERY, BEFORE_EXECUTE, AFTER_EXECUTE, each carrying a DatabaseEvent with the SqlStatement, the executor and the result
  • No measurable overhead when no observer is attached (benchmarked against the 6.0 executor: difference within run-to-run noise)

Journal (record and restore DML changes)

  • JournalRecorder::forAllTables() / ::forTables(...) records INSERT/UPDATE/DELETE with row values before and after each operation; configurable primary keys
  • JournalRestorer replays the journal in reverse — designed for functional test setUp/tearDown
  • Optional strict mode: throws JournalException on statements that cannot be journaled/restored (unparseable DML is blocked before execution) instead of skipping silently

Infrastructure

  • SQL Server image pinned to 2022-latest (compose + CI): the 2025 image crashes on startup on hybrid CPUs (Intel P/E-cores) with a topology assert; compose service renamed mssqlsqlserver to match CI; MSSQL_SA_PASSWORD; wait-for-db.sh no longer reports success on health-check timeout

Testing

  • 28 new tests (observers; journal recording, restore round-trips, custom PKs, strict mode)
  • Full suite green locally: 711 tests, 0 errors against SQLite, MySQL, PostgreSQL and SQL Server (dblib + sqlsrv); Psalm clean

Supersedes #35.

byjg added 3 commits July 12, 2026 11:44
…thods (7.0)

Version 7.0 completes the refactoring started in 6.0 and adds the
observability features:

Breaking changes:
- Remove the query methods deprecated since 6.0 (getIterator, getScalar,
  getAllFields, execute, executeAndGetId) from DbDriverInterface, the
  PDO/OCI8 drivers and DatabaseRouter. DatabaseExecutor is now the
  single API for executing queries and commands.

New features:
- Generic event mechanism on DatabaseExecutor
  (DatabaseEventObserverInterface, addObserver/removeObserver) firing
  BEFORE/AFTER_QUERY and BEFORE/AFTER_EXECUTE events, with no overhead
  when no observer is attached.
- Journal package records INSERT, UPDATE and DELETE statements with the
  row values before and after each operation:
  - JournalRecorder watches all tables or a specific set, with
    configurable primary keys
  - JournalRestorer replays the journal in reverse to restore the
    previous database state (functional test setUp/tearDown)
  - Optional strict mode throws JournalException on statements that
    cannot be journaled/restored instead of skipping them silently

Infrastructure:
- Pin the SQL Server image to 2022-latest in docker-compose.yml and CI:
  the 2025 image (current 'latest') crashes on startup on hybrid CPUs
  (Intel P/E-cores) with a topology assert. Rename the compose service
  from mssql to sqlserver (matching CI), use MSSQL_SA_PASSWORD instead
  of the deprecated SA_PASSWORD, and fix wait-for-db.sh reporting the
  database as up when the health check timed out.

Includes tests, documentation (docs/observers.md, docs/journal.md,
removal notes across existing docs) and CHANGELOG-7.0.md.
Cloudflare D1 is SQLite compatible but reachable only over HTTPS, so it has
no PDO driver. DbD1Driver implements DbDriverInterface directly on top of the
D1 REST API, following the structure of the existing non-PDO driver
(DbOci8Driver): prepareStatement builds the request, executeCursor performs
the POST and D1Iterator wraps the returned rows.

    d1://{account_id}:{api_token}@api.cloudflare.com/{database_id}

Details worth noting:

- Named parameters are rewritten to the positional "?" placeholders the API
  expects, handling repeated parameters, quoted literals and "::" casts.
- executeAndGetInsertedId() reads meta.last_row_id from the response.
  "select last_insert_rowid()" would run as a separate HTTP request on a
  different connection and always answer 0.
- Transactions throw NotAvailableException: the API rejects BEGIN/COMMIT
  because every request is already committed atomically on its own.
- The Sessions API is only available through the Workers binding, so the
  driver cannot provide sequential consistency when read replication is
  enabled. isServedByPrimary()/getServedByRegion() expose what D1 reports.

The driver works with any PSR-18 client and falls back to byjg/webrequest.
tests/D1DriverTest.php covers it through a recording transport double, so it
runs in CI without credentials; testsdb/D1Test.php runs against a real
database and skips unless D1_ACCOUNT_ID, D1_DATABASE_ID and D1_API_TOKEN are
set. Both suites were verified against a live D1 database.

Dependencies byjg/uri, byjg/anydataset, byjg/cache-engine and byjg/webrequest
move to ^7.0.
Widen the PHP constraint to ">=8.3 <8.7"; the previous "<8.6" is
exclusive and excluded PHP 8.6.

Bump byjg/* dependencies to ^7.0. While 7.0 is unreleased these resolve
to 7.0.x-dev from each component's 7.0 branch, via minimum-stability dev
with prefer-stable.

Pin PHPUnit to ^12.5 and move Psalm to tools/psalm/composer.json. Psalm
enumerates supported PHP versions and no release lists 8.6, so as a
require-dev it made "composer install" fail on the 8.6 build before any
test ran. "composer psalm" bootstraps the tool and runs it.

CI: add PHP 8.6 to the matrix; the Psalm job runs on 8.5.

Housekeeping: rename phpunit.xml.dist to phpunit.xml, carry the 6.x
changelogs onto this branch, and update CHANGELOG-7.0.md.
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.

1 participant