Skip to content

Commit 8d27055

Browse files
esseswannLegNeato
authored andcommitted
Added async mutable context example
1 parent 7ba7585 commit 8d27055

File tree

1 file changed

+54
-4
lines changed

1 file changed

+54
-4
lines changed

docs/book/content/types/objects/using_contexts.md

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,13 @@ struct User {
5959
// Assign Database as the context type for User
6060
#[graphql_object(context = Database)]
6161
impl User {
62-
// 3. Inject the context by specifying an argument
62+
// Inject the context by specifying an argument
6363
// with the context type.
6464
// Note:
6565
// - the type must be a reference
6666
// - the name of the argument SHOULD be `context`
6767
fn friends<'db>(&self, context: &'db Database) -> Vec<&'db User> {
68-
69-
// 5. Use the database to lookup users
68+
// Use the database to lookup users
7069
self.friend_ids.iter()
7170
.map(|id| context.users.get(id).expect("Could not find user with ID"))
7271
.collect()
@@ -87,4 +86,55 @@ impl User {
8786
You only get an immutable reference to the context, so if you want to affect
8887
change to the execution, you'll need to use [interior
8988
mutability](https://doc.rust-lang.org/book/first-edition/mutability.html#interior-vs-exterior-mutability)
90-
using e.g. `RwLock` or `RefCell`.
89+
using e.g. `RwLock` or `RefCell`. \
90+
If you are using async runtime like `tokio` for mutable references you will need to use a corresponding async version of RwLock:
91+
```rust
92+
# extern crate juniper;
93+
# use std::collections::HashMap;
94+
# use juniper::graphql_object;
95+
# use tokio::sync::RwLock;
96+
#
97+
// This struct represents our context.
98+
struct Database {
99+
requested_count: HashMap<i32, i32>,
100+
}
101+
102+
// Mark the Database as a valid context type for Juniper
103+
impl juniper::Context for Database {}
104+
105+
struct User {
106+
id: i32,
107+
name: String,
108+
times_requested: i32,
109+
}
110+
111+
// Assign Database as the context type for User and envelope it in RwLock
112+
#[graphql_object(context = RwLock<Database>)]
113+
impl User {
114+
// Inject the context by specifying an argument
115+
// with the context type.
116+
// Note:
117+
// - the type must be a reference
118+
// - the name of the argument SHOULD be `context`
119+
fn times_requested<'db>(&self, context: &'db RwLock<Database>) -> Vec<&'db User> {
120+
// Acquire a mutable reference and await if async RwLock is used,
121+
// which is neccessary if context consists async operations
122+
// like querying remote databases
123+
// If context is immutable use .read() on RwLock
124+
let mut context = context.write().await;
125+
// Preform a mutable operation
126+
context.requested_count.entry(0).and_modify(|e| { *e += 1 }).or_insert(1)
127+
}
128+
129+
fn name(&self) -> &str {
130+
self.name.as_str()
131+
}
132+
133+
fn id(&self) -> i32 {
134+
self.id
135+
}
136+
}
137+
#
138+
# fn main() { }
139+
```
140+
Replace `tokio::sync::RwLock` with `std::sync::RwLock` if async runtime is not intended

0 commit comments

Comments
 (0)