mirror of
https://github.com/getml/sqlgen.git
synced 2026-01-01 06:59:42 -06:00
4.4 KiB
4.4 KiB
sqlgen::Result
The sqlgen::Result type provides a way to handle errors without exceptions in sqlgen. It is an alias for rfl::Result and is used throughout sqlgen's API to handle potential failures in database operations.
Note that sqlgen::Result and rfl::Result are deliberately designed
to resemble C++ 23's std::expected.
Usage
Basic Usage
Handle database operations that might fail:
// Reading from database
const auto people = sqlgen::read<std::vector<Person>>(conn);
if (people) {
// Success case - use the value
const auto& result = *people;
} else {
// Error case - handle the error
const auto& error = people.error();
}
// Writing to database
const auto write_result = sqlgen::write(conn, data);
if (!write_result) {
// Handle write error
const auto& error = write_result.error();
}
Monadic Operations
The Result type supports several monadic operations for chaining operations:
// Transform values (T -> U)
const auto count = result.transform([](const auto& people) {
return people.size();
});
// Chain operations that might fail (T -> Result<U>)
const auto processed = result.and_then([](const auto& people) {
return process_people(people); // Returns Result<ProcessedData>
});
// Handle errors with alternative computation (Error -> Result<T>)
const auto recovered = result.or_else([](const auto& error) {
return fallback_operation(); // Returns Result<T>
});
Value Access Methods
Multiple ways to safely access the contained value:
const auto result = sqlgen::read<std::vector<Person>>(conn);
// Method 1: Using .value() (throws if error)
try {
const auto& people = result.value();
} catch (const std::runtime_error& e) {
// Handle error
}
// Method 2: Using .value_or() (provides default if error)
const auto people = result.value_or(std::vector<Person>());
// Method 3: Using operator * (undefined if error)
if (result) {
const auto& people = *result;
}
// Method 4: Using operator -> for member access
if (result) {
const auto size = result->size();
}
// Method 5: Using .has_value() to check, same as if (result) {...}
if (result.has_value()) {
// Safe to access value
}
Error Access Methods
Multiple ways to access error information:
const auto result = sqlgen::read<std::vector<Person>>(conn);
// Method 1: Using .error() (throws if success)
try {
const auto& err = result.error();
} catch (const std::runtime_error& e) {
// Handle case where result contains a value
}
// Method 2: Using .error_or() to provide default error
const auto err = result.error_or(sqlgen::error("No error occurred"));
// Method 3: Using boolean check
if (!result) {
const auto& err = result.error();
}
Error Creation and Handling
Create and handle errors using the error helper function:
// Create an error
const auto err = sqlgen::error("Database connection failed");
// Use in Result
const auto result = sqlgen::Result<std::vector<Person>>(sqlgen::error("Failed to read data"));
// Transform errors to provide more context
const auto better_error = result.transform_error([](const auto& e) {
return sqlgen::error("Database operation failed: " + e.what());
});
Implementation Details
sqlgen::Resultis implemented as an alias forrfl::Result- The implementation uses a union-like storage to hold either the value or error
- Move and copy semantics are fully supported
- All operations that might fail return a
Resulttype - The implementation is compatible with C++23's
std::expectedwhen available
Best Practices
- Prefer explicit error handling over using
.value()which throws exceptions - Use monadic operations (
transform,and_then,or_else) for clean operation chaining - Always check for errors before accessing values
- Use
value_or()when a sensible default exists - Consider using
transform_error()to add context to errors - Use
error_or()when you need to provide a default error message
Notes
sqlgen::Resultis an alias forrfl::Result- All database operations in sqlgen return
Resulttypes - The type supports:
- Safe value access with
.value()and.value_or() - Monadic operations with
.transform()and.and_then() - Error handling with
.error() - Boolean checks for success/failure
- Move and copy semantics
- Safe value access with
- It's recommended to handle errors explicitly rather than using
.value()which throws exceptions