Repository navigation
Name event columns explicitly in Postgres event storage adapter - #131
Open
wickedwukong wants to merge 13 commits into
Open
wickedwukong wants to merge 13 commits into
wickedwukong wants to merge 13 commits into
Conversation
insert_batch_query returned *, so an events table with a column StoredEvent does not know broke every save with TypeError. Derive the column list from StoredEvent's fields and use it in RETURNING. Part of #130.
read_last_query selected *, so an events table with a column StoredEvent does not know broke latest and every save to an existing stream with TypeError. Select the StoredEvent columns by name instead. Part of #130.
scan_query selected *, so an events table with a column StoredEvent does not know broke scan with TypeError. Select the StoredEvent columns by name instead. Part of #130.
read_last_category_batch_query selected DISTINCT ON ... *, so an events table with a column StoredEvent does not know broke every save to a category with existing streams with TypeError. Select the StoredEvent columns by name instead. Part of #130.
event_columns() took no input and always built the same SQL, so hold it as EVENT_COLUMNS_SQL instead. Part of #130.
Add a fragment for the explicit event columns fix and its limits. Correct the metadata fragment: releases before metadata support, such as 0.1.11, do not ignore the extra column. Their wildcard reads and RETURNING fail once it exists, so an application-only rollback does not work. Split the migration so the default stays while any writer omits metadata. Part of #130.
wickedwukong
force-pushed
the
gh-130-explicit-event-columns
branch
from
October 5, 2026 09:43
d6b7587 to
dbf70c1
Compare
This branch has not been deployed
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.
Summary
PostgresEventStorageAdapternow names theStoredEventcolumns in every query whose rows reachclass_row(StoredEvent), instead of using*. Aneventstable with a column the installedStoredEventdoes not know no longer breaks reads or writes.Closes #130.
Motivation
psycopg's
class_rowcallsStoredEvent(**row), so any extra column becomes an unexpected keyword argument:This turns additive schema changes into read-time and write-time breaks. It forced a read shim onto both sides of a downstream 0.1.11 → 0.1.12a3 upgrade.
The issue names the
SELECT *reads. Two more wildcards fedclass_rowand are fixed here too:RETURNING *(every save) andSELECT DISTINCT ON (...) *(save to a category).Changes
Key Changes
saveinsert_batch_queryRETURNING *latest,saveto an existing streamread_last_querySELECT *scanscan_queryQuery().select_all()saveto a category with existing streamsread_last_category_batch_querySELECT DISTINCT ON (category, stream ) *EVENT_COLUMNS, derived fromdataclasses.fields(StoredEvent), and its SQL formEVENT_COLUMNS_SQL.class_rowalready relies on field names matching column names, so this adds no new coupling.metadatachangelog fragment (see below).Implementation Details
scan_queryusesQuery().select(*EVENT_COLUMNS), so the constraint appliers (which only addWHERE/ORDER BY) are unaffected.Star,select_all()and the generic query converters are unchanged. Their other users never buildStoredEvent.dict_rowand pick columns by name, so they are unchanged.Changelog correction for
metadataThe
metadatafragment said the previous version "ignores the extra column", so an application-only rollback could leave it in place. That is not true: 0.1.11 reads withSELECT *andRETURNING *and fails as soon as the column exists. The fragment now:DEFAULT 'null'::jsonbuntil every writer suppliesmetadata;DROP COLUMN.Breaking Changes
None. No API or schema change. Queries now fetch only known columns, so an extra column is no longer read.
What this does and does not guarantee
NOT NULLcolumn keeps a default while old and new versions overlap, and the migration runs before the new version starts.metadataupgrade rolling-safe. Pods still on 0.1.11 break oncemetadataexists. A 0.1.11.x backport of this fix, deployed first, would make that upgrade safe.How to Verify
mise run --force: 1747 unit, 143 integration, 3 component tests pass; lint, format and types clean.TestPostgresStorageAdapterUnknownColumnsaddsunknown_column TEXT NOT NULL DEFAULT 'unknown'to a real table and covers everyclass_rowpath: save to a new stream, save to an existing stream,latest(log, category, stream),scan(log, category, stream), and save to a category with existing streams. Each test was seen failing with theTypeErrorbefore its query change.test_batch_insert_query_builds_correct_sqlnow pins the explicitRETURNINGlist.The plan and research for this change are in
meta/plans/andmeta/research/.🤖 Generated with Claude Code