From db8ff19de74aa8b5f243e8879af52de28b32738c Mon Sep 17 00:00:00 2001 From: Sandipsinh Rathod Date: Thu, 12 Sep 2024 14:07:22 -0400 Subject: [PATCH] inteoduceborrowed_fields --- .../ssddOnTop/src/http/request_handler.rs | 6 +- projects/ssddOnTop/src/ir/eval_ctx.rs | 12 - projects/ssddOnTop/src/jit/model.rs | 324 ++++++++++-------- projects/ssddOnTop/src/value/value.rs | 11 +- 4 files changed, 191 insertions(+), 162 deletions(-) diff --git a/projects/ssddOnTop/src/http/request_handler.rs b/projects/ssddOnTop/src/http/request_handler.rs index 5ea3ea5..66984f9 100644 --- a/projects/ssddOnTop/src/http/request_handler.rs +++ b/projects/ssddOnTop/src/http/request_handler.rs @@ -15,7 +15,9 @@ pub async fn handle_request( app_ctx: AppCtx, ) -> anyhow::Result>> { let resp = match req.method { - Method::GET => hyper::Response::new(Full::new(Bytes::from_static(b"Hello, World!"))), + Method::GET => hyper::Response::builder() + .status(hyper::StatusCode::OK) + .body(Full::new(Bytes::from(async_graphql::http::GraphiQLSource::build().finish())))?, Method::POST => handle_gql_req(req, app_ctx).await?, _ => hyper::Response::builder() .status(hyper::StatusCode::METHOD_NOT_ALLOWED) @@ -39,6 +41,8 @@ async fn handle_gql_req( let eval_ctx = EvalContext::new(&req_ctx); let path_finder = PathFinder::new(doc, &app_ctx.blueprint); let fields = path_finder.exec().await; + let borrowed_fields = fields.to_borrowed(); + let resolved = fields.resolve(eval_ctx).await?; let finalized = resolved.finalize(); Ok(hyper::Response::new(Full::new(Bytes::from( diff --git a/projects/ssddOnTop/src/ir/eval_ctx.rs b/projects/ssddOnTop/src/ir/eval_ctx.rs index 9a20b79..3a4ed43 100644 --- a/projects/ssddOnTop/src/ir/eval_ctx.rs +++ b/projects/ssddOnTop/src/ir/eval_ctx.rs @@ -33,18 +33,6 @@ impl<'a> EvalContext<'a> { ..self } } - pub fn clear_args(self) -> Self { - Self { - graphql_ctx_args: None, - ..self - } - } - pub fn clear_value(self) -> Self { - Self { - graphql_ctx_value: None, - ..self - } - } pub fn path_arg>(&self, path: &[T]) -> Option> { let args = self.graphql_ctx_args.as_ref()?; get_path_value(args, path).map(|a| Cow::Owned(a.clone())) diff --git a/projects/ssddOnTop/src/jit/model.rs b/projects/ssddOnTop/src/jit/model.rs index e6dac1d..f3bf3fc 100644 --- a/projects/ssddOnTop/src/jit/model.rs +++ b/projects/ssddOnTop/src/jit/model.rs @@ -1,15 +1,15 @@ -use std::borrow::Cow; -use std::fmt::{Debug, Formatter}; -use std::future::Future; -use std::pin::Pin; use crate::blueprint::model::{FieldName, TypeName}; use crate::blueprint::{Blueprint, FieldHash}; +use crate::ir::eval_ctx::EvalContext; use crate::ir::IR; +use crate::json::JsonObjectLike; use crate::value::Value; use async_graphql::parser::types::{DocumentOperations, ExecutableDocument, OperationType, Selection, SelectionSet}; use async_graphql::Positioned; use serde_json::Map; -use crate::ir::eval_ctx::EvalContext; +use std::fmt::Debug; +use std::future::Future; +use std::pin::Pin; pub struct PathFinder<'a> { doc: ExecutableDocument, @@ -20,7 +20,12 @@ pub struct Fields { fields: Vec, } -// #[derive(Debug)] +#[derive(Debug)] +pub struct Fields1<'a> { + fields: Vec>, +} + +#[derive(Debug)] // TODO: give it a lifetime // it won't make much difference.. // but anyways @@ -33,86 +38,186 @@ pub struct Field { pub resolved: Option, } -pub struct Field1<'a> { - value: serde_json_borrow::Value<'a>, - pub name: &'a str, - pub type_of: crate::blueprint::wrapping_type::Type, - nexted: Vec>, - pub args: Option, -} - -impl Debug for Field { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let mut debug_struct = f.debug_struct("Field"); - debug_struct.field("name", &self.name); - if self.ir.is_some() { - debug_struct.field("ir", &"Some(..)"); - } - debug_struct.field("type_of", &self.type_of); - if self.args.is_some() { - debug_struct.field("args", &self.args); +impl Fields { + #[inline(always)] + pub fn to_borrowed<'a>(&'a self) -> Fields1<'a> { + let fields = Self::borrowed_inner(&self.fields); + Fields1 { + fields, } - if self.resolved.is_some() { - debug_struct.field("resolved", &self.resolved.as_ref().map(|v| v.serde())); + } + + #[inline(always)] + pub fn borrowed_inner<'a>(vec: &'a [Field]) -> Vec> { + let mut ans = vec![]; + for field in vec.iter() { + let field = Field1 { + ir: field.ir.as_ref(), + name: field.name.as_str(), + type_of: &field.type_of, + nested: Self::borrowed_inner(&field.nested), + args: field.args.as_ref(), + resolved: field.resolved.as_ref().map(|v| serde_json_borrow::Value::from(v.serde())), + }; + ans.push(field); } - debug_struct.field("nested", &self.nested); - debug_struct.finish() + ans } + } +#[derive(Debug)] +pub struct Field1<'a> { + ir: Option<&'a IR>, + pub name: &'a str, + pub type_of: &'a crate::blueprint::wrapping_type::Type, + nested: Vec>, + pub args: Option<&'a Value>, + pub resolved: Option>, +} impl Fields { #[inline(always)] pub fn finalize(self) -> serde_json::Value { let mut map = Map::new(); - for field in self.fields { - if field.nested.is_empty() { - map.insert(field.name.clone(), field.resolved.unwrap_or(Value::new(serde_json::Value::Null)).into_serde()); - } else { - let nested_value = Fields { fields: field.nested }.finalize(); - map.insert(field.name.clone(), nested_value); + for field in self.fields.iter() { + let name = field.name.as_str().to_string(); + let val = Self::finalize_inner(field, None, None); + map.insert(name, val); + } + let mut ans = Map::new(); + ans.insert("data".to_string(), serde_json::Value::Object(map)); + // map.insert("data".to_string(), self.finalize_inner()); + // serde_json::Value::Object(map) + serde_json::Value::Object(ans) + } + #[inline(always)] + fn finalize_inner<'a>(field: &'a Field, mut value: Option<&'a serde_json::Value>, index: Option) -> serde_json::Value { + if let Some(val) = &field.resolved { + if value.is_none() { + value = Some(val.serde()); } } - let mut data = Map::new(); - data.insert("data".to_string(), serde_json::Value::Object(map)); - serde_json::Value::Object(data) + if let Some(val) = value { + match (val.as_array(), val.as_object()) { + (_, Some(obj)) => { + let mut ans = Map::new(); + + if field.nested.is_empty() { + let val = obj.get_key(field.name.as_str()); + let value = Self::finalize_inner(field, val, index); + ans.insert(field.name.as_str().to_string(), value); + } else { + for child in field.nested.iter() { + let child_name = child.name.as_str().to_string(); + let val = obj.get_key(child.name.as_str()); + let val = Self::finalize_inner(child, val, index); + ans.insert(child_name, val); + } + } + + serde_json::Value::Object(ans) + } + (Some(arr), _) => { + if let Some(index) = index { + let val = arr.get(index); + let val = Self::finalize_inner(field, val, None); + val + } else { + let mut ans = vec![]; + for (i, val) in arr.iter().enumerate() { + let val = Self::finalize_inner(field, Some(val), Some(i)); + ans.push(val); + } + serde_json::Value::Array(ans) + } + } + _ => value.cloned().unwrap_or_default(), + } + } else { + serde_json::Value::Null + } } #[inline(always)] pub async fn resolve<'a>(mut self, eval_context: EvalContext<'a>) -> anyhow::Result { let mut ans = vec![]; - ans = Self::resolve_inner(self.fields, eval_context).await?; + ans = Self::resolve_inner(self.fields, eval_context, None).await?; Ok(Fields { fields: ans, }) } #[inline(always)] - fn resolve_inner<'a>(fields: Vec, mut eval_context: EvalContext<'a>) -> Pin>> + Send + 'a>> { + fn resolve_inner<'a>(fields: Vec, mut eval_context: EvalContext<'a>, parent: Option) -> Pin>> + Send + 'a>> { Box::pin(async move { let mut ans = vec![]; for mut field in fields { + let mut parent_val = None; + if let Some(ir) = field.ir.clone() { if let Some(val) = field.args.clone() { eval_context = eval_context.with_args(val); } - let val = ir.eval(&mut eval_context.clone()).await?; - eval_context = eval_context.with_value(val.clone()); - field.resolved = Some(val); - } else { - // println!("{:?}", eval_context.graphql_ctx_value); - let val = eval_context.path_value(&[field.name.as_str()]); - // println!("{}", val.is_some()); - let val = val.unwrap_or(Cow::Owned(Value::new(serde_json::Value::Null))).into_owned(); - // println!("field: {} val: {}",field.name, val); - // eval_context = eval_context.with_value(val.clone()); - field.resolved = Some(val); + let val = match &parent { + Some(val) => { + match val.clone().into_serde() { + serde_json::Value::Array(arr) => { + let mut ans = vec![]; + for val in arr { + eval_context = eval_context.with_value(Value::new(val)); + let val = ir.eval(&mut eval_context.clone()).await?; + ans.push(val.into_serde()); + } + Some(Value::new(serde_json::Value::Array(ans))) + } + val => { + eval_context = eval_context.with_value(Value::new(val)); + let val = ir.eval(&mut eval_context.clone()).await?; + Some(val) + } + } + } + None => { + let val = ir.eval(&mut eval_context.clone()).await?; + Some(val) + } + }; + parent_val = val.clone(); + field.resolved = val; + } else { + // println!("hx: {}", field.name); + // let val = Self::resolve_non_ir(eval_context.graphql_ctx_value.as_ref().map(|v| v.serde()).unwrap_or(&serde_json::Value::Null), field.name.as_str()); + // println!("{}",val); + // let val = eval_context.path_value(&[field.name.as_str()]); + // let val = val.unwrap_or(Cow::Owned(Value::new(serde_json::Value::Null))).into_owned(); + // field.resolved = Some(Value::new(val)); } - field.nested = Self::resolve_inner(field.nested, eval_context.clone()).await?; + + let eval_ctx_clone = eval_context.clone(); + field.nested = Self::resolve_inner(field.nested, eval_ctx_clone, parent_val).await?; ans.push(field); } Ok(ans) }) } + #[inline(always)] + fn resolve_non_ir(value: &serde_json::Value, key: &str) -> serde_json::Value { + match value { + serde_json::Value::Array(arr) => { + let mut ans = vec![]; + for val in arr { + ans.push(Self::resolve_non_ir(val, key)); + } + serde_json::Value::Array(ans) + } + serde_json::Value::Object(obj) => { + let mut ans = Map::new(); + obj.get_key(key).map(|v| ans.insert(key.to_string(), v.clone())).unwrap_or_default(); + serde_json::Value::Object(ans) + } + val => val.clone(), + } + } } pub struct Holder<'a> { @@ -148,7 +253,28 @@ impl<'a> PathFinder<'a> { } } } - DocumentOperations::Multiple(_) => todo!() + DocumentOperations::Multiple(multi) => { + let (_,single) = multi.iter().next().unwrap(); + let operation = &single.node; + let selection_set = &operation.selection_set.node; + let ty = match &operation.ty { + OperationType::Query => { + let query = self.blueprint.schema.query.as_ref().map(|v| v.as_str()); + query + } + OperationType::Mutation => None, + OperationType::Subscription => None, + }; + if let Some(ty) = ty { + Fields { + fields: self.iter(selection_set, ty), + } + } else { + Fields { + fields: vec![], + } + } + } } } #[inline(always)] @@ -161,23 +287,6 @@ impl<'a> PathFinder<'a> { for selection in &selection.items { match &selection.node { Selection::Field(Positioned { node: gql_field, .. }) => { - // let conditions = self.include(&gql_field.directives); - - /*for directive in &gql_field.directives { - let directive = &directive.node; - if directive.name.node == "skip" || directive.name.node == "include" { - continue; - } - let arguments = directive - .arguments - .iter() - .map(|(k, v)| (k.node.to_string(), v.node.clone())) - .collect::>(); - // println!("directive args: {:?}", arguments); - }*/ - - // let (include, skip) = conditions.into_variable_tuple(); - let field_name = gql_field.name.node.as_str(); let request_args = gql_field .arguments @@ -185,39 +294,7 @@ impl<'a> PathFinder<'a> { .map(|(k, v)| (k.node.as_str().to_string(), v.node.to_owned().into_const().map(|v| v.into_json().ok()).flatten().unwrap())) .collect::>(); - // println!("req args: {:?}", request_args); - // println!("{}: {}",field_name, type_condition); - // println!("{:#?}", self.blueprint.fields); - if let Some(field_def) = self.blueprint.fields.get(&FieldHash::new(FieldName(field_name.to_string()), TypeName(type_condition.to_string()))) { - // let mut args = Vec::with_capacity(request_args.len()); - /* if let QueryField::Field((_, schema_args)) = field_def { - for (arg_name, arg_value) in schema_args { - let type_of = arg_value.of_type.clone(); - let id = ArgId::new(self.arg_id.next()); - let name = arg_name.clone(); - let default_value = arg_value - .default_value - .as_ref() - .and_then(|v| v.to_owned().try_into().ok()); - args.push(Arg { - id, - name, - type_of, - // TODO: handle errors for non existing request_args without the - // default - value: request_args.get(arg_name).cloned(), - default_value, - }); - } - }*/ - - /* let type_of = match field_def { - QueryField::Field((field_def, _)) => field_def.of_type.clone(), - QueryField::InputField(field_def) => field_def.of_type.clone(), - }; - - let id = FieldId::new(self.field_id.next());*/ let type_of = field_def.type_of.clone(); let child_fields = self.iter( &gql_field.selection_set.node, @@ -235,51 +312,8 @@ impl<'a> PathFinder<'a> { resolved: None, }; - /* let ir = match field_def { - QueryField::Field((field_def, _)) => field_def.resolver.clone(), - _ => None, - }; - let flat_field = Field { - id, - name: field_name.to_string(), - output_name: gql_field - .alias - .as_ref() - .map(|a| a.node.to_string()) - .unwrap_or(field_name.to_owned()), - ir, - type_of, - type_condition: Some(type_condition.to_string()), - skip, - include, - args, - pos: selection.pos.into(), - extensions: exts.clone(), - directives, - };*/ - fields.push(field); - // fields = fields.merge_right(child_fields); - } /*else if field_name == "__typename" { - let flat_field = Field { - id: FieldId::new(self.field_id.next()), - name: field_name.to_string(), - output_name: field_name.to_string(), - ir: None, - type_of: Type::Named { name: "String".to_owned(), non_null: true }, - // __typename has a special meaning and could be applied - // to any type - type_condition: None, - skip, - include, - args: Vec::new(), - pos: selection.pos.into(), - extensions: exts.clone(), - directives, - }; - - fields.push(flat_field); - }*/ + } } _ => (), } diff --git a/projects/ssddOnTop/src/value/value.rs b/projects/ssddOnTop/src/value/value.rs index a5f2249..a4528f0 100644 --- a/projects/ssddOnTop/src/value/value.rs +++ b/projects/ssddOnTop/src/value/value.rs @@ -4,7 +4,7 @@ use std::fmt::{Display, Formatter}; #[derive(Getters, Debug, Clone, PartialEq, Eq, Hash)] pub struct Value { serde: serde_json::Value, - borrowed: serde_json_borrow::Value<'static>, + // borrowed: serde_json_borrow::Value<'static>, } impl Display for Value { @@ -15,8 +15,11 @@ impl Display for Value { impl Value { pub fn new(serde: serde_json::Value) -> Self { - let borrowed = extend_lifetime(serde_json_borrow::Value::from(&serde)); - Self { serde, borrowed } + // let borrowed = extend_lifetime(serde_json_borrow::Value::from(&serde)); + Self { + serde, + // borrowed, + } } pub fn into_serde(self) -> serde_json::Value { self.serde @@ -39,6 +42,6 @@ mod test { let val = json!({"key": "value"}); let value = Value::new(val.clone()); assert_eq!(value.serde(), &val); - assert_eq!(value.borrowed(), &serde_json_borrow::Value::from(&val)); + // assert_eq!(value.borrowed(), &serde_json_borrow::Value::from(&val)); } } \ No newline at end of file