Skip to content

pgxoption: nested module for native pgx v5 (pgtype) integration - #54

Open
moznion wants to merge 1 commit into
mainfrom
pgxoption-submodule
Open

pgxoption: nested module for native pgx v5 (pgtype) integration#54
moznion wants to merge 1 commit into
mainfrom
pgxoption-submodule

Conversation

@moznion

@moznion moznion commented Aug 9, 2026

Copy link
Copy Markdown
Owner

What

Adds github.com/moznion/go-optional/pgxoption as a nested Go module (own go.mod, so the core package stays dependency-free; release by tagging pgxoption/vX.Y.Z).

pgxoption.Register(m *pgtype.Map) installs TryWrapScanPlanFunc/TryWrapEncodePlanFunc wrappers that plug Option[T] directly into pgx v5's plan machinery:

  • Scan: wraps the destination as **T, so pgx's own NULL→nil-pointer handling applies; nil maps to None, a value maps to Some (a previous Some is overwritten by a NULL scan).
  • Encode: None → SQL NULL; Some(v) delegates to T's registered codec.

Why

Without registration, pgx handles Option[T] via the generic sql.Scanner/driver.Valuer fallback, which detours through driver.Value — extra conversions, text-ish and lossy for types like numeric, and Option[T]'s underlying []T shape sits uncomfortably close to pgx's slice→array reflection. Native plans give full type fidelity in both text and binary formats for every element type the connection's pgtype.Map supports.

Detection is by defined type (PkgPath + Option[ name prefix), so plain slices keep flowing through pgx's array machinery untouched (pinned by a test).

Notes

  • go 1.23.0 / pgx v5.7.6 — the oldest pgx line that doesn't force a newer Go directive on consumers (MVS lets users float pgx upward freely). CI gets a separate pgxoption job (1.23.x/1.24.x), since the root matrix still includes 1.22.
  • Tests are offline against pgtype.NewMap(): text/binary scans, NULL→None, None→NULL encoding, a timestamptz binary round-trip, and the plain-slice non-interference pin.
  • Root README gains a short pointer section.

Context: sqletch is adopting Option[T] across its generated code (moznion/go-sqletch#21). Its generated scan path deliberately does not require this module — pgxoption is the opt-in native-fidelity path for direct pgx users.

🤖 Generated with Claude Code

https://claude.ai/code/session_01P7UbMMpmzxDECU9gqxAAZ3

Registers Option[T] wrapper plans into pgx's pgtype.Map so Option
values encode and scan with the element type's own codec: None <=> SQL
NULL, Some(v) behaves exactly like v, in both text and binary formats.
This bypasses the generic sql.Scanner/driver.Valuer fallback, which
detours through driver.Value (lossy for types like numeric and slower).

A nested module (github.com/moznion/go-optional/pgxoption) keeps the
core package dependency-free; tag releases as pgxoption/vX.Y.Z.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P7UbMMpmzxDECU9gqxAAZ3
@codecov

codecov Bot commented Aug 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (f8828b8) to head (55a3a47).

Additional details and impacted files
@@            Coverage Diff            @@
##              main       #54   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            2         2           
  Lines          211       168   -43     
=========================================
- Hits           211       168   -43     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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