Restructure types module

This commit is contained in:
Koxiaet 2020-09-13 10:38:19 +01:00
parent d4eed93ad4
commit 6cf7e78ea9
24 changed files with 93 additions and 162 deletions

View File

@ -61,7 +61,7 @@ pub fn generate(enum_args: &args::Enum, input: &DeriveInput) -> Result<TokenStre
.unwrap_or_else(|| quote! {None});
enum_items.push(quote! { #(#item_attrs)* #item_ident});
items.push(quote! {
#crate_name::EnumItem {
#crate_name::resolver_utils::EnumItem {
name: #gql_item_name,
value: #ident::#item_ident,
}
@ -77,8 +77,8 @@ pub fn generate(enum_args: &args::Enum, input: &DeriveInput) -> Result<TokenStre
let expanded = quote! {
#[allow(clippy::all, clippy::pedantic)]
impl #crate_name::EnumType for #ident {
fn items() -> &'static [#crate_name::EnumItem<#ident>] {
impl #crate_name::resolver_utils::EnumType for #ident {
fn items() -> &'static [#crate_name::resolver_utils::EnumItem<#ident>] {
&[#(#items),*]
}
}
@ -107,18 +107,18 @@ pub fn generate(enum_args: &args::Enum, input: &DeriveInput) -> Result<TokenStre
#[allow(clippy::all, clippy::pedantic)]
impl #crate_name::InputValueType for #ident {
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 {
#crate_name::EnumType::to_value(self)
#crate_name::resolver_utils::enum_value(*self)
}
}
#[#crate_name::async_trait::async_trait]
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> {
Ok(#crate_name::EnumType::to_value(self).into_json().unwrap())
Ok(#crate_name::resolver_utils::enum_value(*self).into_json().unwrap())
}
}
};

View File

@ -105,16 +105,15 @@ mod look_ahead;
mod model;
mod request;
mod response;
mod scalars;
mod schema;
mod serialize_resp;
mod subscription;
mod types;
mod validation;
pub mod extensions;
pub mod guard;
pub mod validators;
pub mod types;
#[doc(hidden)]
pub mod resolver_utils;
@ -145,15 +144,11 @@ pub use parser::{types::ConstValue as Value, Pos, Positioned};
pub use registry::CacheControl;
pub use request::Request;
pub use response::Response;
pub use scalars::{Any, Json, OutputJson, ID};
pub use schema::{Schema, SchemaBuilder, SchemaEnv};
pub use serde_json::Number;
pub use subscription::SimpleBroker;
pub use types::{
connection, EmptyMutation, EmptySubscription, MaybeUndefined, MergedObject,
MergedObjectSubscriptionTail, MergedObjectTail, Upload,
};
pub use validation::ValidationMode;
pub use types::*;
/// Result type
pub type Result<T> = std::result::Result<T, Error>;
@ -168,8 +163,6 @@ pub mod registry;
pub use base::{InputObjectType, InputValueType, OutputValueType};
#[doc(hidden)]
pub use subscription::SubscriptionType;
#[doc(hidden)]
pub use types::{EnumItem, EnumType};
/// Define a GraphQL object with methods
///

View 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()))
}

View File

@ -1,5 +1,7 @@
//! Utilities for implementing `OutputValueType::resolve`.
mod object;
mod r#enum;
pub use object::*;
pub use r#enum::*;

View File

@ -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!");
}
}
}

View File

@ -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
View 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;

View File

@ -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.
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
pub struct ID(String);
pub struct ID(pub String);
impl Deref for ID {
type Target = String;
@ -26,18 +26,15 @@ impl DerefMut for ID {
}
}
impl<T> From<T> for ID
where
T: std::fmt::Display,
{
impl<T: std::fmt::Display> From<T> for ID {
fn from(value: T) -> Self {
ID(value.to_string())
}
}
impl Into<String> for ID {
fn into(self) -> String {
self.0
impl From<ID> for String {
fn from(id: ID) -> Self {
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 {
type Error = uuid::Error;

View File

@ -1,19 +1,26 @@
//! Useful GraphQL types.
pub mod connection;
mod any;
mod json;
mod empty_mutation;
mod empty_subscription;
mod r#enum;
mod list;
mod maybe_undefined;
mod merged_object;
mod optional;
mod query_root;
mod upload;
mod id;
mod external;
pub use any::Any;
pub use json::{Json, OutputJson};
pub use empty_mutation::EmptyMutation;
pub use empty_subscription::EmptySubscription;
pub use maybe_undefined::MaybeUndefined;
pub use merged_object::{MergedObject, MergedObjectSubscriptionTail, MergedObjectTail};
pub use query_root::QueryRoot;
pub use r#enum::{EnumItem, EnumType};
pub use upload::Upload;
pub use id::ID;
pub(crate) use query_root::QueryRoot;

View File

@ -1,9 +1,8 @@
use crate::model::{__Schema, __Type};
use crate::parser::types::Field;
use crate::resolver_utils::{resolve_object, ObjectType};
use crate::scalars::Any;
use crate::{
registry, Context, ContextSelectionSet, Error, GQLSimpleObject, OutputValueType, Positioned,
registry, Any, Context, ContextSelectionSet, Error, GQLSimpleObject, OutputValueType, Positioned,
QueryError, Result, Type,
};
@ -17,9 +16,9 @@ struct Service {
sdl: Option<String>,
}
pub struct QueryRoot<T> {
pub inner: T,
pub disable_introspection: bool,
pub(crate) struct QueryRoot<T> {
pub(crate) inner: T,
pub(crate) disable_introspection: bool,
}
impl<T: Type> Type for QueryRoot<T> {