Merge branch 'async-await' into remove-async-closure-feature
# Conflicts: # examples/warp_async/src/main.rs # integration_tests/async_await/src/main.rs # juniper/src/lib.rs # juniper_benchmarks/src/lib.rs # juniper_rocket/src/lib.rs # juniper_warp/src/lib.rs
This commit is contained in:
commit
635bf1ff34
26 changed files with 344 additions and 45 deletions
|
@ -2,9 +2,15 @@
|
|||
|
||||
- No changes yet
|
||||
|
||||
# [[0.14.0] 2019-09-29](https://github.com/graphql-rust/juniper/releases/tag/juniper-0.14.0)
|
||||
|
||||
- Require `url` 2.x if `url` feature is enabled.
|
||||
- Improve lookahead visitability.
|
||||
- Add ability to parse 'subscription'.
|
||||
|
||||
# [[0.13.1] 2019-07-29](https://github.com/graphql-rust/juniper/releases/tag/juniper-0.13.1)
|
||||
|
||||
- Fix a regression when using lookaheads with fragments containing nested types [#404](https://github.com/graphql-rust/juniper/pull/404)
|
||||
- Fix a regression when using lookaheads with fragments containing nested types [#404](https://github.com/graphql-rust/juniper/pull/404)
|
||||
|
||||
- Allow `mut` arguments for resolver functions in `#[object]` macros [#402](https://github.com/graphql-rust/juniper/pull/402)
|
||||
|
||||
|
@ -15,7 +21,7 @@
|
|||
See [#345](https://github.com/graphql-rust/juniper/pull/345).
|
||||
|
||||
The newtype pattern can now be used with the `GraphQLScalarValue` custom derive
|
||||
to easily implement custom scalar values that just wrap another scalar,
|
||||
to easily implement custom scalar values that just wrap another scalar,
|
||||
similar to serdes `#[serde(transparent)]` functionality.
|
||||
|
||||
Example:
|
||||
|
@ -34,7 +40,7 @@ struct UserId(i32);
|
|||
|
||||
### object macro
|
||||
|
||||
The `graphql_object!` macro is deprecated and will be removed in the future.
|
||||
The `graphql_object!` macro is deprecated and will be removed in the future.
|
||||
It is replaced by the new [object](https://docs.rs/juniper/latest/juniper/macro.object.html) procedural macro.
|
||||
|
||||
[#333](https://github.com/graphql-rust/juniper/pull/333)
|
||||
|
@ -53,7 +59,7 @@ This should not have any impact on your code, since juniper already was 2018 com
|
|||
- The `GraphQLType` impl for () was removed to improve compile time safefty. [#355](https://github.com/graphql-rust/juniper/pull/355)
|
||||
- The `ScalarValue` custom derive has been renamed to `GraphQLScalarValue`.
|
||||
- Added built-in support for the canonical schema introspection query via
|
||||
`juniper::introspect()`.
|
||||
`juniper::introspect()`.
|
||||
[#307](https://github.com/graphql-rust/juniper/issues/307)
|
||||
- Fix introspection query validity
|
||||
The DirectiveLocation::InlineFragment had an invalid literal value,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "juniper"
|
||||
version = "0.13.1"
|
||||
version = "0.14.0"
|
||||
authors = [
|
||||
"Magnus Hallin <mhallin@fastmail.com>",
|
||||
"Christoph Herzog <chris@theduke.at>",
|
||||
|
@ -33,7 +33,7 @@ default = [
|
|||
]
|
||||
|
||||
[dependencies]
|
||||
juniper_codegen = { version = "0.13.2", path = "../juniper_codegen" }
|
||||
juniper_codegen = { version = "0.14.0", path = "../juniper_codegen" }
|
||||
|
||||
fnv = "1.0.3"
|
||||
indexmap = { version = "1.0.0", features = ["serde-1"] }
|
||||
|
@ -42,7 +42,7 @@ serde_derive = { version = "1.0.2" }
|
|||
|
||||
chrono = { version = "0.4.0", optional = true }
|
||||
serde_json = { version="1.0.2", optional = true }
|
||||
url = { version = "1.5.1", optional = true }
|
||||
url = { version = "2", optional = true }
|
||||
uuid = { version = "0.7", optional = true }
|
||||
|
||||
futures-preview = { version = "=0.3.0-alpha.19", optional = true }
|
||||
|
|
|
@ -116,6 +116,7 @@ pub struct Directive<'a, S> {
|
|||
pub enum OperationType {
|
||||
Query,
|
||||
Mutation,
|
||||
Subscription,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
|
|
|
@ -88,6 +88,11 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// The argument's name
|
||||
pub fn name(&'a self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
/// The value of the argument
|
||||
pub fn value(&'a self) -> &LookAheadValue<'a, S> {
|
||||
&self.value
|
||||
|
@ -347,6 +352,12 @@ pub trait LookAheadMethods<S> {
|
|||
self.select_child(name).is_some()
|
||||
}
|
||||
|
||||
/// Does the current node have any arguments?
|
||||
fn has_arguments(&self) -> bool;
|
||||
|
||||
/// Does the current node have any children?
|
||||
fn has_children(&self) -> bool;
|
||||
|
||||
/// Get the top level arguments for the current selection
|
||||
fn arguments(&self) -> &[LookAheadArgument<S>];
|
||||
|
||||
|
@ -354,6 +365,9 @@ pub trait LookAheadMethods<S> {
|
|||
fn argument(&self, name: &str) -> Option<&LookAheadArgument<S>> {
|
||||
self.arguments().iter().find(|a| a.name == name)
|
||||
}
|
||||
|
||||
/// Get the top level children for the current selection
|
||||
fn child_names(&self) -> Vec<&str>;
|
||||
}
|
||||
|
||||
impl<'a, S> LookAheadMethods<S> for ConcreteLookAheadSelection<'a, S> {
|
||||
|
@ -368,6 +382,21 @@ impl<'a, S> LookAheadMethods<S> for ConcreteLookAheadSelection<'a, S> {
|
|||
fn arguments(&self) -> &[LookAheadArgument<S>] {
|
||||
&self.arguments
|
||||
}
|
||||
|
||||
fn child_names(&self) -> Vec<&str> {
|
||||
self.children
|
||||
.iter()
|
||||
.map(|c| c.alias.unwrap_or(c.name))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn has_arguments(&self) -> bool {
|
||||
!self.arguments.is_empty()
|
||||
}
|
||||
|
||||
fn has_children(&self) -> bool {
|
||||
!self.children.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S> LookAheadMethods<S> for LookAheadSelection<'a, S> {
|
||||
|
@ -385,6 +414,21 @@ impl<'a, S> LookAheadMethods<S> for LookAheadSelection<'a, S> {
|
|||
fn arguments(&self) -> &[LookAheadArgument<S>] {
|
||||
&self.arguments
|
||||
}
|
||||
|
||||
fn child_names(&self) -> Vec<&str> {
|
||||
self.children
|
||||
.iter()
|
||||
.map(|c| c.inner.alias.unwrap_or(c.inner.name))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn has_arguments(&self) -> bool {
|
||||
!self.arguments.is_empty()
|
||||
}
|
||||
|
||||
fn has_children(&self) -> bool {
|
||||
!self.children.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -1399,4 +1443,59 @@ fragment heroFriendNames on Hero {
|
|||
panic!("No Operation found");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_visitability() {
|
||||
let docs = parse_document_source::<DefaultScalarValue>(
|
||||
"
|
||||
query Hero {
|
||||
hero(episode: EMPIRE) {
|
||||
name
|
||||
friends {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
",
|
||||
)
|
||||
.unwrap();
|
||||
let fragments = extract_fragments(&docs);
|
||||
|
||||
if let crate::ast::Definition::Operation(ref op) = docs[0] {
|
||||
let vars = Variables::default();
|
||||
let look_ahead = LookAheadSelection::build_from_selection(
|
||||
&op.item.selection_set[0],
|
||||
&vars,
|
||||
&fragments,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(look_ahead.field_name(), "hero");
|
||||
|
||||
assert!(look_ahead.has_arguments());
|
||||
let args = look_ahead.arguments();
|
||||
assert_eq!(args[0].name(), "episode");
|
||||
assert_eq!(args[0].value(), &LookAheadValue::Enum("EMPIRE"));
|
||||
|
||||
assert!(look_ahead.has_children());
|
||||
assert_eq!(look_ahead.child_names(), vec!["name", "friends"]);
|
||||
|
||||
let child0 = look_ahead.select_child("name").unwrap();
|
||||
assert_eq!(child0.field_name(), "name");
|
||||
assert!(!child0.has_arguments());
|
||||
assert!(!child0.has_children());
|
||||
|
||||
let child1 = look_ahead.select_child("friends").unwrap();
|
||||
assert_eq!(child1.field_name(), "friends");
|
||||
assert!(!child1.has_arguments());
|
||||
assert!(child1.has_children());
|
||||
assert_eq!(child1.child_names(), vec!["name"]);
|
||||
|
||||
let child2 = child1.select_child("name").unwrap();
|
||||
assert!(!child2.has_arguments());
|
||||
assert!(!child2.has_children());
|
||||
} else {
|
||||
panic!("No Operation found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -713,6 +713,121 @@ where
|
|||
None => return Err(GraphQLError::UnknownOperationName),
|
||||
};
|
||||
|
||||
if op.item.operation_type == OperationType::Subscription {
|
||||
return Err(GraphQLError::IsSubscription);
|
||||
}
|
||||
|
||||
let default_variable_values = op.item.variable_definitions.map(|defs| {
|
||||
defs.item
|
||||
.items
|
||||
.iter()
|
||||
.filter_map(|&(ref name, ref def)| {
|
||||
def.default_value
|
||||
.as_ref()
|
||||
.map(|i| (name.item.to_owned(), i.item.clone()))
|
||||
})
|
||||
.collect::<HashMap<String, InputValue<S>>>()
|
||||
});
|
||||
|
||||
let errors = RwLock::new(Vec::new());
|
||||
let value;
|
||||
|
||||
{
|
||||
let mut all_vars;
|
||||
let mut final_vars = variables;
|
||||
|
||||
if let Some(defaults) = default_variable_values {
|
||||
all_vars = variables.clone();
|
||||
|
||||
for (name, value) in defaults {
|
||||
all_vars.entry(name).or_insert(value);
|
||||
}
|
||||
|
||||
final_vars = &all_vars;
|
||||
}
|
||||
|
||||
let root_type = match op.item.operation_type {
|
||||
OperationType::Query => root_node.schema.query_type(),
|
||||
OperationType::Mutation => root_node
|
||||
.schema
|
||||
.mutation_type()
|
||||
.expect("No mutation type found"),
|
||||
OperationType::Subscription => unreachable!(),
|
||||
};
|
||||
|
||||
let executor = Executor {
|
||||
fragments: &fragments
|
||||
.iter()
|
||||
.map(|f| (f.item.name.item, &f.item))
|
||||
.collect(),
|
||||
variables: final_vars,
|
||||
current_selection_set: Some(&op.item.selection_set[..]),
|
||||
parent_selection_set: None,
|
||||
current_type: root_type,
|
||||
schema: &root_node.schema,
|
||||
context,
|
||||
errors: &errors,
|
||||
field_path: FieldPath::Root(op.start),
|
||||
};
|
||||
|
||||
value = match op.item.operation_type {
|
||||
OperationType::Query => executor.resolve_into_value(&root_node.query_info, &root_node),
|
||||
OperationType::Mutation => {
|
||||
executor.resolve_into_value(&root_node.mutation_info, &root_node.mutation_type)
|
||||
}
|
||||
OperationType::Subscription => unreachable!(),
|
||||
};
|
||||
}
|
||||
|
||||
let mut errors = errors.into_inner().unwrap();
|
||||
errors.sort();
|
||||
|
||||
Ok((value, errors))
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
pub async fn execute_validated_query_async<'a, QueryT, MutationT, CtxT, S>(
|
||||
document: Document<'a, S>,
|
||||
operation_name: Option<&str>,
|
||||
root_node: &RootNode<'a, QueryT, MutationT, S>,
|
||||
variables: &Variables<S>,
|
||||
context: &CtxT,
|
||||
) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>>
|
||||
where
|
||||
S: ScalarValue + Send + Sync,
|
||||
QueryT: crate::GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
|
||||
QueryT::TypeInfo: Send + Sync,
|
||||
MutationT: crate::GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
|
||||
MutationT::TypeInfo: Send + Sync,
|
||||
CtxT: Send + Sync,
|
||||
for<'b> &'b S: ScalarRefValue<'b>,
|
||||
{
|
||||
let mut fragments = vec![];
|
||||
let mut operation = None;
|
||||
|
||||
for def in document {
|
||||
match def {
|
||||
Definition::Operation(op) => {
|
||||
if operation_name.is_none() && operation.is_some() {
|
||||
return Err(GraphQLError::MultipleOperationsProvided);
|
||||
}
|
||||
|
||||
let move_op = operation_name.is_none()
|
||||
|| op.item.name.as_ref().map(|s| s.item) == operation_name;
|
||||
|
||||
if move_op {
|
||||
operation = Some(op);
|
||||
}
|
||||
}
|
||||
Definition::Fragment(f) => fragments.push(f),
|
||||
};
|
||||
}
|
||||
|
||||
let op = match operation {
|
||||
Some(op) => op,
|
||||
None => return Err(GraphQLError::UnknownOperationName),
|
||||
};
|
||||
|
||||
let default_variable_values = op.item.variable_definitions.map(|defs| {
|
||||
defs.item
|
||||
.items
|
||||
|
@ -766,9 +881,15 @@ where
|
|||
};
|
||||
|
||||
value = match op.item.operation_type {
|
||||
OperationType::Query => executor.resolve_into_value(&root_node.query_info, &root_node),
|
||||
OperationType::Query => {
|
||||
executor
|
||||
.resolve_into_value_async(&root_node.query_info, &root_node)
|
||||
.await
|
||||
}
|
||||
OperationType::Mutation => {
|
||||
executor.resolve_into_value(&root_node.mutation_info, &root_node.mutation_type)
|
||||
executor
|
||||
.resolve_into_value_async(&root_node.mutation_info, &root_node.mutation_type)
|
||||
.await
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -70,6 +70,10 @@ impl<'a> ser::Serialize for GraphQLError<'a> {
|
|||
message: "Unknown operation",
|
||||
}]
|
||||
.serialize(serializer),
|
||||
GraphQLError::IsSubscription => [SerializeHelper {
|
||||
message: "Expected query, got subscription",
|
||||
}]
|
||||
.serialize(serializer),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,8 +88,7 @@ Juniper has not reached 1.0 yet, thus some API instability should be expected.
|
|||
[chrono]: https://crates.io/crates/chrono
|
||||
|
||||
*/
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/juniper/0.13.1")]
|
||||
#![doc(html_root_url = "https://docs.rs/juniper/0.14.0")]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
#[doc(hidden)]
|
||||
|
@ -191,6 +190,7 @@ pub enum GraphQLError<'a> {
|
|||
NoOperationProvided,
|
||||
MultipleOperationsProvided,
|
||||
UnknownOperationName,
|
||||
IsSubscription,
|
||||
}
|
||||
|
||||
/// Execute a query in a provided schema
|
||||
|
|
|
@ -56,9 +56,12 @@ where
|
|||
S: ScalarValue,
|
||||
{
|
||||
match parser.peek().item {
|
||||
Token::CurlyOpen | Token::Name("query") | Token::Name("mutation") => Ok(
|
||||
Definition::Operation(parse_operation_definition(parser, schema)?),
|
||||
),
|
||||
Token::CurlyOpen
|
||||
| Token::Name("query")
|
||||
| Token::Name("mutation")
|
||||
| Token::Name("subscription") => Ok(Definition::Operation(parse_operation_definition(
|
||||
parser, schema,
|
||||
)?)),
|
||||
Token::Name("fragment") => Ok(Definition::Fragment(parse_fragment_definition(
|
||||
parser, schema,
|
||||
)?)),
|
||||
|
@ -95,6 +98,7 @@ where
|
|||
let op = match operation_type.item {
|
||||
OperationType::Query => Some(schema.concrete_query_type()),
|
||||
OperationType::Mutation => schema.concrete_mutation_type(),
|
||||
OperationType::Subscription => schema.concrete_subscription_type(),
|
||||
};
|
||||
let fields = op.and_then(|m| m.fields(schema));
|
||||
let fields = fields.as_ref().map(|c| c as &[_]);
|
||||
|
@ -394,6 +398,7 @@ fn parse_operation_type<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Operatio
|
|||
match parser.peek().item {
|
||||
Token::Name("query") => Ok(parser.next()?.map(|_| OperationType::Query)),
|
||||
Token::Name("mutation") => Ok(parser.next()?.map(|_| OperationType::Mutation)),
|
||||
Token::Name("subscription") => Ok(parser.next()?.map(|_| OperationType::Subscription)),
|
||||
_ => Err(parser.next()?.map(ParseError::UnexpectedToken)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ pub struct DirectiveType<'a, S> {
|
|||
pub enum DirectiveLocation {
|
||||
Query,
|
||||
Mutation,
|
||||
Subscription,
|
||||
Field,
|
||||
#[graphql(name = "FRAGMENT_DEFINITION")]
|
||||
FragmentDefinition,
|
||||
|
@ -243,6 +244,18 @@ impl<'a, S> SchemaType<'a, S> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn subscription_type(&self) -> Option<TypeType<S>> {
|
||||
// subscription is not yet in `RootNode`,
|
||||
// so return `None` for now
|
||||
None
|
||||
}
|
||||
|
||||
pub fn concrete_subscription_type(&self) -> Option<&MetaType<S>> {
|
||||
// subscription is not yet in `RootNode`,
|
||||
// so return `None` for now
|
||||
None
|
||||
}
|
||||
|
||||
pub fn type_list(&self) -> Vec<TypeType<S>> {
|
||||
self.types.values().map(|t| TypeType::Concrete(t)).collect()
|
||||
}
|
||||
|
@ -452,6 +465,7 @@ impl fmt::Display for DirectiveLocation {
|
|||
f.write_str(match *self {
|
||||
DirectiveLocation::Query => "query",
|
||||
DirectiveLocation::Mutation => "mutation",
|
||||
DirectiveLocation::Subscription => "subscription",
|
||||
DirectiveLocation::Field => "field",
|
||||
DirectiveLocation::FragmentDefinition => "fragment definition",
|
||||
DirectiveLocation::FragmentSpread => "fragment spread",
|
||||
|
|
|
@ -138,9 +138,8 @@ where
|
|||
self.mutation_type()
|
||||
}
|
||||
|
||||
// Included for compatibility with the introspection query in GraphQL.js
|
||||
fn subscription_type(&self) -> Option<TypeType<S>> {
|
||||
None
|
||||
self.subscription_type()
|
||||
}
|
||||
|
||||
fn directives(&self) -> Vec<&DirectiveType<S>> {
|
||||
|
|
|
@ -997,6 +997,12 @@ pub(crate) fn schema_introspection_result() -> value::Value {
|
|||
"isDeprecated": false,
|
||||
"deprecationReason": Null
|
||||
},
|
||||
{
|
||||
"name": "SUBSCRIPTION",
|
||||
"description": Null,
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": Null
|
||||
},
|
||||
{
|
||||
"name": "FIELD",
|
||||
"description": Null,
|
||||
|
@ -2204,6 +2210,11 @@ pub(crate) fn schema_introspection_result_without_descriptions() -> value::Value
|
|||
"isDeprecated": false,
|
||||
"deprecationReason": Null
|
||||
},
|
||||
{
|
||||
"name": "SUBSCRIPTION",
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": Null
|
||||
},
|
||||
{
|
||||
"name": "FIELD",
|
||||
"isDeprecated": false,
|
||||
|
|
|
@ -28,6 +28,7 @@ where
|
|||
self.location_stack.push(match op.item.operation_type {
|
||||
OperationType::Query => DirectiveLocation::Query,
|
||||
OperationType::Mutation => DirectiveLocation::Mutation,
|
||||
OperationType::Subscription => DirectiveLocation::Subscription,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -37,7 +38,11 @@ where
|
|||
_: &'a Spanning<Operation<S>>,
|
||||
) {
|
||||
let top = self.location_stack.pop();
|
||||
assert!(top == Some(DirectiveLocation::Query) || top == Some(DirectiveLocation::Mutation));
|
||||
assert!(
|
||||
top == Some(DirectiveLocation::Query)
|
||||
|| top == Some(DirectiveLocation::Mutation)
|
||||
|| top == Some(DirectiveLocation::Subscription)
|
||||
);
|
||||
}
|
||||
|
||||
fn enter_field(&mut self, _: &mut ValidatorContext<'a, S>, _: &'a Spanning<Field<S>>) {
|
||||
|
|
|
@ -64,6 +64,17 @@ fn visit_definitions<'a, S, V>(
|
|||
.schema
|
||||
.concrete_mutation_type()
|
||||
.map(|t| Type::NonNullNamed(Cow::Borrowed(t.name().unwrap()))),
|
||||
Definition::Operation(Spanning {
|
||||
item:
|
||||
Operation {
|
||||
operation_type: OperationType::Subscription,
|
||||
..
|
||||
},
|
||||
..
|
||||
}) => ctx
|
||||
.schema
|
||||
.concrete_subscription_type()
|
||||
.map(|t| Type::NonNullNamed(Cow::Borrowed(t.name().unwrap()))),
|
||||
};
|
||||
|
||||
ctx.with_pushed_type(def_type.as_ref(), |ctx| {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "juniper_codegen"
|
||||
version = "0.13.2"
|
||||
version = "0.14.0"
|
||||
authors = [
|
||||
"Magnus Hallin <mhallin@fastmail.com>",
|
||||
"Christoph Herzog <chris@theduke.at>",
|
||||
|
@ -21,11 +21,9 @@ async = []
|
|||
proc-macro2 = "1.0.1"
|
||||
syn = { version = "1.0.3", features = ["full", "extra-traits", "parsing"] }
|
||||
quote = "1.0.2"
|
||||
regex = "1"
|
||||
lazy_static = "1.0.0"
|
||||
|
||||
[dev-dependencies]
|
||||
juniper = { version = "0.13.1", path = "../juniper" }
|
||||
juniper = { version = "0.14.0", path = "../juniper" }
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "graphql-rust/juniper" }
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//! You should not depend on juniper_codegen directly.
|
||||
//! You only need the `juniper` crate.
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/juniper_codegen/0.13.2")]
|
||||
#![doc(html_root_url = "https://docs.rs/juniper_codegen/0.14.0")]
|
||||
#![recursion_limit = "1024"]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use quote::quote;
|
||||
use regex::Regex;
|
||||
use std::collections::HashMap;
|
||||
use syn::{
|
||||
parse, parse_quote, punctuated::Punctuated, Attribute, Lit, Meta, MetaList, MetaNameValue,
|
||||
|
@ -279,10 +278,16 @@ pub(crate) fn to_upper_snake_case(s: &str) -> String {
|
|||
|
||||
#[doc(hidden)]
|
||||
pub fn is_valid_name(field_name: &str) -> bool {
|
||||
lazy_static::lazy_static! {
|
||||
static ref GRAPHQL_NAME_SPEC: Regex = Regex::new("^[_A-Za-z][_0-9A-Za-z]*$").unwrap();
|
||||
}
|
||||
GRAPHQL_NAME_SPEC.is_match(field_name)
|
||||
let mut chars = field_name.chars();
|
||||
|
||||
match chars.next() {
|
||||
// first char can't be a digit
|
||||
Some(c) if c.is_ascii_alphabetic() || c == '_' => (),
|
||||
// can't be an empty string or any other character
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
chars.all(|c| c.is_ascii_alphanumeric() || c == '_')
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
- Compatibility with the latest `juniper`.
|
||||
|
||||
# [[0.5.0] 2019-09-29](https://github.com/graphql-rust/juniper/releases/tag/juniper_hyper-0.5.0)
|
||||
|
||||
- Compatibility with the latest `juniper`.
|
||||
|
||||
# [[0.4.1] 2019-07-29](https://github.com/graphql-rust/juniper/releases/tag/juniper_hyper-0.4.1)
|
||||
|
||||
- Compatibility with the latest `juniper`.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "juniper_hyper"
|
||||
version = "0.4.1"
|
||||
version = "0.5.0"
|
||||
authors = ["Damir Vandic <info@dvic.io>"]
|
||||
description = "Juniper GraphQL integration with Hyper"
|
||||
license = "BSD-2-Clause"
|
||||
|
@ -12,8 +12,8 @@ edition = "2018"
|
|||
serde = "1.0"
|
||||
serde_json = "1.0"
|
||||
serde_derive = "1.0"
|
||||
url = "1.7"
|
||||
juniper = { version = "0.13.1" , default-features = false, path = "../juniper"}
|
||||
url = "2"
|
||||
juniper = { version = "0.14.0", default-features = false, path = "../juniper"}
|
||||
|
||||
futures = "0.1"
|
||||
tokio = "0.1.8"
|
||||
|
@ -25,6 +25,6 @@ pretty_env_logger = "0.2"
|
|||
reqwest = "0.9"
|
||||
|
||||
[dev-dependencies.juniper]
|
||||
version = "0.13.1"
|
||||
version = "0.14.0"
|
||||
features = ["expose-test-schema", "serde_json"]
|
||||
path = "../juniper"
|
||||
|
|
|
@ -27,7 +27,7 @@ fn main() {
|
|||
let new_service = move || {
|
||||
let root_node = root_node.clone();
|
||||
let ctx = db.clone();
|
||||
service_fn(move |req| -> Box<Future<Item = _, Error = _> + Send> {
|
||||
service_fn(move |req| -> Box<dyn Future<Item = _, Error = _> + Send> {
|
||||
let root_node = root_node.clone();
|
||||
let ctx = ctx.clone();
|
||||
match (req.method(), req.uri().path()) {
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
- Compatibility with the latest `juniper`.
|
||||
|
||||
# [[0.6.0] 2019-09-29](https://github.com/graphql-rust/juniper/releases/tag/juniper_iron-0.6.0)
|
||||
|
||||
- Compatibility with the latest `juniper`.
|
||||
|
||||
# [[0.5.1] 2019-07-29](https://github.com/graphql-rust/juniper/releases/tag/juniper_iron-0.5.1)
|
||||
|
||||
- Compatibility with the latest `juniper`.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "juniper_iron"
|
||||
version = "0.5.1"
|
||||
version = "0.6.0"
|
||||
authors = [
|
||||
"Magnus Hallin <mhallin@fastmail.com>",
|
||||
"Christoph Herzog <chris@theduke.at>",
|
||||
|
@ -15,7 +15,7 @@ edition = "2018"
|
|||
serde = { version = "1.0.2" }
|
||||
serde_json = { version = "1.0.2" }
|
||||
serde_derive = { version = "1.0.2" }
|
||||
juniper = { version = "0.13.1", path = "../juniper" }
|
||||
juniper = { version = "0.14.0", path = "../juniper" }
|
||||
|
||||
urlencoded = { version = ">= 0.5, < 0.7" }
|
||||
iron = ">= 0.5, < 0.7"
|
||||
|
@ -25,9 +25,10 @@ iron-test = "0.6"
|
|||
router = "0.6"
|
||||
mount = "0.4"
|
||||
logger = "0.4"
|
||||
url = "1.7.1"
|
||||
url = "2"
|
||||
percent-encoding = "2"
|
||||
|
||||
[dev-dependencies.juniper]
|
||||
version = "0.13.1"
|
||||
version = "0.14.0"
|
||||
features = ["expose-test-schema", "serde_json"]
|
||||
path = "../juniper"
|
||||
|
|
|
@ -431,7 +431,7 @@ mod tests {
|
|||
use super::*;
|
||||
use iron::{Handler, Headers, Url};
|
||||
use iron_test::{request, response};
|
||||
use url::percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET};
|
||||
use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};
|
||||
|
||||
use juniper::{
|
||||
http::tests as http_tests,
|
||||
|
@ -441,6 +441,9 @@ mod tests {
|
|||
|
||||
use super::GraphQLHandler;
|
||||
|
||||
/// https://url.spec.whatwg.org/#query-state
|
||||
const QUERY_ENCODE_SET: &AsciiSet = &CONTROLS.add(b' ').add(b'"').add(b'#').add(b'<').add(b'>');
|
||||
|
||||
// This is ugly but it works. `iron_test` just dumps the path/url in headers
|
||||
// and newer `hyper` doesn't allow unescaped "{" or "}".
|
||||
fn fixup_url(url: &str) -> String {
|
||||
|
@ -454,7 +457,7 @@ mod tests {
|
|||
format!(
|
||||
"http://localhost:3000{}?{}",
|
||||
path,
|
||||
utf8_percent_encode(url.query().unwrap_or(""), DEFAULT_ENCODE_SET)
|
||||
utf8_percent_encode(url.query().unwrap_or(""), QUERY_ENCODE_SET)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -521,7 +524,7 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
fn make_handler() -> Box<Handler> {
|
||||
fn make_handler() -> Box<dyn Handler> {
|
||||
Box::new(GraphQLHandler::new(
|
||||
context_factory,
|
||||
Query,
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
- Compatibility with the latest `juniper`.
|
||||
|
||||
# [[0.5.0] 2019-09-29](https://github.com/graphql-rust/juniper/releases/tag/juniper_rocket-0.5.0)
|
||||
|
||||
- Compatibility with the latest `juniper`.
|
||||
|
||||
# [[0.4.1] 2019-07-29](https://github.com/graphql-rust/juniper/releases/tag/juniper_rocket-0.4.1)
|
||||
|
||||
- Compatibility with the latest `juniper`.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "juniper_rocket"
|
||||
version = "0.4.1"
|
||||
version = "0.5.0"
|
||||
authors = [
|
||||
"Magnus Hallin <mhallin@fastmail.com>",
|
||||
"Christoph Herzog <chris@theduke.at>",
|
||||
|
@ -18,13 +18,13 @@ async = [ "juniper/async" ]
|
|||
serde = { version = "1.0.2" }
|
||||
serde_json = { version = "1.0.2" }
|
||||
serde_derive = { version = "1.0.2" }
|
||||
juniper = { version = "0.13.1" , default-features = false, path = "../juniper"}
|
||||
juniper = { version = "0.14.0", default-features = false, path = "../juniper"}
|
||||
|
||||
futures03 = { version = "=0.3.0-alpha.19", package = "futures-preview", features = ["compat"] }
|
||||
rocket = { git = "https://github.com/SergioBenitez/Rocket", branch = "async" }
|
||||
tokio = "=0.2.0-alpha.6"
|
||||
|
||||
[dev-dependencies.juniper]
|
||||
version = "0.13.1"
|
||||
version = "0.14.0"
|
||||
features = ["expose-test-schema", "serde_json"]
|
||||
path = "../juniper"
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
- Compatibility with the latest `juniper`.
|
||||
|
||||
# [[0.5.0] 2019-09-29](https://github.com/graphql-rust/juniper/releases/tag/juniper_warp-0.5.0)
|
||||
|
||||
- Compatibility with the latest `juniper`.
|
||||
|
||||
# [[0.4.1] 2019-07-29](https://github.com/graphql-rust/juniper/releases/tag/juniper_warp-0.4.1)
|
||||
|
||||
- Compatibility with the latest `juniper`.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "juniper_warp"
|
||||
version = "0.4.1"
|
||||
version = "0.5.0"
|
||||
authors = ["Tom Houlé <tom@tomhoule.com>"]
|
||||
description = "Juniper GraphQL integration with Warp"
|
||||
license = "BSD-2-Clause"
|
||||
|
@ -13,7 +13,7 @@ async = [ "juniper/async", "futures03" ]
|
|||
|
||||
[dependencies]
|
||||
warp = "0.1.8"
|
||||
juniper = { version = "0.13.1", path = "../juniper" }
|
||||
juniper = { version = "0.14.0", path = "../juniper", default-features = false }
|
||||
serde_json = "1.0.24"
|
||||
serde_derive = "1.0.75"
|
||||
failure = "0.1.2"
|
||||
|
@ -24,7 +24,7 @@ tokio-threadpool = "0.1.7"
|
|||
futures03 = { version = "=0.3.0-alpha.19", optional = true, package = "futures-preview", features = ["compat"] }
|
||||
|
||||
[dev-dependencies]
|
||||
juniper = { version = "0.13.1", path = "../juniper", features = ["expose-test-schema", "serde_json"] }
|
||||
juniper = { version = "0.14.0", path = "../juniper", features = ["expose-test-schema", "serde_json"] }
|
||||
env_logger = "0.5.11"
|
||||
log = "0.4.3"
|
||||
percent-encoding = "1.0"
|
||||
|
|
Loading…
Reference in a new issue