Restructure types module
This commit is contained in:
parent
1af9ce5b95
commit
f204841d1f
|
@ -61,7 +61,7 @@ pub fn generate(enum_args: &args::Enum, input: &DeriveInput) -> Result<TokenStre
|
||||||
.unwrap_or_else(|| quote! {None});
|
.unwrap_or_else(|| quote! {None});
|
||||||
enum_items.push(quote! { #(#item_attrs)* #item_ident});
|
enum_items.push(quote! { #(#item_attrs)* #item_ident});
|
||||||
items.push(quote! {
|
items.push(quote! {
|
||||||
#crate_name::EnumItem {
|
#crate_name::resolver_utils::EnumItem {
|
||||||
name: #gql_item_name,
|
name: #gql_item_name,
|
||||||
value: #ident::#item_ident,
|
value: #ident::#item_ident,
|
||||||
}
|
}
|
||||||
|
@ -77,8 +77,8 @@ pub fn generate(enum_args: &args::Enum, input: &DeriveInput) -> Result<TokenStre
|
||||||
|
|
||||||
let expanded = quote! {
|
let expanded = quote! {
|
||||||
#[allow(clippy::all, clippy::pedantic)]
|
#[allow(clippy::all, clippy::pedantic)]
|
||||||
impl #crate_name::EnumType for #ident {
|
impl #crate_name::resolver_utils::EnumType for #ident {
|
||||||
fn items() -> &'static [#crate_name::EnumItem<#ident>] {
|
fn items() -> &'static [#crate_name::resolver_utils::EnumItem<#ident>] {
|
||||||
&[#(#items),*]
|
&[#(#items),*]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,18 +107,18 @@ pub fn generate(enum_args: &args::Enum, input: &DeriveInput) -> Result<TokenStre
|
||||||
#[allow(clippy::all, clippy::pedantic)]
|
#[allow(clippy::all, clippy::pedantic)]
|
||||||
impl #crate_name::InputValueType for #ident {
|
impl #crate_name::InputValueType for #ident {
|
||||||
fn parse(value: Option<#crate_name::Value>) -> #crate_name::InputValueResult<Self> {
|
fn parse(value: Option<#crate_name::Value>) -> #crate_name::InputValueResult<Self> {
|
||||||
#crate_name::EnumType::parse_enum(value.unwrap_or_default())
|
#crate_name::resolver_utils::parse_enum(value.unwrap_or_default())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_value(&self) -> #crate_name::Value {
|
fn to_value(&self) -> #crate_name::Value {
|
||||||
#crate_name::EnumType::to_value(self)
|
#crate_name::resolver_utils::enum_value(*self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[#crate_name::async_trait::async_trait]
|
#[#crate_name::async_trait::async_trait]
|
||||||
impl #crate_name::OutputValueType for #ident {
|
impl #crate_name::OutputValueType for #ident {
|
||||||
async fn resolve(&self, _: &#crate_name::ContextSelectionSet<'_>, _field: &#crate_name::Positioned<#crate_name::parser::types::Field>) -> #crate_name::Result<#crate_name::serde_json::Value> {
|
async fn resolve(&self, _: &#crate_name::ContextSelectionSet<'_>, _field: &#crate_name::Positioned<#crate_name::parser::types::Field>) -> #crate_name::Result<#crate_name::serde_json::Value> {
|
||||||
Ok(#crate_name::EnumType::to_value(self).into_json().unwrap())
|
Ok(#crate_name::resolver_utils::enum_value(*self).into_json().unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
11
src/lib.rs
11
src/lib.rs
|
@ -105,16 +105,15 @@ mod look_ahead;
|
||||||
mod model;
|
mod model;
|
||||||
mod request;
|
mod request;
|
||||||
mod response;
|
mod response;
|
||||||
mod scalars;
|
|
||||||
mod schema;
|
mod schema;
|
||||||
mod serialize_resp;
|
mod serialize_resp;
|
||||||
mod subscription;
|
mod subscription;
|
||||||
mod types;
|
|
||||||
mod validation;
|
mod validation;
|
||||||
|
|
||||||
pub mod extensions;
|
pub mod extensions;
|
||||||
pub mod guard;
|
pub mod guard;
|
||||||
pub mod validators;
|
pub mod validators;
|
||||||
|
pub mod types;
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod resolver_utils;
|
pub mod resolver_utils;
|
||||||
|
@ -145,15 +144,11 @@ pub use parser::{types::ConstValue as Value, Pos, Positioned};
|
||||||
pub use registry::CacheControl;
|
pub use registry::CacheControl;
|
||||||
pub use request::Request;
|
pub use request::Request;
|
||||||
pub use response::Response;
|
pub use response::Response;
|
||||||
pub use scalars::{Any, Json, OutputJson, ID};
|
|
||||||
pub use schema::{Schema, SchemaBuilder, SchemaEnv};
|
pub use schema::{Schema, SchemaBuilder, SchemaEnv};
|
||||||
pub use serde_json::Number;
|
pub use serde_json::Number;
|
||||||
pub use subscription::SimpleBroker;
|
pub use subscription::SimpleBroker;
|
||||||
pub use types::{
|
|
||||||
connection, EmptyMutation, EmptySubscription, MaybeUndefined, MergedObject,
|
|
||||||
MergedObjectSubscriptionTail, MergedObjectTail, Upload,
|
|
||||||
};
|
|
||||||
pub use validation::ValidationMode;
|
pub use validation::ValidationMode;
|
||||||
|
pub use types::*;
|
||||||
|
|
||||||
/// Result type
|
/// Result type
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
@ -168,8 +163,6 @@ pub mod registry;
|
||||||
pub use base::{InputObjectType, InputValueType, OutputValueType};
|
pub use base::{InputObjectType, InputValueType, OutputValueType};
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use subscription::SubscriptionType;
|
pub use subscription::SubscriptionType;
|
||||||
#[doc(hidden)]
|
|
||||||
pub use types::{EnumItem, EnumType};
|
|
||||||
|
|
||||||
/// Define a GraphQL object with methods
|
/// Define a GraphQL object with methods
|
||||||
///
|
///
|
||||||
|
|
45
src/resolver_utils/enum.rs
Normal file
45
src/resolver_utils/enum.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
use crate::parser::types::Name;
|
||||||
|
use crate::{InputValueError, InputValueResult, Type, Value};
|
||||||
|
|
||||||
|
/// A variant of an enum.
|
||||||
|
pub struct EnumItem<T> {
|
||||||
|
/// The name of the variant.
|
||||||
|
pub name: &'static str,
|
||||||
|
/// The value of the variant.
|
||||||
|
pub value: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An enum value.
|
||||||
|
pub trait EnumType: Type + Sized + Eq + Send + Copy + Sized + 'static {
|
||||||
|
/// Get a list of the variants of the enum value.
|
||||||
|
fn items() -> &'static [EnumItem<Self>];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse a value as an enum value.
|
||||||
|
///
|
||||||
|
/// This can be used to implement `InputValueType::parse`.
|
||||||
|
pub fn parse_enum<T: EnumType>(value: Value) -> InputValueResult<T> {
|
||||||
|
let value = match &value {
|
||||||
|
Value::Enum(s) => s,
|
||||||
|
Value::String(s) => s.as_str(),
|
||||||
|
_ => return Err(InputValueError::ExpectedType(value)),
|
||||||
|
};
|
||||||
|
|
||||||
|
T::items()
|
||||||
|
.iter()
|
||||||
|
.find(|item| item.name == value)
|
||||||
|
.map(|item| item.value)
|
||||||
|
.ok_or_else(|| InputValueError::Custom(format!(
|
||||||
|
r#"Enumeration type "{}" does not contain the value "{}""#,
|
||||||
|
T::type_name(),
|
||||||
|
value,
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert the enum value into a GraphQL value.
|
||||||
|
///
|
||||||
|
/// This can be used to implement `InputValueType::to_value` or `OutputValueType::resolve`.
|
||||||
|
pub fn enum_value<T: EnumType>(value: T) -> Value {
|
||||||
|
let item = T::items().iter().find(|item| item.value == value).unwrap();
|
||||||
|
Value::Enum(Name::new_unchecked(item.name.to_owned()))
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
//! Utilities for implementing `OutputValueType::resolve`.
|
//! Utilities for implementing `OutputValueType::resolve`.
|
||||||
|
|
||||||
mod object;
|
mod object;
|
||||||
|
mod r#enum;
|
||||||
|
|
||||||
pub use object::*;
|
pub use object::*;
|
||||||
|
pub use r#enum::*;
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
mod any;
|
|
||||||
mod bool;
|
|
||||||
mod datetime;
|
|
||||||
mod floats;
|
|
||||||
mod id;
|
|
||||||
mod integers;
|
|
||||||
mod json;
|
|
||||||
mod naive_time;
|
|
||||||
mod string;
|
|
||||||
mod uuid;
|
|
||||||
|
|
||||||
#[cfg(feature = "bson")]
|
|
||||||
mod bson;
|
|
||||||
#[cfg(feature = "chrono_tz")]
|
|
||||||
mod chrono_tz;
|
|
||||||
#[cfg(feature = "url")]
|
|
||||||
mod url;
|
|
||||||
|
|
||||||
pub use any::Any;
|
|
||||||
pub use id::ID;
|
|
||||||
pub use json::{Json, OutputJson};
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::ID;
|
|
||||||
use crate::Type;
|
|
||||||
use bson::oid::ObjectId;
|
|
||||||
use chrono::{DateTime, FixedOffset, Local, NaiveDate, NaiveTime, Utc};
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_scalar_type() {
|
|
||||||
assert_eq!(<bool as Type>::type_name(), "Boolean");
|
|
||||||
assert_eq!(<bool as Type>::qualified_type_name(), "Boolean!");
|
|
||||||
|
|
||||||
assert_eq!(<i32 as Type>::type_name(), "Int");
|
|
||||||
assert_eq!(<i32 as Type>::qualified_type_name(), "Int!");
|
|
||||||
|
|
||||||
assert_eq!(<f32 as Type>::type_name(), "Float");
|
|
||||||
assert_eq!(<f32 as Type>::qualified_type_name(), "Float!");
|
|
||||||
|
|
||||||
assert_eq!(<&str as Type>::type_name(), "String");
|
|
||||||
assert_eq!(<&str as Type>::qualified_type_name(), "String!");
|
|
||||||
|
|
||||||
assert_eq!(<String as Type>::type_name(), "String");
|
|
||||||
assert_eq!(<String as Type>::qualified_type_name(), "String!");
|
|
||||||
|
|
||||||
assert_eq!(<ID as Type>::type_name(), "ID");
|
|
||||||
assert_eq!(<ID as Type>::qualified_type_name(), "ID!");
|
|
||||||
|
|
||||||
assert_eq!(<NaiveDate as Type>::type_name(), "NaiveDate");
|
|
||||||
assert_eq!(<NaiveDate as Type>::qualified_type_name(), "NaiveDate!");
|
|
||||||
|
|
||||||
assert_eq!(<NaiveTime as Type>::type_name(), "NaiveTime");
|
|
||||||
assert_eq!(<NaiveTime as Type>::qualified_type_name(), "NaiveTime!");
|
|
||||||
|
|
||||||
assert_eq!(<DateTime::<Utc> as Type>::type_name(), "DateTime");
|
|
||||||
assert_eq!(
|
|
||||||
<DateTime::<Utc> as Type>::qualified_type_name(),
|
|
||||||
"DateTime!"
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(<DateTime::<Local> as Type>::type_name(), "DateTime");
|
|
||||||
assert_eq!(
|
|
||||||
<DateTime::<Local> as Type>::qualified_type_name(),
|
|
||||||
"DateTime!"
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(<DateTime::<FixedOffset> as Type>::type_name(), "DateTime");
|
|
||||||
assert_eq!(
|
|
||||||
<DateTime::<FixedOffset> as Type>::qualified_type_name(),
|
|
||||||
"DateTime!"
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(<Uuid as Type>::type_name(), "UUID");
|
|
||||||
assert_eq!(<Uuid as Type>::qualified_type_name(), "UUID!");
|
|
||||||
|
|
||||||
#[cfg(feature = "bson")]
|
|
||||||
{
|
|
||||||
assert_eq!(<ObjectId as Type>::type_name(), "ObjectId");
|
|
||||||
assert_eq!(<ObjectId as Type>::qualified_type_name(), "ObjectId!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
use crate::parser::types::Name;
|
|
||||||
use crate::{InputValueError, InputValueResult, Type, Value};
|
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub struct EnumItem<T> {
|
|
||||||
pub name: &'static str,
|
|
||||||
pub value: T,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
pub trait EnumType: Type + Sized + Eq + Send + Copy + Sized + 'static {
|
|
||||||
fn items() -> &'static [EnumItem<Self>];
|
|
||||||
|
|
||||||
fn parse_enum(value: Value) -> InputValueResult<Self> {
|
|
||||||
let value = match &value {
|
|
||||||
Value::Enum(s) => s,
|
|
||||||
Value::String(s) => s.as_str(),
|
|
||||||
_ => return Err(InputValueError::ExpectedType(value)),
|
|
||||||
};
|
|
||||||
|
|
||||||
let items = Self::items();
|
|
||||||
for item in items {
|
|
||||||
if item.name == value {
|
|
||||||
return Ok(item.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(InputValueError::Custom(format!(
|
|
||||||
r#"Enumeration type "{}" does not contain the value "{}""#,
|
|
||||||
Self::type_name(),
|
|
||||||
value
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_value(&self) -> Value {
|
|
||||||
let items = Self::items();
|
|
||||||
for item in items {
|
|
||||||
if item.value == *self {
|
|
||||||
return Value::Enum(Name::new_unchecked(item.name.to_owned()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
16
src/types/external/mod.rs
vendored
Normal file
16
src/types/external/mod.rs
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
//! Implementations of `Type`, `ScalarType`, etc on external types.
|
||||||
|
|
||||||
|
mod string;
|
||||||
|
mod list;
|
||||||
|
mod optional;
|
||||||
|
mod bool;
|
||||||
|
mod integers;
|
||||||
|
mod floats;
|
||||||
|
mod url;
|
||||||
|
mod uuid;
|
||||||
|
mod datetime;
|
||||||
|
|
||||||
|
#[cfg(feature = "bson")]
|
||||||
|
mod bson;
|
||||||
|
#[cfg(feature = "chrono_tz")]
|
||||||
|
mod chrono_tz;
|
|
@ -10,7 +10,7 @@ use std::ops::{Deref, DerefMut};
|
||||||
///
|
///
|
||||||
/// The input is a `&str`, `String`, `usize` or `uuid::UUID`, and the output is a string.
|
/// The input is a `&str`, `String`, `usize` or `uuid::UUID`, and the output is a string.
|
||||||
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
|
||||||
pub struct ID(String);
|
pub struct ID(pub String);
|
||||||
|
|
||||||
impl Deref for ID {
|
impl Deref for ID {
|
||||||
type Target = String;
|
type Target = String;
|
||||||
|
@ -26,18 +26,15 @@ impl DerefMut for ID {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> From<T> for ID
|
impl<T: std::fmt::Display> From<T> for ID {
|
||||||
where
|
|
||||||
T: std::fmt::Display,
|
|
||||||
{
|
|
||||||
fn from(value: T) -> Self {
|
fn from(value: T) -> Self {
|
||||||
ID(value.to_string())
|
ID(value.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<String> for ID {
|
impl From<ID> for String {
|
||||||
fn into(self) -> String {
|
fn from(id: ID) -> Self {
|
||||||
self.0
|
id.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +52,7 @@ macro_rules! try_from_integers {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
try_from_integers!(i8, i16, i32, i64, u8, u16, u32, u64, isize, usize);
|
try_from_integers!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, isize, usize);
|
||||||
|
|
||||||
impl TryFrom<ID> for uuid::Uuid {
|
impl TryFrom<ID> for uuid::Uuid {
|
||||||
type Error = uuid::Error;
|
type Error = uuid::Error;
|
|
@ -1,19 +1,26 @@
|
||||||
|
//! Useful GraphQL types.
|
||||||
|
|
||||||
pub mod connection;
|
pub mod connection;
|
||||||
|
|
||||||
|
mod any;
|
||||||
|
mod json;
|
||||||
mod empty_mutation;
|
mod empty_mutation;
|
||||||
mod empty_subscription;
|
mod empty_subscription;
|
||||||
mod r#enum;
|
|
||||||
mod list;
|
|
||||||
mod maybe_undefined;
|
mod maybe_undefined;
|
||||||
mod merged_object;
|
mod merged_object;
|
||||||
mod optional;
|
|
||||||
mod query_root;
|
mod query_root;
|
||||||
mod upload;
|
mod upload;
|
||||||
|
mod id;
|
||||||
|
|
||||||
|
mod external;
|
||||||
|
|
||||||
|
pub use any::Any;
|
||||||
|
pub use json::{Json, OutputJson};
|
||||||
pub use empty_mutation::EmptyMutation;
|
pub use empty_mutation::EmptyMutation;
|
||||||
pub use empty_subscription::EmptySubscription;
|
pub use empty_subscription::EmptySubscription;
|
||||||
pub use maybe_undefined::MaybeUndefined;
|
pub use maybe_undefined::MaybeUndefined;
|
||||||
pub use merged_object::{MergedObject, MergedObjectSubscriptionTail, MergedObjectTail};
|
pub use merged_object::{MergedObject, MergedObjectSubscriptionTail, MergedObjectTail};
|
||||||
pub use query_root::QueryRoot;
|
|
||||||
pub use r#enum::{EnumItem, EnumType};
|
|
||||||
pub use upload::Upload;
|
pub use upload::Upload;
|
||||||
|
pub use id::ID;
|
||||||
|
|
||||||
|
pub(crate) use query_root::QueryRoot;
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
use crate::model::{__Schema, __Type};
|
use crate::model::{__Schema, __Type};
|
||||||
use crate::parser::types::Field;
|
use crate::parser::types::Field;
|
||||||
use crate::resolver_utils::{resolve_object, ObjectType};
|
use crate::resolver_utils::{resolve_object, ObjectType};
|
||||||
use crate::scalars::Any;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
registry, Context, ContextSelectionSet, Error, GQLSimpleObject, OutputValueType, Positioned,
|
registry, Any, Context, ContextSelectionSet, Error, GQLSimpleObject, OutputValueType, Positioned,
|
||||||
QueryError, Result, Type,
|
QueryError, Result, Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -17,9 +16,9 @@ struct Service {
|
||||||
sdl: Option<String>,
|
sdl: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct QueryRoot<T> {
|
pub(crate) struct QueryRoot<T> {
|
||||||
pub inner: T,
|
pub(crate) inner: T,
|
||||||
pub disable_introspection: bool,
|
pub(crate) disable_introspection: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Type> Type for QueryRoot<T> {
|
impl<T: Type> Type for QueryRoot<T> {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user