Skip to content

Conversation

@dsgallups
Copy link
Contributor

@dsgallups dsgallups commented Jan 17, 2026

Objective

This PR adds new methods onto Option<T> to convert the None branch into an Error.

A common pattern I've found using loco is handling errors for model results when I need a specific model from sea_orm. For example, you usually have to do this in some controller:

let my_model = my_models::Entity::find_by_id(model_id)
  .await?
  .ok_or(Error::NotFound)?;

This is easy enough for converting into not found, but what if you'd like to do something else, like a custom error?

let my_model = my_models::Entity::find_by_id(model_id)
  .await?
  .ok_or(Error::CustomError(
      StatusCode::IM_A_TEAPOT,
      ErrorDetail::new("foo", "barbazqux")
  ));

After a while, this can get a big annoying to type everywhere. This PR adds new methods onto Option<T> to return errors with less syntax:

let my_model = my_models::Entity::find_by_id(model_id)
  .await?
  .status(
    StatusCode::IM_A_TEAPOT,
    "foo",
    "barbazqux"
  )?;

Further examples

LocoOptionExt::status

let optional_foo: Option<i32> = None;
let result: Result<i32> = optional_foo
    .status(StatusCode::BAD_REQUEST, "Missing number", "Maybe don't set optional_foo to None");

let Err(Error::CustomError(status, error_detail)) = result else {
    unreachable!();
};

assert_eq!(status, StatusCode::BAD_REQUEST);
assert_eq!(error_detail.error, Some("Missing number".to_string()));
assert_eq!(error_detail.description, Some("Maybe don't set optional_foo to None".to_string()));

LocoOptionExt::msg

let optional_foo: Option<i32> = None;
let result: Result<i32> = optional_foo
    .msg("Where'd my number go?");
let Err(Error::Message(msg)) = result else {
    unreachable!();
};
assert_eq!(msg, "Where'd my number go?".to_string())

LocoOptionExt::dbg()

let optional_foo: Option<i32> = None;
let result: Result<i32> = optional_foo.dbg();
let Err(Error::Message(msg)) = result else {
    unreachable!();
};

assert!(msg, "Found None::<i32> at src/errors.rs:7:40".to_string());

@dsgallups dsgallups changed the title feat: LocoOptionExt helper straight to convert Option<T> into loco_rs::Result<T> feat: LocoOptionExt: Helper methods to convert Option<T> into loco_rs::Result<T> Jan 17, 2026
@dsgallups
Copy link
Contributor Author

dsgallups commented Jan 17, 2026

Note: in order to not expose the dbg callsite and type information in release builds, I could wrap this information in an #[cfg(profile = "dev")] block

The callsite of Option::<T>::dbg depends on the location of the call,
leading to CI test failures.
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