1use std::sync::Arc;
7use std::time::Instant;
8
9use apollo_compiler::ExecutableDocument;
10use apollo_compiler::validation::Valid;
11use dashmap::DashMap;
12use dashmap::mapref::multiple::RefMulti;
13use dashmap::mapref::multiple::RefMutMulti;
14use derivative::Derivative;
15use extensions::sync::ExtensionsMutex;
16use serde::Deserialize;
17use serde::Serialize;
18use tower::BoxError;
19
20use crate::json_ext::Value;
21use crate::services::layers::query_analysis::ParsedDocument;
22
23pub(crate) mod deprecated;
24pub(crate) mod extensions;
25
26pub(crate) const OPERATION_NAME: &str = "apollo::supergraph::operation_name";
28pub(crate) const OPERATION_KIND: &str = "apollo::supergraph::operation_kind";
30pub(crate) const CONTAINS_GRAPHQL_ERROR: &str = "apollo::telemetry::contains_graphql_error";
32pub(crate) const COUNTED_ERRORS: &str = "apollo::telemetry::counted_errors";
35pub(crate) const ROUTER_RESPONSE_ERRORS: &str = "apollo::router::response_errors";
39
40pub(crate) use deprecated::context_key_from_deprecated;
41pub(crate) use deprecated::context_key_to_deprecated;
42
43pub(crate) type Entries = Arc<DashMap<String, Value>>;
45
46#[derive(Clone, Deserialize, Serialize, Derivative)]
58#[serde(default)]
59#[derivative(Debug)]
60pub struct Context {
61 entries: Entries,
63
64 #[serde(skip)]
65 extensions: ExtensionsMutex,
66
67 #[serde(skip)]
69 pub(crate) created_at: Instant,
70
71 #[serde(skip)]
72 pub(crate) id: String,
73}
74
75impl Context {
76 pub fn new() -> Self {
78 let id = uuid::Uuid::new_v4()
79 .as_hyphenated()
80 .encode_lower(&mut uuid::Uuid::encode_buffer())
81 .to_string();
82 Context {
83 entries: Default::default(),
84 extensions: ExtensionsMutex::default(),
85 created_at: Instant::now(),
86 id,
87 }
88 }
89}
90
91impl FromIterator<(String, Value)> for Context {
92 fn from_iter<T: IntoIterator<Item = (String, Value)>>(iter: T) -> Self {
93 Self {
94 entries: Arc::new(DashMap::from_iter(iter)),
95 extensions: ExtensionsMutex::default(),
96 created_at: Instant::now(),
97 id: String::new(),
98 }
99 }
100}
101
102impl Context {
103 pub fn extensions(&self) -> &ExtensionsMutex {
112 &self.extensions
113 }
114
115 pub fn contains_key<K>(&self, key: K) -> bool
117 where
118 K: Into<String>,
119 {
120 self.entries.contains_key(&key.into())
121 }
122
123 pub fn get<K, V>(&self, key: K) -> Result<Option<V>, BoxError>
129 where
130 K: Into<String>,
131 V: for<'de> serde::Deserialize<'de>,
132 {
133 self.entries
134 .get(&key.into())
135 .map(|v| serde_json_bytes::from_value(v.value().clone()))
136 .transpose()
137 .map_err(|e| e.into())
138 }
139
140 pub fn insert<K, V>(&self, key: K, value: V) -> Result<Option<V>, BoxError>
146 where
147 K: Into<String>,
148 V: for<'de> serde::Deserialize<'de> + Serialize,
149 {
150 match serde_json_bytes::to_value(value) {
151 Ok(value) => self
152 .entries
153 .insert(key.into(), value)
154 .map(|v| serde_json_bytes::from_value(v))
155 .transpose()
156 .map_err(|e| e.into()),
157 Err(e) => Err(e.into()),
158 }
159 }
160
161 pub fn insert_json_value<K>(&self, key: K, value: Value) -> Option<Value>
165 where
166 K: Into<String>,
167 {
168 self.entries.insert(key.into(), value)
169 }
170
171 pub fn get_json_value<K>(&self, key: K) -> Option<Value>
173 where
174 K: Into<String>,
175 {
176 self.entries.get(&key.into()).map(|v| v.value().clone())
177 }
178
179 pub fn upsert<K, V>(&self, key: K, upsert: impl FnOnce(V) -> V) -> Result<(), BoxError>
192 where
193 K: Into<String>,
194 V: for<'de> serde::Deserialize<'de> + Serialize + Default,
195 {
196 let key = key.into();
197 self.entries
198 .entry(key.clone())
199 .or_try_insert_with(|| serde_json_bytes::to_value::<V>(Default::default()))?;
200 let mut result = Ok(());
201 self.entries
202 .alter(&key, |_, v| match serde_json_bytes::from_value(v.clone()) {
203 Ok(value) => match serde_json_bytes::to_value((upsert)(value)) {
204 Ok(value) => value,
205 Err(e) => {
206 result = Err(e);
207 v
208 }
209 },
210 Err(e) => {
211 result = Err(e);
212 v
213 }
214 });
215 result.map_err(|e| e.into())
216 }
217
218 pub(crate) fn upsert_json_value<K>(&self, key: K, upsert: impl FnOnce(Value) -> Value)
225 where
226 K: Into<String>,
227 {
228 let key = key.into();
229 self.entries.entry(key.clone()).or_insert(Value::Null);
230 self.entries.alter(&key, |_, v| upsert(v));
231 }
232
233 pub(crate) fn try_into_iter(
235 self,
236 ) -> Result<impl IntoIterator<Item = (String, Value)>, BoxError> {
237 Ok(Arc::try_unwrap(self.entries)
238 .map_err(|_e| anyhow::anyhow!("cannot take ownership of dashmap"))?
239 .into_iter())
240 }
241
242 pub fn iter(&self) -> impl Iterator<Item = RefMulti<'_, String, Value>> + '_ {
244 self.entries.iter()
245 }
246
247 pub fn iter_mut(&self) -> impl Iterator<Item = RefMutMulti<'_, String, Value>> + '_ {
249 self.entries.iter_mut()
250 }
251
252 pub(crate) fn extend(&self, other: &Context) {
253 for kv in other.entries.iter() {
254 self.entries.insert(kv.key().clone(), kv.value().clone());
255 }
256 }
257
258 pub(crate) fn retain(&self, f: impl Fn(&String, &Value) -> bool) {
259 self.entries.retain(|k, v| f(k, v));
260 }
261
262 pub(crate) fn len(&self) -> usize {
263 self.entries.len()
264 }
265
266 pub(crate) fn executable_document(&self) -> Option<Arc<Valid<ExecutableDocument>>> {
268 self.extensions()
269 .with_lock(|lock| lock.get::<ParsedDocument>().map(|d| d.executable.clone()))
270 }
271}
272
273impl Default for Context {
274 fn default() -> Self {
275 Self::new()
276 }
277}
278
279#[cfg(test)]
280mod test {
281 use crate::Configuration;
282 use crate::Context;
283 use crate::spec::Query;
284 use crate::spec::Schema;
285
286 #[test]
287 fn test_context_insert() {
288 let c = Context::new();
289 assert!(c.insert("key1", 1).is_ok());
290 assert_eq!(c.get("key1").unwrap(), Some(1));
291 }
292
293 #[test]
294 fn test_context_overwrite() {
295 let c = Context::new();
296 assert!(c.insert("overwrite", 2).is_ok());
297 assert!(c.insert("overwrite", 3).is_ok());
298 assert_eq!(c.get("overwrite").unwrap(), Some(3));
299 }
300
301 #[test]
302 fn test_context_upsert() {
303 let c = Context::new();
304 assert!(c.insert("present", 1).is_ok());
305 assert!(c.upsert("present", |v: usize| v + 1).is_ok());
306 assert_eq!(c.get("present").unwrap(), Some(2));
307 assert!(c.upsert("not_present", |v: usize| v + 1).is_ok());
308 assert_eq!(c.get("not_present").unwrap(), Some(1));
309 }
310
311 #[test]
312 fn test_context_marshall_errors() {
313 let c = Context::new();
314 assert!(c.insert("string", "Some value".to_string()).is_ok());
315 assert!(c.upsert("string", |v: usize| v + 1).is_err());
316 }
317
318 #[test]
319 fn it_iterates_over_context() {
320 let c = Context::new();
321 assert!(c.insert("one", 1).is_ok());
322 assert!(c.insert("two", 2).is_ok());
323 assert_eq!(c.iter().count(), 2);
324 assert_eq!(
325 c.iter()
326 .map(|r| serde_json_bytes::from_value::<usize>(r.value().clone()).unwrap())
328 .sum::<usize>(),
329 3
330 );
331 }
332
333 #[test]
334 fn it_iterates_mutably_over_context() {
335 let c = Context::new();
336 assert!(c.insert("one", 1usize).is_ok());
337 assert!(c.insert("two", 2usize).is_ok());
338 assert_eq!(c.iter().count(), 2);
339 c.iter_mut().for_each(|mut r| {
340 let new: usize = serde_json_bytes::from_value::<usize>(r.value().clone()).unwrap() + 1;
342 *r = new.into();
343 });
344 assert_eq!(c.get("one").unwrap(), Some(2));
345 assert_eq!(c.get("two").unwrap(), Some(3));
346 }
347
348 #[test]
349 fn context_extensions() {
350 let c = Context::new();
352 c.extensions().with_lock(|lock| lock.insert(1usize));
353 let v = c
354 .extensions()
355 .with_lock(|lock| lock.get::<usize>().cloned());
356 assert_eq!(v, Some(1usize));
357 }
358
359 #[test]
360 fn test_executable_document_access() {
361 let c = Context::new();
362 let schema = include_str!("../testdata/minimal_supergraph.graphql");
363 let schema = Schema::parse(schema, &Default::default()).unwrap();
364 let document =
365 Query::parse_document("{ me }", None, &schema, &Configuration::default()).unwrap();
366 assert!(c.executable_document().is_none());
367 c.extensions().with_lock(|lock| lock.insert(document));
368 assert!(c.executable_document().is_some());
369 }
370}