-
Notifications
You must be signed in to change notification settings - Fork 280
/
Copy pathtraits.rs
97 lines (85 loc) · 3.29 KB
/
traits.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use crate::prelude::graphql::*;
use async_trait::async_trait;
use std::fmt::Debug;
use std::sync::Arc;
/// A cache resolution trait.
///
/// Clients of CachingMap are required to provider a resolver during Map creation. The resolver
/// will be used to find values for cache misses. A Result is expected, because retrieval may fail.
#[async_trait]
pub trait CacheResolver<K, V> {
async fn retrieve(&self, key: K) -> Result<V, CacheResolverError>;
}
/// A planner key.
///
/// This type consists of a query string, an optional operation string and the
/// [`QueryPlanOptions`].
pub(crate) type QueryKey = (String, Option<String>, QueryPlanOptions);
/// Maintains a map of services to fetchers.
pub trait ServiceRegistry: Send + Sync + Debug {
/// Get a fetcher for a service.
fn get(&self, service: &str) -> Option<&(dyn Fetcher)>;
/// Get a fetcher for a service.
fn has(&self, service: &str) -> bool;
}
/// A fetcher is responsible for turning a graphql request into a stream of responses.
///
/// The goal of this trait is to hide the implementation details of fetching a stream of graphql responses.
/// We can then create multiple implementations that can be plugged into federation.
#[async_trait]
pub trait Fetcher: Send + Sync + Debug {
/// Constructs a stream of responses.
#[must_use = "streams do nothing unless polled"]
async fn stream(&self, request: Request) -> ResponseStream;
}
/// QueryPlanner can be used to plan queries.
///
/// Implementations may cache query plans.
#[async_trait]
pub trait QueryPlanner: Send + Sync + Debug {
/// Returns a query plan given the query, operation and options.
/// Implementations may cache query plans.
#[must_use = "query plan result must be used"]
async fn get(
&self,
query: String,
operation: Option<String>,
options: QueryPlanOptions,
) -> Result<Arc<QueryPlan>, QueryPlannerError>;
}
/// With caching trait.
///
/// Adds with_caching to any query planner.
pub trait WithCaching: QueryPlanner
where
Self: Sized + QueryPlanner + 'static,
{
/// Wrap this query planner in a caching decorator.
/// The original query planner is consumed.
fn with_caching(self, plan_cache_limit: usize) -> CachingQueryPlanner<Self> {
CachingQueryPlanner::new(self, plan_cache_limit)
}
}
impl<T: ?Sized> WithCaching for T where T: QueryPlanner + Sized + 'static {}
/// An object that accepts a [`Request`] and allow creating [`PreparedQuery`]'s.
///
/// The call to the function will either succeeds and return a [`PreparedQuery`] or it will fail and return
/// a [`ResponseStream`] that can be returned immediately to the user. This is because GraphQL does
/// not use the HTTP error codes, therefore it always return a response even if it fails.
#[async_trait::async_trait]
pub trait Router<T: PreparedQuery>: Send + Sync + Debug {
async fn prepare_query(&self, request: &Request) -> Result<T, ResponseStream>;
}
/// An object that can be executed to return a [`ResponseStream`].
#[async_trait::async_trait]
pub trait PreparedQuery: Send + Debug {
async fn execute(self, request: Arc<Request>) -> ResponseStream;
}
#[cfg(test)]
mod tests {
use super::*;
use static_assertions::*;
assert_obj_safe!(ServiceRegistry);
assert_obj_safe!(Fetcher);
assert_obj_safe!(QueryPlanner);
}