launchbadge / sqlx

🧰 The Rust SQL Toolkit. An async, pure Rust SQL crate featuring compile-time checked queries without a DSL. Supports PostgreSQL, MySQL, and SQLite.
Apache License 2.0
13.5k stars 1.28k forks source link

Custom newtype wrappers for sqlx types in query! parameters #2957

Open Ekleog opened 10 months ago

Ekleog commented 10 months ago

Hey!

I have some arrays of ObjectId, which are newtype wrappers around ULIDs. I wanted to pass these to PostgreSQL queries. So, I implemented the Type, Encode and PgHasArrayType traits for it, to have them delegate to an UUID constructed from the underlying ULID.

Considering this requires a manual conversion between ULID and UUID I don't think sqlx could make this much more convenient, aside from supporting the ulid crate as a way to generate data stored in postgresql as the UUID type.

However, now I'm trying to use the query! macro, and it looks like the macro only allows me to pass in straight Uuids as parameters.

I'll probably just deal with it manually, as I don't think I'll ever need to pass array parameters, so I can just manually cast my ObjectId to an Uuid. But I wanted to say that there may be room for improvement in sqlx's handling of newtypes around existing types, between the sheer number of traits to derive and the fact that sqlx::query! does not treat two types defined as equal by these traits as being equal :)

Anyway, thank you for sqlx, it definitely makes sql quite pleasant to use in Rust! :D

Ekleog commented 10 months ago

Actually, it seems like even sqlx itself hits this issue: sqlx::types::Json<T> cannot be used as a parameter of a sqlx::query!() macro call, and I must manually convert to a serde_json::Value in order to be able to use the macro

abonander commented 10 months ago

Have either of you tried this? https://docs.rs/sqlx/latest/sqlx/macro.query.html#type-overrides-bind-parameters-postgres-only

Ekleog commented 10 months ago

Oh this looks interesting, thank you! I hadn't found it again when searching through the docs of query_as.

Do you want to keep this issue open to track the sqlx::types::Json<T> issue, or do you think the type cast syntax is enough and we should close this? :)

samuela commented 10 months ago
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, sqlx::Type)]
#[sqlx(type_name = "keypair_algorithm")]
pub enum KeypairAlgorithm {
  #[sqlx(rename = "ssh-rsa")]
  RSA,

  #[sqlx(rename = "ssh-ed25519")]
  Ed25519,
}
impl sqlx::postgres::PgHasArrayType for KeypairAlgorithm {
  fn array_type_info() -> sqlx::postgres::PgTypeInfo {
    sqlx::postgres::PgTypeInfo::with_name("keypair_algorithm[]")
  }
}

did the trick for me