Juniper: How to make BigDecimal scalar type

Created on 22 Sep 2019  Â·  9Comments  Â·  Source: graphql-rust/juniper

I'm not able to do implement the bigdecimal by myself because I don't have experience enough with rust to do it.

I just know that is possible but don't know how, and I can't just use graphql_scalar! macro because it needs implementations on the struct.

support

All 9 comments

You need to use a newtype, since you can't implement foreign traits on foreign structs.

struct MyBigDecimal(pub bigdecimal::BigDecimal);

juniper::graphql_scalar!( ..... );

But the 'MyBugDecimal' has to have all the implementations that the bigdecimal have to work properly with diesel (to diesel see as the same) right ?

@SharksT Does https://gitlab.com/williamyaoh/shrinkwraprs help with what you want?

this took me ages to piece together as I'm still trying to figure this stuff out, but I hope it helps. ;)

__dependencies__

juniper = "0.14.0"
serde = "1.0"
serde_derive = "1.0"
diesel = { version = "1.4.2", features = ["postgres", "numeric"] }
bigdecimal = { version = "0.0.14", features = ["serde"] }
use bigdecimal::BigDecimal;

use diesel::sql_types::Numeric;
use diesel::backend::Backend;
use diesel::deserialize::{FromSql};
use diesel::serialize::{ToSql, Output};

use serde::{Serialize, Serializer, Deserialize};
use serde::de::{
    Deserializer,
    self, Visitor,
};

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, FromSqlRow, AsExpression)]
#[sql_type = "Numeric"]
pub struct MyBigDecimal(pub BigDecimal);

impl Serialize for MyBigDecimal {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_newtype_struct("MyBigDecimal", &self.0)
    }
}

struct MyBigDecimalVisitor;

impl<'de> Visitor<'de> for MyBigDecimalVisitor {
    type Value = MyBigDecimal;

    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        formatter.write_str("a Decimal represented as a string.")
    }

    fn visit_str<E>(self, value: &str) -> Result<MyBigDecimal, E>
        where
            E: de::Error,
    {
        Ok(MyBigDecimal(BigDecimal::from_str(&value).unwrap()))
    }

    fn visit_f32<E>(self, value: f32) -> Result<MyBigDecimal, E>
        where
            E: de::Error,
    {
        Ok(MyBigDecimal(BigDecimal::from(value)))
    }

    fn visit_f64<E>(self, value: f64) -> Result<MyBigDecimal, E>
        where
            E: de::Error,
    {
        Ok(MyBigDecimal(BigDecimal::from(value)))
    }
}

impl<'de> Deserialize<'de> for MyBigDecimal {
    fn deserialize<D>(deserializer: D) -> Result<MyBigDecimal, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_any(MyBigDecimalVisitor)
    }
}

impl<DB: Backend> ToSql<Numeric, DB> for MyBigDecimal 
where
    BigDecimal: ToSql<Numeric, DB>, 
{
    fn to_sql<W: std::io::Write>(&self, out: &mut Output<W, DB>) -> ::diesel::serialize::Result {
        ToSql::<Numeric, DB>::to_sql(&self.0, out)
    }
}

impl<DB: Backend> FromSql<Numeric, DB> for MyBigDecimal 
where
    BigDecimal: FromSql<Numeric, DB>,  
{
    fn from_sql(bytes: Option<&DB::RawValue>) -> diesel::deserialize::Result<Self> {
        FromSql::<Numeric, DB>::from_sql(bytes).map(MyBigDecimal) 
    }
}

use juniper::{Value, ParseScalarResult, ParseScalarValue};
use std::str::FromStr;

graphql_scalar!(MyBigDecimal where Scalar = <S> {
    description: "BigDecimal"

    resolve(&self) -> Value {
        Value::scalar(self.0.to_string())
    }

    from_input_value(v: &InputValue) -> Option<MyBigDecimal> {
        v.as_scalar_value::<String>()
        .and_then(|str_val| 
            match BigDecimal::from_str(&str_val) {
            Ok(big_decimal) => Some(MyBigDecimal(big_decimal)),
            Err(_) => None,
        })
    }

    from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a, S> {
        <String as ParseScalarValue<S>>::from_str(value)
    }
});

Hello, thank you very much for your taking your time to help out!
I'm getting an error in your code :

the trait boundbigdecimal::BigDecimal: errors::_IMPL_SERIALIZE_FOR_Error::_serde::Serializeis not satisfied

Whoops! I forgot to add the dependency version for BigDecimal. You need to use bigdecimal = "0.0.14"

I'm using that version

Try adding the serde feature to the bigdecimal dependency.

On Fri., 4 Oct. 2019, 10:35 pm Felipe Passos, notifications@github.com
wrote:

I'm using that version

—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/graphql-rust/juniper/issues/429?email_source=notifications&email_token=ABCDTAZRENT2H6DIWGBPKTLQM4Z7HA5CNFSM4IZCSMYKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEALP7BY#issuecomment-538378119,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABCDTA2BW2MNO53OBOHRFVTQM4Z7HANCNFSM4IZCSMYA
.

Now it's working, thank you so much !

Was this page helpful?
0 / 5 - 0 ratings