Preserve field order for introspection. #89

This commit is contained in:
sunli 2020-05-16 10:05:48 +08:00
parent abd0da6f50
commit 42a4639dc3
24 changed files with 59 additions and 59 deletions

View File

@ -1,6 +1,6 @@
[package] [package]
name = "async-graphql" name = "async-graphql"
version = "1.12.7" version = "1.12.8"
authors = ["sunli <scott_s829@163.com>"] authors = ["sunli <scott_s829@163.com>"]
edition = "2018" edition = "2018"
description = "The GraphQL server library implemented by rust" description = "The GraphQL server library implemented by rust"
@ -17,8 +17,8 @@ readme = "README.md"
default = ["bson", "uuid", "url", "chrono-tz"] default = ["bson", "uuid", "url", "chrono-tz"]
[dependencies] [dependencies]
async-graphql-parser = { path = "async-graphql-parser", version = "0.3.1" } async-graphql-parser = { path = "async-graphql-parser", version = "0.4.0" }
async-graphql-derive = { path = "async-graphql-derive", version = "1.12.7" } async-graphql-derive = { path = "async-graphql-derive", version = "1.12.8" }
anyhow = "1.0.26" anyhow = "1.0.26"
thiserror = "1.0.11" thiserror = "1.0.11"
async-trait = "0.1.30" async-trait = "0.1.30"
@ -42,6 +42,7 @@ http = "0.2.1"
fnv = "1.0.6" fnv = "1.0.6"
regex = "1.3.5" regex = "1.3.5"
tracing = "0.1.13" tracing = "0.1.13"
indexmap = "1.3.2"
bson = { version = "0.14.1", optional = true } bson = { version = "0.14.1", optional = true }
uuid = { version = "0.8.1", optional = true } uuid = { version = "0.8.1", optional = true }
url = { version = "2.1.1", optional = true } url = { version = "2.1.1", optional = true }

View File

@ -1,6 +1,6 @@
[package] [package]
name = "async-graphql-actix-web" name = "async-graphql-actix-web"
version = "1.4.7" version = "1.4.8"
authors = ["sunli <scott_s829@163.com>"] authors = ["sunli <scott_s829@163.com>"]
edition = "2018" edition = "2018"
description = "async-graphql for actix-web" description = "async-graphql for actix-web"
@ -13,7 +13,7 @@ keywords = ["futures", "async", "graphql"]
categories = ["network-programming", "asynchronous"] categories = ["network-programming", "asynchronous"]
[dependencies] [dependencies]
async-graphql = { path = "..", version = "1.12.7" } async-graphql = { path = "..", version = "1.12.8" }
actix-web = "2.0.0" actix-web = "2.0.0"
actix-web-actors = "2.0.0" actix-web-actors = "2.0.0"
actix = "0.9.0" actix = "0.9.0"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "async-graphql-derive" name = "async-graphql-derive"
version = "1.12.7" version = "1.12.8"
authors = ["sunli <scott_s829@163.com>"] authors = ["sunli <scott_s829@163.com>"]
edition = "2018" edition = "2018"
description = "Macros for async-graphql" description = "Macros for async-graphql"
@ -16,7 +16,7 @@ categories = ["network-programming", "asynchronous"]
proc-macro = true proc-macro = true
[dependencies] [dependencies]
async-graphql-parser = { path = "../async-graphql-parser", version = "0.3.1" } async-graphql-parser = { path = "../async-graphql-parser", version = "0.4.0" }
proc-macro2 = "1.0.6" proc-macro2 = "1.0.6"
syn = { version = "1.0.20", features = ["full", "extra-traits"] } syn = { version = "1.0.20", features = ["full", "extra-traits"] }
quote = "1.0.3" quote = "1.0.3"

View File

