diff --git a/benches/impl_path_string_for_evaluation_context.rs b/benches/impl_path_string_for_evaluation_context.rs index aedfcd3d22..111359ac53 100644 --- a/benches/impl_path_string_for_evaluation_context.rs +++ b/benches/impl_path_string_for_evaluation_context.rs @@ -174,24 +174,24 @@ fn to_bench_id(input: &[&str]) -> BenchmarkId { #[derive(Clone)] struct MockGraphqlContext; -impl<'a> ResolverContextLike<'a> for MockGraphqlContext { - fn value(&'a self) -> Option<&'a Value> { +impl ResolverContextLike for MockGraphqlContext { + fn value(&self) -> Option<&Value> { Some(&TEST_VALUES) } - fn args(&'a self) -> Option<&'a IndexMap> { + fn args(&self) -> Option<&IndexMap> { Some(&TEST_ARGS) } - fn field(&'a self) -> Option { + fn field(&self) -> Option { None } - fn is_query(&'a self) -> bool { + fn is_query(&self) -> bool { false } - fn add_error(&'a self, _: async_graphql::ServerError) {} + fn add_error(&self, _: async_graphql::ServerError) {} } // assert that everything was set up correctly for the benchmark diff --git a/src/core/blueprint/into_schema.rs b/src/core/blueprint/into_schema.rs index 45eab366d6..ed225f844c 100644 --- a/src/core/blueprint/into_schema.rs +++ b/src/core/blueprint/into_schema.rs @@ -94,10 +94,12 @@ fn to_type(def: &Definition) -> dynamic::Type { FieldFuture::new( async move { let ctx: ResolverContext = ctx.into(); - let ctx = EvaluationContext::new(req_ctx, &ctx); + let mut ctx = EvaluationContext::new(req_ctx, &ctx); - let const_value = - expr.eval(ctx).await.map_err(|err| err.extend())?; + let const_value = expr + .eval(&mut ctx) + .await + .map_err(|err| err.extend())?; let p = match const_value { ConstValue::List(a) => Some(FieldValue::list(a)), ConstValue::Null => FieldValue::NONE, diff --git a/src/core/has_headers.rs b/src/core/has_headers.rs index e285caabf3..25c6d44d76 100644 --- a/src/core/has_headers.rs +++ b/src/core/has_headers.rs @@ -6,7 +6,7 @@ pub trait HasHeaders { fn headers(&self) -> &HeaderMap; } -impl<'a, Ctx: ResolverContextLike<'a>> HasHeaders for EvaluationContext<'a, Ctx> { +impl<'a, Ctx: ResolverContextLike> HasHeaders for EvaluationContext<'a, Ctx> { fn headers(&self) -> &HeaderMap { self.headers() } diff --git a/src/core/ir/cache.rs b/src/core/ir/cache.rs index c139c60146..aec7a3bd4c 100644 --- a/src/core/ir/cache.rs +++ b/src/core/ir/cache.rs @@ -1,7 +1,5 @@ -use core::future::Future; use std::num::NonZeroU64; use std::ops::Deref; -use std::pin::Pin; use async_graphql_value::ConstValue; @@ -42,31 +40,32 @@ impl Cache { } impl Eval for Cache { - fn eval<'a, Ctx: ResolverContextLike<'a> + Sync + Send>( - &'a self, - ctx: EvaluationContext<'a, Ctx>, - ) -> Pin> + 'a + Send>> { - Box::pin(async move { - if let IR::IO(io) = self.expr.deref() { - let key = io.cache_key(&ctx); - if let Some(key) = key { - if let Some(val) = ctx.request_ctx.runtime.cache.get(&key).await? { - Ok(val) - } else { - let val = self.expr.eval(ctx.clone()).await?; - ctx.request_ctx - .runtime - .cache - .set(key, val.clone(), self.max_age) - .await?; - Ok(val) - } + async fn eval( + &self, + ctx: &mut EvaluationContext<'_, Ctx>, + ) -> Result + where + Ctx: ResolverContextLike + Sync, + { + if let IR::IO(io) = self.expr.deref() { + let key = io.cache_key(ctx); + if let Some(key) = key { + if let Some(val) = ctx.request_ctx.runtime.cache.get(&key).await? { + Ok(val) } else { - self.expr.eval(ctx).await + let val = self.expr.eval(ctx).await?; + ctx.request_ctx + .runtime + .cache + .set(key, val.clone(), self.max_age) + .await?; + Ok(val) } } else { - Ok(self.expr.eval(ctx).await?) + self.expr.eval(ctx).await } - }) + } else { + Ok(self.expr.eval(ctx).await?) + } } } diff --git a/src/core/ir/eval.rs b/src/core/ir/eval.rs index a1b16985b2..469a7c8df1 100644 --- a/src/core/ir/eval.rs +++ b/src/core/ir/eval.rs @@ -1,16 +1,12 @@ -use core::future::Future; -use std::pin::Pin; +use std::future::Future; use super::{EvaluationContext, EvaluationError, ResolverContextLike}; -pub trait Eval -where - Self: Send + Sync, -{ - fn eval<'a, Ctx: ResolverContextLike<'a> + Sync + Send>( - &'a self, - ctx: EvaluationContext<'a, Ctx>, - ) -> Pin> + 'a + Send>> +pub trait Eval { + fn eval( + &self, + ctx: &mut EvaluationContext<'_, Ctx>, + ) -> impl Future> where - Output: 'a; + Ctx: ResolverContextLike + Sync; } diff --git a/src/core/ir/evaluation_context.rs b/src/core/ir/evaluation_context.rs index 04f9f6a1bc..0cb35f9e8a 100644 --- a/src/core/ir/evaluation_context.rs +++ b/src/core/ir/evaluation_context.rs @@ -10,7 +10,7 @@ use crate::core::http::RequestContext; // TODO: rename to ResolverContext #[derive(Clone)] -pub struct EvaluationContext<'a, Ctx: ResolverContextLike<'a>> { +pub struct EvaluationContext<'a, Ctx: ResolverContextLike> { // Context create for each GraphQL Request pub request_ctx: &'a RequestContext, @@ -25,7 +25,7 @@ pub struct EvaluationContext<'a, Ctx: ResolverContextLike<'a>> { graphql_ctx_args: Option>, } -impl<'a, A: ResolverContextLike<'a>> EvaluationContext<'a, A> { +impl<'a, A: ResolverContextLike> EvaluationContext<'a, A> { pub fn with_value(&self, value: Value) -> EvaluationContext<'a, A> { let mut ctx = self.clone(); ctx.graphql_ctx_value = Some(Arc::new(value)); @@ -43,7 +43,7 @@ impl<'a, A: ResolverContextLike<'a>> EvaluationContext<'a, A> { } } -impl<'a, Ctx: ResolverContextLike<'a>> EvaluationContext<'a, Ctx> { +impl<'a, Ctx: ResolverContextLike> EvaluationContext<'a, Ctx> { pub fn new(req_ctx: &'a RequestContext, graphql_ctx: &'a Ctx) -> EvaluationContext<'a, Ctx> { Self { request_ctx: req_ctx, @@ -109,7 +109,7 @@ impl<'a, Ctx: ResolverContextLike<'a>> EvaluationContext<'a, Ctx> { } } -impl<'a, Ctx: ResolverContextLike<'a>> GraphQLOperationContext for EvaluationContext<'a, Ctx> { +impl<'a, Ctx: ResolverContextLike> GraphQLOperationContext for EvaluationContext<'a, Ctx> { fn selection_set(&self) -> Option { let selection_set = self.graphql_ctx.field()?.selection_set(); diff --git a/src/core/ir/io.rs b/src/core/ir/io.rs index 0f8930e197..5a8f24ebd8 100644 --- a/src/core/ir/io.rs +++ b/src/core/ir/io.rs @@ -1,5 +1,3 @@ -use core::future::Future; -use std::pin::Pin; use std::sync::Arc; use async_graphql::from_value; @@ -60,111 +58,112 @@ impl DataLoaderId { } impl Eval for IO { - fn eval<'a, Ctx: super::ResolverContextLike<'a> + Sync + Send>( - &'a self, - ctx: super::EvaluationContext<'a, Ctx>, - ) -> Pin> + 'a + Send>> { + async fn eval( + &self, + ctx: &mut EvaluationContext<'_, Ctx>, + ) -> Result + where + Ctx: ResolverContextLike + Sync, + { // Note: Handled the case separately for performance reasons. It avoids cache // key generation when it's not required if !ctx.request_ctx.server.dedupe || !ctx.is_query() { - return self.eval_inner(ctx); + return self.eval_inner(ctx).await; } - if let Some(key) = self.cache_key(&ctx) { - Box::pin(async move { - ctx.request_ctx - .cache - .dedupe(&key, || async { - ctx.request_ctx - .dedupe_handler - .dedupe(&key, || self.eval_inner(ctx)) - .await - }) - .await - }) + if let Some(key) = self.cache_key(ctx) { + ctx.request_ctx + .cache + .dedupe(&key, || async { + ctx.request_ctx + .dedupe_handler + .dedupe(&key, || self.eval_inner(ctx)) + .await + }) + .await } else { - self.eval_inner(ctx) + self.eval_inner(ctx).await } } } impl IO { - fn eval_inner<'a, Ctx: super::ResolverContextLike<'a> + Sync + Send>( - &'a self, - ctx: super::EvaluationContext<'a, Ctx>, - ) -> Pin> + 'a + Send>> { - Box::pin(async move { - match self { - IO::Http { req_template, dl_id, http_filter, .. } => { - let worker = &ctx.request_ctx.runtime.cmd_worker; - let executor = HttpRequestExecutor::new(ctx, req_template, dl_id); - let request = executor.init_request()?; - let response = match (&worker, http_filter) { - (Some(worker), Some(http_filter)) => { - executor - .execute_with_worker(request, worker, http_filter) - .await? - } - _ => executor.execute(request).await?, - }; - - Ok(response.body) - } - IO::GraphQL { req_template, field_name, dl_id, .. } => { - let req = req_template.to_request(&ctx)?; - - let res = if ctx.request_ctx.upstream.batch.is_some() - && matches!(req_template.operation_type, GraphQLOperationType::Query) - { - let data_loader: Option<&DataLoader> = - dl_id.and_then(|index| ctx.request_ctx.gql_data_loaders.get(index.0)); - execute_request_with_dl(&ctx, req, data_loader).await? - } else { - execute_raw_request(&ctx, req).await? - }; + async fn eval_inner( + &self, + ctx: &mut EvaluationContext<'_, Ctx>, + ) -> Result + where + Ctx: ResolverContextLike + Sync, + { + match self { + IO::Http { req_template, dl_id, http_filter, .. } => { + let worker = &ctx.request_ctx.runtime.cmd_worker; + let executor = HttpRequestExecutor::new(ctx, req_template, dl_id); + let request = executor.init_request()?; + let response = match (&worker, http_filter) { + (Some(worker), Some(http_filter)) => { + executor + .execute_with_worker(request, worker, http_filter) + .await? + } + _ => executor.execute(request).await?, + }; - set_headers(&ctx, &res); - parse_graphql_response(&ctx, res, field_name) - } - IO::Grpc { req_template, dl_id, .. } => { - let rendered = req_template.render(&ctx)?; + Ok(response.body) + } + IO::GraphQL { req_template, field_name, dl_id, .. } => { + let req = req_template.to_request(ctx)?; + + let res = if ctx.request_ctx.upstream.batch.is_some() + && matches!(req_template.operation_type, GraphQLOperationType::Query) + { + let data_loader: Option<&DataLoader> = + dl_id.and_then(|index| ctx.request_ctx.gql_data_loaders.get(index.0)); + execute_request_with_dl(ctx, req, data_loader).await? + } else { + execute_raw_request(ctx, req).await? + }; + + set_headers(ctx, &res); + parse_graphql_response(ctx, res, field_name) + } + IO::Grpc { req_template, dl_id, .. } => { + let rendered = req_template.render(ctx)?; - let res = if ctx.request_ctx.upstream.batch.is_some() && + let res = if ctx.request_ctx.upstream.batch.is_some() && // TODO: share check for operation_type for resolvers matches!(req_template.operation_type, GraphQLOperationType::Query) - { - let data_loader: Option< - &DataLoader, - > = dl_id.and_then(|index| ctx.request_ctx.grpc_data_loaders.get(index.0)); - execute_grpc_request_with_dl(&ctx, rendered, data_loader).await? - } else { - let req = rendered.to_request()?; - execute_raw_grpc_request(&ctx, req, &req_template.operation).await? - }; - - set_headers(&ctx, &res); - - Ok(res.body) - } - IO::Js { name } => { - if let Some((worker, value)) = ctx - .request_ctx - .runtime - .worker - .as_ref() - .zip(ctx.value().cloned()) - { - let val = worker.call(name, value).await?; - Ok(val.unwrap_or_default()) - } else { - Ok(ConstValue::Null) - } + { + let data_loader: Option<&DataLoader> = + dl_id.and_then(|index| ctx.request_ctx.grpc_data_loaders.get(index.0)); + execute_grpc_request_with_dl(ctx, rendered, data_loader).await? + } else { + let req = rendered.to_request()?; + execute_raw_grpc_request(ctx, req, &req_template.operation).await? + }; + + set_headers(ctx, &res); + + Ok(res.body) + } + IO::Js { name } => { + if let Some((worker, value)) = ctx + .request_ctx + .runtime + .worker + .as_ref() + .zip(ctx.value().cloned()) + { + let val = worker.call(name, value).await?; + Ok(val.unwrap_or_default()) + } else { + Ok(ConstValue::Null) } } - }) + } } } -impl<'a, Ctx: ResolverContextLike<'a> + Sync + Send> CacheKey> for IO { +impl<'a, Ctx: ResolverContextLike + Sync> CacheKey> for IO { fn cache_key(&self, ctx: &EvaluationContext<'a, Ctx>) -> Option { match self { IO::Http { req_template, .. } => req_template.cache_key(ctx), @@ -175,8 +174,8 @@ impl<'a, Ctx: ResolverContextLike<'a> + Sync + Send> CacheKey>( - ctx: &EvaluationContext<'ctx, Ctx>, +fn set_headers( + ctx: &EvaluationContext<'_, Ctx>, res: &Response, ) { set_cache_control(ctx, res); @@ -184,8 +183,8 @@ fn set_headers<'ctx, Ctx: ResolverContextLike<'ctx>>( set_experimental_headers(ctx, res); } -fn set_cache_control<'ctx, Ctx: ResolverContextLike<'ctx>>( - ctx: &EvaluationContext<'ctx, Ctx>, +fn set_cache_control( + ctx: &EvaluationContext<'_, Ctx>, res: &Response, ) { if ctx.request_ctx.server.get_enable_cache_control() && res.status.is_success() { @@ -195,15 +194,15 @@ fn set_cache_control<'ctx, Ctx: ResolverContextLike<'ctx>>( } } -fn set_experimental_headers<'ctx, Ctx: ResolverContextLike<'ctx>>( - ctx: &EvaluationContext<'ctx, Ctx>, +fn set_experimental_headers( + ctx: &EvaluationContext<'_, Ctx>, res: &Response, ) { ctx.request_ctx.add_x_headers(&res.headers); } -fn set_cookie_headers<'ctx, Ctx: ResolverContextLike<'ctx>>( - ctx: &EvaluationContext<'ctx, Ctx>, +fn set_cookie_headers( + ctx: &EvaluationContext<'_, Ctx>, res: &Response, ) { if res.status.is_success() { @@ -211,8 +210,8 @@ fn set_cookie_headers<'ctx, Ctx: ResolverContextLike<'ctx>>( } } -async fn execute_raw_request<'ctx, Ctx: ResolverContextLike<'ctx>>( - ctx: &EvaluationContext<'ctx, Ctx>, +async fn execute_raw_request( + ctx: &EvaluationContext<'_, Ctx>, req: Request, ) -> Result, EvaluationError> { let response = ctx @@ -227,8 +226,8 @@ async fn execute_raw_request<'ctx, Ctx: ResolverContextLike<'ctx>>( Ok(response) } -async fn execute_raw_grpc_request<'ctx, Ctx: ResolverContextLike<'ctx>>( - ctx: &EvaluationContext<'ctx, Ctx>, +async fn execute_raw_grpc_request( + ctx: &EvaluationContext<'_, Ctx>, req: Request, operation: &ProtobufOperation, ) -> Result, EvaluationError> { @@ -238,15 +237,14 @@ async fn execute_raw_grpc_request<'ctx, Ctx: ResolverContextLike<'ctx>>( } async fn execute_grpc_request_with_dl< - 'ctx, - Ctx: ResolverContextLike<'ctx>, + Ctx: ResolverContextLike, Dl: Loader< grpc::DataLoaderRequest, Value = Response, Error = Arc, >, >( - ctx: &EvaluationContext<'ctx, Ctx>, + ctx: &EvaluationContext<'_, Ctx>, rendered: RenderedRequestTemplate, data_loader: Option<&DataLoader>, ) -> Result, EvaluationError> { @@ -269,7 +267,7 @@ async fn execute_grpc_request_with_dl< async fn execute_request_with_dl< 'ctx, - Ctx: ResolverContextLike<'ctx>, + Ctx: ResolverContextLike, Dl: Loader, Error = Arc>, >( ctx: &EvaluationContext<'ctx, Ctx>, @@ -293,8 +291,8 @@ async fn execute_request_with_dl< .unwrap_or_default()) } -fn parse_graphql_response<'ctx, Ctx: ResolverContextLike<'ctx>>( - ctx: &EvaluationContext<'ctx, Ctx>, +fn parse_graphql_response( + ctx: &EvaluationContext<'_, Ctx>, res: Response, field_name: &str, ) -> Result { @@ -317,15 +315,15 @@ fn parse_graphql_response<'ctx, Ctx: ResolverContextLike<'ctx>>( /// and getting a response. There are optimizations and customizations that the /// user might have configured. HttpRequestExecutor is responsible for handling /// all of that. -struct HttpRequestExecutor<'a, Context: ResolverContextLike<'a> + Send + Sync> { - evaluation_ctx: EvaluationContext<'a, Context>, +struct HttpRequestExecutor<'a, 'ctx, Context: ResolverContextLike + Sync> { + evaluation_ctx: &'ctx EvaluationContext<'a, Context>, data_loader: Option<&'a DataLoader>, request_template: &'a http::RequestTemplate, } -impl<'a, Context: ResolverContextLike<'a> + Send + Sync> HttpRequestExecutor<'a, Context> { +impl<'a, 'ctx, Context: ResolverContextLike + Sync> HttpRequestExecutor<'a, 'ctx, Context> { pub fn new( - evaluation_ctx: EvaluationContext<'a, Context>, + evaluation_ctx: &'ctx EvaluationContext<'a, Context>, request_template: &'a RequestTemplate, id: &Option, ) -> Self { @@ -339,8 +337,7 @@ impl<'a, Context: ResolverContextLike<'a> + Send + Sync> HttpRequestExecutor<'a, } pub fn init_request(&self) -> Result { - let ctx = &self.evaluation_ctx; - Ok(self.request_template.to_request(ctx)?) + Ok(self.request_template.to_request(self.evaluation_ctx)?) } async fn execute( diff --git a/src/core/ir/mod.rs b/src/core/ir/mod.rs index 2482745928..99f31282b8 100644 --- a/src/core/ir/mod.rs +++ b/src/core/ir/mod.rs @@ -7,10 +7,9 @@ mod io; mod modify; mod resolver_context_like; -use core::future::Future; use std::collections::HashMap; use std::fmt::Debug; -use std::pin::Pin; +use std::future::Future; use async_graphql_value::ConstValue; pub use cache::*; @@ -64,39 +63,40 @@ pub struct Map { } impl Eval for Map { - fn eval<'a, Ctx: ResolverContextLike<'a> + Sync + Send>( - &'a self, - ctx: EvaluationContext<'a, Ctx>, - ) -> Pin> + 'a + Send>> + async fn eval( + &self, + ctx: &mut EvaluationContext<'_, Ctx>, + ) -> Result where - async_graphql::Value: 'a, + Ctx: ResolverContextLike + Sync, { - Box::pin(async move { - let value = self.input.eval(ctx).await?; - if let ConstValue::String(key) = value { - if let Some(value) = self.map.get(&key) { - Ok(ConstValue::String(value.to_owned())) - } else { - Err(EvaluationError::ExprEvalError(format!( - "Can't find mapped key: {}.", - key - ))) - } + let value = self.input.eval(ctx).await?; + if let ConstValue::String(key) = value { + if let Some(value) = self.map.get(&key) { + Ok(ConstValue::String(value.to_owned())) } else { - Err(EvaluationError::ExprEvalError( - "Mapped key must be string value.".to_owned(), - )) + Err(EvaluationError::ExprEvalError(format!( + "Can't find mapped key: {}.", + key + ))) } - }) + } else { + Err(EvaluationError::ExprEvalError( + "Mapped key must be string value.".to_owned(), + )) + } } } impl Eval for IR { #[tracing::instrument(skip_all, fields(otel.name = %self), err)] - fn eval<'a, Ctx: ResolverContextLike<'a> + Sync + Send>( - &'a self, - ctx: EvaluationContext<'a, Ctx>, - ) -> Pin> + 'a + Send>> { + fn eval( + &self, + ctx: &mut EvaluationContext<'_, Ctx>, + ) -> impl Future> + where + Ctx: ResolverContextLike + Sync, + { Box::pin(async move { match self { IR::Context(op) => match op { @@ -108,13 +108,13 @@ impl Eval for IR { .map(|a| a.into_owned()) .unwrap_or(async_graphql::Value::Null)), Context::PushArgs { expr, and_then } => { - let args = expr.eval(ctx.clone()).await?; - let ctx = ctx.with_args(args).clone(); + let args = expr.eval(ctx).await?; + let ctx = &mut ctx.with_args(args); and_then.eval(ctx).await } Context::PushValue { expr, and_then } => { - let value = expr.eval(ctx.clone()).await?; - let ctx = ctx.with_value(value); + let value = expr.eval(ctx).await?; + let ctx = &mut ctx.with_value(value); and_then.eval(ctx).await } }, @@ -125,7 +125,7 @@ impl Eval for IR { .unwrap_or(&async_graphql::Value::Null) .clone()) } - IR::Dynamic(value) => Ok(value.render_value(&ctx)), + IR::Dynamic(value) => Ok(value.render_value(ctx)), IR::Protect(expr) => { ctx.request_ctx .auth_ctx diff --git a/src/core/ir/resolver_context_like.rs b/src/core/ir/resolver_context_like.rs index 441a1539bd..92333a92d9 100644 --- a/src/core/ir/resolver_context_like.rs +++ b/src/core/ir/resolver_context_like.rs @@ -5,35 +5,35 @@ use async_graphql::parser::types::OperationType; use async_graphql::{Name, ServerError, Value}; use indexmap::IndexMap; -pub trait ResolverContextLike<'a>: Clone { - fn value(&'a self) -> Option<&'a Value>; - fn args(&'a self) -> Option<&'a IndexMap>; - fn field(&'a self) -> Option; - fn is_query(&'a self) -> bool; - fn add_error(&'a self, error: ServerError); +pub trait ResolverContextLike: Clone { + fn value(&self) -> Option<&Value>; + fn args(&self) -> Option<&IndexMap>; + fn field(&self) -> Option; + fn is_query(&self) -> bool; + fn add_error(&self, error: ServerError); } #[derive(Clone)] pub struct EmptyResolverContext; -impl<'a> ResolverContextLike<'a> for EmptyResolverContext { - fn value(&'a self) -> Option<&'a Value> { +impl ResolverContextLike for EmptyResolverContext { + fn value(&self) -> Option<&Value> { None } - fn args(&'a self) -> Option<&'a IndexMap> { + fn args(&self) -> Option<&IndexMap> { None } - fn field(&'a self) -> Option { + fn field(&self) -> Option { None } - fn is_query(&'a self) -> bool { + fn is_query(&self) -> bool { false } - fn add_error(&'a self, _: ServerError) {} + fn add_error(&self, _: ServerError) {} } #[derive(Clone)] @@ -47,24 +47,24 @@ impl<'a> From> for ResolverContext<' } } -impl<'a> ResolverContextLike<'a> for ResolverContext<'a> { - fn value(&'a self) -> Option<&'a Value> { +impl<'a> ResolverContextLike for ResolverContext<'a> { + fn value(&self) -> Option<&Value> { self.inner.parent_value.as_value() } - fn args(&'a self) -> Option<&'a IndexMap> { + fn args(&self) -> Option<&IndexMap> { Some(self.inner.args.as_index_map()) } - fn field(&'a self) -> Option { + fn field(&self) -> Option { Some(self.inner.ctx.field()) } - fn is_query(&'a self) -> bool { + fn is_query(&self) -> bool { self.inner.ctx.query_env.operation.node.ty == OperationType::Query } - fn add_error(&'a self, error: ServerError) { + fn add_error(&self, error: ServerError) { self.inner.ctx.add_error(error) } } diff --git a/src/core/path.rs b/src/core/path.rs index 21b67cb17b..ac40ffef32 100644 --- a/src/core/path.rs +++ b/src/core/path.rs @@ -49,7 +49,7 @@ fn convert_value(value: Cow<'_, async_graphql::Value>) -> Option> { } } -impl<'a, Ctx: ResolverContextLike<'a>> PathString for EvaluationContext<'a, Ctx> { +impl<'a, Ctx: ResolverContextLike> PathString for EvaluationContext<'a, Ctx> { fn path_string>(&self, path: &[T]) -> Option> { let ctx = self; @@ -78,7 +78,7 @@ impl<'a, Ctx: ResolverContextLike<'a>> PathString for EvaluationContext<'a, Ctx> } } -impl<'a, Ctx: ResolverContextLike<'a>> PathGraphql for EvaluationContext<'a, Ctx> { +impl<'a, Ctx: ResolverContextLike> PathGraphql for EvaluationContext<'a, Ctx> { fn path_graphql>(&self, path: &[T]) -> Option { let ctx = self; @@ -192,24 +192,24 @@ mod tests { #[derive(Clone)] struct MockGraphqlContext; - impl<'a> ResolverContextLike<'a> for MockGraphqlContext { - fn value(&'a self) -> Option<&'a Value> { + impl ResolverContextLike for MockGraphqlContext { + fn value(&self) -> Option<&Value> { Some(&TEST_VALUES) } - fn args(&'a self) -> Option<&'a IndexMap> { + fn args(&self) -> Option<&IndexMap> { Some(&TEST_ARGS) } - fn field(&'a self) -> Option { + fn field(&self) -> Option { None } - fn is_query(&'a self) -> bool { + fn is_query(&self) -> bool { false } - fn add_error(&'a self, _: async_graphql::ServerError) {} + fn add_error(&self, _: async_graphql::ServerError) {} } static REQ_CTX: Lazy = Lazy::new(|| { diff --git a/tailcall-query-plan/src/execution/executor.rs b/tailcall-query-plan/src/execution/executor.rs index 930c6a7d2a..c952742226 100644 --- a/tailcall-query-plan/src/execution/executor.rs +++ b/tailcall-query-plan/src/execution/executor.rs @@ -134,24 +134,24 @@ struct GraphqlContext<'a> { value: Option<&'a Value>, } -impl<'a> ResolverContextLike<'a> for GraphqlContext<'a> { - fn value(&'a self) -> Option<&'a Value> { +impl<'a> ResolverContextLike for GraphqlContext<'a> { + fn value(&self) -> Option<&Value> { self.value } - fn args(&'a self) -> Option<&'a IndexMap> { + fn args(&self) -> Option<&IndexMap> { self.arguments } - fn field(&'a self) -> Option { + fn field(&self) -> Option { None } - fn is_query(&'a self) -> bool { + fn is_query(&self) -> bool { false } - fn add_error(&'a self, _error: async_graphql::ServerError) { + fn add_error(&self, _error: async_graphql::ServerError) { // TODO: add implementation } } diff --git a/tailcall-query-plan/src/resolver.rs b/tailcall-query-plan/src/resolver.rs index 9d7e2f471a..d1cfd84ef6 100644 --- a/tailcall-query-plan/src/resolver.rs +++ b/tailcall-query-plan/src/resolver.rs @@ -55,11 +55,11 @@ impl Display for FieldPlan { } impl FieldPlan { - pub async fn eval<'a, Ctx: ResolverContextLike<'a> + Sync + Send>( - &'a self, - ctx: EvaluationContext<'a, Ctx>, + pub async fn eval( + &self, + mut ctx: EvaluationContext<'_, Ctx>, ) -> Result { - Ok(self.resolver.eval(ctx).await?) + Ok(self.resolver.eval(&mut ctx).await?) } } diff --git a/tests/expression_spec.rs b/tests/expression_spec.rs index 80d46f0fb9..f812bd4ded 100644 --- a/tests/expression_spec.rs +++ b/tests/expression_spec.rs @@ -12,8 +12,8 @@ mod tests { let runtime = tailcall::cli::runtime::init(&Blueprint::default()); let req_ctx = RequestContext::new(runtime); let res_ctx = EmptyResolverContext {}; - let eval_ctx = EvaluationContext::new(&req_ctx, &res_ctx); - expr.eval(eval_ctx).await + let mut eval_ctx = EvaluationContext::new(&req_ctx, &res_ctx); + expr.eval(&mut eval_ctx).await } #[tokio::test]