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
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