@ -146,7 +146,7 @@ pub fn generate(enum_args: &args::Enum, input: &DeriveInput) -> Result<TokenStre
name: #gql_typename.to_string(), name: #gql_typename.to_string(),
description: #desc, description: #desc,
enum_values: { enum_values: {
let mut enum_items = std::collections::HashMap::new(); let mut enum_items = #crate_name::indexmap::IndexMap::new();
#(#schema_enum_items)* #(#schema_enum_items)*
enum_items enum_items
}, },

View File

@ -120,7 +120,7 @@ pub fn generate(object_args: &args::InputObject, input: &DeriveInput) -> Result<
name: #gql_typename.to_string(), name: #gql_typename.to_string(),
description: #desc, description: #desc,
input_fields: { input_fields: {
let mut fields = std::collections::HashMap::new(); let mut fields = #crate_name::indexmap::IndexMap::new();
#(#schema_fields)* #(#schema_fields)*
fields fields
} }

View File

@ -223,7 +223,7 @@ pub fn generate(interface_args: &args::Interface, input: &DeriveInput) -> Result
name: #name.to_string(), name: #name.to_string(),
description: #desc, description: #desc,
args: { args: {
let mut args = std::collections::HashMap::new(); let mut args = #crate_name::indexmap::IndexMap::new();
#(#schema_args)* #(#schema_args)*
args args
}, },
@ -286,12 +286,12 @@ pub fn generate(interface_args: &args::Interface, input: &DeriveInput) -> Result
name: #gql_typename.to_string(), name: #gql_typename.to_string(),
description: #desc, description: #desc,
fields: { fields: {
let mut fields = std::collections::HashMap::new(); let mut fields = #crate_name::indexmap::IndexMap::new();
#(#schema_fields)* #(#schema_fields)*
fields fields
}, },
possible_types: { possible_types: {
let mut possible_types = std::collections::HashSet::new(); let mut possible_types = #crate_name::indexmap::IndexSet::new();
#(#possible_types)* #(#possible_types)*
possible_types possible_types
}, },

View File

@ -343,7 +343,7 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
name: #field_name.to_string(), name: #field_name.to_string(),
description: #field_desc, description: #field_desc,
args: { args: {
let mut args = std::collections::HashMap::new(); let mut args = #crate_name::indexmap::IndexMap::new();
#(#schema_args)* #(#schema_args)*
args args
}, },
@ -441,7 +441,7 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
name: #gql_typename.to_string(), name: #gql_typename.to_string(),
description: #desc, description: #desc,
fields: { fields: {
let mut fields = std::collections::HashMap::new(); let mut fields = #crate_name::indexmap::IndexMap::new();
#(#schema_fields)* #(#schema_fields)*
fields fields
}, },

View File

@ -161,7 +161,7 @@ pub fn generate(object_args: &args::Object, input: &mut DeriveInput) -> Result<T
name: #gql_typename.to_string(), name: #gql_typename.to_string(),
description: #desc, description: #desc,
fields: { fields: {
let mut fields = std::collections::HashMap::new(); let mut fields = #crate_name::indexmap::IndexMap::new();
#(#schema_fields)* #(#schema_fields)*
fields fields
}, },

View File

@ -213,7 +213,7 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
name: #field_name.to_string(), name: #field_name.to_string(),
description: #field_desc, description: #field_desc,
args: { args: {
let mut args = std::collections::HashMap::new(); let mut args = #crate_name::indexmap::IndexMap::new();
#(#schema_args)* #(#schema_args)*
args args
}, },
@ -316,7 +316,7 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
name: #gql_typename.to_string(), name: #gql_typename.to_string(),
description: #desc, description: #desc,
fields: { fields: {
let mut fields = std::collections::HashMap::new(); let mut fields = #crate_name::indexmap::IndexMap::new();
#(#schema_fields)* #(#schema_fields)*
fields fields
}, },

View File

