Default to generic ScalarValue in #[graphql_object] macro (#779)
* Change codegen ScalarValue defaults for #[graphql_object] macro * Fix integration tests * Fix codegen failure tests * Fix 'juniper' crate tests * Fix integration crates tests * Fix 'juniper_benchmarks' crate * Fix examples * Fix Book * Fix * Add CHANGELOG entry * Some Book corrections * Fix * Bootstrap coercion machinery * Reimpl coercion * Correct tests, vol.1 * Correct tests, vol.2 * Correct tests, vol.3 * Correct tests, vol.4 * Correct tests, vol.5 * Fix coercion for subscriptions * README fixes Co-authored-by: Christian Legnitto <christian@legnitto.com> Co-authored-by: Christian Legnitto <LegNeato@users.noreply.github.com>
This commit is contained in:
parent
4c40826eff
commit
a4871887bb
52 changed files with 817 additions and 646 deletions
|
@ -33,11 +33,14 @@ result can then be converted to JSON for use with tools and libraries such as
|
|||
# #![allow(unused_variables)]
|
||||
# extern crate juniper;
|
||||
# extern crate serde_json;
|
||||
use juniper::{EmptyMutation, EmptySubscription, FieldResult, IntrospectionFormat};
|
||||
use juniper::{
|
||||
graphql_object, EmptyMutation, EmptySubscription, FieldResult,
|
||||
GraphQLObject, IntrospectionFormat,
|
||||
};
|
||||
|
||||
// Define our schema.
|
||||
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
#[derive(GraphQLObject)]
|
||||
struct Example {
|
||||
id: String,
|
||||
}
|
||||
|
@ -47,9 +50,7 @@ impl juniper::Context for Context {}
|
|||
|
||||
struct Query;
|
||||
|
||||
#[juniper::graphql_object(
|
||||
Context = Context,
|
||||
)]
|
||||
#[graphql_object(context = Context)]
|
||||
impl Query {
|
||||
fn example(id: String) -> FieldResult<Example> {
|
||||
unimplemented!()
|
||||
|
|
|
@ -10,9 +10,10 @@ errors from a mutation:
|
|||
|
||||
```rust
|
||||
# extern crate juniper;
|
||||
# use juniper::{graphql_object, GraphQLObject};
|
||||
# #[derive(juniper::GraphQLObject)] struct User { name: String }
|
||||
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
#
|
||||
#[derive(GraphQLObject)]
|
||||
struct ValidationError {
|
||||
field: String,
|
||||
message: String,
|
||||
|
@ -24,7 +25,7 @@ enum SignUpResult {
|
|||
Error(Vec<ValidationError>),
|
||||
}
|
||||
|
||||
#[juniper::graphql_object]
|
||||
#[graphql_object]
|
||||
impl SignUpResult {
|
||||
fn user(&self) -> Option<&User> {
|
||||
match *self {
|
||||
|
@ -40,7 +41,7 @@ impl SignUpResult {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ sequentially:
|
|||
# extern crate juniper;
|
||||
# extern crate juniper_subscriptions;
|
||||
# extern crate tokio;
|
||||
# use juniper::FieldError;
|
||||
# use juniper::{graphql_object, graphql_subscription, FieldError};
|
||||
# use futures::Stream;
|
||||
# use std::pin::Pin;
|
||||
#
|
||||
|
@ -38,7 +38,7 @@ sequentially:
|
|||
# impl juniper::Context for Database {}
|
||||
|
||||
# pub struct Query;
|
||||
# #[juniper::graphql_object(Context = Database)]
|
||||
# #[graphql_object(context = Database)]
|
||||
# impl Query {
|
||||
# fn hello_world() -> &str {
|
||||
# "Hello World!"
|
||||
|
@ -48,7 +48,7 @@ pub struct Subscription;
|
|||
|
||||
type StringStream = Pin<Box<dyn Stream<Item = Result<String, FieldError>> + Send>>;
|
||||
|
||||
#[juniper::graphql_subscription(Context = Database)]
|
||||
#[graphql_subscription(context = Database)]
|
||||
impl Subscription {
|
||||
async fn hello_world() -> StringStream {
|
||||
let stream = tokio::stream::iter(vec![
|
||||
|
@ -58,8 +58,9 @@ impl Subscription {
|
|||
Box::pin(stream)
|
||||
}
|
||||
}
|
||||
#
|
||||
# fn main () {}
|
||||
```
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
@ -84,8 +85,12 @@ where [`Connection`][Connection] is a `Stream` of values returned by the operati
|
|||
# extern crate juniper_subscriptions;
|
||||
# extern crate serde_json;
|
||||
# extern crate tokio;
|
||||
# use juniper::http::GraphQLRequest;
|
||||
# use juniper::{DefaultScalarValue, EmptyMutation, FieldError, RootNode, SubscriptionCoordinator};
|
||||
# use juniper::{
|
||||
# http::GraphQLRequest,
|
||||
# graphql_object, graphql_subscription,
|
||||
# DefaultScalarValue, EmptyMutation, FieldError,
|
||||
# RootNode, SubscriptionCoordinator,
|
||||
# };
|
||||
# use juniper_subscriptions::Coordinator;
|
||||
# use futures::{Stream, StreamExt};
|
||||
# use std::pin::Pin;
|
||||
|
@ -103,7 +108,7 @@ where [`Connection`][Connection] is a `Stream` of values returned by the operati
|
|||
#
|
||||
# pub struct Query;
|
||||
#
|
||||
# #[juniper::graphql_object(Context = Database)]
|
||||
# #[graphql_object(context = Database)]
|
||||
# impl Query {
|
||||
# fn hello_world() -> &str {
|
||||
# "Hello World!"
|
||||
|
@ -114,7 +119,7 @@ where [`Connection`][Connection] is a `Stream` of values returned by the operati
|
|||
#
|
||||
# type StringStream = Pin<Box<dyn Stream<Item = Result<String, FieldError>> + Send>>;
|
||||
#
|
||||
# #[juniper::graphql_subscription(Context = Database)]
|
||||
# #[graphql_subscription(context = Database)]
|
||||
# impl Subscription {
|
||||
# async fn hello_world() -> StringStream {
|
||||
# let stream =
|
||||
|
@ -132,11 +137,9 @@ async fn run_subscription() {
|
|||
let schema = schema();
|
||||
let coordinator = Coordinator::new(schema);
|
||||
let req: GraphQLRequest<DefaultScalarValue> = serde_json::from_str(
|
||||
r#"
|
||||
{
|
||||
r#"{
|
||||
"query": "subscription { helloWorld }"
|
||||
}
|
||||
"#,
|
||||
}"#,
|
||||
)
|
||||
.unwrap();
|
||||
let ctx = Database::new();
|
||||
|
@ -145,7 +148,7 @@ async fn run_subscription() {
|
|||
println!("{}", serde_json::to_string(&result).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
|
|
|
@ -28,8 +28,12 @@ resolvers, which you will use for the `Query` and `Mutation` roots.
|
|||
```rust
|
||||
# #![allow(unused_variables)]
|
||||
# extern crate juniper;
|
||||
use juniper::{FieldResult, EmptySubscription};
|
||||
|
||||
# use std::fmt::Display;
|
||||
use juniper::{
|
||||
graphql_object, EmptySubscription, FieldResult, GraphQLEnum,
|
||||
GraphQLInputObject, GraphQLObject, ScalarValue,
|
||||
};
|
||||
#
|
||||
# struct DatabasePool;
|
||||
# impl DatabasePool {
|
||||
# fn get_connection(&self) -> FieldResult<DatabasePool> { Ok(DatabasePool) }
|
||||
|
@ -37,15 +41,15 @@ use juniper::{FieldResult, EmptySubscription};
|
|||
# fn insert_human(&self, _human: &NewHuman) -> FieldResult<Human> { Err("")? }
|
||||
# }
|
||||
|
||||
#[derive(juniper::GraphQLEnum)]
|
||||
#[derive(GraphQLEnum)]
|
||||
enum Episode {
|
||||
NewHope,
|
||||
Empire,
|
||||
Jedi,
|
||||
}
|
||||
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
#[graphql(description="A humanoid creature in the Star Wars universe")]
|
||||
#[derive(GraphQLObject)]
|
||||
#[graphql(description = "A humanoid creature in the Star Wars universe")]
|
||||
struct Human {
|
||||
id: String,
|
||||
name: String,
|
||||
|
@ -55,8 +59,8 @@ struct Human {
|
|||
|
||||
// There is also a custom derive for mapping GraphQL input objects.
|
||||
|
||||
#[derive(juniper::GraphQLInputObject)]
|
||||
#[graphql(description="A humanoid creature in the Star Wars universe")]
|
||||
#[derive(GraphQLInputObject)]
|
||||
#[graphql(description = "A humanoid creature in the Star Wars universe")]
|
||||
struct NewHuman {
|
||||
name: String,
|
||||
appears_in: Vec<Episode>,
|
||||
|
@ -78,14 +82,13 @@ impl juniper::Context for Context {}
|
|||
|
||||
struct Query;
|
||||
|
||||
#[juniper::graphql_object(
|
||||
#[graphql_object(
|
||||
// Here we specify the context type for the object.
|
||||
// We need to do this in every type that
|
||||
// needs access to the context.
|
||||
Context = Context,
|
||||
context = Context,
|
||||
)]
|
||||
impl Query {
|
||||
|
||||
fn apiVersion() -> &str {
|
||||
"1.0"
|
||||
}
|
||||
|
@ -109,14 +112,18 @@ impl Query {
|
|||
|
||||
struct Mutation;
|
||||
|
||||
#[juniper::graphql_object(
|
||||
Context = Context,
|
||||
)]
|
||||
impl Mutation {
|
||||
#[graphql_object(
|
||||
context = Context,
|
||||
|
||||
fn createHuman(context: &Context, new_human: NewHuman) -> FieldResult<Human> {
|
||||
let db = context.pool.get_connection()?;
|
||||
let human: Human = db.insert_human(&new_human)?;
|
||||
// If we need to use `ScalarValue` parametrization explicitly somewhere
|
||||
// in the object definition (like here in `FieldResult`), we should
|
||||
// declare an explicit type parameter for that, and specify it.
|
||||
scalar = S,
|
||||
)]
|
||||
impl<S: ScalarValue + Display> Mutation {
|
||||
fn createHuman(context: &Context, new_human: NewHuman) -> FieldResult<Human, S> {
|
||||
let db = context.pool.get_connection().map_err(|e| e.map_scalar_value())?;
|
||||
let human: Human = db.insert_human(&new_human).map_err(|e| e.map_scalar_value())?;
|
||||
Ok(human)
|
||||
}
|
||||
}
|
||||
|
@ -124,7 +131,7 @@ impl Mutation {
|
|||
// A root schema consists of a query, a mutation, and a subscription.
|
||||
// Request queries can be executed against a RootNode.
|
||||
type Schema = juniper::RootNode<'static, Query, Mutation, EmptySubscription<Context>>;
|
||||
|
||||
#
|
||||
# fn main() {
|
||||
# let _ = Schema::new(Query, Mutation{}, EmptySubscription::new());
|
||||
# }
|
||||
|
@ -143,10 +150,12 @@ You can invoke `juniper::execute` directly to run a GraphQL query:
|
|||
```rust
|
||||
# // Only needed due to 2018 edition because the macro is not accessible.
|
||||
# #[macro_use] extern crate juniper;
|
||||
use juniper::{FieldResult, Variables, EmptyMutation, EmptySubscription};
|
||||
use juniper::{
|
||||
graphql_object, EmptyMutation, EmptySubscription, FieldResult,
|
||||
GraphQLEnum, Variables,
|
||||
};
|
||||
|
||||
|
||||
#[derive(juniper::GraphQLEnum, Clone, Copy)]
|
||||
#[derive(GraphQLEnum, Clone, Copy)]
|
||||
enum Episode {
|
||||
NewHope,
|
||||
Empire,
|
||||
|
@ -160,16 +169,13 @@ impl juniper::Context for Ctx {}
|
|||
|
||||
struct Query;
|
||||
|
||||
#[juniper::graphql_object(
|
||||
Context = Ctx,
|
||||
)]
|
||||
#[graphql_object(context = Ctx)]
|
||||
impl Query {
|
||||
fn favoriteEpisode(context: &Ctx) -> FieldResult<Episode> {
|
||||
Ok(context.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// A root schema consists of a query, a mutation, and a subscription.
|
||||
// Request queries can be executed against a RootNode.
|
||||
type Schema = juniper::RootNode<'static, Query, EmptyMutation<Ctx>, EmptySubscription<Ctx>>;
|
||||
|
|
|
@ -24,18 +24,18 @@ object in Juniper, most commonly using the `graphql_object` proc macro:
|
|||
```rust
|
||||
# #![allow(unused_variables)]
|
||||
# extern crate juniper;
|
||||
# use juniper::FieldResult;
|
||||
# #[derive(juniper::GraphQLObject)] struct User { name: String }
|
||||
# use juniper::{graphql_object, FieldResult, GraphQLObject};
|
||||
# #[derive(GraphQLObject)] struct User { name: String }
|
||||
struct Root;
|
||||
|
||||
#[juniper::graphql_object]
|
||||
#[graphql_object]
|
||||
impl Root {
|
||||
fn userWithUsername(username: String) -> FieldResult<Option<User>> {
|
||||
// Look up user in database...
|
||||
# unimplemented!()
|
||||
# unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
|
@ -47,18 +47,18 @@ that performs some mutating side-effect such as updating a database.
|
|||
```rust
|
||||
# #![allow(unused_variables)]
|
||||
# extern crate juniper;
|
||||
# use juniper::FieldResult;
|
||||
# #[derive(juniper::GraphQLObject)] struct User { name: String }
|
||||
# use juniper::{graphql_object, FieldResult, GraphQLObject};
|
||||
# #[derive(GraphQLObject)] struct User { name: String }
|
||||
struct Mutations;
|
||||
|
||||
#[juniper::graphql_object]
|
||||
#[graphql_object]
|
||||
impl Mutations {
|
||||
fn signUpUser(name: String, email: String) -> FieldResult<User> {
|
||||
// Validate inputs and save user in database...
|
||||
# unimplemented!()
|
||||
# unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
|
@ -68,11 +68,13 @@ Many tools in the GraphQL ecosystem require the schema to be defined in the [Gra
|
|||
|
||||
```rust
|
||||
# extern crate juniper;
|
||||
use juniper::{FieldResult, EmptyMutation, EmptySubscription, RootNode};
|
||||
use juniper::{
|
||||
graphql_object, EmptyMutation, EmptySubscription, FieldResult, RootNode,
|
||||
};
|
||||
|
||||
struct Query;
|
||||
|
||||
#[juniper::graphql_object]
|
||||
#[graphql_object]
|
||||
impl Query {
|
||||
fn hello(&self) -> FieldResult<&str> {
|
||||
Ok("hello world")
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
If you've got a struct that can't be mapped directly to GraphQL, that contains
|
||||
computed fields or circular structures, you have to use a more powerful tool:
|
||||
the `object` procedural macro. This macro lets you define GraphQL object
|
||||
the `#[graphql_object]` procedural macro. This macro lets you define GraphQL object
|
||||
fields in a Rust `impl` block for a type. Note that only GraphQL fields
|
||||
can be specified in this `impl` block. If you want to define normal methods on the struct,
|
||||
you have to do so in a separate, normal `impl` block. Continuing with the
|
||||
|
@ -12,13 +12,14 @@ macro:
|
|||
```rust
|
||||
# #![allow(dead_code)]
|
||||
# extern crate juniper;
|
||||
# use juniper::graphql_object;
|
||||
#
|
||||
struct Person {
|
||||
name: String,
|
||||
age: i32,
|
||||
}
|
||||
|
||||
#[juniper::graphql_object]
|
||||
#[graphql_object]
|
||||
impl Person {
|
||||
fn name(&self) -> &str {
|
||||
self.name.as_str()
|
||||
|
@ -36,7 +37,7 @@ impl Person {
|
|||
// [...]
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
|
@ -46,7 +47,9 @@ field resolver. With this syntax, fields can also take arguments:
|
|||
|
||||
```rust
|
||||
# extern crate juniper;
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
# use juniper::{graphql_object, GraphQLObject};
|
||||
#
|
||||
#[derive(GraphQLObject)]
|
||||
struct Person {
|
||||
name: String,
|
||||
age: i32,
|
||||
|
@ -56,14 +59,14 @@ struct House {
|
|||
inhabitants: Vec<Person>,
|
||||
}
|
||||
|
||||
#[juniper::graphql_object]
|
||||
#[graphql_object]
|
||||
impl House {
|
||||
// Creates the field inhabitantWithName(name), returning a nullable person
|
||||
fn inhabitant_with_name(&self, name: String) -> Option<&Person> {
|
||||
self.inhabitants.iter().find(|p| p.name == name)
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
|
@ -79,20 +82,20 @@ the field. Also, the type name can be changed with an alias:
|
|||
|
||||
```rust
|
||||
# extern crate juniper;
|
||||
|
||||
struct Person {
|
||||
}
|
||||
# use juniper::graphql_object;
|
||||
#
|
||||
struct Person;
|
||||
|
||||
/// Doc comments are used as descriptions for GraphQL.
|
||||
#[juniper::graphql_object(
|
||||
#[graphql_object(
|
||||
// With this attribute you can change the public GraphQL name of the type.
|
||||
name = "PersonObject",
|
||||
|
||||
// You can also specify a description here, which will overwrite
|
||||
// a doc comment description.
|
||||
description = "...",
|
||||
)]
|
||||
impl Person {
|
||||
|
||||
/// A doc comment on the field will also be used for GraphQL.
|
||||
#[graphql(
|
||||
// Or provide a description here.
|
||||
|
@ -103,9 +106,7 @@ impl Person {
|
|||
}
|
||||
|
||||
// Fields can also be renamed if required.
|
||||
#[graphql(
|
||||
name = "myCustomFieldName",
|
||||
)]
|
||||
#[graphql(name = "myCustomFieldName")]
|
||||
fn renamed_field() -> bool {
|
||||
true
|
||||
}
|
||||
|
@ -122,7 +123,7 @@ impl Person {
|
|||
true
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
|
@ -137,10 +138,11 @@ This will become better once the [Rust RFC 2565](https://github.com/rust-lang/ru
|
|||
|
||||
```rust
|
||||
# extern crate juniper;
|
||||
|
||||
# use juniper::graphql_object;
|
||||
#
|
||||
struct Person {}
|
||||
|
||||
#[juniper::graphql_object]
|
||||
#[graphql_object]
|
||||
impl Person {
|
||||
#[graphql(
|
||||
arguments(
|
||||
|
@ -160,7 +162,7 @@ impl Person {
|
|||
format!("{} {}", arg1, arg2)
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
|
@ -172,5 +174,5 @@ GraphQL fields expose more features than Rust's standard method syntax gives us:
|
|||
* Per-argument default values
|
||||
* Per-argument descriptions
|
||||
|
||||
These, and more features, are described more thorougly in [the reference
|
||||
These, and more features, are described more thoroughly in [the reference
|
||||
documentation](https://docs.rs/juniper/latest/juniper/macro.object.html).
|
||||
|
|
|
@ -10,12 +10,13 @@ chapter.
|
|||
|
||||
```rust
|
||||
# extern crate juniper;
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
# use juniper::GraphQLObject;
|
||||
#[derive(GraphQLObject)]
|
||||
struct Person {
|
||||
name: String,
|
||||
age: i32,
|
||||
}
|
||||
|
||||
#
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
|
@ -33,7 +34,8 @@ descriptions:
|
|||
|
||||
```rust
|
||||
# extern crate juniper;
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
# use juniper::GraphQLObject;
|
||||
#[derive(GraphQLObject)]
|
||||
/// Information about a person
|
||||
struct Person {
|
||||
/// The person's full name, including both first and last names
|
||||
|
@ -41,7 +43,7 @@ struct Person {
|
|||
/// The person's age in years, rounded down
|
||||
age: i32,
|
||||
}
|
||||
|
||||
#
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
|
@ -52,15 +54,16 @@ via the `graphql` attribute. The following example is equivalent to the above:
|
|||
|
||||
```rust
|
||||
# extern crate juniper;
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
#[graphql(description="Information about a person")]
|
||||
# use juniper::GraphQLObject;
|
||||
#[derive(GraphQLObject)]
|
||||
#[graphql(description = "Information about a person")]
|
||||
struct Person {
|
||||
#[graphql(description="The person's full name, including both first and last names")]
|
||||
#[graphql(description = "The person's full name, including both first and last names")]
|
||||
name: String,
|
||||
#[graphql(description="The person's age in years, rounded down")]
|
||||
#[graphql(description = "The person's age in years, rounded down")]
|
||||
age: i32,
|
||||
}
|
||||
|
||||
#
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
|
@ -70,17 +73,18 @@ documentation to differ:
|
|||
|
||||
```rust
|
||||
# extern crate juniper;
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
#[graphql(description="This description shows up in GraphQL")]
|
||||
# use juniper::GraphQLObject;
|
||||
#[derive(GraphQLObject)]
|
||||
#[graphql(description = "This description shows up in GraphQL")]
|
||||
/// This description shows up in RustDoc
|
||||
struct Person {
|
||||
#[graphql(description="This description shows up in GraphQL")]
|
||||
#[graphql(description = "This description shows up in GraphQL")]
|
||||
/// This description shows up in RustDoc
|
||||
name: String,
|
||||
/// This description shows up in both RustDoc and GraphQL
|
||||
age: i32,
|
||||
}
|
||||
|
||||
#
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
|
@ -100,18 +104,19 @@ Let's see what that means for building relationships between objects:
|
|||
|
||||
```rust
|
||||
# extern crate juniper;
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
# use juniper::GraphQLObject;
|
||||
#[derive(GraphQLObject)]
|
||||
struct Person {
|
||||
name: String,
|
||||
age: i32,
|
||||
}
|
||||
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
#[derive(GraphQLObject)]
|
||||
struct House {
|
||||
address: Option<String>, // Converted into String (nullable)
|
||||
inhabitants: Vec<Person>, // Converted into [Person!]!
|
||||
}
|
||||
|
||||
#
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
|
@ -126,12 +131,13 @@ convention into GraphQL's `camelCase` convention:
|
|||
|
||||
```rust
|
||||
# extern crate juniper;
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
# use juniper::GraphQLObject;
|
||||
#[derive(GraphQLObject)]
|
||||
struct Person {
|
||||
first_name: String, // Would be exposed as firstName in the GraphQL schema
|
||||
last_name: String, // Exposed as lastName
|
||||
}
|
||||
|
||||
#
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
|
@ -140,14 +146,15 @@ fields:
|
|||
|
||||
```rust
|
||||
# extern crate juniper;
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
# use juniper::GraphQLObject;
|
||||
#[derive(GraphQLObject)]
|
||||
struct Person {
|
||||
name: String,
|
||||
age: i32,
|
||||
#[graphql(name="websiteURL")]
|
||||
#[graphql(name = "websiteURL")]
|
||||
website_url: Option<String>, // Now exposed as websiteURL in the schema
|
||||
}
|
||||
|
||||
#
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
|
@ -158,14 +165,15 @@ attribute:
|
|||
|
||||
```rust
|
||||
# extern crate juniper;
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
# use juniper::GraphQLObject;
|
||||
#[derive(GraphQLObject)]
|
||||
struct Person {
|
||||
name: String,
|
||||
age: i32,
|
||||
#[graphql(deprecated = "Please use the name field instead")]
|
||||
first_name: String,
|
||||
}
|
||||
|
||||
#
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
|
@ -179,7 +187,8 @@ By default all fields in a `GraphQLObject` are included in the generated GraphQL
|
|||
|
||||
```rust
|
||||
# extern crate juniper;
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
# use juniper::GraphQLObject;
|
||||
#[derive(GraphQLObject)]
|
||||
struct Person {
|
||||
name: String,
|
||||
age: i32,
|
||||
|
@ -187,6 +196,6 @@ struct Person {
|
|||
# #[allow(dead_code)]
|
||||
password_hash: String, // This cannot be queried or modified from GraphQL
|
||||
}
|
||||
|
||||
#
|
||||
# fn main() {}
|
||||
```
|
||||
|
|
|
@ -28,13 +28,13 @@ use std::{
|
|||
fs::{File},
|
||||
io::{Read},
|
||||
};
|
||||
use juniper::FieldResult;
|
||||
use juniper::{graphql_object, FieldResult};
|
||||
|
||||
struct Example {
|
||||
filename: PathBuf,
|
||||
}
|
||||
|
||||
#[juniper::graphql_object]
|
||||
#[graphql_object]
|
||||
impl Example {
|
||||
fn contents() -> FieldResult<String> {
|
||||
let mut file = File::open(&self.filename)?;
|
||||
|
@ -53,7 +53,7 @@ impl Example {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
|
@ -137,14 +137,16 @@ to clients. This can be accomplished by implementing [`IntoFieldError`](https://
|
|||
|
||||
```rust
|
||||
# #[macro_use] extern crate juniper;
|
||||
# use juniper::{graphql_object, FieldError, IntoFieldError, ScalarValue};
|
||||
#
|
||||
enum CustomError {
|
||||
WhateverNotSet,
|
||||
}
|
||||
|
||||
impl juniper::IntoFieldError for CustomError {
|
||||
fn into_field_error(self) -> juniper::FieldError {
|
||||
impl<S: ScalarValue> IntoFieldError<S> for CustomError {
|
||||
fn into_field_error(self) -> FieldError<S> {
|
||||
match self {
|
||||
CustomError::WhateverNotSet => juniper::FieldError::new(
|
||||
CustomError::WhateverNotSet => FieldError::new(
|
||||
"Whatever does not exist",
|
||||
graphql_value!({
|
||||
"type": "NO_WHATEVER"
|
||||
|
@ -158,7 +160,7 @@ struct Example {
|
|||
whatever: Option<bool>,
|
||||
}
|
||||
|
||||
#[juniper::graphql_object]
|
||||
#[graphql_object]
|
||||
impl Example {
|
||||
fn whatever() -> Result<bool, CustomError> {
|
||||
if let Some(value) = self.whatever {
|
||||
|
@ -167,21 +169,21 @@ impl Example {
|
|||
Err(CustomError::WhateverNotSet)
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
The specified structured error information is included in the [`extensions`](https://facebook.github.io/graphql/June2018/#sec-Errors) key:
|
||||
|
||||
```js
|
||||
```json
|
||||
{
|
||||
"errors": [
|
||||
"errors": [{
|
||||
"message": "Whatever does not exist",
|
||||
"locations": [{ "line": 2, "column": 4 }]),
|
||||
"locations": [{"line": 2, "column": 4}],
|
||||
"extensions": {
|
||||
"type": "NO_WHATEVER"
|
||||
}
|
||||
]
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -211,24 +213,26 @@ possible to return a unique string identifier and have the client present a loca
|
|||
|
||||
```rust
|
||||
# extern crate juniper;
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
# use juniper::{graphql_object, GraphQLObject, GraphQLUnion};
|
||||
#
|
||||
#[derive(GraphQLObject)]
|
||||
pub struct Item {
|
||||
name: String,
|
||||
quantity: i32,
|
||||
}
|
||||
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
#[derive(GraphQLObject)]
|
||||
pub struct ValidationError {
|
||||
field: String,
|
||||
message: String,
|
||||
}
|
||||
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
#[derive(GraphQLObject)]
|
||||
pub struct ValidationErrors {
|
||||
errors: Vec<ValidationError>,
|
||||
}
|
||||
|
||||
#[derive(juniper::GraphQLUnion)]
|
||||
#[derive(GraphQLUnion)]
|
||||
pub enum GraphQLResult {
|
||||
Ok(Item),
|
||||
Err(ValidationErrors),
|
||||
|
@ -236,7 +240,7 @@ pub enum GraphQLResult {
|
|||
|
||||
pub struct Mutation;
|
||||
|
||||
#[juniper::graphql_object]
|
||||
#[graphql_object]
|
||||
impl Mutation {
|
||||
fn addItem(&self, name: String, quantity: i32) -> GraphQLResult {
|
||||
let mut errors = Vec::new();
|
||||
|
@ -262,7 +266,7 @@ impl Mutation {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
|
@ -308,19 +312,21 @@ contains only fields provided by the function.
|
|||
|
||||
```rust
|
||||
# extern crate juniper;
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
# use juniper::{graphql_object, GraphQLObject, GraphQLUnion};
|
||||
#
|
||||
#[derive(GraphQLObject)]
|
||||
pub struct Item {
|
||||
name: String,
|
||||
quantity: i32,
|
||||
}
|
||||
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
#[derive(GraphQLObject)]
|
||||
pub struct ValidationError {
|
||||
name: Option<String>,
|
||||
quantity: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(juniper::GraphQLUnion)]
|
||||
#[derive(GraphQLUnion)]
|
||||
pub enum GraphQLResult {
|
||||
Ok(Item),
|
||||
Err(ValidationError),
|
||||
|
@ -328,7 +334,7 @@ pub enum GraphQLResult {
|
|||
|
||||
pub struct Mutation;
|
||||
|
||||
#[juniper::graphql_object]
|
||||
#[graphql_object]
|
||||
impl Mutation {
|
||||
fn addItem(&self, name: String, quantity: i32) -> GraphQLResult {
|
||||
let mut error = ValidationError {
|
||||
|
@ -351,7 +357,7 @@ impl Mutation {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
|
@ -385,22 +391,23 @@ and would generate errors. Since it is not common for the database to
|
|||
fail, the corresponding error is returned as a critical error:
|
||||
|
||||
```rust
|
||||
# // Only needed due to 2018 edition because the macro is not accessible.
|
||||
# #[macro_use] extern crate juniper;
|
||||
# extern crate juniper;
|
||||
#
|
||||
use juniper::{graphql_object, graphql_value, FieldError, GraphQLObject, GraphQLUnion, ScalarValue};
|
||||
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
#[derive(GraphQLObject)]
|
||||
pub struct Item {
|
||||
name: String,
|
||||
quantity: i32,
|
||||
}
|
||||
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
#[derive(GraphQLObject)]
|
||||
pub struct ValidationErrorItem {
|
||||
name: Option<String>,
|
||||
quantity: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(juniper::GraphQLUnion)]
|
||||
#[derive(GraphQLUnion)]
|
||||
pub enum GraphQLResult {
|
||||
Ok(Item),
|
||||
Err(ValidationErrorItem),
|
||||
|
@ -410,10 +417,10 @@ pub enum ApiError {
|
|||
Database,
|
||||
}
|
||||
|
||||
impl juniper::IntoFieldError for ApiError {
|
||||
fn into_field_error(self) -> juniper::FieldError {
|
||||
impl<S: ScalarValue> juniper::IntoFieldError<S> for ApiError {
|
||||
fn into_field_error(self) -> FieldError<S> {
|
||||
match self {
|
||||
ApiError::Database => juniper::FieldError::new(
|
||||
ApiError::Database => FieldError::new(
|
||||
"Internal database error",
|
||||
graphql_value!({
|
||||
"type": "DATABASE"
|
||||
|
@ -425,7 +432,7 @@ impl juniper::IntoFieldError for ApiError {
|
|||
|
||||
pub struct Mutation;
|
||||
|
||||
#[juniper::graphql_object]
|
||||
#[graphql_object]
|
||||
impl Mutation {
|
||||
fn addItem(&self, name: String, quantity: i32) -> Result<GraphQLResult, ApiError> {
|
||||
let mut error = ValidationErrorItem {
|
||||
|
@ -448,7 +455,7 @@ impl Mutation {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ resolvers. Let's say that we have a simple user database in a `HashMap`:
|
|||
```rust
|
||||
# #![allow(dead_code)]
|
||||
# use std::collections::HashMap;
|
||||
|
||||
#
|
||||
struct Database {
|
||||
users: HashMap<i32, User>,
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ struct User {
|
|||
name: String,
|
||||
friend_ids: Vec<i32>,
|
||||
}
|
||||
|
||||
#
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
|
@ -38,9 +38,10 @@ type as the specified `Context` for the type:
|
|||
|
||||
|
||||
```rust
|
||||
# extern crate juniper;
|
||||
# use std::collections::HashMap;
|
||||
extern crate juniper;
|
||||
|
||||
# use juniper::graphql_object;
|
||||
#
|
||||
// This struct represents our context.
|
||||
struct Database {
|
||||
users: HashMap<i32, User>,
|
||||
|
@ -55,11 +56,8 @@ struct User {
|
|||
friend_ids: Vec<i32>,
|
||||
}
|
||||
|
||||
|
||||
// Assign Database as the context type for User
|
||||
#[juniper::graphql_object(
|
||||
Context = Database,
|
||||
)]
|
||||
#[graphql_object(context = Database)]
|
||||
impl User {
|
||||
// 3. Inject the context by specifying an argument
|
||||
// with the context type.
|
||||
|
@ -82,7 +80,7 @@ impl User {
|
|||
self.id
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# fn main() { }
|
||||
```
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ use actix_cors::Cors;
|
|||
use actix_web::{middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer};
|
||||
|
||||
use juniper::{
|
||||
graphql_object, graphql_subscription,
|
||||
tests::fixtures::starwars::schema::{Character as _, Database, Query},
|
||||
DefaultScalarValue, EmptyMutation, FieldError, RootNode,
|
||||
};
|
||||
|
@ -37,7 +38,7 @@ struct RandomHuman {
|
|||
}
|
||||
|
||||
// TODO: remove this when async interfaces are merged
|
||||
#[juniper::graphql_object(Context = Database)]
|
||||
#[graphql_object(context = Database)]
|
||||
impl RandomHuman {
|
||||
fn id(&self) -> &str {
|
||||
&self.id
|
||||
|
@ -51,7 +52,7 @@ impl RandomHuman {
|
|||
type RandomHumanStream =
|
||||
Pin<Box<dyn futures::Stream<Item = Result<RandomHuman, FieldError>> + Send>>;
|
||||
|
||||
#[juniper::graphql_subscription(Context = Database)]
|
||||
#[graphql_subscription(context = Database)]
|
||||
impl Subscription {
|
||||
#[graphql(
|
||||
description = "A random humanoid creature in the Star Wars universe every 3 seconds. Second result will be an error."
|
||||
|
|
|
@ -4,8 +4,8 @@ use std::pin::Pin;
|
|||
|
||||
use futures::{Stream, StreamExt};
|
||||
use juniper::{
|
||||
http::GraphQLRequest, DefaultScalarValue, EmptyMutation, FieldError, RootNode,
|
||||
SubscriptionCoordinator,
|
||||
graphql_object, graphql_subscription, http::GraphQLRequest, DefaultScalarValue, EmptyMutation,
|
||||
FieldError, RootNode, SubscriptionCoordinator,
|
||||
};
|
||||
use juniper_subscriptions::Coordinator;
|
||||
|
||||
|
@ -22,7 +22,7 @@ impl Database {
|
|||
|
||||
pub struct Query;
|
||||
|
||||
#[juniper::graphql_object(Context = Database)]
|
||||
#[graphql_object(context = Database)]
|
||||
impl Query {
|
||||
fn hello_world() -> &str {
|
||||
"Hello World!"
|
||||
|
@ -33,7 +33,7 @@ pub struct Subscription;
|
|||
|
||||
type StringStream = Pin<Box<dyn Stream<Item = Result<String, FieldError>> + Send>>;
|
||||
|
||||
#[juniper::graphql_subscription(Context = Database)]
|
||||
#[graphql_subscription(context = Database)]
|
||||
impl Subscription {
|
||||
async fn hello_world() -> StringStream {
|
||||
let stream =
|
||||
|
|
|
@ -23,7 +23,7 @@ struct User {
|
|||
name: String,
|
||||
}
|
||||
|
||||
#[graphql_object(Context = Context)]
|
||||
#[graphql_object(context = Context)]
|
||||
impl User {
|
||||
fn id(&self) -> i32 {
|
||||
self.id
|
||||
|
@ -45,7 +45,7 @@ impl User {
|
|||
#[derive(Clone, Copy, Debug)]
|
||||
struct Query;
|
||||
|
||||
#[graphql_object(Context = Context)]
|
||||
#[graphql_object(context = Context)]
|
||||
impl Query {
|
||||
async fn users() -> Vec<User> {
|
||||
vec![User {
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
use std::{env, pin::Pin, sync::Arc, time::Duration};
|
||||
|
||||
use futures::{FutureExt as _, Stream};
|
||||
use juniper::{DefaultScalarValue, EmptyMutation, FieldError, RootNode};
|
||||
use juniper::{
|
||||
graphql_object, graphql_subscription, DefaultScalarValue, EmptyMutation, FieldError,
|
||||
GraphQLEnum, RootNode,
|
||||
};
|
||||
use juniper_graphql_ws::ConnectionConfig;
|
||||
use juniper_warp::{playground_filter, subscriptions::serve_graphql_ws};
|
||||
use warp::{http::Response, Filter};
|
||||
|
@ -13,7 +16,7 @@ struct Context {}
|
|||
|
||||
impl juniper::Context for Context {}
|
||||
|
||||
#[derive(Clone, Copy, juniper::GraphQLEnum)]
|
||||
#[derive(Clone, Copy, GraphQLEnum)]
|
||||
enum UserKind {
|
||||
Admin,
|
||||
User,
|
||||
|
@ -27,7 +30,7 @@ struct User {
|
|||
}
|
||||
|
||||
// Field resolvers implementation
|
||||
#[juniper::graphql_object(Context = Context)]
|
||||
#[graphql_object(context = Context)]
|
||||
impl User {
|
||||
fn id(&self) -> i32 {
|
||||
self.id
|
||||
|
@ -87,7 +90,7 @@ impl User {
|
|||
|
||||
struct Query;
|
||||
|
||||
#[juniper::graphql_object(Context = Context)]
|
||||
#[graphql_object(context = Context)]
|
||||
impl Query {
|
||||
async fn users(id: i32) -> Vec<User> {
|
||||
vec![User {
|
||||
|
@ -102,7 +105,7 @@ type UsersStream = Pin<Box<dyn Stream<Item = Result<User, FieldError>> + Send>>;
|
|||
|
||||
struct Subscription;
|
||||
|
||||
#[juniper::graphql_subscription(Context = Context)]
|
||||
#[graphql_subscription(context = Context)]
|
||||
impl Subscription {
|
||||
async fn users() -> UsersStream {
|
||||
let mut counter = 0;
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#[cfg(test)]
|
||||
use juniper::{graphql_value, EmptyMutation, EmptySubscription, GraphQLError, RootNode, Value};
|
||||
use juniper::{
|
||||
graphql_object, graphql_value, EmptyMutation, EmptySubscription, GraphQLEnum, GraphQLError,
|
||||
RootNode, Value,
|
||||
};
|
||||
|
||||
#[derive(juniper::GraphQLEnum)]
|
||||
#[derive(GraphQLEnum)]
|
||||
enum UserKind {
|
||||
Admin,
|
||||
User,
|
||||
|
@ -15,7 +17,7 @@ struct User {
|
|||
kind: UserKind,
|
||||
}
|
||||
|
||||
#[juniper::graphql_object]
|
||||
#[graphql_object]
|
||||
impl User {
|
||||
async fn id(&self) -> i32 {
|
||||
self.id
|
||||
|
@ -47,7 +49,7 @@ impl User {
|
|||
|
||||
struct Query;
|
||||
|
||||
#[juniper::graphql_object]
|
||||
#[graphql_object]
|
||||
impl Query {
|
||||
fn field_sync(&self) -> &'static str {
|
||||
"field_sync"
|
||||
|
|
|
@ -1,16 +1,29 @@
|
|||
error[E0277]: the trait bound `Obj: IsInputType<DefaultScalarValue>` is not satisfied
|
||||
error[E0277]: the trait bound `Obj: IsInputType<__S>` is not satisfied
|
||||
--> $DIR/impl_argument_no_object.rs:8:1
|
||||
|
|
||||
8 | #[juniper::graphql_object]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IsInputType<DefaultScalarValue>` is not implemented for `Obj`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IsInputType<__S>` is not implemented for `Obj`
|
||||
|
|
||||
= note: required by `juniper::marker::IsInputType::mark`
|
||||
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0277]: the trait bound `Obj: FromInputValue` is not satisfied
|
||||
error[E0277]: the trait bound `Obj: FromInputValue<__S>` is not satisfied
|
||||
--> $DIR/impl_argument_no_object.rs:8:1
|
||||
|
|
||||
8 | #[juniper::graphql_object]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromInputValue` is not implemented for `Obj`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromInputValue<__S>` is not implemented for `Obj`
|
||||
|
|
||||
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0277]: the trait bound `Obj: FromInputValue` is not satisfied
|
||||
--> $DIR/impl_argument_no_object.rs:8:1
|
||||
|
|
||||
8 | #[juniper::graphql_object]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromInputValue` is not implemented for `Obj`
|
||||
|
|
||||
::: $WORKSPACE/juniper/src/ast.rs
|
||||
|
|
||||
| pub trait FromInputValue<S = DefaultScalarValue>: Sized {
|
||||
| ------------------------------------------------------- required by this bound in `FromInputValue`
|
||||
|
|
||||
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
#[cfg(test)]
|
||||
use fnv::FnvHashMap;
|
||||
|
||||
#[cfg(test)]
|
||||
use juniper::{self, DefaultScalarValue, FromInputValue, GraphQLType, InputValue, ToInputValue};
|
||||
use juniper::{
|
||||
DefaultScalarValue, FromInputValue, GraphQLEnum, GraphQLType, InputValue, Registry,
|
||||
ToInputValue,
|
||||
};
|
||||
|
||||
pub struct CustomContext {}
|
||||
|
||||
impl juniper::Context for CustomContext {}
|
||||
|
||||
#[derive(juniper::GraphQLEnum, Debug, PartialEq)]
|
||||
#[derive(GraphQLEnum, Debug, PartialEq)]
|
||||
#[graphql(name = "Some", description = "enum descr")]
|
||||
enum SomeEnum {
|
||||
Regular,
|
||||
|
@ -24,7 +24,7 @@ enum NoRenameEnum {
|
|||
}
|
||||
|
||||
/// Enum doc.
|
||||
#[derive(juniper::GraphQLEnum)]
|
||||
#[derive(GraphQLEnum)]
|
||||
enum DocEnum {
|
||||
/// Variant doc.
|
||||
Foo,
|
||||
|
@ -34,7 +34,7 @@ enum DocEnum {
|
|||
/// Doc 2.
|
||||
///
|
||||
/// Doc 4.
|
||||
#[derive(juniper::GraphQLEnum, Debug, PartialEq)]
|
||||
#[derive(GraphQLEnum, Debug, PartialEq)]
|
||||
enum MultiDocEnum {
|
||||
/// Variant 1.
|
||||
/// Variant 2.
|
||||
|
@ -42,7 +42,7 @@ enum MultiDocEnum {
|
|||
}
|
||||
|
||||
/// This is not used as the description.
|
||||
#[derive(juniper::GraphQLEnum, Debug, PartialEq)]
|
||||
#[derive(GraphQLEnum, Debug, PartialEq)]
|
||||
#[graphql(description = "enum override")]
|
||||
enum OverrideDocEnum {
|
||||
/// This is not used as the description.
|
||||
|
@ -50,7 +50,7 @@ enum OverrideDocEnum {
|
|||
Foo,
|
||||
}
|
||||
|
||||
#[derive(juniper::GraphQLEnum)]
|
||||
#[derive(GraphQLEnum)]
|
||||
#[graphql(context = CustomContext, noasync)]
|
||||
enum ContextEnum {
|
||||
A,
|
||||
|
@ -65,7 +65,7 @@ fn test_derived_enum() {
|
|||
);
|
||||
|
||||
// Ensure validity of meta info.
|
||||
let mut registry: juniper::Registry = juniper::Registry::new(FnvHashMap::default());
|
||||
let mut registry: Registry = Registry::new(FnvHashMap::default());
|
||||
let meta = SomeEnum::meta(&(), &mut registry);
|
||||
|
||||
assert_eq!(meta.name(), Some("Some"));
|
||||
|
@ -100,14 +100,14 @@ fn test_derived_enum() {
|
|||
|
||||
#[test]
|
||||
fn test_doc_comment() {
|
||||
let mut registry: juniper::Registry = juniper::Registry::new(FnvHashMap::default());
|
||||
let mut registry: Registry = Registry::new(FnvHashMap::default());
|
||||
let meta = DocEnum::meta(&(), &mut registry);
|
||||
assert_eq!(meta.description(), Some(&"Enum doc.".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multi_doc_comment() {
|
||||
let mut registry: juniper::Registry = juniper::Registry::new(FnvHashMap::default());
|
||||
let mut registry: Registry = Registry::new(FnvHashMap::default());
|
||||
let meta = MultiDocEnum::meta(&(), &mut registry);
|
||||
assert_eq!(
|
||||
meta.description(),
|
||||
|
@ -117,7 +117,7 @@ fn test_multi_doc_comment() {
|
|||
|
||||
#[test]
|
||||
fn test_doc_comment_override() {
|
||||
let mut registry: juniper::Registry = juniper::Registry::new(FnvHashMap::default());
|
||||
let mut registry: Registry = Registry::new(FnvHashMap::default());
|
||||
let meta = OverrideDocEnum::meta(&(), &mut registry);
|
||||
assert_eq!(meta.description(), Some(&"enum override".to_string()));
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
use fnv::FnvHashMap;
|
||||
|
||||
use juniper::{
|
||||
marker, DefaultScalarValue, FromInputValue, GraphQLInputObject, GraphQLType, GraphQLValue,
|
||||
InputValue, ToInputValue,
|
||||
InputValue, Registry, ToInputValue,
|
||||
};
|
||||
|
||||
#[derive(GraphQLInputObject, Debug, PartialEq)]
|
||||
|
@ -74,7 +73,7 @@ impl<'a> GraphQLType<DefaultScalarValue> for &'a Fake {
|
|||
fn name(_: &()) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
fn meta<'r>(_: &(), registry: &mut juniper::Registry<'r>) -> juniper::meta::MetaType<'r>
|
||||
fn meta<'r>(_: &(), registry: &mut Registry<'r>) -> juniper::meta::MetaType<'r>
|
||||
where
|
||||
DefaultScalarValue: 'r,
|
||||
{
|
||||
|
@ -113,7 +112,7 @@ fn test_derived_input_object() {
|
|||
);
|
||||
|
||||
// Validate meta info.
|
||||
let mut registry: juniper::Registry = juniper::Registry::new(FnvHashMap::default());
|
||||
let mut registry: Registry = Registry::new(FnvHashMap::default());
|
||||
let meta = Input::meta(&(), &mut registry);
|
||||
assert_eq!(meta.name(), Some("MyInput"));
|
||||
assert_eq!(meta.description(), Some(&"input descr".to_string()));
|
||||
|
@ -172,14 +171,14 @@ fn test_derived_input_object() {
|
|||
|
||||
#[test]
|
||||
fn test_doc_comment() {
|
||||
let mut registry: juniper::Registry = juniper::Registry::new(FnvHashMap::default());
|
||||
let mut registry: Registry = Registry::new(FnvHashMap::default());
|
||||
let meta = DocComment::meta(&(), &mut registry);
|
||||
assert_eq!(meta.description(), Some(&"Object comment.".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multi_doc_comment() {
|
||||
let mut registry: juniper::Registry = juniper::Registry::new(FnvHashMap::default());
|
||||
let mut registry: Registry = Registry::new(FnvHashMap::default());
|
||||
let meta = MultiDocComment::meta(&(), &mut registry);
|
||||
assert_eq!(
|
||||
meta.description(),
|
||||
|
@ -189,7 +188,7 @@ fn test_multi_doc_comment() {
|
|||
|
||||
#[test]
|
||||
fn test_doc_comment_override() {
|
||||
let mut registry: juniper::Registry = juniper::Registry::new(FnvHashMap::default());
|
||||
let mut registry: Registry = Registry::new(FnvHashMap::default());
|
||||
let meta = OverrideDocComment::meta(&(), &mut registry);
|
||||
assert_eq!(meta.description(), Some(&"obj override".to_string()));
|
||||
}
|
||||
|
|
|
@ -1,20 +1,11 @@
|
|||
#[cfg(test)]
|
||||
use fnv::FnvHashMap;
|
||||
#[cfg(test)]
|
||||
use juniper::Object;
|
||||
use juniper::{DefaultScalarValue, GraphQLObject};
|
||||
|
||||
#[cfg(test)]
|
||||
use juniper::{
|
||||
self, execute, EmptyMutation, EmptySubscription, GraphQLType, RootNode, Value, Variables,
|
||||
execute, graphql_object, DefaultScalarValue, EmptyMutation, EmptySubscription, GraphQLObject,
|
||||
GraphQLType, Object, Registry, RootNode, Value, Variables,
|
||||
};
|
||||
|
||||
#[derive(GraphQLObject, Debug, PartialEq)]
|
||||
#[graphql(
|
||||
name = "MyObj",
|
||||
description = "obj descr",
|
||||
scalar = DefaultScalarValue
|
||||
)]
|
||||
#[graphql(name = "MyObj", description = "obj descr")]
|
||||
struct Obj {
|
||||
regular_field: bool,
|
||||
#[graphql(
|
||||
|
@ -26,14 +17,10 @@ struct Obj {
|
|||
}
|
||||
|
||||
#[derive(GraphQLObject, Debug, PartialEq)]
|
||||
#[graphql(scalar = DefaultScalarValue)]
|
||||
struct Nested {
|
||||
obj: Obj,
|
||||
}
|
||||
|
||||
struct Query;
|
||||
struct NoRenameQuery;
|
||||
|
||||
/// Object comment.
|
||||
#[derive(GraphQLObject, Debug, PartialEq)]
|
||||
struct DocComment {
|
||||
|
@ -79,16 +66,19 @@ struct NoRenameObj {
|
|||
one_field: bool,
|
||||
another_field: i32,
|
||||
}
|
||||
|
||||
struct Context;
|
||||
impl juniper::Context for Context {}
|
||||
|
||||
#[derive(GraphQLObject, Debug)]
|
||||
#[graphql(Context = Context)]
|
||||
#[graphql(context = Context)]
|
||||
struct WithCustomContext {
|
||||
a: bool,
|
||||
}
|
||||
|
||||
#[juniper::graphql_object]
|
||||
struct Query;
|
||||
|
||||
#[graphql_object]
|
||||
impl Query {
|
||||
fn obj() -> Obj {
|
||||
Obj {
|
||||
|
@ -139,7 +129,9 @@ impl Query {
|
|||
}
|
||||
}
|
||||
|
||||
#[juniper::graphql_object(rename = "none")]
|
||||
struct NoRenameQuery;
|
||||
|
||||
#[graphql_object(rename = "none")]
|
||||
impl NoRenameQuery {
|
||||
fn obj() -> Obj {
|
||||
Obj {
|
||||
|
@ -158,7 +150,7 @@ impl NoRenameQuery {
|
|||
|
||||
#[tokio::test]
|
||||
async fn test_doc_comment_simple() {
|
||||
let mut registry: juniper::Registry = juniper::Registry::new(FnvHashMap::default());
|
||||
let mut registry: Registry = Registry::new(FnvHashMap::default());
|
||||
let meta = DocComment::meta(&(), &mut registry);
|
||||
assert_eq!(meta.description(), Some(&"Object comment.".to_string()));
|
||||
|
||||
|
@ -173,7 +165,7 @@ async fn test_doc_comment_simple() {
|
|||
|
||||
#[tokio::test]
|
||||
async fn test_multi_doc_comment() {
|
||||
let mut registry: juniper::Registry = juniper::Registry::new(FnvHashMap::default());
|
||||
let mut registry: Registry = Registry::new(FnvHashMap::default());
|
||||
let meta = MultiDocComment::meta(&(), &mut registry);
|
||||
assert_eq!(
|
||||
meta.description(),
|
||||
|
@ -191,7 +183,7 @@ async fn test_multi_doc_comment() {
|
|||
|
||||
#[tokio::test]
|
||||
async fn test_doc_comment_override() {
|
||||
let mut registry: juniper::Registry = juniper::Registry::new(FnvHashMap::default());
|
||||
let mut registry: Registry = Registry::new(FnvHashMap::default());
|
||||
let meta = OverrideDocComment::meta(&(), &mut registry);
|
||||
assert_eq!(meta.description(), Some(&"obj override".to_string()));
|
||||
|
||||
|
@ -204,98 +196,6 @@ async fn test_doc_comment_override() {
|
|||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_no_rename_root() {
|
||||
let doc = r#"
|
||||
{
|
||||
no_rename_obj {
|
||||
one_field
|
||||
another_field
|
||||
}
|
||||
|
||||
obj {
|
||||
regularField
|
||||
}
|
||||
}"#;
|
||||
|
||||
let schema = RootNode::new(
|
||||
NoRenameQuery,
|
||||
EmptyMutation::<()>::new(),
|
||||
EmptySubscription::<()>::new(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
execute(doc, None, &schema, &Variables::new(), &()).await,
|
||||
Ok((
|
||||
Value::object(
|
||||
vec![
|
||||
(
|
||||
"no_rename_obj",
|
||||
Value::object(
|
||||
vec![
|
||||
("one_field", Value::scalar(true)),
|
||||
("another_field", Value::scalar(146)),
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
),
|
||||
),
|
||||
(
|
||||
"obj",
|
||||
Value::object(
|
||||
vec![("regularField", Value::scalar(false)),]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
),
|
||||
)
|
||||
]
|
||||
.into_iter()
|
||||
.collect()
|
||||
),
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_no_rename_obj() {
|
||||
let doc = r#"
|
||||
{
|
||||
noRenameObj {
|
||||
one_field
|
||||
another_field
|
||||
}
|
||||
}"#;
|
||||
|
||||
let schema = RootNode::new(
|
||||
Query,
|
||||
EmptyMutation::<()>::new(),
|
||||
EmptySubscription::<()>::new(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
execute(doc, None, &schema, &Variables::new(), &()).await,
|
||||
Ok((
|
||||
Value::object(
|
||||
vec![(
|
||||
"noRenameObj",
|
||||
Value::object(
|
||||
vec![
|
||||
("one_field", Value::scalar(true)),
|
||||
("another_field", Value::scalar(146)),
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
),
|
||||
)]
|
||||
.into_iter()
|
||||
.collect()
|
||||
),
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_derived_object() {
|
||||
assert_eq!(
|
||||
|
@ -304,7 +204,7 @@ async fn test_derived_object() {
|
|||
);
|
||||
|
||||
// Verify meta info.
|
||||
let mut registry: juniper::Registry = juniper::Registry::new(FnvHashMap::default());
|
||||
let mut registry: Registry = Registry::new(FnvHashMap::default());
|
||||
let meta = Obj::meta(&(), &mut registry);
|
||||
|
||||
assert_eq!(meta.name(), Some("MyObj"));
|
||||
|
@ -432,7 +332,98 @@ async fn test_derived_object_nested() {
|
|||
);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[tokio::test]
|
||||
async fn test_no_rename_root() {
|
||||
let doc = r#"
|
||||
{
|
||||
no_rename_obj {
|
||||
one_field
|
||||
another_field
|
||||
}
|
||||
|
||||
obj {
|
||||
regularField
|
||||
}
|
||||
}"#;
|
||||
|
||||
let schema = RootNode::new(
|
||||
NoRenameQuery,
|
||||
EmptyMutation::<()>::new(),
|
||||
EmptySubscription::<()>::new(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
execute(doc, None, &schema, &Variables::new(), &()).await,
|
||||
Ok((
|
||||
Value::object(
|
||||
vec![
|
||||
(
|
||||
"no_rename_obj",
|
||||
Value::object(
|
||||
vec![
|
||||
("one_field", Value::scalar(true)),
|
||||
("another_field", Value::scalar(146)),
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
),
|
||||
),
|
||||
(
|
||||
"obj",
|
||||
Value::object(
|
||||
vec![("regularField", Value::scalar(false)),]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
),
|
||||
)
|
||||
]
|
||||
.into_iter()
|
||||
.collect()
|
||||
),
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_no_rename_obj() {
|
||||
let doc = r#"
|
||||
{
|
||||
noRenameObj {
|
||||
one_field
|
||||
another_field
|
||||
}
|
||||
}"#;
|
||||
|
||||
let schema = RootNode::new(
|
||||
Query,
|
||||
EmptyMutation::<()>::new(),
|
||||
EmptySubscription::<()>::new(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
execute(doc, None, &schema, &Variables::new(), &()).await,
|
||||
Ok((
|
||||
Value::object(
|
||||
vec![(
|
||||
"noRenameObj",
|
||||
Value::object(
|
||||
vec![
|
||||
("one_field", Value::scalar(true)),
|
||||
("another_field", Value::scalar(146)),
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
),
|
||||
)]
|
||||
.into_iter()
|
||||
.collect()
|
||||
),
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
async fn check_descriptions(
|
||||
object_name: &str,
|
||||
object_description: &Value,
|
||||
|
@ -475,7 +466,6 @@ async fn check_descriptions(
|
|||
.await;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
async fn run_type_info_query<F>(doc: &str, f: F)
|
||||
where
|
||||
F: Fn((&Object<DefaultScalarValue>, &Vec<Value>)) -> (),
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
#[cfg(test)]
|
||||
use juniper::{
|
||||
self, execute, graphql_value, EmptyMutation, EmptySubscription, GraphQLInputObject, RootNode,
|
||||
Value, Variables,
|
||||
execute, graphql_object, graphql_value, EmptyMutation, EmptySubscription, GraphQLInputObject,
|
||||
RootNode, Value, Variables,
|
||||
};
|
||||
|
||||
pub struct Query;
|
||||
|
||||
#[juniper::graphql_object]
|
||||
#[graphql_object]
|
||||
impl Query {
|
||||
fn r#type(r#fn: MyInputType) -> Vec<String> {
|
||||
let _ = r#fn;
|
||||
|
@ -87,7 +86,6 @@ async fn supports_raw_idents_in_fields_of_input_types() {
|
|||
);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
async fn run_type_info_query(doc: &str) -> Value {
|
||||
let schema = RootNode::new(
|
||||
Query,
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
use juniper::DefaultScalarValue;
|
||||
#[cfg(test)]
|
||||
use juniper::Object;
|
||||
|
||||
#[cfg(test)]
|
||||
use juniper::{execute, EmptyMutation, EmptySubscription, FieldError, RootNode, Value, Variables};
|
||||
use juniper::{
|
||||
execute, graphql_object, DefaultScalarValue, EmptyMutation, EmptySubscription, Object,
|
||||
RootNode, Value, Variables,
|
||||
};
|
||||
|
||||
pub struct MyObject;
|
||||
|
||||
#[juniper::graphql_object]
|
||||
#[graphql_object]
|
||||
impl MyObject {
|
||||
#[graphql(arguments(arg(name = "test")))]
|
||||
fn test(&self, arg: String) -> String {
|
||||
|
@ -49,7 +47,6 @@ async fn check_argument_rename() {
|
|||
.await;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
async fn run_type_info_query<F>(doc: &str, f: F)
|
||||
where
|
||||
F: Fn((&Object<DefaultScalarValue>, &Vec<Value>)) -> (),
|
||||
|
@ -86,11 +83,11 @@ where
|
|||
}
|
||||
|
||||
mod fallible {
|
||||
use super::*;
|
||||
use juniper::{graphql_object, FieldError};
|
||||
|
||||
struct Obj;
|
||||
|
||||
#[juniper::graphql_object]
|
||||
#[graphql_object]
|
||||
impl Obj {
|
||||
fn test(&self, arg: String) -> Result<String, FieldError> {
|
||||
Ok(arg)
|
||||
|
|
|
@ -86,7 +86,7 @@ impl GraphQLScalar for ScalarDescription {
|
|||
}
|
||||
}
|
||||
|
||||
#[graphql_object]
|
||||
#[graphql_object(scalar = DefaultScalarValue)]
|
||||
impl Root {
|
||||
fn default_name() -> DefaultName {
|
||||
DefaultName(0)
|
||||
|
@ -278,7 +278,7 @@ async fn scalar_description_introspection() {
|
|||
async fn resolves_with_custom_scalar_value() {
|
||||
const DOC: &str = r#"{ withCustomScalarValue }"#;
|
||||
|
||||
let schema = RootNode::<_, _, _, MyScalarValue>::new(
|
||||
let schema = RootNode::<_, _, _, MyScalarValue>::new_with_scalar_value(
|
||||
RootWithCustomScalarValue,
|
||||
EmptyMutation::<()>::new(),
|
||||
EmptySubscription::<()>::new(),
|
||||
|
|
|
@ -6,12 +6,25 @@ use juniper::{
|
|||
IntoFieldError, RootNode, ScalarValue, Variables,
|
||||
};
|
||||
|
||||
fn schema<'q, C, S, Q>(query_root: Q) -> RootNode<'q, Q, EmptyMutation<C>, EmptySubscription<C>, S>
|
||||
fn schema<'q, C, Q>(query_root: Q) -> RootNode<'q, Q, EmptyMutation<C>, EmptySubscription<C>>
|
||||
where
|
||||
Q: GraphQLType<DefaultScalarValue, Context = C, TypeInfo = ()> + 'q,
|
||||
{
|
||||
RootNode::new(
|
||||
query_root,
|
||||
EmptyMutation::<C>::new(),
|
||||
EmptySubscription::<C>::new(),
|
||||
)
|
||||
}
|
||||
|
||||
fn schema_with_scalar<'q, S, C, Q>(
|
||||
query_root: Q,
|
||||
) -> RootNode<'q, Q, EmptyMutation<C>, EmptySubscription<C>, S>
|
||||
where
|
||||
Q: GraphQLType<S, Context = C, TypeInfo = ()> + 'q,
|
||||
S: ScalarValue + 'q,
|
||||
{
|
||||
RootNode::new(
|
||||
RootNode::new_with_scalar_value(
|
||||
query_root,
|
||||
EmptyMutation::<C>::new(),
|
||||
EmptySubscription::<C>::new(),
|
||||
|
@ -39,7 +52,7 @@ mod no_implers {
|
|||
unimplemented!()
|
||||
}
|
||||
|
||||
fn hero(&self) -> Box<DynHero<'_>> {
|
||||
fn hero(&self) -> Box<DynHero<'_, __S>> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
@ -170,8 +183,8 @@ mod trivial {
|
|||
Droid,
|
||||
}
|
||||
|
||||
#[graphql_object]
|
||||
impl QueryRoot {
|
||||
#[graphql_object(scalar = S)]
|
||||
impl<S: ScalarValue + Send + Sync> QueryRoot {
|
||||
fn character(&self) -> CharacterValue {
|
||||
match self {
|
||||
Self::Human => Human {
|
||||
|
@ -187,8 +200,8 @@ mod trivial {
|
|||
}
|
||||
}
|
||||
|
||||
fn hero(&self) -> Box<DynHero<'_>> {
|
||||
let ch: Box<DynHero<'_>> = match self {
|
||||
fn hero(&self) -> Box<DynHero<'_, S>> {
|
||||
let ch: Box<DynHero<'_, _>> = match self {
|
||||
Self::Human => Box::new(Human {
|
||||
id: "human-32".to_string(),
|
||||
home_planet: "earth".to_string(),
|
||||
|
@ -692,8 +705,8 @@ mod trivial_async {
|
|||
Droid,
|
||||
}
|
||||
|
||||
#[graphql_object]
|
||||
impl QueryRoot {
|
||||
#[graphql_object(scalar = S)]
|
||||
impl<S: ScalarValue + Send + Sync> QueryRoot {
|
||||
fn character(&self) -> CharacterValue {
|
||||
match self {
|
||||
Self::Human => Human {
|
||||
|
@ -709,8 +722,8 @@ mod trivial_async {
|
|||
}
|
||||
}
|
||||
|
||||
fn hero(&self) -> Box<DynHero<'_>> {
|
||||
let ch: Box<DynHero<'_>> = match self {
|
||||
fn hero(&self) -> Box<DynHero<'_, S>> {
|
||||
let ch: Box<DynHero<'_, _>> = match self {
|
||||
Self::Human => Box::new(Human {
|
||||
id: "human-32".to_string(),
|
||||
home_planet: "earth".to_string(),
|
||||
|
@ -1055,8 +1068,8 @@ mod explicit_async {
|
|||
Droid,
|
||||
}
|
||||
|
||||
#[graphql_object]
|
||||
impl QueryRoot {
|
||||
#[graphql_object(scalar = S)]
|
||||
impl<S: ScalarValue + Send + Sync> QueryRoot {
|
||||
fn character(&self) -> CharacterValue {
|
||||
match self {
|
||||
Self::Human => Human {
|
||||
|
@ -1072,8 +1085,8 @@ mod explicit_async {
|
|||
}
|
||||
}
|
||||
|
||||
fn hero(&self) -> Box<DynHero<'_>> {
|
||||
let ch: Box<DynHero<'_>> = match self {
|
||||
fn hero(&self) -> Box<DynHero<'_, S>> {
|
||||
let ch: Box<DynHero<'_, _>> = match self {
|
||||
Self::Human => Box::new(Human {
|
||||
id: "human-32".to_string(),
|
||||
home_planet: "earth".to_string(),
|
||||
|
@ -1305,8 +1318,8 @@ mod fallible_field {
|
|||
Droid,
|
||||
}
|
||||
|
||||
#[graphql_object]
|
||||
impl QueryRoot {
|
||||
#[graphql_object(scalar = S)]
|
||||
impl<S: ScalarValue + Send + Sync> QueryRoot {
|
||||
fn character(&self) -> CharacterValue {
|
||||
match self {
|
||||
Self::Human => Human {
|
||||
|
@ -1322,8 +1335,8 @@ mod fallible_field {
|
|||
}
|
||||
}
|
||||
|
||||
fn hero(&self) -> Box<DynHero<'_>> {
|
||||
let ch: Box<DynHero<'_>> = match self {
|
||||
fn hero(&self) -> Box<DynHero<'_, S>> {
|
||||
let ch: Box<DynHero<'_, _>> = match self {
|
||||
Self::Human => Box::new(Human {
|
||||
id: "human-32".to_string(),
|
||||
home_planet: "earth".to_string(),
|
||||
|
@ -1571,8 +1584,8 @@ mod generic {
|
|||
Droid,
|
||||
}
|
||||
|
||||
#[graphql_object]
|
||||
impl QueryRoot {
|
||||
#[graphql_object(scalar = S)]
|
||||
impl<S: ScalarValue + Send + Sync> QueryRoot {
|
||||
fn character(&self) -> CharacterValue {
|
||||
match self {
|
||||
Self::Human => Human {
|
||||
|
@ -1588,8 +1601,8 @@ mod generic {
|
|||
}
|
||||
}
|
||||
|
||||
fn hero(&self) -> Box<DynHero<'_, u8, ()>> {
|
||||
let ch: Box<DynHero<'_, u8, ()>> = match self {
|
||||
fn hero(&self) -> Box<DynHero<'_, u8, (), S>> {
|
||||
let ch: Box<DynHero<'_, u8, (), _>> = match self {
|
||||
Self::Human => Box::new(Human {
|
||||
id: "human-32".to_string(),
|
||||
home_planet: "earth".to_string(),
|
||||
|
@ -1815,8 +1828,8 @@ mod generic_async {
|
|||
Droid,
|
||||
}
|
||||
|
||||
#[graphql_object]
|
||||
impl QueryRoot {
|
||||
#[graphql_object(scalar = S)]
|
||||
impl<S: ScalarValue + Send + Sync> QueryRoot {
|
||||
fn character(&self) -> CharacterValue {
|
||||
match self {
|
||||
Self::Human => Human {
|
||||
|
@ -1832,8 +1845,8 @@ mod generic_async {
|
|||
}
|
||||
}
|
||||
|
||||
fn hero(&self) -> Box<DynHero<'_, u8, ()>> {
|
||||
let ch: Box<DynHero<'_, u8, ()>> = match self {
|
||||
fn hero(&self) -> Box<DynHero<'_, u8, (), S>> {
|
||||
let ch: Box<DynHero<'_, u8, (), _>> = match self {
|
||||
Self::Human => Box::new(Human {
|
||||
id: "human-32".to_string(),
|
||||
home_planet: "earth".to_string(),
|
||||
|
@ -2059,8 +2072,8 @@ mod generic_lifetime_async {
|
|||
Droid,
|
||||
}
|
||||
|
||||
#[graphql_object]
|
||||
impl QueryRoot {
|
||||
#[graphql_object(scalar = S)]
|
||||
impl<S: ScalarValue + Send + Sync> QueryRoot {
|
||||
fn character(&self) -> CharacterValue<'_, ()> {
|
||||
match self {
|
||||
Self::Human => Human {
|
||||
|
@ -2076,8 +2089,8 @@ mod generic_lifetime_async {
|
|||
}
|
||||
}
|
||||
|
||||
fn hero(&self) -> Box<DynHero<'_, '_, ()>> {
|
||||
let ch: Box<DynHero<'_, '_, ()>> = match self {
|
||||
fn hero(&self) -> Box<DynHero<'_, '_, (), S>> {
|
||||
let ch: Box<DynHero<'_, '_, (), _>> = match self {
|
||||
Self::Human => Box::new(Human {
|
||||
id: "human-32".to_string(),
|
||||
home_planet: "earth".to_string(),
|
||||
|
@ -2286,8 +2299,8 @@ mod argument {
|
|||
|
||||
struct QueryRoot;
|
||||
|
||||
#[graphql_object]
|
||||
impl QueryRoot {
|
||||
#[graphql_object(scalar = S)]
|
||||
impl<S: ScalarValue + Send + Sync> QueryRoot {
|
||||
fn character(&self) -> CharacterValue {
|
||||
Human {
|
||||
id: "human-32".to_string(),
|
||||
|
@ -2296,7 +2309,7 @@ mod argument {
|
|||
.into()
|
||||
}
|
||||
|
||||
fn hero(&self) -> Box<DynHero<'_>> {
|
||||
fn hero(&self) -> Box<DynHero<'_, S>> {
|
||||
Box::new(Human {
|
||||
id: "human-32".to_string(),
|
||||
home_planet: "earth".to_string(),
|
||||
|
@ -3011,7 +3024,7 @@ mod explicit_scalar {
|
|||
}
|
||||
}"#;
|
||||
|
||||
let schema = schema::<_, DefaultScalarValue, _>(QueryRoot::Human);
|
||||
let schema = schema(QueryRoot::Human);
|
||||
|
||||
assert_eq!(
|
||||
execute(DOC, None, &schema, &Variables::new(), &()).await,
|
||||
|
@ -3033,7 +3046,7 @@ mod explicit_scalar {
|
|||
}
|
||||
}"#;
|
||||
|
||||
let schema = schema::<_, DefaultScalarValue, _>(QueryRoot::Droid);
|
||||
let schema = schema(QueryRoot::Droid);
|
||||
|
||||
assert_eq!(
|
||||
execute(DOC, None, &schema, &Variables::new(), &()).await,
|
||||
|
@ -3055,7 +3068,7 @@ mod explicit_scalar {
|
|||
}
|
||||
}"#;
|
||||
|
||||
let schema = schema::<_, DefaultScalarValue, _>(QueryRoot::Human);
|
||||
let schema = schema(QueryRoot::Human);
|
||||
|
||||
assert_eq!(
|
||||
execute(DOC, None, &schema, &Variables::new(), &()).await,
|
||||
|
@ -3077,7 +3090,7 @@ mod explicit_scalar {
|
|||
}
|
||||
}"#;
|
||||
|
||||
let schema = schema::<_, DefaultScalarValue, _>(QueryRoot::Droid);
|
||||
let schema = schema(QueryRoot::Droid);
|
||||
|
||||
assert_eq!(
|
||||
execute(DOC, None, &schema, &Variables::new(), &()).await,
|
||||
|
@ -3100,7 +3113,7 @@ mod explicit_scalar {
|
|||
(QueryRoot::Human, "human-32"),
|
||||
(QueryRoot::Droid, "droid-99"),
|
||||
] {
|
||||
let schema = schema::<_, DefaultScalarValue, _>(*root);
|
||||
let schema = schema(*root);
|
||||
|
||||
let expected_id: &str = *expected_id;
|
||||
assert_eq!(
|
||||
|
@ -3119,7 +3132,7 @@ mod explicit_scalar {
|
|||
}"#;
|
||||
|
||||
for (root, expected_info) in &[(QueryRoot::Human, "earth"), (QueryRoot::Droid, "run")] {
|
||||
let schema = schema::<_, DefaultScalarValue, _>(*root);
|
||||
let schema = schema(*root);
|
||||
|
||||
let expected_info: &str = *expected_info;
|
||||
assert_eq!(
|
||||
|
@ -3237,7 +3250,7 @@ mod custom_scalar {
|
|||
}
|
||||
}"#;
|
||||
|
||||
let schema = schema::<_, MyScalarValue, _>(QueryRoot::Human);
|
||||
let schema = schema_with_scalar::<MyScalarValue, _, _>(QueryRoot::Human);
|
||||
|
||||
assert_eq!(
|
||||
execute(DOC, None, &schema, &Variables::new(), &()).await,
|
||||
|
@ -3259,7 +3272,7 @@ mod custom_scalar {
|
|||
}
|
||||
}"#;
|
||||
|
||||
let schema = schema::<_, MyScalarValue, _>(QueryRoot::Droid);
|
||||
let schema = schema_with_scalar::<MyScalarValue, _, _>(QueryRoot::Droid);
|
||||
|
||||
assert_eq!(
|
||||
execute(DOC, None, &schema, &Variables::new(), &()).await,
|
||||
|
@ -3281,7 +3294,7 @@ mod custom_scalar {
|
|||
}
|
||||
}"#;
|
||||
|
||||
let schema = schema::<_, MyScalarValue, _>(QueryRoot::Human);
|
||||
let schema = schema_with_scalar::<MyScalarValue, _, _>(QueryRoot::Human);
|
||||
|
||||
assert_eq!(
|
||||
execute(DOC, None, &schema, &Variables::new(), &()).await,
|
||||
|
@ -3303,7 +3316,7 @@ mod custom_scalar {
|
|||
}
|
||||
}"#;
|
||||
|
||||
let schema = schema::<_, MyScalarValue, _>(QueryRoot::Droid);
|
||||
let schema = schema_with_scalar::<MyScalarValue, _, _>(QueryRoot::Droid);
|
||||
|
||||
assert_eq!(
|
||||
execute(DOC, None, &schema, &Variables::new(), &()).await,
|
||||
|
@ -3326,7 +3339,7 @@ mod custom_scalar {
|
|||
(QueryRoot::Human, "human-32"),
|
||||
(QueryRoot::Droid, "droid-99"),
|
||||
] {
|
||||
let schema = schema::<_, MyScalarValue, _>(*root);
|
||||
let schema = schema_with_scalar::<MyScalarValue, _, _>(*root);
|
||||
|
||||
let expected_id: &str = *expected_id;
|
||||
assert_eq!(
|
||||
|
@ -3345,7 +3358,7 @@ mod custom_scalar {
|
|||
}"#;
|
||||
|
||||
for (root, expected_info) in &[(QueryRoot::Human, "earth"), (QueryRoot::Droid, "run")] {
|
||||
let schema = schema::<_, MyScalarValue, _>(*root);
|
||||
let schema = schema_with_scalar::<MyScalarValue, _, _>(*root);
|
||||
|
||||
let expected_info: &str = *expected_info;
|
||||
assert_eq!(
|
||||
|
@ -3417,9 +3430,9 @@ mod explicit_generic_scalar {
|
|||
Droid,
|
||||
}
|
||||
|
||||
#[graphql_object(scalar = DefaultScalarValue)]
|
||||
impl QueryRoot {
|
||||
fn character(&self) -> CharacterValue {
|
||||
#[graphql_object(scalar = S)]
|
||||
impl<S: ScalarValue + Send + Sync> QueryRoot {
|
||||
fn character(&self) -> CharacterValue<S> {
|
||||
match self {
|
||||
Self::Human => Human {
|
||||
id: "human-32".to_string(),
|
||||
|
@ -3434,8 +3447,8 @@ mod explicit_generic_scalar {
|
|||
}
|
||||
}
|
||||
|
||||
fn hero(&self) -> Box<DynHero<'_>> {
|
||||
let ch: Box<DynHero<'_>> = match self {
|
||||
fn hero(&self) -> Box<DynHero<'_, S>> {
|
||||
let ch: Box<DynHero<'_, _>> = match self {
|
||||
Self::Human => Box::new(Human {
|
||||
id: "human-32".to_string(),
|
||||
home_planet: "earth".to_string(),
|
||||
|
@ -3685,8 +3698,8 @@ mod explicit_custom_context {
|
|||
Droid,
|
||||
}
|
||||
|
||||
#[graphql_object(context = CustomContext)]
|
||||
impl QueryRoot {
|
||||
#[graphql_object(context = CustomContext, scalar = S)]
|
||||
impl<S: ScalarValue + Send + Sync> QueryRoot {
|
||||
fn character(&self) -> CharacterValue {
|
||||
match self {
|
||||
Self::Human => Human {
|
||||
|
@ -3702,8 +3715,8 @@ mod explicit_custom_context {
|
|||
}
|
||||
}
|
||||
|
||||
fn hero(&self) -> Box<DynHero<'_>> {
|
||||
let ch: Box<DynHero<'_>> = match self {
|
||||
fn hero(&self) -> Box<DynHero<'_, S>> {
|
||||
let ch: Box<DynHero<'_, _>> = match self {
|
||||
Self::Human => Box::new(Human {
|
||||
id: "human-32".to_string(),
|
||||
home_planet: "earth".to_string(),
|
||||
|
@ -3931,8 +3944,8 @@ mod inferred_custom_context_from_field {
|
|||
Droid,
|
||||
}
|
||||
|
||||
#[graphql_object(context = CustomContext)]
|
||||
impl QueryRoot {
|
||||
#[graphql_object(context = CustomContext, scalar = S)]
|
||||
impl<S: ScalarValue + Send + Sync> QueryRoot {
|
||||
fn character(&self) -> CharacterValue {
|
||||
match self {
|
||||
Self::Human => Human {
|
||||
|
@ -3948,8 +3961,8 @@ mod inferred_custom_context_from_field {
|
|||
}
|
||||
}
|
||||
|
||||
fn hero(&self) -> Box<DynHero<'_>> {
|
||||
let ch: Box<DynHero<'_>> = match self {
|
||||
fn hero(&self) -> Box<DynHero<'_, S>> {
|
||||
let ch: Box<DynHero<'_, _>> = match self {
|
||||
Self::Human => Box::new(Human {
|
||||
id: "human-32".to_string(),
|
||||
home_planet: "earth".to_string(),
|
||||
|
@ -4183,8 +4196,8 @@ mod inferred_custom_context_from_downcast {
|
|||
Droid,
|
||||
}
|
||||
|
||||
#[graphql_object(context = Database)]
|
||||
impl QueryRoot {
|
||||
#[graphql_object(context = Database, scalar = S)]
|
||||
impl<S: ScalarValue + Send + Sync> QueryRoot {
|
||||
fn character(&self) -> CharacterValue {
|
||||
match self {
|
||||
Self::Human => Human {
|
||||
|
@ -4200,8 +4213,8 @@ mod inferred_custom_context_from_downcast {
|
|||
}
|
||||
}
|
||||
|
||||
fn hero(&self) -> Box<DynHero<'_>> {
|
||||
let ch: Box<DynHero<'_>> = match self {
|
||||
fn hero(&self) -> Box<DynHero<'_, S>> {
|
||||
let ch: Box<DynHero<'_, _>> = match self {
|
||||
Self::Human => Box::new(Human {
|
||||
id: "human-32".to_string(),
|
||||
home_planet: "earth".to_string(),
|
||||
|
@ -4793,8 +4806,8 @@ mod downcast_method {
|
|||
Droid,
|
||||
}
|
||||
|
||||
#[graphql_object]
|
||||
impl QueryRoot {
|
||||
#[graphql_object(scalar = S)]
|
||||
impl<S: ScalarValue + Send + Sync> QueryRoot {
|
||||
fn character(&self) -> CharacterValue {
|
||||
match self {
|
||||
Self::Human => Human {
|
||||
|
@ -4810,8 +4823,8 @@ mod downcast_method {
|
|||
}
|
||||
}
|
||||
|
||||
fn hero(&self) -> Box<DynHero<'_>> {
|
||||
let ch: Box<DynHero<'_>> = match self {
|
||||
fn hero(&self) -> Box<DynHero<'_, S>> {
|
||||
let ch: Box<DynHero<'_, _>> = match self {
|
||||
Self::Human => Box::new(Human {
|
||||
id: "human-32".to_string(),
|
||||
home_planet: "earth".to_string(),
|
||||
|
@ -5058,8 +5071,8 @@ mod external_downcast {
|
|||
Droid,
|
||||
}
|
||||
|
||||
#[graphql_object(context = Database)]
|
||||
impl QueryRoot {
|
||||
#[graphql_object(context = Database, scalar = S)]
|
||||
impl<S: ScalarValue + Send + Sync> QueryRoot {
|
||||
fn character(&self) -> CharacterValue {
|
||||
match self {
|
||||
Self::Human => Human {
|
||||
|
@ -5075,8 +5088,8 @@ mod external_downcast {
|
|||
}
|
||||
}
|
||||
|
||||
fn hero(&self) -> Box<DynHero<'_>> {
|
||||
let ch: Box<DynHero<'_>> = match self {
|
||||
fn hero(&self) -> Box<DynHero<'_, S>> {
|
||||
let ch: Box<DynHero<'_, _>> = match self {
|
||||
Self::Human => Box::new(Human {
|
||||
id: "human-32".to_string(),
|
||||
home_planet: "earth".to_string(),
|
||||
|
|
|
@ -1,20 +1,23 @@
|
|||
use fnv::FnvHashMap;
|
||||
use juniper::{DefaultScalarValue, FromInputValue, GraphQLType, InputValue, ToInputValue};
|
||||
use juniper::{
|
||||
graphql_object, DefaultScalarValue, FromInputValue, GraphQLObject, GraphQLScalarValue,
|
||||
GraphQLType, InputValue, Registry, ToInputValue,
|
||||
};
|
||||
|
||||
#[derive(juniper::GraphQLScalarValue, PartialEq, Eq, Debug)]
|
||||
#[derive(GraphQLScalarValue, Debug, Eq, PartialEq)]
|
||||
#[graphql(transparent)]
|
||||
struct UserId(String);
|
||||
|
||||
#[derive(juniper::GraphQLScalarValue, PartialEq, Eq, Debug)]
|
||||
#[derive(GraphQLScalarValue, Debug, Eq, PartialEq)]
|
||||
#[graphql(transparent, name = "MyUserId", description = "custom description...")]
|
||||
struct CustomUserId(String);
|
||||
|
||||
/// The doc comment...
|
||||
#[derive(juniper::GraphQLScalarValue, PartialEq, Eq, Debug)]
|
||||
#[derive(GraphQLScalarValue, Debug, Eq, PartialEq)]
|
||||
#[graphql(transparent)]
|
||||
struct IdWithDocComment(i32);
|
||||
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
#[derive(GraphQLObject)]
|
||||
struct User {
|
||||
id: UserId,
|
||||
id_custom: CustomUserId,
|
||||
|
@ -22,7 +25,7 @@ struct User {
|
|||
|
||||
struct User2;
|
||||
|
||||
#[juniper::graphql_object]
|
||||
#[graphql_object]
|
||||
impl User2 {
|
||||
fn id(&self) -> UserId {
|
||||
UserId("id".to_string())
|
||||
|
@ -36,7 +39,7 @@ fn test_scalar_value_simple() {
|
|||
Some("UserId")
|
||||
);
|
||||
|
||||
let mut registry: juniper::Registry = juniper::Registry::new(FnvHashMap::default());
|
||||
let mut registry: Registry = Registry::new(FnvHashMap::default());
|
||||
let meta = UserId::meta(&(), &mut registry);
|
||||
assert_eq!(meta.name(), Some("UserId"));
|
||||
assert_eq!(meta.description(), None);
|
||||
|
@ -57,7 +60,7 @@ fn test_scalar_value_custom() {
|
|||
Some("MyUserId")
|
||||
);
|
||||
|
||||
let mut registry: juniper::Registry = juniper::Registry::new(FnvHashMap::default());
|
||||
let mut registry: Registry = Registry::new(FnvHashMap::default());
|
||||
let meta = CustomUserId::meta(&(), &mut registry);
|
||||
assert_eq!(meta.name(), Some("MyUserId"));
|
||||
assert_eq!(
|
||||
|
@ -76,7 +79,7 @@ fn test_scalar_value_custom() {
|
|||
|
||||
#[test]
|
||||
fn test_scalar_value_doc_comment() {
|
||||
let mut registry: juniper::Registry = juniper::Registry::new(FnvHashMap::default());
|
||||
let mut registry: Registry = Registry::new(FnvHashMap::default());
|
||||
let meta = IdWithDocComment::meta(&(), &mut registry);
|
||||
assert_eq!(meta.description(), Some(&"The doc comment...".to_string()));
|
||||
}
|
||||
|
|
|
@ -51,12 +51,25 @@ struct EwokCustomContext {
|
|||
funny: bool,
|
||||
}
|
||||
|
||||
fn schema<'q, C, S, Q>(query_root: Q) -> RootNode<'q, Q, EmptyMutation<C>, EmptySubscription<C>, S>
|
||||
fn schema<'q, C, Q>(query_root: Q) -> RootNode<'q, Q, EmptyMutation<C>, EmptySubscription<C>>
|
||||
where
|
||||
Q: GraphQLType<DefaultScalarValue, Context = C, TypeInfo = ()> + 'q,
|
||||
{
|
||||
RootNode::new(
|
||||
query_root,
|
||||
EmptyMutation::<C>::new(),
|
||||
EmptySubscription::<C>::new(),
|
||||
)
|
||||
}
|
||||
|
||||
fn schema_with_scalar<'q, S, C, Q>(
|
||||
query_root: Q,
|
||||
) -> RootNode<'q, Q, EmptyMutation<C>, EmptySubscription<C>, S>
|
||||
where
|
||||
Q: GraphQLType<S, Context = C, TypeInfo = ()> + 'q,
|
||||
S: ScalarValue + 'q,
|
||||
{
|
||||
RootNode::new(
|
||||
RootNode::new_with_scalar_value(
|
||||
query_root,
|
||||
EmptyMutation::<C>::new(),
|
||||
EmptySubscription::<C>::new(),
|
||||
|
@ -531,7 +544,7 @@ mod explicit_scalar {
|
|||
|
||||
#[tokio::test]
|
||||
async fn resolves_human() {
|
||||
let schema = schema::<_, DefaultScalarValue, _>(QueryRoot::Human);
|
||||
let schema = schema(QueryRoot::Human);
|
||||
|
||||
assert_eq!(
|
||||
execute(DOC, None, &schema, &Variables::new(), &()).await,
|
||||
|
@ -544,7 +557,7 @@ mod explicit_scalar {
|
|||
|
||||
#[tokio::test]
|
||||
async fn resolves_droid() {
|
||||
let schema = schema::<_, DefaultScalarValue, _>(QueryRoot::Droid);
|
||||
let schema = schema(QueryRoot::Droid);
|
||||
|
||||
assert_eq!(
|
||||
execute(DOC, None, &schema, &Variables::new(), &()).await,
|
||||
|
@ -622,7 +635,7 @@ mod custom_scalar {
|
|||
|
||||
#[tokio::test]
|
||||
async fn resolves_human() {
|
||||
let schema = schema::<_, MyScalarValue, _>(QueryRoot::Human);
|
||||
let schema = schema_with_scalar::<MyScalarValue, _, _>(QueryRoot::Human);
|
||||
|
||||
assert_eq!(
|
||||
execute(DOC, None, &schema, &Variables::new(), &()).await,
|
||||
|
@ -635,7 +648,7 @@ mod custom_scalar {
|
|||
|
||||
#[tokio::test]
|
||||
async fn resolves_droid() {
|
||||
let schema = schema::<_, MyScalarValue, _>(QueryRoot::Droid);
|
||||
let schema = schema_with_scalar::<MyScalarValue, _, _>(QueryRoot::Droid);
|
||||
|
||||
assert_eq!(
|
||||
execute(DOC, None, &schema, &Variables::new(), &()).await,
|
||||
|
@ -1054,7 +1067,7 @@ mod full_featured {
|
|||
|
||||
struct QueryRoot;
|
||||
|
||||
#[graphql_object(context = CustomContext)]
|
||||
#[graphql_object(context = CustomContext, scalar = DefaultScalarValue)]
|
||||
impl QueryRoot {
|
||||
fn character(&self, ctx: &CustomContext) -> Box<DynCharacter<'_, ()>> {
|
||||
let ch: Box<DynCharacter<'_, ()>> = match ctx {
|
||||
|
|
|
@ -53,12 +53,25 @@ struct EwokCustomContext {
|
|||
funny: bool,
|
||||
}
|
||||
|
||||
fn schema<'q, C, S, Q>(query_root: Q) -> RootNode<'q, Q, EmptyMutation<C>, EmptySubscription<C>, S>
|
||||
fn schema<'q, C, Q>(query_root: Q) -> RootNode<'q, Q, EmptyMutation<C>, EmptySubscription<C>>
|
||||
where
|
||||
Q: GraphQLType<DefaultScalarValue, Context = C, TypeInfo = ()> + 'q,
|
||||
{
|
||||
RootNode::new(
|
||||
query_root,
|
||||
EmptyMutation::<C>::new(),
|
||||
EmptySubscription::<C>::new(),
|
||||
)
|
||||
}
|
||||
|
||||
fn schema_with_scalar<'q, S, C, Q>(
|
||||
query_root: Q,
|
||||
) -> RootNode<'q, Q, EmptyMutation<C>, EmptySubscription<C>, S>
|
||||
where
|
||||
Q: GraphQLType<S, Context = C, TypeInfo = ()> + 'q,
|
||||
S: ScalarValue + 'q,
|
||||
{
|
||||
RootNode::new(
|
||||
RootNode::new_with_scalar_value(
|
||||
query_root,
|
||||
EmptyMutation::<C>::new(),
|
||||
EmptySubscription::<C>::new(),
|
||||
|
@ -429,7 +442,7 @@ mod explicit_scalar {
|
|||
Droid,
|
||||
}
|
||||
|
||||
#[graphql_object]
|
||||
#[graphql_object(scalar = DefaultScalarValue)]
|
||||
impl QueryRoot {
|
||||
fn character(&self) -> Character {
|
||||
match self {
|
||||
|
@ -460,7 +473,7 @@ mod explicit_scalar {
|
|||
|
||||
#[tokio::test]
|
||||
async fn resolves_human() {
|
||||
let schema = schema::<_, DefaultScalarValue, _>(QueryRoot::Human);
|
||||
let schema = schema(QueryRoot::Human);
|
||||
|
||||
assert_eq!(
|
||||
execute(DOC, None, &schema, &Variables::new(), &()).await,
|
||||
|
@ -473,7 +486,7 @@ mod explicit_scalar {
|
|||
|
||||
#[tokio::test]
|
||||
async fn resolves_droid() {
|
||||
let schema = schema::<_, DefaultScalarValue, _>(QueryRoot::Droid);
|
||||
let schema = schema(QueryRoot::Droid);
|
||||
|
||||
assert_eq!(
|
||||
execute(DOC, None, &schema, &Variables::new(), &()).await,
|
||||
|
@ -533,7 +546,7 @@ mod custom_scalar {
|
|||
|
||||
#[tokio::test]
|
||||
async fn resolves_human() {
|
||||
let schema = schema::<_, MyScalarValue, _>(QueryRoot::Human);
|
||||
let schema = schema_with_scalar::<MyScalarValue, _, _>(QueryRoot::Human);
|
||||
|
||||
assert_eq!(
|
||||
execute(DOC, None, &schema, &Variables::new(), &()).await,
|
||||
|
@ -546,7 +559,7 @@ mod custom_scalar {
|
|||
|
||||
#[tokio::test]
|
||||
async fn resolves_droid() {
|
||||
let schema = schema::<_, MyScalarValue, _>(QueryRoot::Droid);
|
||||
let schema = schema_with_scalar::<MyScalarValue, _, _>(QueryRoot::Droid);
|
||||
|
||||
assert_eq!(
|
||||
execute(DOC, None, &schema, &Variables::new(), &()).await,
|
||||
|
@ -993,7 +1006,7 @@ mod full_featured_enum {
|
|||
|
||||
struct QueryRoot;
|
||||
|
||||
#[graphql_object(context = CustomContext)]
|
||||
#[graphql_object(context = CustomContext, scalar = DefaultScalarValue)]
|
||||
impl QueryRoot {
|
||||
fn character(&self, ctx: &CustomContext) -> Character<()> {
|
||||
match ctx {
|
||||
|
@ -1349,7 +1362,7 @@ mod full_featured_struct {
|
|||
Droid,
|
||||
}
|
||||
|
||||
#[graphql_object(context = Database)]
|
||||
#[graphql_object(context = Database, scalar = DefaultScalarValue)]
|
||||
impl QueryRoot {
|
||||
fn character(&self) -> Character<()> {
|
||||
Character {
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
use std::fmt;
|
||||
use std::{fmt, pin::Pin};
|
||||
|
||||
use futures::{stream, Stream};
|
||||
use juniper::{
|
||||
execute,
|
||||
execute, graphql_object, graphql_scalar, graphql_subscription,
|
||||
parser::{ParseError, ScalarToken, Spanning, Token},
|
||||
serde::de,
|
||||
EmptyMutation, FieldResult, InputValue, Object, ParseScalarResult, RootNode, ScalarValue,
|
||||
Value, Variables,
|
||||
EmptyMutation, FieldResult, GraphQLScalarValue, InputValue, Object, ParseScalarResult,
|
||||
RootNode, ScalarValue, Value, Variables,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, juniper::GraphQLScalarValue)]
|
||||
#[derive(GraphQLScalarValue, Clone, Debug, PartialEq)]
|
||||
pub(crate) enum MyScalarValue {
|
||||
Int(i32),
|
||||
Long(i64),
|
||||
|
@ -22,42 +23,49 @@ impl ScalarValue for MyScalarValue {
|
|||
|
||||
fn as_int(&self) -> Option<i32> {
|
||||
match *self {
|
||||
MyScalarValue::Int(ref i) => Some(*i),
|
||||
Self::Int(ref i) => Some(*i),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn as_string(&self) -> Option<String> {
|
||||
match *self {
|
||||
MyScalarValue::String(ref s) => Some(s.clone()),
|
||||
Self::String(ref s) => Some(s.clone()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_string(self) -> Option<String> {
|
||||
match self {
|
||||
Self::String(s) => Some(s),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn as_str(&self) -> Option<&str> {
|
||||
match *self {
|
||||
MyScalarValue::String(ref s) => Some(s.as_str()),
|
||||
Self::String(ref s) => Some(s.as_str()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn as_float(&self) -> Option<f64> {
|
||||
match *self {
|
||||
MyScalarValue::Int(ref i) => Some(*i as f64),
|
||||
MyScalarValue::Float(ref f) => Some(*f),
|
||||
Self::Int(ref i) => Some(f64::from(*i)),
|
||||
Self::Float(ref f) => Some(*f),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn as_boolean(&self) -> Option<bool> {
|
||||
match *self {
|
||||
MyScalarValue::Boolean(ref b) => Some(*b),
|
||||
Self::Boolean(ref b) => Some(*b),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct MyScalarValueVisitor;
|
||||
|
||||
impl<'de> de::Visitor<'de> for MyScalarValueVisitor {
|
||||
|
@ -82,7 +90,7 @@ impl<'de> de::Visitor<'de> for MyScalarValueVisitor {
|
|||
where
|
||||
E: de::Error,
|
||||
{
|
||||
if value <= i32::max_value() as i64 {
|
||||
if value <= i64::from(i32::max_value()) {
|
||||
self.visit_i32(value as i32)
|
||||
} else {
|
||||
Ok(MyScalarValue::Long(value))
|
||||
|
@ -132,7 +140,7 @@ impl<'de> de::Visitor<'de> for MyScalarValueVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
#[juniper::graphql_scalar(name = "Long")]
|
||||
#[graphql_scalar(name = "Long")]
|
||||
impl GraphQLScalar for i64 {
|
||||
fn resolve(&self) -> Value {
|
||||
Value::scalar(*self)
|
||||
|
@ -158,12 +166,10 @@ impl GraphQLScalar for i64 {
|
|||
|
||||
struct TestType;
|
||||
|
||||
#[juniper::graphql_object(
|
||||
Scalar = MyScalarValue
|
||||
)]
|
||||
#[graphql_object(scalar = MyScalarValue)]
|
||||
impl TestType {
|
||||
fn long_field() -> i64 {
|
||||
(::std::i32::MAX as i64) + 1
|
||||
i64::from(i32::max_value()) + 1
|
||||
}
|
||||
|
||||
fn long_with_arg(long_arg: i64) -> i64 {
|
||||
|
@ -173,14 +179,10 @@ impl TestType {
|
|||
|
||||
struct TestSubscriptionType;
|
||||
|
||||
#[juniper::graphql_subscription(
|
||||
Scalar = MyScalarValue
|
||||
)]
|
||||
#[graphql_subscription(scalar = MyScalarValue)]
|
||||
impl TestSubscriptionType {
|
||||
async fn foo(
|
||||
) -> std::pin::Pin<Box<dyn futures::Stream<Item = FieldResult<i32, MyScalarValue>> + Send>>
|
||||
{
|
||||
Box::pin(futures::stream::empty())
|
||||
async fn foo() -> Pin<Box<dyn Stream<Item = FieldResult<i32, MyScalarValue>> + Send>> {
|
||||
Box::pin(stream::empty())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,7 +190,8 @@ async fn run_variable_query<F>(query: &str, vars: Variables<MyScalarValue>, f: F
|
|||
where
|
||||
F: Fn(&Object<MyScalarValue>) -> (),
|
||||
{
|
||||
let schema = RootNode::new(TestType, EmptyMutation::<()>::new(), TestSubscriptionType);
|
||||
let schema =
|
||||
RootNode::new_with_scalar_value(TestType, EmptyMutation::<()>::new(), TestSubscriptionType);
|
||||
|
||||
let (result, errs) = execute(query, None, &schema, &vars, &())
|
||||
.await
|
||||
|
@ -215,7 +218,7 @@ async fn querying_long() {
|
|||
run_query("{ longField }", |result| {
|
||||
assert_eq!(
|
||||
result.get_field_value("longField"),
|
||||
Some(&Value::scalar((::std::i32::MAX as i64) + 1))
|
||||
Some(&Value::scalar(i64::from(i32::max_value()) + 1))
|
||||
);
|
||||
})
|
||||
.await;
|
||||
|
@ -226,12 +229,12 @@ async fn querying_long_arg() {
|
|||
run_query(
|
||||
&format!(
|
||||
"{{ longWithArg(longArg: {}) }}",
|
||||
(::std::i32::MAX as i64) + 3
|
||||
i64::from(i32::max_value()) + 3
|
||||
),
|
||||
|result| {
|
||||
assert_eq!(
|
||||
result.get_field_value("longWithArg"),
|
||||
Some(&Value::scalar((::std::i32::MAX as i64) + 3))
|
||||
Some(&Value::scalar(i64::from(i32::max_value()) + 3))
|
||||
);
|
||||
},
|
||||
)
|
||||
|
@ -244,14 +247,14 @@ async fn querying_long_variable() {
|
|||
"query q($test: Long!){ longWithArg(longArg: $test) }",
|
||||
vec![(
|
||||
"test".to_owned(),
|
||||
InputValue::Scalar(MyScalarValue::Long((::std::i32::MAX as i64) + 42)),
|
||||
InputValue::Scalar(MyScalarValue::Long(i64::from(i32::max_value()) + 42)),
|
||||
)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
|result| {
|
||||
assert_eq!(
|
||||
result.get_field_value("longWithArg"),
|
||||
Some(&Value::scalar((::std::i32::MAX as i64) + 42))
|
||||
Some(&Value::scalar(i64::from(i32::max_value()) + 42))
|
||||
);
|
||||
},
|
||||
)
|
||||
|
@ -260,7 +263,7 @@ async fn querying_long_variable() {
|
|||
|
||||
#[test]
|
||||
fn deserialize_variable() {
|
||||
let json = format!("{{\"field\": {}}}", (::std::i32::MAX as i64) + 42);
|
||||
let json = format!("{{\"field\": {}}}", i64::from(i32::max_value()) + 42);
|
||||
|
||||
let input_value: InputValue<MyScalarValue> = serde_json::from_str(&json).unwrap();
|
||||
assert_eq!(
|
||||
|
@ -268,7 +271,7 @@ fn deserialize_variable() {
|
|||
InputValue::Object(vec![(
|
||||
Spanning::unlocated("field".into()),
|
||||
Spanning::unlocated(InputValue::Scalar(MyScalarValue::Long(
|
||||
(::std::i32::MAX as i64) + 42
|
||||
i64::from(i32::max_value()) + 42
|
||||
)))
|
||||
)])
|
||||
);
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
// Original author of this test is <https://github.com/davidpdrsn>.
|
||||
use juniper::*;
|
||||
|
||||
use juniper::{
|
||||
graphql_object, EmptyMutation, EmptySubscription, LookAheadMethods as _, RootNode, Variables,
|
||||
};
|
||||
|
||||
pub struct Context;
|
||||
|
||||
|
@ -7,9 +10,7 @@ impl juniper::Context for Context {}
|
|||
|
||||
pub struct Query;
|
||||
|
||||
#[graphql_object(
|
||||
Context = Context
|
||||
)]
|
||||
#[graphql_object(context = Context)]
|
||||
impl Query {
|
||||
fn users(exec: &Executor) -> Vec<User> {
|
||||
let lh = exec.look_ahead();
|
||||
|
@ -27,9 +28,7 @@ impl Query {
|
|||
#[derive(Clone)]
|
||||
pub struct User;
|
||||
|
||||
#[graphql_object(
|
||||
Context = Context
|
||||
)]
|
||||
#[graphql_object(context = Context)]
|
||||
impl User {
|
||||
fn id() -> i32 {
|
||||
1
|
||||
|
@ -46,7 +45,7 @@ impl Country {
|
|||
}
|
||||
}
|
||||
|
||||
type Schema = juniper::RootNode<'static, Query, EmptyMutation<Context>, EmptySubscription<Context>>;
|
||||
type Schema = RootNode<'static, Query, EmptyMutation<Context>, EmptySubscription<Context>>;
|
||||
|
||||
#[tokio::test]
|
||||
async fn users() {
|
||||
|
@ -109,7 +108,7 @@ async fn both() {
|
|||
EmptyMutation::<Context>::new(),
|
||||
EmptySubscription::<Context>::new(),
|
||||
),
|
||||
&juniper::Variables::new(),
|
||||
&Variables::new(),
|
||||
&ctx,
|
||||
)
|
||||
.await
|
||||
|
@ -137,7 +136,7 @@ async fn both_in_different_order() {
|
|||
EmptyMutation::<Context>::new(),
|
||||
EmptySubscription::<Context>::new(),
|
||||
),
|
||||
&juniper::Variables::new(),
|
||||
&Variables::new(),
|
||||
&ctx,
|
||||
)
|
||||
.await
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
// Original author of this test is <https://github.com/davidpdrsn>.
|
||||
use juniper::*;
|
||||
|
||||
use juniper::{graphql_object, EmptyMutation, EmptySubscription, RootNode, Variables};
|
||||
|
||||
struct Query;
|
||||
|
||||
#[juniper::graphql_object]
|
||||
#[graphql_object]
|
||||
impl Query {
|
||||
fn users(executor: &Executor) -> Vec<User> {
|
||||
// This doesn't cause a panic
|
||||
|
@ -19,7 +20,7 @@ struct User {
|
|||
country: Country,
|
||||
}
|
||||
|
||||
#[juniper::graphql_object]
|
||||
#[graphql_object]
|
||||
impl User {
|
||||
fn country(&self, executor: &Executor) -> &Country {
|
||||
// This panics!
|
||||
|
@ -33,14 +34,14 @@ struct Country {
|
|||
id: i32,
|
||||
}
|
||||
|
||||
#[juniper::graphql_object]
|
||||
#[graphql_object]
|
||||
impl Country {
|
||||
fn id(&self) -> i32 {
|
||||
self.id
|
||||
}
|
||||
}
|
||||
|
||||
type Schema = juniper::RootNode<'static, Query, EmptyMutation<()>, EmptySubscription<()>>;
|
||||
type Schema = RootNode<'static, Query, EmptyMutation<()>, EmptySubscription<()>>;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_lookahead_from_fragment_with_nested_type() {
|
||||
|
|
|
@ -32,11 +32,10 @@
|
|||
- `LexerError`
|
||||
- `ParseError`
|
||||
- `RuleError`
|
||||
|
||||
|
||||
- Support `chrono-tz::Tz` scalar behind a `chrono-tz` feature flag. ([#519](https://github.com/graphql-rust/juniper/pull/519))
|
||||
|
||||
- Added support for distinguishing between between implicit and explicit null. ([#795](https://github.com/graphql-rust/juniper/pull/795))
|
||||
|
||||
|
||||
- Implement `IntoFieldError` for `std::convert::Infallible`. ([#796](https://github.com/graphql-rust/juniper/pull/796))
|
||||
|
||||
|
@ -76,7 +75,7 @@
|
|||
```rust
|
||||
#[graphql(arguments(argA(name = "test")))]
|
||||
```
|
||||
|
||||
|
||||
- `SchemaType` is now public.
|
||||
- This is helpful when using `context.getSchema()` inside of your field resolvers.
|
||||
|
||||
|
@ -94,9 +93,10 @@
|
|||
|
||||
- `juniper::graphiql` has moved to `juniper::http::graphiql`.
|
||||
- `juniper::http::graphiql::graphiql_source()` now requires a second parameter for subscriptions.
|
||||
|
||||
|
||||
- Renamed the `object` proc macro to `graphql_object`.
|
||||
- Removed the `graphql_object!` macro. Use the `#[graphql_object]` proc macro instead.
|
||||
- Made `#[graphql_object]` macro to generate code generic over `ScalarValue` by default. ([#779](https://github.com/graphql-rust/juniper/pull/779))
|
||||
|
||||
- Renamed the `scalar` proc macro to `graphql_scalar`.
|
||||
- Removed the `graphql_scalar!` macro. Use the `#[graphql_scalar]` proc macro instead.
|
||||
|
@ -117,7 +117,7 @@
|
|||
- The return type of `GraphQLType::resolve()` has been changed to `ExecutionResult`.
|
||||
- This was done to unify the return type of all resolver methods. The previous `Value` return type was just an internal artifact of
|
||||
error handling.
|
||||
|
||||
|
||||
- Subscription-related:
|
||||
- Add subscription type to `RootNode`.
|
||||
- Add subscription endpoint to `playground_source()`.
|
||||
|
@ -130,6 +130,8 @@
|
|||
- Renamed `http::tests::HTTPIntegration` as `http::tests::HttpIntegration`.
|
||||
- Added support for `application/graphql` POST request.
|
||||
|
||||
- `RootNode::new()` now returns `RootNode` parametrized with `DefaultScalarValue`. For custom `ScalarValue` use `RootNode::new_with_scalar_value()` instead. ([#779](https://github.com/graphql-rust/juniper/pull/779))
|
||||
|
||||
- When using `LookAheadMethods` to access child selections, children are always found using their alias if it exists rather than their name. ([#662](https://github.com/graphql-rust/juniper/pull/662))
|
||||
- These methods are also deprecated in favor of the new `LookAheadMethods::children()` method.
|
||||
|
||||
|
|
|
@ -216,6 +216,18 @@ impl<S> FieldError<S> {
|
|||
pub fn extensions(&self) -> &Value<S> {
|
||||
&self.extensions
|
||||
}
|
||||
|
||||
/// Maps the [`ScalarValue`] type of this [`FieldError`] into the specified one.
|
||||
pub fn map_scalar_value<Into>(self) -> FieldError<Into>
|
||||
where
|
||||
S: ScalarValue,
|
||||
Into: ScalarValue,
|
||||
{
|
||||
FieldError {
|
||||
message: self.message,
|
||||
extensions: self.extensions.map_scalar_value(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The result of resolving the value of a field of type `T`
|
||||
|
@ -240,9 +252,10 @@ pub trait IntoFieldError<S = DefaultScalarValue> {
|
|||
fn into_field_error(self) -> FieldError<S>;
|
||||
}
|
||||
|
||||
impl<S> IntoFieldError<S> for FieldError<S> {
|
||||
fn into_field_error(self) -> FieldError<S> {
|
||||
self
|
||||
impl<S1: ScalarValue, S2: ScalarValue> IntoFieldError<S2> for FieldError<S1> {
|
||||
#[inline]
|
||||
fn into_field_error(self) -> FieldError<S2> {
|
||||
self.map_scalar_value()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -315,28 +328,31 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, S, T, C> IntoResolvable<'a, S, T, C> for FieldResult<(&'a T::Context, T), S>
|
||||
impl<'a, S1, S2, T, C> IntoResolvable<'a, S2, T, C> for FieldResult<(&'a T::Context, T), S1>
|
||||
where
|
||||
S: ScalarValue,
|
||||
T: GraphQLValue<S>,
|
||||
S1: ScalarValue,
|
||||
S2: ScalarValue,
|
||||
T: GraphQLValue<S2>,
|
||||
{
|
||||
type Type = T;
|
||||
|
||||
fn into(self, _: &'a C) -> FieldResult<Option<(&'a T::Context, T)>, S> {
|
||||
self.map(Some)
|
||||
fn into(self, _: &'a C) -> FieldResult<Option<(&'a T::Context, T)>, S2> {
|
||||
self.map(Some).map_err(FieldError::map_scalar_value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S, T, C> IntoResolvable<'a, S, Option<T>, C>
|
||||
for FieldResult<Option<(&'a T::Context, T)>, S>
|
||||
impl<'a, S1, S2, T, C> IntoResolvable<'a, S2, Option<T>, C>
|
||||
for FieldResult<Option<(&'a T::Context, T)>, S1>
|
||||
where
|
||||
S: ScalarValue,
|
||||
T: GraphQLValue<S>,
|
||||
S1: ScalarValue,
|
||||
S2: ScalarValue,
|
||||
T: GraphQLValue<S2>,
|
||||
{
|
||||
type Type = T;
|
||||
|
||||
fn into(self, _: &'a C) -> FieldResult<Option<(&'a T::Context, Option<T>)>, S> {
|
||||
fn into(self, _: &'a C) -> FieldResult<Option<(&'a T::Context, Option<T>)>, S2> {
|
||||
self.map(|o| o.map(|(ctx, v)| (ctx, Some(v))))
|
||||
.map_err(FieldError::map_scalar_value)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{EmptyMutation, RootNode, Value};
|
||||
use crate::{graphql_object, EmptyMutation, EmptySubscription, GraphQLEnum, RootNode, Value};
|
||||
|
||||
#[derive(crate::GraphQLEnum)]
|
||||
#[derive(GraphQLEnum)]
|
||||
enum UserKind {
|
||||
Admin,
|
||||
User,
|
||||
|
@ -14,7 +14,7 @@ struct User {
|
|||
kind: UserKind,
|
||||
}
|
||||
|
||||
#[crate::graphql_object]
|
||||
#[graphql_object]
|
||||
impl User {
|
||||
async fn id(&self) -> i32 {
|
||||
self.id
|
||||
|
@ -46,7 +46,7 @@ impl User {
|
|||
|
||||
struct Query;
|
||||
|
||||
#[crate::graphql_object]
|
||||
#[graphql_object]
|
||||
impl Query {
|
||||
fn field_sync(&self) -> &'static str {
|
||||
"field_sync"
|
||||
|
@ -72,7 +72,7 @@ impl Query {
|
|||
|
||||
#[tokio::test]
|
||||
async fn async_simple() {
|
||||
let schema = RootNode::new(Query, EmptyMutation::new(), crate::EmptySubscription::new());
|
||||
let schema = RootNode::new(Query, EmptyMutation::new(), EmptySubscription::new());
|
||||
let doc = r#"
|
||||
query {
|
||||
fieldSync
|
||||
|
|
|
@ -58,7 +58,7 @@ mod field_execution {
|
|||
|
||||
#[tokio::test]
|
||||
async fn test() {
|
||||
let schema = RootNode::<_, _, _, crate::DefaultScalarValue>::new(
|
||||
let schema = RootNode::new(
|
||||
DataType,
|
||||
EmptyMutation::<()>::new(),
|
||||
EmptySubscription::<()>::new(),
|
||||
|
@ -470,6 +470,7 @@ mod dynamic_context_switching {
|
|||
|
||||
use crate::{
|
||||
executor::{Context, ExecutionError, FieldError, FieldResult},
|
||||
graphql_object,
|
||||
parser::SourcePosition,
|
||||
schema::model::RootNode,
|
||||
types::scalars::{EmptyMutation, EmptySubscription},
|
||||
|
@ -491,7 +492,7 @@ mod dynamic_context_switching {
|
|||
|
||||
struct ItemRef;
|
||||
|
||||
#[crate::graphql_object(Context = OuterContext)]
|
||||
#[graphql_object(context = OuterContext)]
|
||||
impl Schema {
|
||||
fn item_opt(_context: &OuterContext, key: i32) -> Option<(&InnerContext, ItemRef)> {
|
||||
executor.context().items.get(&key).map(|c| (c, ItemRef))
|
||||
|
@ -521,7 +522,7 @@ mod dynamic_context_switching {
|
|||
}
|
||||
}
|
||||
|
||||
#[crate::graphql_object(Context = InnerContext)]
|
||||
#[graphql_object(context = InnerContext)]
|
||||
impl ItemRef {
|
||||
fn value(context: &InnerContext) -> String {
|
||||
context.value.clone()
|
||||
|
@ -828,6 +829,7 @@ mod dynamic_context_switching {
|
|||
mod propagates_errors_to_nullable_fields {
|
||||
use crate::{
|
||||
executor::{ExecutionError, FieldError, FieldResult, IntoFieldError},
|
||||
graphql_object,
|
||||
parser::SourcePosition,
|
||||
schema::model::RootNode,
|
||||
types::scalars::{EmptyMutation, EmptySubscription},
|
||||
|
@ -857,7 +859,7 @@ mod propagates_errors_to_nullable_fields {
|
|||
}
|
||||
}
|
||||
|
||||
#[crate::graphql_object]
|
||||
#[graphql_object]
|
||||
impl Schema {
|
||||
fn inner() -> Inner {
|
||||
Inner
|
||||
|
@ -870,7 +872,7 @@ mod propagates_errors_to_nullable_fields {
|
|||
}
|
||||
}
|
||||
|
||||
#[crate::graphql_object]
|
||||
#[graphql_object]
|
||||
impl Inner {
|
||||
fn nullable_field() -> Option<Inner> {
|
||||
Some(Inner)
|
||||
|
@ -1176,7 +1178,7 @@ mod named_operations {
|
|||
|
||||
#[tokio::test]
|
||||
async fn uses_inline_operation_if_no_name_provided() {
|
||||
let schema = RootNode::<_, _, _, crate::DefaultScalarValue>::new(
|
||||
let schema = RootNode::new(
|
||||
Schema,
|
||||
EmptyMutation::<()>::new(),
|
||||
EmptySubscription::<()>::new(),
|
||||
|
|
|
@ -7,10 +7,10 @@ use self::input_object::{NamedPublic, NamedPublicWithDescription};
|
|||
|
||||
use crate::{
|
||||
executor::Variables,
|
||||
graphql_interface, graphql_object,
|
||||
graphql_interface, graphql_object, graphql_scalar,
|
||||
schema::model::RootNode,
|
||||
types::scalars::{EmptyMutation, EmptySubscription},
|
||||
value::{DefaultScalarValue, ParseScalarResult, ParseScalarValue, Value},
|
||||
value::{ParseScalarResult, ParseScalarValue, ScalarValue, Value},
|
||||
GraphQLEnum,
|
||||
};
|
||||
|
||||
|
@ -23,23 +23,23 @@ enum Sample {
|
|||
|
||||
struct Scalar(i32);
|
||||
|
||||
#[crate::graphql_scalar(name = "SampleScalar")]
|
||||
impl GraphQLScalar for Scalar {
|
||||
#[graphql_scalar(name = "SampleScalar")]
|
||||
impl<S: ScalarValue> GraphQLScalar for Scalar {
|
||||
fn resolve(&self) -> Value {
|
||||
Value::scalar(self.0)
|
||||
}
|
||||
|
||||
fn from_input_value(v: &InputValue) -> Option<Scalar> {
|
||||
v.as_scalar_value().map(|i: &i32| Scalar(*i))
|
||||
v.as_scalar().and_then(ScalarValue::as_int).map(Scalar)
|
||||
}
|
||||
|
||||
fn from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a, DefaultScalarValue> {
|
||||
<i32 as ParseScalarValue>::from_str(value)
|
||||
fn from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a, S> {
|
||||
<i32 as ParseScalarValue<S>>::from_str(value)
|
||||
}
|
||||
}
|
||||
|
||||
/// A sample interface
|
||||
#[graphql_interface(name = "SampleInterface", for = Root, scalar = DefaultScalarValue)]
|
||||
#[graphql_interface(name = "SampleInterface", for = Root)]
|
||||
trait Interface {
|
||||
/// A sample field in the interface
|
||||
fn sample_enum(&self) -> Sample {
|
||||
|
@ -50,7 +50,7 @@ trait Interface {
|
|||
struct Root;
|
||||
|
||||
/// The root query object in the schema
|
||||
#[graphql_object(interfaces = InterfaceValue)]
|
||||
#[graphql_object(impl = InterfaceValue)]
|
||||
impl Root {
|
||||
fn sample_enum() -> Sample {
|
||||
Sample::One
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
use crate::{
|
||||
ast::InputValue,
|
||||
executor::Variables,
|
||||
graphql_object, graphql_scalar,
|
||||
parser::SourcePosition,
|
||||
schema::model::RootNode,
|
||||
types::scalars::{EmptyMutation, EmptySubscription},
|
||||
validation::RuleError,
|
||||
value::{DefaultScalarValue, Object, ParseScalarResult, ParseScalarValue, Value},
|
||||
value::{DefaultScalarValue, Object, ParseScalarResult, ParseScalarValue, ScalarValue, Value},
|
||||
GraphQLError::ValidationError,
|
||||
GraphQLInputObject,
|
||||
};
|
||||
|
@ -13,17 +14,15 @@ use crate::{
|
|||
#[derive(Debug)]
|
||||
struct TestComplexScalar;
|
||||
|
||||
struct TestType;
|
||||
|
||||
#[crate::graphql_scalar]
|
||||
impl GraphQLScalar for TestComplexScalar {
|
||||
#[graphql_scalar]
|
||||
impl<S: ScalarValue> GraphQLScalar for TestComplexScalar {
|
||||
fn resolve(&self) -> Value {
|
||||
Value::scalar(String::from("SerializedValue"))
|
||||
}
|
||||
|
||||
fn from_input_value(v: &InputValue) -> Option<TestComplexScalar> {
|
||||
if let Some(s) = v.as_scalar_value::<String>() {
|
||||
if *s == "SerializedValue" {
|
||||
if let Some(s) = v.as_scalar().and_then(ScalarValue::as_str) {
|
||||
if s == "SerializedValue" {
|
||||
return Some(TestComplexScalar);
|
||||
}
|
||||
}
|
||||
|
@ -31,13 +30,12 @@ impl GraphQLScalar for TestComplexScalar {
|
|||
None
|
||||
}
|
||||
|
||||
fn from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a, DefaultScalarValue> {
|
||||
<String as ParseScalarValue>::from_str(value)
|
||||
fn from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a, S> {
|
||||
<String as ParseScalarValue<S>>::from_str(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(GraphQLInputObject, Debug)]
|
||||
#[graphql(scalar = DefaultScalarValue)]
|
||||
struct TestInputObject {
|
||||
a: Option<String>,
|
||||
b: Option<Vec<Option<String>>>,
|
||||
|
@ -46,7 +44,6 @@ struct TestInputObject {
|
|||
}
|
||||
|
||||
#[derive(GraphQLInputObject, Debug)]
|
||||
#[graphql(scalar = DefaultScalarValue)]
|
||||
struct TestNestedInputObject {
|
||||
na: TestInputObject,
|
||||
nb: String,
|
||||
|
@ -64,7 +61,9 @@ struct InputWithDefaults {
|
|||
a: i32,
|
||||
}
|
||||
|
||||
#[crate::graphql_object]
|
||||
struct TestType;
|
||||
|
||||
#[graphql_object]
|
||||
impl TestType {
|
||||
fn field_with_object_input(input: Option<TestInputObject>) -> String {
|
||||
format!("{:?}", input)
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
use futures::Stream;
|
||||
|
||||
use crate::{FieldError, GraphQLValue, ScalarValue};
|
||||
use crate::{FieldError, GraphQLValue, IntoFieldError, ScalarValue};
|
||||
|
||||
/// Trait for wrapping [`Stream`] into [`Ok`] if it's not [`Result`].
|
||||
///
|
||||
|
@ -22,12 +22,12 @@ pub trait IntoFieldResult<T, S> {
|
|||
impl<T, E, S> IntoFieldResult<T, S> for Result<T, E>
|
||||
where
|
||||
T: IntoFieldResult<T, S>,
|
||||
E: Into<FieldError<S>>,
|
||||
E: IntoFieldError<S>,
|
||||
{
|
||||
type Item = T::Item;
|
||||
|
||||
fn into_result(self) -> Result<T, FieldError<S>> {
|
||||
self.map_err(|e| e.into())
|
||||
self.map_err(E::into_field_error)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ use crate::{
|
|||
#[derive(Debug)]
|
||||
struct Root;
|
||||
|
||||
#[graphql_object(interfaces = [InterfaceValue])]
|
||||
#[graphql_object(impl = InterfaceValue)]
|
||||
impl Root {
|
||||
fn simple() -> i32 {
|
||||
0
|
||||
|
@ -104,7 +104,7 @@ impl Root {
|
|||
}
|
||||
}
|
||||
|
||||
#[graphql_interface(scalar = DefaultScalarValue)]
|
||||
#[graphql_interface]
|
||||
impl Interface for Root {
|
||||
fn simple(&self) -> i32 {
|
||||
0
|
||||
|
@ -147,7 +147,7 @@ impl Interface for Root {
|
|||
}
|
||||
}
|
||||
|
||||
#[graphql_interface(for = Root, scalar = DefaultScalarValue)]
|
||||
#[graphql_interface(for = Root)]
|
||||
trait Interface {
|
||||
fn simple(&self) -> i32;
|
||||
|
||||
|
|
|
@ -29,44 +29,44 @@ impl Concrete {
|
|||
}
|
||||
}
|
||||
|
||||
#[graphql_interface(for = Concrete, name = "ACustomNamedInterface", scalar = DefaultScalarValue)]
|
||||
#[graphql_interface(for = Concrete, name = "ACustomNamedInterface")]
|
||||
trait CustomName {
|
||||
fn simple(&self) -> i32;
|
||||
}
|
||||
#[graphql_interface(scalar = DefaultScalarValue)]
|
||||
#[graphql_interface]
|
||||
impl CustomName for Concrete {
|
||||
fn simple(&self) -> i32 {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
#[graphql_interface(for = Concrete, scalar = DefaultScalarValue)]
|
||||
#[graphql_interface(for = Concrete)]
|
||||
trait WithLifetime<'a> {
|
||||
fn simple(&self) -> i32;
|
||||
}
|
||||
#[graphql_interface(scalar = DefaultScalarValue)]
|
||||
#[graphql_interface]
|
||||
impl<'a> WithLifetime<'a> for Concrete {
|
||||
fn simple(&self) -> i32 {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
#[graphql_interface(for = Concrete, scalar = DefaultScalarValue)]
|
||||
#[graphql_interface(for = Concrete)]
|
||||
trait WithGenerics<T> {
|
||||
fn simple(&self) -> i32;
|
||||
}
|
||||
#[graphql_interface(scalar = DefaultScalarValue)]
|
||||
#[graphql_interface]
|
||||
impl<T> WithGenerics<T> for Concrete {
|
||||
fn simple(&self) -> i32 {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
#[graphql_interface(for = Concrete, desc = "A description", scalar = DefaultScalarValue)]
|
||||
#[graphql_interface(for = Concrete, desc = "A description")]
|
||||
trait Description {
|
||||
fn simple(&self) -> i32;
|
||||
}
|
||||
#[graphql_interface(scalar = DefaultScalarValue)]
|
||||
#[graphql_interface]
|
||||
impl Description for Concrete {
|
||||
fn simple(&self) -> i32 {
|
||||
0
|
||||
|
@ -75,7 +75,7 @@ impl Description for Concrete {
|
|||
|
||||
struct Root;
|
||||
|
||||
#[crate::graphql_object]
|
||||
#[graphql_object]
|
||||
impl Root {
|
||||
fn custom_name() -> CustomNameValue {
|
||||
Concrete.into()
|
||||
|
|
|
@ -31,13 +31,13 @@ impl Concrete {
|
|||
}
|
||||
|
||||
#[derive(GraphQLUnion)]
|
||||
#[graphql(name = "ACustomNamedUnion", scalar = DefaultScalarValue)]
|
||||
#[graphql(name = "ACustomNamedUnion")]
|
||||
enum CustomName {
|
||||
Concrete(Concrete),
|
||||
}
|
||||
|
||||
#[derive(GraphQLUnion)]
|
||||
#[graphql(on Concrete = WithLifetime::resolve, scalar = DefaultScalarValue)]
|
||||
#[graphql(on Concrete = WithLifetime::resolve)]
|
||||
enum WithLifetime<'a> {
|
||||
#[graphql(ignore)]
|
||||
Int(PhantomData<&'a i32>),
|
||||
|
@ -54,7 +54,7 @@ impl<'a> WithLifetime<'a> {
|
|||
}
|
||||
|
||||
#[derive(GraphQLUnion)]
|
||||
#[graphql(on Concrete = WithGenerics::resolve, scalar = DefaultScalarValue)]
|
||||
#[graphql(on Concrete = WithGenerics::resolve)]
|
||||
enum WithGenerics<T> {
|
||||
#[graphql(ignore)]
|
||||
Generic(T),
|
||||
|
@ -71,20 +71,19 @@ impl<T> WithGenerics<T> {
|
|||
}
|
||||
|
||||
#[derive(GraphQLUnion)]
|
||||
#[graphql(description = "A description", scalar = DefaultScalarValue)]
|
||||
#[graphql(description = "A description")]
|
||||
enum DescriptionFirst {
|
||||
Concrete(Concrete),
|
||||
}
|
||||
|
||||
struct Root;
|
||||
|
||||
// FIXME: make async work
|
||||
#[crate::graphql_object(noasync)]
|
||||
impl<'a> Root {
|
||||
#[graphql_object]
|
||||
impl Root {
|
||||
fn custom_name() -> CustomName {
|
||||
CustomName::Concrete(Concrete)
|
||||
}
|
||||
fn with_lifetime() -> WithLifetime<'a> {
|
||||
fn with_lifetime() -> WithLifetime<'_> {
|
||||
WithLifetime::Int(PhantomData)
|
||||
}
|
||||
fn with_generics() -> WithGenerics<i32> {
|
||||
|
|
|
@ -162,11 +162,11 @@ fn issue_427_panic_is_not_expected() {
|
|||
}
|
||||
}
|
||||
|
||||
let schema = SchemaType::new::<QueryWithoutFloat, EmptyMutation<()>, EmptySubscription<()>>(
|
||||
&(),
|
||||
&(),
|
||||
&(),
|
||||
);
|
||||
let schema = <SchemaType<DefaultScalarValue>>::new::<
|
||||
QueryWithoutFloat,
|
||||
EmptyMutation<()>,
|
||||
EmptySubscription<()>,
|
||||
>(&(), &(), &());
|
||||
let parse_result = parse_document_source(r##"{ echo(value: 123.0) }"##, &schema);
|
||||
|
||||
assert_eq!(
|
||||
|
|
|
@ -88,6 +88,20 @@ pub enum DirectiveLocation {
|
|||
InlineFragment,
|
||||
}
|
||||
|
||||
impl<'a, QueryT, MutationT, SubscriptionT>
|
||||
RootNode<'a, QueryT, MutationT, SubscriptionT, DefaultScalarValue>
|
||||
where
|
||||
QueryT: GraphQLType<DefaultScalarValue, TypeInfo = ()>,
|
||||
MutationT: GraphQLType<DefaultScalarValue, TypeInfo = ()>,
|
||||
SubscriptionT: GraphQLType<DefaultScalarValue, TypeInfo = ()>,
|
||||
{
|
||||
/// Constructs a new [`RootNode`] from `query`, `mutation` and `subscription` nodes,
|
||||
/// parametrizing it with a [`DefaultScalarValue`].
|
||||
pub fn new(query: QueryT, mutation: MutationT, subscription: SubscriptionT) -> Self {
|
||||
Self::new_with_info(query, mutation, subscription, (), (), ())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, QueryT, MutationT, SubscriptionT, S> RootNode<'a, QueryT, MutationT, SubscriptionT, S>
|
||||
where
|
||||
S: ScalarValue + 'a,
|
||||
|
@ -95,16 +109,14 @@ where
|
|||
MutationT: GraphQLType<S, TypeInfo = ()>,
|
||||
SubscriptionT: GraphQLType<S, TypeInfo = ()>,
|
||||
{
|
||||
/// Construct a new root node from query, mutation, and subscription nodes
|
||||
///
|
||||
/// If the schema should not support mutations, use the
|
||||
/// `new` constructor instead.
|
||||
pub fn new(
|
||||
query_obj: QueryT,
|
||||
mutation_obj: MutationT,
|
||||
subscription_obj: SubscriptionT,
|
||||
/// Constructs a new [`RootNode`] from `query`, `mutation` and `subscription` nodes,
|
||||
/// parametrizing it with the provided [`ScalarValue`].
|
||||
pub fn new_with_scalar_value(
|
||||
query: QueryT,
|
||||
mutation: MutationT,
|
||||
subscription: SubscriptionT,
|
||||
) -> Self {
|
||||
RootNode::new_with_info(query_obj, mutation_obj, subscription_obj, (), (), ())
|
||||
RootNode::new_with_info(query, mutation, subscription, (), (), ())
|
||||
}
|
||||
|
||||
#[cfg(feature = "schema-language")]
|
||||
|
@ -560,19 +572,18 @@ mod test {
|
|||
|
||||
#[cfg(feature = "graphql-parser-integration")]
|
||||
mod graphql_parser_integration {
|
||||
use crate as juniper;
|
||||
use crate::{EmptyMutation, EmptySubscription};
|
||||
use crate::{graphql_object, EmptyMutation, EmptySubscription, RootNode};
|
||||
|
||||
#[test]
|
||||
fn graphql_parser_doc() {
|
||||
struct Query;
|
||||
#[juniper::graphql_object]
|
||||
#[graphql_object]
|
||||
impl Query {
|
||||
fn blah() -> bool {
|
||||
true
|
||||
}
|
||||
};
|
||||
let schema = crate::RootNode::new(
|
||||
let schema = RootNode::new(
|
||||
Query,
|
||||
EmptyMutation::<()>::new(),
|
||||
EmptySubscription::<()>::new(),
|
||||
|
@ -598,10 +609,9 @@ mod test {
|
|||
|
||||
#[cfg(feature = "schema-language")]
|
||||
mod schema_language {
|
||||
use crate as juniper;
|
||||
use crate::{
|
||||
EmptyMutation, EmptySubscription, GraphQLEnum, GraphQLInputObject, GraphQLObject,
|
||||
GraphQLUnion,
|
||||
graphql_object, EmptyMutation, EmptySubscription, GraphQLEnum, GraphQLInputObject,
|
||||
GraphQLObject, GraphQLUnion, RootNode,
|
||||
};
|
||||
|
||||
#[test]
|
||||
|
@ -630,7 +640,7 @@ mod test {
|
|||
longitude: f64,
|
||||
}
|
||||
struct Query;
|
||||
#[juniper::graphql_object]
|
||||
#[graphql_object]
|
||||
impl Query {
|
||||
fn blah() -> bool {
|
||||
true
|
||||
|
@ -666,7 +676,7 @@ mod test {
|
|||
}
|
||||
};
|
||||
|
||||
let schema = crate::RootNode::new(
|
||||
let schema = RootNode::new(
|
||||
Query,
|
||||
EmptyMutation::<()>::new(),
|
||||
EmptySubscription::<()>::new(),
|
||||
|
|
25
juniper/src/tests/fixtures/starwars/schema.rs
vendored
25
juniper/src/tests/fixtures/starwars/schema.rs
vendored
|
@ -2,14 +2,11 @@
|
|||
|
||||
use std::{collections::HashMap, pin::Pin};
|
||||
|
||||
use crate::{
|
||||
graphql_interface, graphql_object, graphql_subscription, Context, DefaultScalarValue,
|
||||
GraphQLEnum,
|
||||
};
|
||||
use crate::{graphql_interface, graphql_object, graphql_subscription, Context, GraphQLEnum};
|
||||
|
||||
pub struct Query;
|
||||
|
||||
#[graphql_object(context = Database, scalar = DefaultScalarValue)]
|
||||
#[graphql_object(context = Database)]
|
||||
/// The root query object of the schema
|
||||
impl Query {
|
||||
#[graphql(arguments(id(description = "id of the human")))]
|
||||
|
@ -51,7 +48,7 @@ pub enum Episode {
|
|||
Jedi,
|
||||
}
|
||||
|
||||
#[graphql_interface(for = [Human, Droid], context = Database, scalar = DefaultScalarValue)]
|
||||
#[graphql_interface(for = [Human, Droid], context = Database)]
|
||||
/// A character in the Star Wars Trilogy
|
||||
pub trait Character {
|
||||
/// The id of the character
|
||||
|
@ -105,11 +102,7 @@ impl Human {
|
|||
}
|
||||
|
||||
/// A humanoid creature in the Star Wars universe.
|
||||
#[graphql_object(
|
||||
context = Database,
|
||||
scalar = DefaultScalarValue,
|
||||
interfaces = CharacterValue,
|
||||
)]
|
||||
#[graphql_object(context = Database, impl = CharacterValue)]
|
||||
impl Human {
|
||||
/// The id of the human
|
||||
fn id(&self) -> &str {
|
||||
|
@ -137,7 +130,7 @@ impl Human {
|
|||
}
|
||||
}
|
||||
|
||||
#[graphql_interface(scalar = DefaultScalarValue)]
|
||||
#[graphql_interface]
|
||||
impl Character for Human {
|
||||
fn id(&self) -> &str {
|
||||
&self.id
|
||||
|
@ -195,11 +188,7 @@ impl Droid {
|
|||
}
|
||||
|
||||
/// A mechanical creature in the Star Wars universe.
|
||||
#[graphql_object(
|
||||
context = Database,
|
||||
scalar = DefaultScalarValue,
|
||||
interfaces = CharacterValue,
|
||||
)]
|
||||
#[graphql_object(context = Database, impl = CharacterValue)]
|
||||
impl Droid {
|
||||
/// The id of the droid
|
||||
fn id(&self) -> &str {
|
||||
|
@ -227,7 +216,7 @@ impl Droid {
|
|||
}
|
||||
}
|
||||
|
||||
#[graphql_interface(scalar = DefaultScalarValue)]
|
||||
#[graphql_interface]
|
||||
impl Character for Droid {
|
||||
fn id(&self) -> &str {
|
||||
&self.id
|
||||
|
|
|
@ -5,6 +5,8 @@ pub const STATIC_GRAPHQL_SCHEMA_DEFINITION: &str = include_str!("starwars.graphq
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use crate::{
|
||||
schema::model::RootNode,
|
||||
tests::fixtures::starwars::{
|
||||
|
@ -13,7 +15,6 @@ mod tests {
|
|||
},
|
||||
types::scalars::{EmptyMutation, EmptySubscription},
|
||||
};
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
fn dynamic_schema_language_matches_static() {
|
||||
|
|
|
@ -827,7 +827,7 @@ where
|
|||
V: Visitor<'a, S> + 'a,
|
||||
F: Fn() -> V,
|
||||
{
|
||||
let mut root = RootNode::new(r, m, s);
|
||||
let mut root = RootNode::new_with_scalar_value(r, m, s);
|
||||
|
||||
root.schema.add_directive(DirectiveType::new(
|
||||
"onQuery",
|
||||
|
|
|
@ -1,14 +1,21 @@
|
|||
mod object;
|
||||
mod scalar;
|
||||
|
||||
use std::{
|
||||
any::TypeId,
|
||||
fmt::{self, Display, Formatter},
|
||||
mem,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ast::{InputValue, ToInputValue},
|
||||
parser::Spanning,
|
||||
};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
mod object;
|
||||
mod scalar;
|
||||
|
||||
pub use self::object::Object;
|
||||
|
||||
pub use self::scalar::{DefaultScalarValue, ParseScalarResult, ParseScalarValue, ScalarValue};
|
||||
pub use self::{
|
||||
object::Object,
|
||||
scalar::{DefaultScalarValue, ParseScalarResult, ParseScalarValue, ScalarValue},
|
||||
};
|
||||
|
||||
/// Serializable value returned from query and field execution.
|
||||
///
|
||||
|
@ -28,15 +35,12 @@ pub enum Value<S = DefaultScalarValue> {
|
|||
Object(Object<S>),
|
||||
}
|
||||
|
||||
impl<S> Value<S>
|
||||
where
|
||||
S: ScalarValue,
|
||||
{
|
||||
impl<S: ScalarValue> Value<S> {
|
||||
// CONSTRUCTORS
|
||||
|
||||
/// Construct a null value.
|
||||
pub fn null() -> Self {
|
||||
Value::Null
|
||||
Self::Null
|
||||
}
|
||||
|
||||
/// Construct an integer value.
|
||||
|
@ -65,12 +69,12 @@ where
|
|||
|
||||
/// Construct a list value.
|
||||
pub fn list(l: Vec<Self>) -> Self {
|
||||
Value::List(l)
|
||||
Self::List(l)
|
||||
}
|
||||
|
||||
/// Construct an object value.
|
||||
pub fn object(o: Object<S>) -> Self {
|
||||
Value::Object(o)
|
||||
Self::Object(o)
|
||||
}
|
||||
|
||||
/// Construct a scalar value
|
||||
|
@ -78,7 +82,7 @@ where
|
|||
where
|
||||
T: Into<S>,
|
||||
{
|
||||
Value::Scalar(s.into())
|
||||
Self::Scalar(s.into())
|
||||
}
|
||||
|
||||
// DISCRIMINATORS
|
||||
|
@ -86,7 +90,7 @@ where
|
|||
/// Does this value represent null?
|
||||
pub fn is_null(&self) -> bool {
|
||||
match *self {
|
||||
Value::Null => true,
|
||||
Self::Null => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -97,16 +101,15 @@ where
|
|||
&'a S: Into<Option<&'a T>>,
|
||||
{
|
||||
match *self {
|
||||
Value::Scalar(ref s) => s.into(),
|
||||
Self::Scalar(ref s) => s.into(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// View the underlying float value, if present.
|
||||
pub fn as_float_value(&self) -> Option<f64>
|
||||
where {
|
||||
pub fn as_float_value(&self) -> Option<f64> {
|
||||
match self {
|
||||
Value::Scalar(ref s) => s.as_float(),
|
||||
Self::Scalar(ref s) => s.as_float(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -114,7 +117,7 @@ where {
|
|||
/// View the underlying object value, if present.
|
||||
pub fn as_object_value(&self) -> Option<&Object<S>> {
|
||||
match *self {
|
||||
Value::Object(ref o) => Some(o),
|
||||
Self::Object(ref o) => Some(o),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -124,7 +127,7 @@ where {
|
|||
/// Returns None if value is not an Object.
|
||||
pub fn into_object(self) -> Option<Object<S>> {
|
||||
match self {
|
||||
Value::Object(o) => Some(o),
|
||||
Self::Object(o) => Some(o),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -132,7 +135,7 @@ where {
|
|||
/// Mutable view into the underlying object value, if present.
|
||||
pub fn as_mut_object_value(&mut self) -> Option<&mut Object<S>> {
|
||||
match *self {
|
||||
Value::Object(ref mut o) => Some(o),
|
||||
Self::Object(ref mut o) => Some(o),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +143,7 @@ where {
|
|||
/// View the underlying list value, if present.
|
||||
pub fn as_list_value(&self) -> Option<&Vec<Self>> {
|
||||
match *self {
|
||||
Value::List(ref l) => Some(l),
|
||||
Self::List(ref l) => Some(l),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -148,7 +151,7 @@ where {
|
|||
/// View the underlying scalar value, if present
|
||||
pub fn as_scalar(&self) -> Option<&S> {
|
||||
match *self {
|
||||
Value::Scalar(ref s) => Some(s),
|
||||
Self::Scalar(ref s) => Some(s),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -160,6 +163,27 @@ where {
|
|||
{
|
||||
self.as_scalar_value::<String>().map(|s| s as &str)
|
||||
}
|
||||
|
||||
/// Maps the [`ScalarValue`] type of this [`Value`] into the specified one.
|
||||
pub fn map_scalar_value<Into: ScalarValue>(self) -> Value<Into> {
|
||||
if TypeId::of::<Into>() == TypeId::of::<S>() {
|
||||
// This is totally safe, because we're transmuting the value into itself,
|
||||
// so no invariants may change and we're just satisfying the type checker.
|
||||
let val = mem::ManuallyDrop::new(self);
|
||||
unsafe { mem::transmute_copy(&*val) }
|
||||
} else {
|
||||
match self {
|
||||
Self::Null => Value::Null,
|
||||
Self::Scalar(s) => Value::Scalar(s.into_another()),
|
||||
Self::List(l) => Value::List(l.into_iter().map(Value::map_scalar_value).collect()),
|
||||
Self::Object(o) => Value::Object(
|
||||
o.into_iter()
|
||||
.map(|(k, v)| (k, v.map_scalar_value()))
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: ScalarValue> ToInputValue<S> for Value<S> {
|
||||
|
|
|
@ -53,36 +53,43 @@ pub trait ParseScalarValue<S = DefaultScalarValue> {
|
|||
///
|
||||
/// fn as_int(&self) -> Option<i32> {
|
||||
/// match *self {
|
||||
/// MyScalarValue::Int(ref i) => Some(*i),
|
||||
/// Self::Int(ref i) => Some(*i),
|
||||
/// _ => None,
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn as_string(&self) -> Option<String> {
|
||||
/// match *self {
|
||||
/// MyScalarValue::String(ref s) => Some(s.clone()),
|
||||
/// Self::String(ref s) => Some(s.clone()),
|
||||
/// _ => None,
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn into_string(self) -> Option<String> {
|
||||
/// match self {
|
||||
/// Self::String(s) => Some(s),
|
||||
/// _ => None,
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn as_str(&self) -> Option<&str> {
|
||||
/// match *self {
|
||||
/// MyScalarValue::String(ref s) => Some(s.as_str()),
|
||||
/// Self::String(ref s) => Some(s.as_str()),
|
||||
/// _ => None,
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn as_float(&self) -> Option<f64> {
|
||||
/// match *self {
|
||||
/// MyScalarValue::Int(ref i) => Some(*i as f64),
|
||||
/// MyScalarValue::Float(ref f) => Some(*f),
|
||||
/// Self::Int(ref i) => Some(*i as f64),
|
||||
/// Self::Float(ref f) => Some(*f),
|
||||
/// _ => None,
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn as_boolean(&self) -> Option<bool> {
|
||||
/// match *self {
|
||||
/// MyScalarValue::Boolean(ref b) => Some(*b),
|
||||
/// Self::Boolean(ref b) => Some(*b),
|
||||
/// _ => None,
|
||||
/// }
|
||||
/// }
|
||||
|
@ -175,6 +182,7 @@ pub trait ScalarValue:
|
|||
+ From<bool>
|
||||
+ From<i32>
|
||||
+ From<f64>
|
||||
+ 'static
|
||||
{
|
||||
/// Serde visitor used to deserialize this scalar value
|
||||
type Visitor: for<'de> de::Visitor<'de, Value = Self> + Default;
|
||||
|
@ -205,12 +213,18 @@ pub trait ScalarValue:
|
|||
/// types with 32 bit or less to an integer if requested.
|
||||
fn as_int(&self) -> Option<i32>;
|
||||
|
||||
/// Convert the given scalar value into a string value
|
||||
/// Represents this [`ScalarValue`] a [`String`] value.
|
||||
///
|
||||
/// This function is used for implementing `GraphQLValue` for `String` for all
|
||||
/// scalar values
|
||||
fn as_string(&self) -> Option<String>;
|
||||
|
||||
/// Converts this [`ScalarValue`] into a [`String`] value.
|
||||
///
|
||||
/// Same as [`ScalarValue::as_string`], but takes ownership, so allows to omit redundant
|
||||
/// cloning.
|
||||
fn into_string(self) -> Option<String>;
|
||||
|
||||
/// Convert the given scalar value into a string value
|
||||
///
|
||||
/// This function is used for implementing `GraphQLValue` for `String` for all
|
||||
|
@ -230,6 +244,21 @@ pub trait ScalarValue:
|
|||
/// This function is used for implementing `GraphQLValue` for `bool` for all
|
||||
/// scalar values.
|
||||
fn as_boolean(&self) -> Option<bool>;
|
||||
|
||||
/// Converts this [`ScalarValue`] into another one.
|
||||
fn into_another<S: ScalarValue>(self) -> S {
|
||||
if let Some(i) = self.as_int() {
|
||||
S::from(i)
|
||||
} else if let Some(f) = self.as_float() {
|
||||
S::from(f)
|
||||
} else if let Some(b) = self.as_boolean() {
|
||||
S::from(b)
|
||||
} else if let Some(s) = self.into_string() {
|
||||
S::from(s)
|
||||
} else {
|
||||
unreachable!("`ScalarValue` must represent at least one of the GraphQL spec types")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The default scalar value representation in juniper
|
||||
|
@ -249,44 +278,60 @@ impl ScalarValue for DefaultScalarValue {
|
|||
|
||||
fn as_int(&self) -> Option<i32> {
|
||||
match *self {
|
||||
DefaultScalarValue::Int(ref i) => Some(*i),
|
||||
Self::Int(ref i) => Some(*i),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn as_float(&self) -> Option<f64> {
|
||||
match *self {
|
||||
DefaultScalarValue::Int(ref i) => Some(*i as f64),
|
||||
DefaultScalarValue::Float(ref f) => Some(*f),
|
||||
Self::Int(ref i) => Some(*i as f64),
|
||||
Self::Float(ref f) => Some(*f),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn as_str(&self) -> Option<&str> {
|
||||
match *self {
|
||||
DefaultScalarValue::String(ref s) => Some(s.as_str()),
|
||||
Self::String(ref s) => Some(s.as_str()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn as_string(&self) -> Option<String> {
|
||||
match *self {
|
||||
DefaultScalarValue::String(ref s) => Some(s.clone()),
|
||||
Self::String(ref s) => Some(s.clone()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_string(self) -> Option<String> {
|
||||
match self {
|
||||
Self::String(s) => Some(s),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn as_boolean(&self) -> Option<bool> {
|
||||
match *self {
|
||||
DefaultScalarValue::Boolean(ref b) => Some(*b),
|
||||
Self::Boolean(ref b) => Some(*b),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_another<S: ScalarValue>(self) -> S {
|
||||
match self {
|
||||
Self::Int(i) => S::from(i),
|
||||
Self::Float(f) => S::from(f),
|
||||
Self::String(s) => S::from(s),
|
||||
Self::Boolean(b) => S::from(b),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for DefaultScalarValue {
|
||||
fn from(s: &'a str) -> Self {
|
||||
DefaultScalarValue::String(s.into())
|
||||
Self::String(s.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -481,7 +481,6 @@ pub mod subscriptions {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use actix_web::{dev::ServiceResponse, http, http::header::CONTENT_TYPE, test, App};
|
||||
use juniper::{
|
||||
futures::stream::StreamExt,
|
||||
|
@ -490,6 +489,8 @@ mod tests {
|
|||
EmptyMutation, EmptySubscription, RootNode,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
type Schema =
|
||||
juniper::RootNode<'static, Query, EmptyMutation<Database>, EmptySubscription<Database>>;
|
||||
|
||||
|
@ -713,7 +714,7 @@ mod tests {
|
|||
impl TestActixWebIntegration {
|
||||
fn make_request(&self, req: test::TestRequest) -> TestResponse {
|
||||
actix_web::rt::System::new("request").block_on(async move {
|
||||
let schema = RootNode::new(
|
||||
let schema = Schema::new(
|
||||
Query,
|
||||
EmptyMutation::<Database>::new(),
|
||||
EmptySubscription::<Database>::new(),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use juniper::{
|
||||
graphql_object, DefaultScalarValue, EmptyMutation, EmptySubscription, ExecutionError,
|
||||
FieldError, GraphQLEnum, Value, Variables,
|
||||
FieldError, GraphQLEnum, GraphQLObject, RootNode, Value, Variables,
|
||||
};
|
||||
|
||||
pub type QueryResult = Result<
|
||||
|
@ -37,7 +37,7 @@ pub enum UserKind {
|
|||
Guest,
|
||||
}
|
||||
|
||||
#[derive(juniper::GraphQLObject)]
|
||||
#[derive(GraphQLObject)]
|
||||
pub struct User {
|
||||
pub id: i32,
|
||||
pub kind: UserKind,
|
||||
|
@ -60,7 +60,7 @@ impl User {
|
|||
|
||||
pub struct Query;
|
||||
|
||||
#[graphql_object(Context = Context)]
|
||||
#[graphql_object(context = Context)]
|
||||
impl Query {
|
||||
fn user_sync_instant(id: i32) -> Result<User, FieldError> {
|
||||
Ok(User::new(id))
|
||||
|
@ -89,9 +89,9 @@ impl Query {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new_schema(
|
||||
) -> juniper::RootNode<'static, Query, EmptyMutation<Context>, EmptySubscription<Context>> {
|
||||
juniper::RootNode::new(Query, EmptyMutation::new(), EmptySubscription::new())
|
||||
pub fn new_schema() -> RootNode<'static, Query, EmptyMutation<Context>, EmptySubscription<Context>>
|
||||
{
|
||||
RootNode::new(Query, EmptyMutation::new(), EmptySubscription::new())
|
||||
}
|
||||
|
||||
pub fn execute_sync(query: &str, vars: Variables) -> QueryResult {
|
||||
|
|
|
@ -223,7 +223,7 @@ fn create(
|
|||
.map(SpanContainer::into_inner)
|
||||
.collect(),
|
||||
include_type_generics: false,
|
||||
generic_scalar: false,
|
||||
generic_scalar: true,
|
||||
no_async: _impl.attrs.no_async.is_some(),
|
||||
};
|
||||
|
||||
|
|
|
@ -1232,11 +1232,10 @@ impl GraphQLTypeDefiniton {
|
|||
// No custom scalar specified, but always generic specified.
|
||||
// Therefore we inject the generic scalar.
|
||||
|
||||
generics.params.push(parse_quote!(__S));
|
||||
|
||||
let where_clause = generics.where_clause.get_or_insert(parse_quote!(where));
|
||||
// Insert ScalarValue constraint.
|
||||
where_clause
|
||||
generics.params.push(parse_quote!(__S));
|
||||
generics
|
||||
.make_where_clause()
|
||||
.predicates
|
||||
.push(parse_quote!(__S: ::juniper::ScalarValue));
|
||||
}
|
||||
|
@ -1248,6 +1247,15 @@ impl GraphQLTypeDefiniton {
|
|||
};
|
||||
let (impl_generics, _, where_clause) = generics.split_for_impl();
|
||||
|
||||
let mut generics_with_send_sync = generics.clone();
|
||||
if self.scalar.is_none() && self.generic_scalar {
|
||||
generics_with_send_sync
|
||||
.make_where_clause()
|
||||
.predicates
|
||||
.push(parse_quote!(__S: Send + Sync));
|
||||
}
|
||||
let (_, _, where_clause_with_send_sync) = generics_with_send_sync.split_for_impl();
|
||||
|
||||
let resolve_matches_async = self.fields.iter().filter(|field| field.is_async).map(
|
||||
|field| {
|
||||
let name = &field.name;
|
||||
|
@ -1378,7 +1386,7 @@ impl GraphQLTypeDefiniton {
|
|||
|
||||
let subscription_implementation = quote!(
|
||||
impl#impl_generics ::juniper::GraphQLSubscriptionValue<#scalar> for #ty #type_generics_tokens
|
||||
#where_clause
|
||||
#where_clause_with_send_sync
|
||||
{
|
||||
#[allow(unused_variables)]
|
||||
fn resolve_field_into_stream<
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::env;
|
|||
use iron::prelude::*;
|
||||
use juniper::{
|
||||
tests::fixtures::starwars::schema::{Database, Query},
|
||||
EmptyMutation, EmptySubscription,
|
||||
DefaultScalarValue, EmptyMutation, EmptySubscription,
|
||||
};
|
||||
use juniper_iron::{GraphQLHandler, GraphiQLHandler};
|
||||
use logger::Logger;
|
||||
|
@ -16,7 +16,7 @@ fn context_factory(_: &mut Request) -> IronResult<Database> {
|
|||
fn main() {
|
||||
let mut mount = Mount::new();
|
||||
|
||||
let graphql_endpoint = GraphQLHandler::new(
|
||||
let graphql_endpoint = <GraphQLHandler<_, _, _, _, _, DefaultScalarValue>>::new(
|
||||
context_factory,
|
||||
Query,
|
||||
EmptyMutation::<Database>::new(),
|
||||
|
|
|
@ -34,7 +34,7 @@ use juniper::{Context, EmptyMutation, EmptySubscription};
|
|||
# struct QueryRoot;
|
||||
# struct Database { users: HashMap<String, User> }
|
||||
#
|
||||
# #[juniper::graphql_object( Context = Database )]
|
||||
# #[juniper::graphql_object(context = Database)]
|
||||
# impl User {
|
||||
# fn id(&self) -> FieldResult<&String> {
|
||||
# Ok(&self.id)
|
||||
|
@ -51,7 +51,7 @@ use juniper::{Context, EmptyMutation, EmptySubscription};
|
|||
# }
|
||||
# }
|
||||
#
|
||||
# #[juniper::graphql_object( Context = Database )]
|
||||
# #[juniper::graphql_object(context = Database, scalar = juniper::DefaultScalarValue)]
|
||||
# impl QueryRoot {
|
||||
# fn user(context: &Database, id: String) -> FieldResult<Option<&User>> {
|
||||
# Ok(executor.context().users.get(&id))
|
||||
|
@ -220,7 +220,7 @@ where
|
|||
) -> Self {
|
||||
GraphQLHandler {
|
||||
context_factory,
|
||||
root_node: RootNode::new(query, mutation, subscription),
|
||||
root_node: RootNode::new_with_scalar_value(query, mutation, subscription),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -412,7 +412,7 @@ mod tests {
|
|||
use juniper::{
|
||||
http::tests as http_tests,
|
||||
tests::fixtures::starwars::schema::{Database, Query},
|
||||
EmptyMutation, EmptySubscription,
|
||||
DefaultScalarValue, EmptyMutation, EmptySubscription,
|
||||
};
|
||||
|
||||
use super::GraphQLHandler;
|
||||
|
@ -511,7 +511,7 @@ mod tests {
|
|||
}
|
||||
|
||||
fn make_handler() -> Box<dyn Handler> {
|
||||
Box::new(GraphQLHandler::new(
|
||||
Box::new(<GraphQLHandler<_, _, _, _, _, DefaultScalarValue>>::new(
|
||||
context_factory,
|
||||
Query,
|
||||
EmptyMutation::<Database>::new(),
|
||||
|
|
|
@ -64,7 +64,7 @@ use warp::{body, filters::BoxedFilter, http, query, Filter};
|
|||
/// ```
|
||||
/// # use std::sync::Arc;
|
||||
/// # use warp::Filter;
|
||||
/// # use juniper::{EmptyMutation, EmptySubscription, RootNode};
|
||||
/// # use juniper::{graphql_object, EmptyMutation, EmptySubscription, RootNode};
|
||||
/// # use juniper_warp::make_graphql_filter;
|
||||
/// #
|
||||
/// type UserId = String;
|
||||
|
@ -74,9 +74,7 @@ use warp::{body, filters::BoxedFilter, http, query, Filter};
|
|||
///
|
||||
/// struct QueryRoot;
|
||||
///
|
||||
/// #[juniper::graphql_object(
|
||||
/// Context = ExampleContext
|
||||
/// )]
|
||||
/// #[graphql_object(context = ExampleContext)]
|
||||
/// impl QueryRoot {
|
||||
/// fn say_hello(context: &ExampleContext) -> String {
|
||||
/// format!(
|
||||
|
@ -683,18 +681,18 @@ mod tests {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests_http_harness {
|
||||
use super::*;
|
||||
use juniper::{
|
||||
http::tests::{run_http_test_suite, HttpIntegration, TestResponse},
|
||||
tests::fixtures::starwars::schema::{Database, Query},
|
||||
EmptyMutation, EmptySubscription, RootNode,
|
||||
};
|
||||
use warp::{
|
||||
self,
|
||||
filters::{path, BoxedFilter},
|
||||
Filter,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
struct TestWarpIntegration {
|
||||
filter: BoxedFilter<(http::Response<Vec<u8>>,)>,
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue