async_graphql/types/
id.rs

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