@ -119,7 +119,7 @@ pub fn generate(union_args: &args::Interface, input: &DeriveInput) -> Result<Tok
name: #gql_typename.to_string(), name: #gql_typename.to_string(),
description: #desc, description: #desc,
possible_types: { possible_types: {
let mut possible_types = std::collections::HashSet::new(); let mut possible_types = #crate_name::indexmap::IndexSet::new();
#(#possible_types)* #(#possible_types)*
possible_types possible_types
} }

View File

@ -13,7 +13,7 @@ keywords = ["futures", "async", "graphql"]
categories = ["network-programming", "asynchronous"] categories = ["network-programming", "asynchronous"]
[dependencies] [dependencies]
async-graphql = { path = "..", version = "1.12.7" } async-graphql = { path = "..", version = "1.12.8" }
lambda_http = { git = "https://github.com/awslabs/aws-lambda-rust-runtime" } lambda_http = { git = "https://github.com/awslabs/aws-lambda-rust-runtime" }
futures = "0.3.0" futures = "0.3.0"
async-trait = "0.1.30" async-trait = "0.1.30"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "async-graphql-parser" name = "async-graphql-parser"
version = "0.3.1" version = "0.4.0"
authors = ["sunli <scott_s829@163.com>"] authors = ["sunli <scott_s829@163.com>"]
edition = "2018" edition = "2018"
description = "GraphQL query parser for async-graphql" description = "GraphQL query parser for async-graphql"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "async-graphql-tide" name = "async-graphql-tide"
version = "1.4.7" version = "1.4.8"
authors = ["vkill <vkill.net@gmail.com>"] authors = ["vkill <vkill.net@gmail.com>"]
edition = "2018" edition = "2018"
description = "async-graphql for tide" description = "async-graphql for tide"
@ -13,7 +13,7 @@ keywords = ["futures", "async", "graphql"]
categories = ["network-programming", "asynchronous"] categories = ["network-programming", "asynchronous"]
[dependencies] [dependencies]
async-graphql = { path = "..", version = "1.12.7" } async-graphql = { path = "..", version = "1.12.8" }
tide = "0.8" tide = "0.8"
async-trait = "0.1.30" async-trait = "0.1.30"
serde_json = "1.0.51" serde_json = "1.0.51"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "async-graphql-warp" name = "async-graphql-warp"
version = "1.4.7" version = "1.4.8"
authors = ["sunli <scott_s829@163.com>"] authors = ["sunli <scott_s829@163.com>"]
edition = "2018" edition = "2018"
description = "async-graphql for warp" description = "async-graphql for warp"
@ -13,7 +13,7 @@ keywords = ["futures", "async", "graphql"]
categories = ["network-programming", "asynchronous"] categories = ["network-programming", "asynchronous"]
[dependencies] [dependencies]
async-graphql = { path = "..", version = "1.12.7" } async-graphql = { path = "..", version = "1.12.8" }
warp = "0.2.2" warp = "0.2.2"
futures = "0.3.0" futures = "0.3.0"
bytes = "0.5.4" bytes = "0.5.4"

View File

@ -109,6 +109,8 @@ pub use async_trait;
#[doc(hidden)] #[doc(hidden)]
pub use futures; pub use futures;
#[doc(hidden)] #[doc(hidden)]
pub use indexmap;
#[doc(hidden)]
pub use serde_json; pub use serde_json;
pub mod http; pub mod http;

View File

@ -20,17 +20,14 @@ impl<'a> __Field<'a> {
} }
async fn args(&self) -> Vec<__InputValue<'a>> { async fn args(&self) -> Vec<__InputValue<'a>> {
let mut args = self self.field
.field
.args .args
.values() .values()
.map(|input_value| __InputValue { .map(|input_value| __InputValue {
registry: self.registry, registry: self.registry,
input_value, input_value,
}) })
.collect_vec(); .collect_vec()
args.sort_by(|a, b| a.input_value.name.cmp(b.input_value.name));
args
} }
#[field(name = "type")] #[field(name = "type")]

View File

