chore(api): flatten Error enum and add ergonomic constructors workspace-wide (#70)#71
Merged
StefanSteiner merged 1 commit intoMay 28, 2026
Conversation
…ce-wide (tableau#70) Replaces hyperdb_api::Error's nested Client/Other shape with a flat canonical enum. Callers now match directly on variants — no kind() indirection, no Box<dyn StdError> cause channel, no Other catch-all. Applies the same ergonomic-constructor pattern to every other workspace error type so call sites no longer need .to_string() / .into() ceremony for string-literal arguments anywhere in the workspace. This is a breaking change to public Error types. Lands as `chore:` to defer release-please version bump until the rest of the v0.3.0 bundle (tableau#61, tableau#62, tableau#69) lands. See MIGRATING-0.3.md. What changed: - hyperdb_api::Error: flat enum with 18 variants (Connection, Authentication, Tls, Server, Protocol, Io, Closed, Timeout, Cancelled, Conversion, Config, FeatureNotSupported, InvalidName, InvalidTableDefinition, NotFound, AlreadyExists, Column, ColumnIndexOutOfBounds, Internal). 19 ergonomic constructors (one per variant; all string fields take impl Into<String>). - New ColumnErrorKind enum (Missing / Null / TypeMismatch). Shipped in tableau#70 so tableau#62's RowAccessor work doesn't require a second Error-type breaking change. - Error::Connection { source: Option<std::io::Error> } preserves the underlying io::Error for direct constructor calls, satisfying M-ERRORS-AVOID-WRAPPING-AND-AS-DYN. - Error::Server { sqlstate, message, detail, hint } provides structured access to PostgreSQL server-error fields. Display walks all fields. - From<client::Error> mapping is exhaustive over client::ErrorKind. Adding a kind upstream forces an explicit mapping decision. - 137 Error::new / Error::with_cause sites migrated across src/, tests/, examples/, benches/, README. ~205 stale rustdoc references to Error::Other / Error::Client updated. ErrorKind re-export removed. - hyperdb-mcp::From<hyperdb_api::Error> updated to dispatch on structured variants first (SQLSTATE matched directly via Error::Server { sqlstate: Some(...), .. }, no string parsing). - Unit tests added covering new variant Display formatting, From<client::Error> mapping completeness (exhaustive), the detail/hint duplication regression, and typed source preservation through std::error::Error::source(). Cross-crate ergonomic-constructor sweep: - hyperdb_api_salesforce::SalesforceAuthError: 8 new constructors (config, private_key, jwt, http, authorization, token_exchange, token_parse, io); 26 internal call sites rewritten. - hyperdb_bootstrap::Error: 6 new constructors (unsupported_platform, unknown_platform_slug, io, http_status, curl_failed, checksum_mismatch); 26 call sites rewritten. - hyperdb_mcp::McpError: already ergonomic; 1 residual .to_string() call site cleaned up. - hyperdb_api_core::client::Error: already ergonomic via existing convenience constructors; no changes needed. - hyperdb-api-node: uses napi::Error directly (NAPI library type, not workspace-defined); already ergonomic; no changes needed. Caveat: SQLSTATE codes from non-Server-kind upstream errors are now folded into the message string instead of surfaced via Error::sqlstate(); see MIGRATING-0.3.md for context and recovery options. Verification: - cargo build --workspace --all-targets — clean - cargo clippy --workspace --all-targets -- -D warnings — clean - cargo test --workspace --lib — 375 tests, 0 failed - cargo doc --workspace --no-deps — 6 warnings (= pre-change baseline) - cargo fmt --check — clean
6c99d09 to
a7d1c5f
Compare
This was referenced May 28, 2026
StefanSteiner
added a commit
that referenced
this pull request
May 28, 2026
* feat: stabilize v0.3.0 public API bundle This commit aggregates the breaking and additive API changes that ship together as v0.3.0. The individual PRs landed under chore: prefixes to defer release-please from cutting an early version; this single feat: commit with a BREAKING CHANGE: footer is the trigger for the v0.3.0 release PR. Bundle contents (all merged to main): - #70 (PR #71) — Flat public Error enum + ergonomic constructors workspace-wide - #69 (PR #73) — Transaction API consolidation (RAII guard recommended; raw trio deprecated and #[doc(hidden)]) - #61 + #62 (PR #74) — FromRow modernization: #[derive(FromRow)] in new hyperdb-api-derive crate, RowAccessor with cached name->index lookup, breaking trait signature change, blanket tuple impls deleted, #[hyperdb(rename)] and #[hyperdb(index)] attributes - #76 — Follow-ups A/B/C: typed io::Error sources in process.rs, Error::InvalidOperation variant for caller misuse, structured SQLSTATE on Cancelled/Closed/Connection Follow-up D (flatten internal client::Error) deferred to v0.3.x as issue #75 — internal-only, zero external consumers, larger than originally scoped. The code change in this commit is a small documentation refresh on the crate-level rustdoc to (a) include hyperdb-api-derive in the companion crates list and (b) fix a stale crate name (sea-query-hyper -> sea-query-hyperdb). The body of the commit is the BREAKING CHANGE: footer below; release-please uses it to generate the v0.3.0 entry in CHANGELOG.md. See MIGRATING-0.3.md for full migration recipes covering every breaking change in the bundle. BREAKING CHANGE: v0.3.0 reshapes the public hyperdb_api::Error enum into a flat canonical structure (no Box<dyn StdError> cause channel, no kind() method, no Other catch-all variant), and its constructor surface (Error::new and Error::with_cause are deleted in favor of domain-specific snake_case constructors). It also changes the FromRow trait signature from fn from_row(row: &Row) to fn from_row(row: RowAccessor<'_>), deletes the blanket 1/2/3/4-tuple FromRow impls, deprecates Connection::begin_transaction/commit/rollback (use the RAII guard at Connection::transaction() instead), introduces a new Error::InvalidOperation variant, and changes Error::Cancelled and Error::Closed from tuple to struct variants carrying structured sqlstate. Every variant has a snake_case constructor; the FromRow derive lives in a re-exported hyperdb-api-derive crate. See MIGRATING-0.3.md for migration recipes. * chore(ci): publish hyperdb-api-derive in release.yml + dry-run in ci.yml Pre-release adversarial review of the v0.3.0 rollup CI/CD config caught that hyperdb-api-derive (added in PR #74) was missing from release.yml's publish-in-dependency-order step. hyperdb-api/Cargo.toml strictly pins hyperdb-api-derive = "=0.X.Y", so cargo publish -p hyperdb-api would fail at release time when crates.io can't resolve the strict version of derive (because release.yml never published it). Verified topologically: - hyperdb-api-derive has zero workspace deps (only syn/quote/proc-macro2 from the registry), so it can publish before any workspace crate. - It's a runtime dep of hyperdb-api only. - Inserted right after hyperdb-api-salesforce; existing order otherwise unchanged. Added a dependency-order comment to the publish step explaining the topology so future contributors don't break it. Also adds hyperdb-api-derive to ci.yml's publish dry-run job. The dry-run job exists exactly to catch this class of bug before release time. Without this addition, the same blocker could re-emerge after a future major-version refactor of derive. Updates the stale "7 workspace-member version rows" comment in release-please.yml to reflect the current 8-member workspace (hyperdb-api-derive added in #74). The lockfile-sync sentinel enumerates members at runtime via cargo metadata, so the count is informational; correctness is unchanged. Verified locally: - cargo publish -p hyperdb-api-derive --dry-run: succeeds - cargo publish -p sea-query-hyperdb --dry-run: succeeds - cargo publish -p hyperdb-bootstrap --dry-run: succeeds - cargo metadata workspace topology check: order in release.yml is consistent with non-dev deps across all 7 publishable crates.
5 tasks
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.
Resolves #70.
Replaces
hyperdb_api::Error's nestedClient(client::Error)/Other { Box<dyn StdError> }shape with a flat canonical enum per the Microsoft Pragmatic Rust Guidelines M-ERRORS-CANONICAL-STRUCTS and M-ERRORS-AVOID-WRAPPING-AND-AS-DYN. Callers now match directly on variants — nokind() -> Option<ErrorKind>indirection, noBox<dyn StdError>cause channel, no catch-all bucket variant.The same ergonomic-constructor pattern was applied to every other workspace error type (
SalesforceAuthError,hyperdb_bootstrap::Error) and one residualMcpErrorsite, so call sites no longer need.to_string()/.into()ceremony for string-literal arguments anywhere in the workspace.What changed
hyperdb_api::ErrorConnection,Authentication,Tls,Server,Protocol,Io,Closed,Timeout,Cancelled,Conversion,Config,FeatureNotSupported,InvalidName,InvalidTableDefinition,NotFound,AlreadyExists,Column,ColumnIndexOutOfBounds,Internal.Error::Connection { source: Option<std::io::Error> }preserves the underlyingio::Errorfor direct constructor calls (typed cause channel — noBox<dyn>).Error::Server { sqlstate, message, detail, hint }provides structured access to PostgreSQL server-error fields. TheDisplayimpl renders all four.Error::Column { name, kind: ColumnErrorKind }+ newColumnErrorKindenum (Missing/Null/TypeMismatch). Shipped here so FromRow redesign (breaking): typed RowAccessor, structured errors, enforced NULL semantics #62'sRowAccessorwork doesn't require a secondError-breaking change.Error::ColumnIndexOutOfBounds { idx, column_count }for positional row access.impl Into<String>). Pattern-matching keeps PascalCase variant names; only construction switches to snake_case.From<client::Error>mapping is exhaustive overclient::ErrorKind; adding a kind upstream forces an explicit mapping decision here.Error::Client,Error::Other,Error::new,Error::with_cause,Error::kind(), thepub use ... ErrorKindre-export, and theFrom<std::convert::Infallible>impl.Cross-crate cleanup (same pattern)
hyperdb_api_salesforce::SalesforceAuthError— added 8 ergonomic constructors (config,private_key,jwt,http,authorization,token_exchange,token_parse,io); 26 internal call sites rewritten.hyperdb_bootstrap::Error— added 6 ergonomic constructors (unsupported_platform,unknown_platform_slug,io,http_status,curl_failed,checksum_mismatch); 26 call sites rewritten acrossdownload.rs,extract.rs,install.rs,platform.rs,release.rs,scrape.rs.hyperdb_mcp::McpError— already ergonomic; one residual.to_string()site cleaned up.hyperdb_api_core::client::Error— already ergonomic via existing convenience constructors; no changes needed.Migration scope
Error::new/Error::with_causecall sites migrated acrosshyperdb-api/src/, plus ~10 more inhyperdb-api-core/tests/,hyperdb-api/tests/,hyperdb-api/examples/,hyperdb-api/benches/, and the workspaceREADME.md. Mapping was applied mechanically per the table inMIGRATING-0.3.md(e.g. catalog name validation →InvalidName, gRPC unsupported →FeatureNotSupported, NULL/conversion failures →Conversion, ambiguous lifecycle →Internal).Error::Other/Error::Clientupdated to the appropriate new variant.hyperdb-mcp::From<hyperdb_api::Error>updated to dispatch on structured variants first (SQLSTATE matched directly viaError::Server { sqlstate: Some(...), .. }, no string parsing), with a substring fallback retained foris_connection_lost/is_resource_busyheuristics that need it.Tests
New unit tests in
hyperdb-api/src/error.rscovering:Error::ServerDisplay with all field combinations (sqlstate/detail/hintpresent and absent).From<client::Error>for everyclient::ErrorKindvariant — exhaustive smoke test.Querymapping does not double-printdetail/hint(regression test for a bug caught in review).Error::sqlstate()returnsSomeonly forServer.Error::ColumnandError::ColumnIndexOutOfBoundsDisplay formatting.Error::connection_with_ioexposes the typedio::Errorviastd::error::Error::source()and downcasts cleanly.Error::internalround-trip viaDisplay.Behavioral note
Error::sqlstate()now returnsSome(...)only forError::Server. Previously, a wrappedclient::Errorcould surface SQLSTATE codes for non-Query kinds (e.g. SQLSTATE57014query_canceledarriving asCancelled). After this change those codes are folded into the message string but not surfaced throughsqlstate(). Documented inMIGRATING-0.3.md.Verification
cargo build --workspace --all-targets— cleancargo clippy --workspace --all-targets -- -D warnings— cleancargo test --workspace --lib— 375 tests, 0 failedcargo test -p hyperdb-mcp --test error_tests— 9 tests, 0 failed (incl. existing SQLSTATE classification tests, retargeted to useError::server(...))cargo doc --workspace --no-deps— 6 warnings, equal to the pre-change baseline (all inhyperdb-mcp, unrelated to this change)cargo fmt --check— cleanProcess notes
detail/hintduplication bug in theFrom<client::Error>Queryarm before merge — added a regression test.process.rslifecycle I/O failures could be promoted fromInternaltoconnection_with_ioto preserve typed sources; someinserter.rsstate-machine errors could be reframed as caller misuse rather thanInternal. Neither is blocking.Related
MIGRATING-0.3.md— consolidated migration guide for the v0.3.0 bundle.#[derive(FromRow)]), FromRow redesign (breaking): typed RowAccessor, structured errors, enforced NULL semantics #62 (breakingRowAccessor), Remove the &self begin_transaction/commit/rollback trio (RAII Transaction is the only safe path) #69 (transaction API consolidation). All four PRs usechore:prefix and the v0.3.0 release-please bump triggers from a finalfeat!:rollup commit after the bundle is complete.Test plan
cargo run --example async_parity_smokeagainst a local hyperdMIGRATING-0.3.mdrecipes against the actual public API