Improve description and fix some test errors
This commit is contained in:
parent
9bd9727cb2
commit
dfda435bc7
2 changed files with 26 additions and 21 deletions
|
@ -59,8 +59,7 @@ struct User {
|
||||||
// Assign Database as the context type for User
|
// Assign Database as the context type for User
|
||||||
#[graphql_object(context = Database)]
|
#[graphql_object(context = Database)]
|
||||||
impl User {
|
impl User {
|
||||||
// Inject the context by specifying an argument
|
// Inject the context by specifying an argument with the context type.
|
||||||
// with the context type.
|
|
||||||
// Note:
|
// Note:
|
||||||
// - the type must be a reference
|
// - the type must be a reference
|
||||||
// - the name of the argument SHOULD be `context`
|
// - the name of the argument SHOULD be `context`
|
||||||
|
@ -86,20 +85,26 @@ impl User {
|
||||||
You only get an immutable reference to the context, so if you want to affect
|
You only get an immutable reference to the context, so if you want to affect
|
||||||
change to the execution, you'll need to use [interior
|
change to the execution, you'll need to use [interior
|
||||||
mutability](https://doc.rust-lang.org/book/first-edition/mutability.html#interior-vs-exterior-mutability)
|
mutability](https://doc.rust-lang.org/book/first-edition/mutability.html#interior-vs-exterior-mutability)
|
||||||
using e.g. `RwLock` or `RefCell`. \
|
using e.g. `RwLock` or `RefCell`.
|
||||||
If you are using async runtime like `tokio` for mutable references you will need to use a corresponding async version of RwLock:
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Dealing with mutable references
|
||||||
|
|
||||||
|
Context cannot be specified by a mutable reference, because concurrent fields resolving may be performed. If you have something in your context that requires access by mutable reference, then you need to leverage the [interior mutability][1] for that.
|
||||||
|
|
||||||
|
For example, when using async runtime with [work stealing][2] (like `tokio`), which obviously requires thread safety in addition, you will need to use a corresponding async version of `RwLock`:
|
||||||
```rust
|
```rust
|
||||||
# extern crate juniper;
|
# extern crate juniper;
|
||||||
# use std::collections::HashMap;
|
# use std::collections::HashMap;
|
||||||
# use juniper::graphql_object;
|
# use juniper::graphql_object;
|
||||||
# use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
#
|
|
||||||
// This struct represents our context.
|
|
||||||
struct Database {
|
struct Database {
|
||||||
requested_count: HashMap<i32, i32>,
|
requested_count: HashMap<i32, i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark the Database as a valid context type for Juniper
|
|
||||||
impl juniper::Context for Database {}
|
impl juniper::Context for Database {}
|
||||||
|
|
||||||
struct User {
|
struct User {
|
||||||
|
@ -108,21 +113,15 @@ struct User {
|
||||||
times_requested: i32,
|
times_requested: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign Database as the context type for User and envelope it in RwLock
|
|
||||||
#[graphql_object(context = RwLock<Database>)]
|
#[graphql_object(context = RwLock<Database>)]
|
||||||
impl User {
|
impl User {
|
||||||
// Inject the context by specifying an argument
|
async fn times_requested<'db>(&self, context: &'db RwLock<Database>) -> Vec<&'db User> {
|
||||||
// with the context type.
|
|
||||||
// Note:
|
|
||||||
// - the type must be a reference
|
|
||||||
// - the name of the argument SHOULD be `context`
|
|
||||||
fn times_requested<'db>(&self, context: &'db RwLock<Database>) -> Vec<&'db User> {
|
|
||||||
// Acquire a mutable reference and await if async RwLock is used,
|
// Acquire a mutable reference and await if async RwLock is used,
|
||||||
// which is neccessary if context consists async operations
|
// which is necessary if context consists async operations like
|
||||||
// like querying remote databases
|
// querying remote databases.
|
||||||
// If context is immutable use .read() on RwLock
|
// If context is immutable use .read() on RwLock.
|
||||||
let mut context = context.write().await;
|
let mut context = context.write().await;
|
||||||
// Preform a mutable operation
|
// Preform a mutable operation.
|
||||||
context.requested_count.entry(self.id).and_modify(|e| { *e += 1 }).or_insert(1)
|
context.requested_count.entry(self.id).and_modify(|e| { *e += 1 }).or_insert(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,4 +136,10 @@ impl User {
|
||||||
#
|
#
|
||||||
# fn main() { }
|
# fn main() { }
|
||||||
```
|
```
|
||||||
Replace `tokio::sync::RwLock` with `std::sync::RwLock` if async runtime is not intended
|
Replace `tokio::sync::RwLock` with `std::sync::RwLock` (or similar) if you don't intend to use async resolving.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[1]: https://doc.rust-lang.org/book/ch15-05-interior-mutability.html
|
||||||
|
[2]: https://en.wikipedia.org/wiki/Work_stealing
|
||||||
|
|
|
@ -16,7 +16,7 @@ iron = "0.5"
|
||||||
mount = "0.4"
|
mount = "0.4"
|
||||||
skeptic = "0.13"
|
skeptic = "0.13"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
|
tokio = { version = "1", features = ["macros", "rt-multi-thread", "sync"] }
|
||||||
uuid = "0.8"
|
uuid = "0.8"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
|
Loading…
Reference in a new issue