Skip to content

Commit

Permalink
Fix discussion issues
Browse files Browse the repository at this point in the history
  • Loading branch information
karatakis committed Aug 12, 2024
1 parent ac70681 commit 9356edc
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 61 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions examples/extension-i18n/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@ anyhow = { workspace = true }
tokio = { workspace = true }
async-graphql = { workspace = true }
async-graphql-value = "7.0.3"
futures = "0.3.30"
async-trait = "0.1.80"

[dev-dependencies]
reqwest = { workspace = true }
serde_json = { workspace = true }
async-trait = "0.1.80"
hyper = { version = "0.14.28", default-features = false }
126 changes: 81 additions & 45 deletions examples/extension-i18n/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,61 +1,100 @@
use std::sync::Arc;
use std::sync::{Arc, Mutex};

use async_graphql_value::ConstValue;
use dotenvy::dotenv;
use futures::executor::block_on;
use tailcall::cli::runtime;
use tailcall::cli::server::Server;
use tailcall::core::blueprint::{Blueprint, ExtensionLoader};
use tailcall::core::blueprint::{Blueprint, ExtensionTrait, PrepareContext, ProcessContext};
use tailcall::core::config::reader::ConfigReader;
use tailcall::core::config::KeyValue;
use tailcall::core::helpers::headers::to_mustache_headers;
use tailcall::core::valid::Validator;

#[derive(Clone, Debug)]
pub struct TranslateExtension;
pub struct TranslateExtension {
pub load_counter: Arc<Mutex<i32>>,
pub prepare_counter: Arc<Mutex<i32>>,
pub process_counter: Arc<Mutex<i32>>,
}

impl Default for TranslateExtension {
fn default() -> Self {
Self {
load_counter: Arc::new(Mutex::new(0)),
prepare_counter: Arc::new(Mutex::new(0)),
process_counter: Arc::new(Mutex::new(0)),
}
}
}