@ -96,8 +96,8 @@ impl<'a> __Type<'a> {
#[arg(default = "false")] include_deprecated: bool, #[arg(default = "false")] include_deprecated: bool,
) -> Option<Vec<__Field<'a>>> { ) -> Option<Vec<__Field<'a>>> {
if let TypeDetail::Named(ty) = &self.detail { if let TypeDetail::Named(ty) = &self.detail {
ty.fields().and_then(|fields| { ty.fields().map(|fields| {
let mut fields = fields fields
.values() .values()
.filter(|field| { .filter(|field| {
(include_deprecated || field.deprecation.is_none()) (include_deprecated || field.deprecation.is_none())
@ -107,9 +107,7 @@ impl<'a> __Type<'a> {
registry: self.registry, registry: self.registry,
field, field,
}) })
.collect_vec(); .collect_vec()
fields.sort_by(|a, b| a.field.name.cmp(&b.field.name));
Some(fields)
}) })
} else { } else {
None None

View File

@ -1,6 +1,8 @@
use crate::parser::query::Type as ParsedType; use crate::parser::query::Type as ParsedType;
use crate::validators::InputValueValidator; use crate::validators::InputValueValidator;
use crate::{model, Any, Type as _, Value}; use crate::{model, Any, Type as _, Value};
use indexmap::map::IndexMap;
use indexmap::set::IndexSet;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::fmt::Write; use std::fmt::Write;
use std::sync::Arc; use std::sync::Arc;
@ -102,7 +104,7 @@ pub struct MetaInputValue {
pub struct MetaField { pub struct MetaField {
pub name: String, pub name: String,
pub description: Option<&'static str>, pub description: Option<&'static str>,
pub args: HashMap<&'static str, MetaInputValue>, pub args: IndexMap<&'static str, MetaInputValue>,
pub ty: String, pub ty: String,
pub deprecation: Option<&'static str>, pub deprecation: Option<&'static str>,
pub cache_control: CacheControl, pub cache_control: CacheControl,
@ -203,7 +205,7 @@ pub enum MetaType {
Object { Object {
name: String, name: String,
description: Option<&'static str>, description: Option<&'static str>,
fields: HashMap<String, MetaField>, fields: IndexMap<String, MetaField>,
cache_control: CacheControl, cache_control: CacheControl,
extends: bool, extends: bool,
keys: Option<Vec<String>>, keys: Option<Vec<String>>,
@ -211,25 +213,25 @@ pub enum MetaType {
Interface { Interface {
name: String, name: String,
description: Option<&'static str>, description: Option<&'static str>,
fields: HashMap<String, MetaField>, fields: IndexMap<String, MetaField>,
possible_types: HashSet<String>, possible_types: IndexSet<String>,
extends: bool, extends: bool,
keys: Option<Vec<String>>, keys: Option<Vec<String>>,
}, },
Union { Union {
name: String, name: String,
description: Option<&'static str>, description: Option<&'static str>,
possible_types: HashSet<String>, possible_types: IndexSet<String>,
}, },
Enum { Enum {
name: String, name: String,
description: Option<&'static str>, description: Option<&'static str>,
enum_values: HashMap<&'static str, MetaEnumValue>, enum_values: IndexMap<&'static str, MetaEnumValue>,
}, },
InputObject { InputObject {
name: String, name: String,
description: Option<&'static str>, description: Option<&'static str>,
input_fields: HashMap<String, MetaInputValue>, input_fields: IndexMap<String, MetaInputValue>,
}, },
} }
@ -238,7 +240,7 @@ impl MetaType {
self.fields().and_then(|fields| fields.get(name)) self.fields().and_then(|fields| fields.get(name))
} }
pub fn fields(&self) -> Option<&HashMap<String, MetaField>> { pub fn fields(&self) -> Option<&IndexMap<String, MetaField>> {
match self { match self {
MetaType::Object { fields, .. } => Some(&fields), MetaType::Object { fields, .. } => Some(&fields),
MetaType::Interface { fields, .. } => Some(&fields), MetaType::Interface { fields, .. } => Some(&fields),
@ -300,7 +302,7 @@ impl MetaType {
} }
} }
pub fn possible_types(&self) -> Option<&HashSet<String>> { pub fn possible_types(&self) -> Option<&IndexSet<String>> {
match self { match self {
MetaType::Interface { possible_types, .. } => Some(possible_types), MetaType::Interface { possible_types, .. } => Some(possible_types),
MetaType::Union { possible_types, .. } => Some(possible_types), MetaType::Union { possible_types, .. } => Some(possible_types),
@ -331,7 +333,7 @@ pub struct MetaDirective {
pub name: &'static str, pub name: &'static str,
pub description: Option<&'static str>, pub description: Option<&'static str>,
pub locations: Vec<model::__DirectiveLocation>, pub locations: Vec<model::__DirectiveLocation>,
pub args: HashMap<&'static str, MetaInputValue>, pub args: IndexMap<&'static str, MetaInputValue>,
} }
pub struct Registry { pub struct Registry {
@ -552,7 +554,7 @@ impl Registry {
name: "_Service".to_string(), name: "_Service".to_string(),
description: None, description: None,
fields: { fields: {
let mut fields = HashMap::new(); let mut fields = IndexMap::new();
fields.insert( fields.insert(
"sdl".to_string(), "sdl".to_string(),
MetaField { MetaField {
@ -600,7 +602,7 @@ impl Registry {
name: "_entities".to_string(), name: "_entities".to_string(),
description: None, description: None,
args: { args: {
let mut args = HashMap::new(); let mut args = IndexMap::new();
args.insert( args.insert(
"representations", "representations",
MetaInputValue { MetaInputValue {

View File

@ -14,8 +14,8 @@ use crate::{
use bytes::Bytes; use bytes::Bytes;
use futures::channel::mpsc; use futures::channel::mpsc;
use futures::Stream; use futures::Stream;
use indexmap::map::IndexMap;
use std::any::Any; use std::any::Any;
use std::collections::HashMap;
use std::sync::atomic::AtomicUsize; use std::sync::atomic::AtomicUsize;
use std::sync::Arc; use std::sync::Arc;
@ -143,7 +143,7 @@ where
__DirectiveLocation::INLINE_FRAGMENT __DirectiveLocation::INLINE_FRAGMENT
], ],
args: { args: {
let mut args = HashMap::new(); let mut args = IndexMap::new();
args.insert("if", MetaInputValue { args.insert("if", MetaInputValue {
name: "if", name: "if",
description: Some("Included when true."), description: Some("Included when true."),
@ -164,7 +164,7 @@ where
__DirectiveLocation::INLINE_FRAGMENT __DirectiveLocation::INLINE_FRAGMENT
], ],
args: { args: {
let mut args = HashMap::new(); let mut args = IndexMap::new();
args.insert("if", MetaInputValue { args.insert("if", MetaInputValue {
name: "if", name: "if",
description: Some("Skipped when true."), description: Some("Skipped when true."),

View File

@ -5,10 +5,10 @@ use crate::{
do_resolve, registry, Context, ContextSelectionSet, EmptyEdgeFields, Error, ObjectType, do_resolve, registry, Context, ContextSelectionSet, EmptyEdgeFields, Error, ObjectType,
OutputValueType, Pos, QueryError, Result, Type, OutputValueType, Pos, QueryError, Result, Type,
}; };
use indexmap::map::IndexMap;
use inflector::Inflector; use inflector::Inflector;
use itertools::Itertools; use itertools::Itertools;
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::HashMap;
/// Connection type /// Connection type
/// ///
@ -103,7 +103,7 @@ impl<T: OutputValueType + Send + Sync, E: ObjectType + Sync + Send> Type for Con
name: Self::type_name().to_string(), name: Self::type_name().to_string(),
description: None, description: None,
fields: { fields: {
let mut fields = HashMap::new(); let mut fields = IndexMap::new();
fields.insert( fields.insert(
"pageInfo".to_string(), "pageInfo".to_string(),

View File

@ -2,8 +2,8 @@ use crate::{
do_resolve, registry, Context, ContextSelectionSet, ObjectType, OutputValueType, Pos, Result, do_resolve, registry, Context, ContextSelectionSet, ObjectType, OutputValueType, Pos, Result,
Type, Type,
}; };
use indexmap::map::IndexMap;
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::HashMap;
pub struct Edge<'a, T, E> { pub struct Edge<'a, T, E> {
pub cursor: &'a str, pub cursor: &'a str,
@ -53,7 +53,7 @@ where
name: Self::type_name().to_string(), name: Self::type_name().to_string(),
description: Some("An edge in a connection."), description: Some("An edge in a connection."),
fields: { fields: {
let mut fields = HashMap::new(); let mut fields = IndexMap::new();
fields.insert( fields.insert(
"node".to_string(), "node".to_string(),

View File

@ -5,8 +5,8 @@ use crate::{
QueryError, Result, Type, Value, QueryError, Result, Type, Value,
}; };
use async_graphql_derive::SimpleObject; use async_graphql_derive::SimpleObject;
use indexmap::map::IndexMap;
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::HashMap;
/// Federation service /// Federation service
#[SimpleObject(internal)] #[SimpleObject(internal)]
@ -51,7 +51,7 @@ impl<T: Type> Type for QueryRoot<T> {
name: "__type".to_string(), name: "__type".to_string(),
description: Some("Request the type information of a single type."), description: Some("Request the type information of a single type."),
args: { args: {
let mut args = HashMap::new(); let mut args = IndexMap::new();
args.insert( args.insert(
"name", "name",
registry::MetaInputValue { registry::MetaInputValue {

View File

@ -4,11 +4,11 @@ use crate::registry::MetaInputValue;
use crate::validation::utils::is_valid_input_value; use crate::validation::utils::is_valid_input_value;
use crate::validation::visitor::{Visitor, VisitorContext}; use crate::validation::visitor::{Visitor, VisitorContext};
use crate::{Positioned, QueryPathSegment, Value}; use crate::{Positioned, QueryPathSegment, Value};
use std::collections::HashMap; use indexmap::map::IndexMap;
#[derive(Default)] #[derive(Default)]
pub struct ArgumentsOfCorrectType<'a> { pub struct ArgumentsOfCorrectType<'a> {
current_args: Option<&'a HashMap<&'static str, MetaInputValue>>, current_args: Option<&'a IndexMap<&'static str, MetaInputValue>>,
} }
impl<'a> Visitor<'a> for ArgumentsOfCorrectType<'a> { impl<'a> Visitor<'a> for ArgumentsOfCorrectType<'a> {

View File

@ -3,7 +3,7 @@ use crate::registry::MetaInputValue;
use crate::validation::suggestion::make_suggestion; use crate::validation::suggestion::make_suggestion;
use crate::validation::visitor::{Visitor, VisitorContext}; use crate::validation::visitor::{Visitor, VisitorContext};
use crate::{Positioned, Value}; use crate::{Positioned, Value};
use std::collections::HashMap; use indexmap::map::IndexMap;
enum ArgsType<'a> { enum ArgsType<'a> {
Directive(&'a str), Directive(&'a str),
@ -15,7 +15,7 @@ enum ArgsType<'a> {
#[derive(Default)] #[derive(Default)]
pub struct KnownArgumentNames<'a> { pub struct KnownArgumentNames<'a> {
current_args: Option<(&'a HashMap<&'static str, MetaInputValue>, ArgsType<'a>)>, current_args: Option<(&'a IndexMap<&'static str, MetaInputValue>, ArgsType<'a>)>,
} }
impl<'a> KnownArgumentNames<'a> { impl<'a> KnownArgumentNames<'a> {