sfackler / rust-postgres

Native PostgreSQL driver for the Rust programming language
Apache License 2.0
3.43k stars 436 forks source link

Unclear error message when enum definition is inconsistent with the Postgres Type definition #1042

Open burkematthew opened 1 year ago

burkematthew commented 1 year ago

I have an enum defined as below:

#[derive(Enum, Copy, Clone, Eq, PartialEq, Serialize, Debug, ToSql, FromSql)]
#[graphql(rename_items = "PascalCase")]
#[postgres(name = "bookable_person_event_type")]
pub enum BookablePersonEventType {
  #[postgres(name = "Account Signup")]
  AccountSignup,
  #[postgres(name = "Favorite")]
  Favorite,
  #[postgres(name = "Search Alert")]
  SearchAlert,
  #[postgres(name = "Tour Requested")]
  TourRequested,
  #[postgres(name = "Referral")]
  Referral,
  #[postgres(name = "Website Chat")]
  WebsiteChat,
  #[postgres(name = "Reservation Booked")]
  ReservationBooked,
  #[postgres(name = "Application Approved")]
  ApplicationApproved,
  #[postgres(name = "Application Denied")]
  ApplicationDenied,
  #[postgres(name = "Zumper")]
  Zumper,
  #[postgres(name = "ApartmentsDotCom")]
  ApartmentsDotCom,
}

The type bookable_person_event_type is defined in Postgres as such:

CREATE TYPE bookable_person_event_type AS ENUM (
    'Account Signup',
    'Favorite',
    'Search Alert',
    'Break Free',
    'Tour Requested',
    'Referral',
    'Website Chat',
    'Reservation Booked',
    'Application Approved',
    'Application Denied',
    'Zumper',
    'ApartmentsDotCom'
);

However, when attempting an INSERT mutation, the enum value is failing to convert to the value defined in the postgres name macro.

Code to handle the mutation:

  let mutation = format!(
    "INSERT INTO bookable_person_events (bookable_person_type, bookable_person_id, eventable_type, eventable_id, last_modified_by)
    VALUES ($1, $2, $3, $4, $5)
    RETURNING id, created_at, updated_at, deleted_at, bookable_person_type, bookable_person_id, eventable_type, eventable_id, last_modified_by"
  );

  log(DEBUG, &format!("{mutation:#?}"));
  let sql_statement = client.prepare(&mutation).await.unwrap();

  let row = client
    .query_opt(
      &sql_statement,
      &[
        &bookable_person_event.bookable_person_type,
        &bookable_person_event.bookable_person_id,
        &bookable_person_event.eventable_type,
        &bookable_person_event.eventable_id,
        &context_user_id,
      ],
    )
    .await
    .expect("Error creating Bookable Person Event");

My understanding is that the ToSql macro should take the value defined in the postgres name and use that in the SQL statement, which means the spaces defined in the name should be preserved. However, I'm receiving an error from Postgres that the type is incorrect.

2023-06-07T14:33:43.268516Z DEBUG website_chat: tokio_postgres::query: executing statement s28 with parameters: [Lead, 49, WebsiteChat, 4631155286, 27679]   
thread 'tokio-runtime-worker' panicked at 'Error creating Bookable Person Event: Error { kind: ToSql(2), cause: Some(WrongType { postgres: Other(Other { name: "bookable_person_event_type", oid: 11843548, kind: Enum(["Account Signup", "Favorite", "Search Alert", "Tour Requested", "Tour Completed", "Referral", "Website Chat", "Reservation Booked", "Application Approved", "Application Denied"]), schema: "public" }), rust: "rusty::member_sales::bookable_persons::events::bookable_person_event::BookablePersonEventType" }) }', src/member_sales/bookable_persons/events/mutation.rs:55:6

This behavior seems to have changed recently, though I can't point to why\where. Any help\insight is greatly appreciated!

burkematthew commented 1 year ago

After digging further, it appears that the issue is that there was a value unexpectedly in the Postgres Type definition (i.e. Break Free) that was NOT defined in the enum of BookablePersonEventType. It seems like there is some sort of validation to ensure that the type defined in Rust matches the type defined in Postgres (which is a nice feature). The reasoning for the failure just wasn't clear in this case.

Would there be any way to improve an error message or documentation on the exact matching of the definitions? Again, that feature makes sense and is nice to include, but I just wasn't aware of that validation\enforcement.