impl ExtensionLoader for TranslateExtension {
fn load(&self) {}
#[async_trait::async_trait]
impl ExtensionTrait<ConstValue> for TranslateExtension {
fn load(&self) {
*(self.load_counter.lock().unwrap()) += 1;
}

fn prepare(
async fn prepare(
&self,
ir: Box<tailcall::core::ir::model::IR>,
_params: ConstValue,
context: PrepareContext<ConstValue>,
) -> Box<tailcall::core::ir::model::IR> {
ir
*(self.prepare_counter.lock().unwrap()) += 1;
context.ir
}

fn process(
async fn process(
&self,
_params: ConstValue,
value: ConstValue,
context: ProcessContext<ConstValue>,
) -> Result<ConstValue, tailcall::core::ir::Error> {
if let ConstValue::String(value) = value {
let new_value = block_on(translate(&value));
*(self.process_counter.lock().unwrap()) += 1;
if let ConstValue::String(value) = context.value {
let new_value = match value.as_str() {
"Multi-layered client-server neural-net" => {
"Red neuronal cliente-servidor multicapa".to_string()
}
"Leanne Graham" => "Leona Grahm".to_string(),
_ => value.to_string(),
};
Ok(ConstValue::String(new_value))
} else {
Ok(value)
Ok(context.value)
}
}
}

#[derive(Clone, Debug)]
pub struct ModifyIrExtension;
pub struct ModifyIrExtension {
pub load_counter: Arc<Mutex<i32>>,
pub prepare_counter: Arc<Mutex<i32>>,
pub process_counter: Arc<Mutex<i32>>,
}

impl Default for ModifyIrExtension {
fn default() -> Self {
Self {
load_counter: Arc::new(Mutex::new(0)),
prepare_counter: Arc::new(Mutex::new(0)),
process_counter: Arc::new(Mutex::new(0)),
}
}
}

impl ExtensionLoader for ModifyIrExtension {
fn load(&self) {}
#[async_trait::async_trait]
impl ExtensionTrait<ConstValue> for ModifyIrExtension {
fn load(&self) {
*(self.load_counter.lock().unwrap()) += 1;
}

fn prepare(
async fn prepare(
&self,
ir: Box<tailcall::core::ir::model::IR>,
_params: ConstValue,
context: PrepareContext<ConstValue>,
) -> Box<tailcall::core::ir::model::IR> {
*(self.prepare_counter.lock().unwrap()) += 1;
if let tailcall::core::ir::model::IR::IO(tailcall::core::ir::model::IO::Http {
req_template,
group_by,
dl_id,
http_filter,
}) = *ir
}) = *context.ir
{
let mut req_template = req_template;
let headers = to_mustache_headers(&[KeyValue {
Expand All @@ -78,33 +117,23 @@ impl ExtensionLoader for ModifyIrExtension {
});
Box::new(ir)
} else {
ir
context.ir
}
}

fn process(
async fn process(
&self,
_params: ConstValue,
value: ConstValue,
context: ProcessContext<ConstValue>,
) -> Result<ConstValue, tailcall::core::ir::Error> {
Ok(value)
}
}

async fn translate(value: &str) -> String {
match value {
"Multi-layered client-server neural-net" => {
"Red neuronal cliente-servidor multicapa".to_string()
}
"Leanne Graham" => "Leona Grahm".to_string(),
_ => value.to_string(),
*(self.process_counter.lock().unwrap()) += 1;
Ok(context.value)
}
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
let translate_ext = Arc::new(TranslateExtension {});
let modify_ir_ext = Arc::new(ModifyIrExtension {});
let translate_ext = Arc::new(TranslateExtension::default());
let modify_ir_ext = Arc::new(ModifyIrExtension::default());
if let Ok(path) = dotenv() {
tracing::info!("Env file: {:?} loaded", path);
}
Expand All @@ -128,7 +157,6 @@ async fn main() -> anyhow::Result<()> {
#[cfg(test)]
mod tests {
use hyper::{Body, Request};

use serde_json::json;
use tailcall::core::app_context::AppContext;
use tailcall::core::async_graphql_hyper::GraphQLRequest;
Expand Down Expand Up @@ -180,8 +208,8 @@ mod tests {

#[tokio::test]
async fn test_tailcall_extensions() {
let translate_ext = Arc::new(TranslateExtension {});
let modify_ir_ext = Arc::new(ModifyIrExtension {});
let translate_ext = Arc::new(TranslateExtension::default());
let modify_ir_ext = Arc::new(ModifyIrExtension::default());
if let Ok(path) = dotenv() {
tracing::info!("Env file: {:?} loaded", path);
}
Expand All @@ -194,10 +222,10 @@ mod tests {
let mut extensions = config_module.extensions().clone();
extensions
.plugin_extensions
.insert("translate".to_string(), translate_ext);
.insert("translate".to_string(), translate_ext.clone());
extensions
.plugin_extensions
.insert("modify_ir".to_string(), modify_ir_ext);
.insert("modify_ir".to_string(), modify_ir_ext.clone());
let config_module = config_module.merge_extensions(extensions);
let blueprint = Blueprint::try_from(&config_module).unwrap();
let app_context = AppContext::new(blueprint, runtime, EndpointSet::default());
Expand Down Expand Up @@ -236,5 +264,13 @@ mod tests {
hyper::body::Bytes::from(expected_response.to_string()),
"Unexpected response from server"
);

assert_eq!(translate_ext.load_counter.lock().unwrap().to_owned(), 2);
assert_eq!(translate_ext.process_counter.lock().unwrap().to_owned(), 2);
assert_eq!(translate_ext.prepare_counter.lock().unwrap().to_owned(), 2);

assert_eq!(modify_ir_ext.load_counter.lock().unwrap().to_owned(), 1);
assert_eq!(modify_ir_ext.process_counter.lock().unwrap().to_owned(), 1);
assert_eq!(modify_ir_ext.prepare_counter.lock().unwrap().to_owned(), 1);
}
}
32 changes: 27 additions & 5 deletions src/core/blueprint/operators/extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::core::config;
use crate::core::config::Field;
use crate::core::ir::model::IR;
use crate::core::ir::Error;
use crate::core::json::JsonLikeOwned;
use crate::core::try_fold::TryFold;
use crate::core::valid::Valid;

Expand Down Expand Up @@ -54,14 +55,35 @@ pub fn update_extension<'a>(
)
}

pub trait ExtensionLoader: std::fmt::Debug + Send + Sync {
pub type ExtensionLoader = dyn ExtensionTrait<ConstValue>;

#[async_trait::async_trait]
pub trait ExtensionTrait<Json: JsonLikeOwned>: std::fmt::Debug + Send + Sync {
fn load(&self) {}

fn modify_inner(&self, ir: Box<IR>) -> Box<IR> {
ir
async fn prepare(&self, context: PrepareContext<Json>) -> Box<IR>;

async fn process(&self, context: ProcessContext<Json>) -> Result<Json, Error>;
}

pub struct PrepareContext<Json: JsonLikeOwned> {
pub params: Json,
pub ir: Box<IR>,
}

impl<Json: JsonLikeOwned> PrepareContext<Json> {
pub fn new(ir: Box<IR>, params: Json) -> Self {
Self { ir, params }
}
}

fn prepare(&self, ir: Box<IR>, params: ConstValue) -> Box<IR>;
pub struct ProcessContext<Json: JsonLikeOwned> {
pub params: Json,
pub value: Json,
}

fn process(&self, params: ConstValue, value: ConstValue) -> Result<ConstValue, Error>;
impl<Json: JsonLikeOwned> ProcessContext<Json> {
pub fn new(params: Json, value: Json) -> Self {
Self { params, value }
}
}
2 changes: 1 addition & 1 deletion src/core/config/config_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ pub struct Extensions {

pub jwks: Vec<Content<JwkSet>>,

pub plugin_extensions: HashMap<String, Arc<dyn ExtensionLoader>>,
pub plugin_extensions: HashMap<String, Arc<ExtensionLoader>>,
}

impl Extensions {
Expand Down
8 changes: 6 additions & 2 deletions src/core/ir/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use async_graphql_value::ConstValue;
use super::eval_io::eval_io;
use super::model::{Cache, CacheKey, Map, IR};
use super::{Error, EvalContext, ResolverContextLike};
use crate::core::blueprint::{PrepareContext, ProcessContext};
use crate::core::json::JsonLike;
use crate::core::serde_value_ext::ValueExt;

Expand Down Expand Up @@ -96,14 +97,17 @@ impl IR {
Ok(value)
}),
IR::Extension { plugin, params, ir } => {
let ir = plugin.prepare(ir.clone(), params.render_value(ctx));
let context = PrepareContext::new(ir.clone(), params.render_value(ctx));
let ir = plugin.prepare(context).await;

let value = {
let mut ctx = ctx.clone();
ir.eval(&mut ctx).await?
};

plugin.process(params.render_value(ctx), value)
let context = ProcessContext::new(params.render_value(ctx), value);

plugin.process(context).await
}
}
})
Expand Down
7 changes: 2 additions & 5 deletions src/core/ir/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub enum IR {
Discriminate(Discriminator, Box<IR>),
Extension {
// path: Vec<String>,
plugin: Arc<dyn ExtensionLoader>,
plugin: Arc<ExtensionLoader>,
params: DynamicValue<Value>,
ir: Box<IR>,
},
Expand Down Expand Up @@ -156,10 +156,7 @@ impl IR {
IR::Discriminate(discriminator, expr) => {
IR::Discriminate(discriminator, expr.modify_box(modifier))
}
IR::Extension { plugin, params, ir } => {
let ir = plugin.modify_inner(ir);
IR::Extension { plugin, params, ir }
}
IR::Extension { ir: _, params: _, plugin: _ } => expr,
}
}
}
Expand Down

0 comments on commit 9356edc

Please sign in to comment.