fix(query): auto-coerce Postgres ENUM columns to text on read (#26) - #29
Merged
Conversation
sqlx's built-in `String` decoder isn't compatible with a user-defined enum's dynamic OID, so `try_get::<Option<String>>` returned Err and every branch of `pg_column_value` fell through to JSON `null` for enum columns. Callers had to remember `::text` on every enum SELECT. The row materialiser now inspects `PgTypeInfo::kind()` and decodes `PgTypeKind::Enum` (and `PgTypeKind::Array(Enum)`) columns via their raw wire form. Postgres transmits enum values as UTF-8 labels, so this is safe and no cast is required. Adds a Liquibase changeset for a `ticket_priority` enum + `tickets` table so the Postgres integration suite covers scalar enum, multi-row enum, enum array, and empty enum array. Closes #26. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
turnerrainer
force-pushed
the
fix/issue-26-pg-enum-text-coerce
branch
from
September 9, 2026 20:56
4b76950 to
1bf03a1
Compare
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
Fixes #26. A bare
SELECT status FROM twherestatusis a Postgres user-defined enum previously returned JSONnullfor the enum column, because sqlx's built-inStringdecoder isn't compatible with the enum's dynamic OID and every branch ofpg_column_valuefell through to the last-resort text probe (which also errors on unknown OIDs).The row materialiser now inspects
PgTypeInfo::kind()and, forPgTypeKind::Enum(andPgTypeKind::Array(Enum)), decodes viarow.try_get_raw+<String as Decode<Postgres>>::decodedirectly. Postgres transmits enum values as UTF-8 labels in both text and binary formats, so no cast is required.::textcast would have produced.Schema changes
010-enum-table—ticket_priorityenum +ticketstable with a scalar enum column and an enum-array column.fixtures-tickets— three rows exercising the scalar, mixed-array, and empty-array cases.Existing operator DBs are unaffected: Liquibase is idempotent by changeset ID and the new changeset only adds a type + a table.
Test plan
cargo +1.88.0 fmt --all -- --checkcargo clippy --all-targets --locked -- -D warningspg_enum_column_selected_without_cast_returns_label_stringpg_enum_column_multi_row_labels_are_stringpg_enum_array_column_returns_array_of_labelspg_empty_enum_array_returns_empty_array🤖 Generated with Claude Code