async_graphql/types/
id.rs

1use std::{
2    num::ParseIntError,
3    ops::{Deref, DerefMut},
4};
5
6use async_graphql_value::ConstValue;
7use serde::{Deserialize, Serialize};
8
9use crate::{InputValueError, InputValueResult, Scalar, ScalarType, Value};
10
11/// ID scalar
12///
13/// The input is a `&str`, `String`, `usize` or `uuid::UUID`, and the output is
14/// a string.
15#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Serialize, Deserialize, Default)]
16#[serde(transparent)]
17pub struct ID(pub String);
18
19impl AsRef<str> for ID {
20    fn as_ref(&self) -> &str {
21        self.0.as_str()
22    }
23}
24
25impl Deref for ID {
26    type Target = String;
27
28    fn deref(&self) -> &Self::Target {
29        &self.0
30    }
31}
32
33impl DerefMut for ID {
34    fn deref_mut(&mut self) -> &mut Self::Target {
35        &mut self.0
36    }
37}
38
39impl<T: std::fmt::Display> From<T> for ID {
40    fn from(value: T) -> Self {
41        ID(value.to_string())
42    }
43}
44
45impl From<ID> for String {
46    fn from(id: ID) -> Self {
47        id.0
48    }
49}
50
51impl From<ID> for ConstValue {
52    fn from(id: ID) -> Self {
53        ConstValue::String(id.0)
54    }
55}
56
57macro_rules! try_from_integers {
58    ($($ty:ty),*) => {
59        $(
60           impl TryFrom<ID> for $ty {
61                type Error = ParseIntError;
62
63                fn try_from(id: ID) -> Result<Self, Self::Error> {
64                    id.0.parse()
65                }
66            }
67         )*
68    };
69}
70
71try_from_integers!(
72    i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, isize, usize
73);
74
75#[cfg(feature = "uuid")]
76impl TryFrom<ID> for uuid::Uuid {
77    type Error = uuid::Error;
78
79    fn try_from(id: ID) -> Result<Self, Self::Error> {
80        uuid::Uuid::parse_str(&id.0)
81    }
82}
83
84impl PartialEq<&str> for ID {
85    fn eq(&self, other: &&str) -> bool {
86        self.0.as_str() == *other
87    }
88}
89
90#[Scalar(internal, name = "ID")]
91impl ScalarType for ID {
92    fn parse(value: Value) -> InputValueResult<Self> {
93        match value {
94            Value::Number(n) if n.is_i64() => Ok(ID(n.to_string())),
95            Value::String(s) => Ok(ID(s)),
96            _ => Err(InputValueError::expected_type(value)),
97        }
98    }
99
100    fn is_valid(value: &Value) -> bool {
101        match value {
102            Value::Number(n) if n.is_i64() => true,
103            Value::String(_) => true,
104            _ => false,
105        }
106    }
107
108    fn to_value(&self) -> Value {
109        Value::String(self.0.clone())
110    }
111}