I'm having difficulties with the following code where I am trying to create a custom type U128
for u128
which Diesel does not implement by default. My goal is to have a u128
primitive stored in a Postgresql database either as a text format or numeric (preferably numeric).
use std::io::Write;
use diesel::{AsExpression, deserialize, FromSqlRow, serialize};
use diesel::deserialize::{FromSql};
use diesel::pg::{Pg};
use diesel::serialize::{IsNull, Output, ToSql};
use diesel::sql_types::{Text};
#[derive(AsExpression, FromSqlRow, Debug, Clone, Copy)]
#[diesel(sql_type = Text)]
pub struct U128(pub u128);
impl ToSql<Text, Pg> for U128 {
fn to_sql<'b>(&self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
write!(out, "{}", self.0.to_string())?;
Ok(IsNull::No)
}
}
impl FromSql<Text, Pg> for U128 {
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
let s = String::from_utf8_lossy(bytes.as_bytes());
Ok(U128(s.parse()?))
}
}
Here is the diesel struct I have created.
#[derive(Queryable, Selectable)]
#[diesel(table_name = crate::schema::balance)]
#[diesel(check_for_backend(diesel::pg::Pg))]
pub struct Balance {
pub id: i32,
pub account_name: String,
pub balance: u128,
}
This is the compile error I am getting when trying to use u128
in a diesel struct.
error[E0277]: the trait bound `u128: diesel::Queryable<diesel::sql_types::Text, Pg>` is not satisfied
--> src\models.rs:117:27
|
117 | pub balance: u128,
| ^^^^ the trait `diesel::Queryable<diesel::sql_types::Text, Pg>` is not implemented for `u128`
|
= help: the following other types implement trait `diesel::Queryable<ST, DB>`:
i8
i16
i32
i64
u8
u16
u32
u64
and 2 others
= note: required for `u128` to implement `FromSqlRow<diesel::sql_types::Text, Pg>`
= help: see issue #48214
diesel
doesn't magically apply any wrapper that might work, that's impossible, instead you have to tell it, which intermediate type it should use with (de)serialize_as
attributes:
#[derive(Queryable, Selectable)]
#[diesel(table_name = crate::schema::balance)]
#[diesel(check_for_backend(diesel::pg::Pg))]
pub struct Balance {
pub id: i32,
pub account_name: String,
#[diesel(serialize_as = U128, deserialize_as = U128)]
pub balance: u128,
}
for that to work, diesel
also needs a way to convert your wrapper from/to the target type, you can provide that with the From
trait:
impl From<u128> for U128 {
fn from(v: u128) -> U128 {
U128(v)
}
}
impl From<U128> for u128 {
fn from (v: U128) -> u128 {
v.0
}
}
Note: diesel
uses TryInto
for conversion, but since this one is infallible and there is a chain of blanket implementations that gets us there for free, I implemented From
instead.