use crate::engine::config::Configuration;
use crate::engine::context::{GraphQLContext, RequestContext};
use crate::engine::database::{CrudOperation, Transaction};
use crate::engine::database::{
DatabaseEndpoint, DatabasePool, NodeQueryVar, RelQueryVar, SuffixGenerator,
};
use crate::engine::objects::resolvers::visitors::{
visit_node_create_mutation_input, visit_node_delete_input, visit_node_query_input,
visit_node_update_input, visit_rel_query_input,
};
use crate::engine::objects::{Node, Rel};
use crate::engine::schema::Info;
use crate::engine::value::Value;
use crate::juniper::BoxFuture;
use crate::Error;
use inflector::Inflector;
use std::collections::HashMap;
use std::convert::TryInto;
pub type BeforeEngineBuildFunc = fn(&mut Configuration) -> Result<(), Error>;
pub type BeforeRequestFunc<R> =
fn(R, EventFacade<R>, HashMap<String, String>) -> BoxFuture<Result<R, Error>>;
pub type AfterRequestFunc<R> =
fn(EventFacade<R>, serde_json::Value) -> BoxFuture<Result<serde_json::Value, Error>>;
pub type BeforeMutationEventFunc<RequestCtx> =
fn(Value, EventFacade<RequestCtx>) -> BoxFuture<Result<Value, Error>>;
pub type BeforeQueryEventFunc<RequestCtx> =
fn(Option<Value>, EventFacade<RequestCtx>) -> BoxFuture<Result<Option<Value>, Error>>;
pub type AfterNodeEventFunc<RequestCtx> = fn(
Vec<Node<RequestCtx>>,
EventFacade<RequestCtx>,
) -> BoxFuture<Result<Vec<Node<RequestCtx>>, Error>>;
pub type AfterRelEventFunc<RequestCtx> = fn(
Vec<Rel<RequestCtx>>,
EventFacade<RequestCtx>,
) -> BoxFuture<Result<Vec<Rel<RequestCtx>>, Error>>;
#[derive(Clone)]
pub struct EventHandlerBag<RequestCtx: RequestContext> {
before_engine_build_handlers: Vec<BeforeEngineBuildFunc>,
before_request_handlers: Vec<BeforeRequestFunc<RequestCtx>>,
after_request_handlers: Vec<AfterRequestFunc<RequestCtx>>,
before_create_handlers: HashMap<String, Vec<BeforeMutationEventFunc<RequestCtx>>>,
after_node_create_handlers: HashMap<String, Vec<AfterNodeEventFunc<RequestCtx>>>,
after_rel_create_handlers: HashMap<String, Vec<AfterRelEventFunc<RequestCtx>>>,
before_read_handlers: HashMap<String, Vec<BeforeQueryEventFunc<RequestCtx>>>,
after_node_read_handlers: HashMap<String, Vec<AfterNodeEventFunc<RequestCtx>>>,
after_rel_read_handlers: HashMap<String, Vec<AfterRelEventFunc<RequestCtx>>>,
before_update_handlers: HashMap<String, Vec<BeforeMutationEventFunc<RequestCtx>>>,
after_node_update_handlers: HashMap<String, Vec<AfterNodeEventFunc<RequestCtx>>>,
after_rel_update_handlers: HashMap<String, Vec<AfterRelEventFunc<RequestCtx>>>,
before_delete_handlers: HashMap<String, Vec<BeforeMutationEventFunc<RequestCtx>>>,
after_node_delete_handlers: HashMap<String, Vec<AfterNodeEventFunc<RequestCtx>>>,
after_rel_delete_handlers: HashMap<String, Vec<AfterRelEventFunc<RequestCtx>>>,
}
impl<RequestCtx: RequestContext> EventHandlerBag<RequestCtx> {
pub fn new() -> EventHandlerBag<RequestCtx> {
EventHandlerBag {
before_engine_build_handlers: vec![],
before_request_handlers: vec![],
after_request_handlers: vec![],
before_create_handlers: HashMap::new(),
after_node_create_handlers: HashMap::new(),
after_rel_create_handlers: HashMap::new(),
before_read_handlers: HashMap::new(),
after_node_read_handlers: HashMap::new(),
after_rel_read_handlers: HashMap::new(),
before_update_handlers: HashMap::new(),
after_node_update_handlers: HashMap::new(),
after_rel_update_handlers: HashMap::new(),
before_delete_handlers: HashMap::new(),
after_node_delete_handlers: HashMap::new(),
after_rel_delete_handlers: HashMap::new(),
}
}
pub fn register_before_engine_build(&mut self, f: BeforeEngineBuildFunc) {
self.before_engine_build_handlers.push(f);
}
pub fn register_before_request(&mut self, f: BeforeRequestFunc<RequestCtx>) {
self.before_request_handlers.push(f);
}
pub fn register_after_request(&mut self, f: AfterRequestFunc<RequestCtx>) {
self.after_request_handlers.push(f);
}
pub fn register_before_node_create(
&mut self,
type_names: Vec<String>,
f: BeforeMutationEventFunc<RequestCtx>,
) {
for type_name in type_names {
if let Some(handlers) = self.before_create_handlers.get_mut(&type_name) {
handlers.push(f);
} else {
self.before_create_handlers.insert(type_name, vec![f]);
}
}
}
pub fn register_before_rel_create(
&mut self,
rel_names: Vec<String>,
f: BeforeMutationEventFunc<RequestCtx>,
) {
for rel_name in rel_names {
if let Some(handlers) = self.before_create_handlers.get_mut(&rel_name) {
handlers.push(f);
} else {
self.before_create_handlers.insert(rel_name, vec![f]);
}
}
}
pub fn register_after_node_create(
&mut self,
names: Vec<String>,
f: AfterNodeEventFunc<RequestCtx>,
) {
for name in names {
if let Some(handlers) = self.after_node_create_handlers.get_mut(&name) {
handlers.push(f);
} else {
self.after_node_create_handlers.insert(name, vec![f]);
}
}
}
pub fn register_after_rel_create(
&mut self,
rel_names: Vec<String>,
f: AfterRelEventFunc<RequestCtx>,
) {
for rel_name in rel_names {
if let Some(handlers) = self.after_rel_create_handlers.get_mut(&rel_name) {
handlers.push(f);
} else {
self.after_rel_create_handlers.insert(rel_name, vec![f]);
}
}
}
pub fn register_before_node_read(
&mut self,
type_names: Vec<String>,
f: BeforeQueryEventFunc<RequestCtx>,
) {
for type_name in type_names {
if let Some(handlers) = self.before_read_handlers.get_mut(&type_name) {
handlers.push(f);
} else {
self.before_read_handlers.insert(type_name, vec![f]);
}
}
}
pub fn register_before_rel_read(
&mut self,
rel_names: Vec<String>,
f: BeforeQueryEventFunc<RequestCtx>,
) {
for rel_name in rel_names {
if let Some(handlers) = self.before_read_handlers.get_mut(&rel_name) {
handlers.push(f);
} else {
self.before_read_handlers.insert(rel_name, vec![f]);
}
}
}
pub fn register_after_node_read(
&mut self,
type_names: Vec<String>,
f: AfterNodeEventFunc<RequestCtx>,
) {
for type_name in type_names {
if let Some(handlers) = self.after_node_read_handlers.get_mut(&type_name) {
handlers.push(f);
} else {
self.after_node_read_handlers.insert(type_name, vec![f]);
}
}
}
pub fn register_after_rel_read(
&mut self,
rel_names: Vec<String>,
f: AfterRelEventFunc<RequestCtx>,
) {
for rel_name in rel_names {
if let Some(handlers) = self.after_rel_read_handlers.get_mut(&rel_name) {
handlers.push(f);
} else {
self.after_rel_read_handlers.insert(rel_name, vec![f]);
}
}
}
pub fn register_before_node_update(
&mut self,
type_names: Vec<String>,
f: BeforeMutationEventFunc<RequestCtx>,
) {
for type_name in type_names {
if let Some(handlers) = self.before_update_handlers.get_mut(&type_name) {
handlers.push(f);
} else {
self.before_update_handlers.insert(type_name, vec![f]);
}
}
}
pub fn register_before_rel_update(
&mut self,
rel_names: Vec<String>,
f: BeforeMutationEventFunc<RequestCtx>,
) {
for rel_name in rel_names {
if let Some(handlers) = self.before_update_handlers.get_mut(&rel_name) {
handlers.push(f);
} else {
self.before_update_handlers.insert(rel_name, vec![f]);
}
}
}
pub fn register_after_node_update(
&mut self,
type_names: Vec<String>,
f: AfterNodeEventFunc<RequestCtx>,
) {
for type_name in type_names {
if let Some(handlers) = self.after_node_update_handlers.get_mut(&type_name) {
handlers.push(f);
} else {
self.after_node_update_handlers.insert(type_name, vec![f]);
}
}
}
pub fn register_after_rel_update(
&mut self,
rel_names: Vec<String>,
f: AfterRelEventFunc<RequestCtx>,
) {
for rel_name in rel_names {
if let Some(handlers) = self.after_rel_update_handlers.get_mut(&rel_name) {
handlers.push(f);
} else {
self.after_rel_update_handlers.insert(rel_name, vec![f]);
}
}
}
pub fn register_before_node_delete(
&mut self,
type_names: Vec<String>,
f: BeforeMutationEventFunc<RequestCtx>,
) {
for type_name in type_names {
if let Some(handlers) = self.before_delete_handlers.get_mut(&type_name) {
handlers.push(f);
} else {
self.before_delete_handlers.insert(type_name, vec![f]);
}
}
}
pub fn register_before_rel_delete(
&mut self,
rel_names: Vec<String>,
f: BeforeMutationEventFunc<RequestCtx>,
) {
for rel_name in rel_names {
if let Some(handlers) = self.before_delete_handlers.get_mut(&rel_name) {
handlers.push(f);
} else {
self.before_delete_handlers.insert(rel_name, vec![f]);
}
}
}
pub fn register_after_node_delete(
&mut self,
type_names: Vec<String>,
f: AfterNodeEventFunc<RequestCtx>,
) {
for type_name in type_names {
if let Some(handlers) = self.after_node_delete_handlers.get_mut(&type_name) {
handlers.push(f);
} else {
self.after_node_delete_handlers.insert(type_name, vec![f]);
}
}
}
pub fn register_after_rel_delete(
&mut self,
rel_names: Vec<String>,
f: AfterRelEventFunc<RequestCtx>,
) {
for rel_name in rel_names {
if let Some(handlers) = self.after_rel_delete_handlers.get_mut(&rel_name) {
handlers.push(f);
} else {
self.after_rel_delete_handlers.insert(rel_name, vec![f]);
}
}
}
pub(crate) fn before_engine_build(&self) -> &Vec<BeforeEngineBuildFunc> {
&self.before_engine_build_handlers
}
pub(crate) fn before_request(&self) -> &Vec<BeforeRequestFunc<RequestCtx>> {
&self.before_request_handlers
}
pub(crate) fn after_request(&self) -> &Vec<AfterRequestFunc<RequestCtx>> {
&self.after_request_handlers
}
pub(crate) fn before_node_create(
&self,
type_name: &str,
) -> Option<&Vec<BeforeMutationEventFunc<RequestCtx>>> {
self.before_create_handlers.get(type_name)
}
pub(crate) fn before_rel_create(
&self,
rel_name: &str,
) -> Option<&Vec<BeforeMutationEventFunc<RequestCtx>>> {
self.before_create_handlers.get(rel_name)
}
pub(crate) fn after_node_create(
&self,
type_name: &str,
) -> Option<&Vec<AfterNodeEventFunc<RequestCtx>>> {
self.after_node_create_handlers.get(type_name)
}
pub(crate) fn after_rel_create(
&self,
rel_name: &str,
) -> Option<&Vec<AfterRelEventFunc<RequestCtx>>> {
self.after_rel_create_handlers.get(rel_name)
}
pub(crate) fn before_node_read(
&self,
type_name: &str,
) -> Option<&Vec<BeforeQueryEventFunc<RequestCtx>>> {
self.before_read_handlers.get(type_name)
}
pub(crate) fn before_rel_read(
&self,
rel_name: &str,
) -> Option<&Vec<BeforeQueryEventFunc<RequestCtx>>> {
self.before_read_handlers.get(rel_name)
}
pub(crate) fn after_node_read(
&self,
type_name: &str,
) -> Option<&Vec<AfterNodeEventFunc<RequestCtx>>> {
self.after_node_read_handlers.get(type_name)
}
pub(crate) fn after_rel_read(
&self,
rel_name: &str,
) -> Option<&Vec<AfterRelEventFunc<RequestCtx>>> {
self.after_rel_read_handlers.get(rel_name)
}
pub(crate) fn before_node_update(
&self,
type_name: &str,
) -> Option<&Vec<BeforeMutationEventFunc<RequestCtx>>> {
self.before_update_handlers.get(type_name)
}
pub(crate) fn before_rel_update(
&self,
rel_name: &str,
) -> Option<&Vec<BeforeMutationEventFunc<RequestCtx>>> {
self.before_update_handlers.get(rel_name)
}
pub(crate) fn after_node_update(
&self,
type_name: &str,
) -> Option<&Vec<AfterNodeEventFunc<RequestCtx>>> {
self.after_node_update_handlers.get(type_name)
}
pub(crate) fn after_rel_update(
&self,
rel_name: &str,
) -> Option<&Vec<AfterRelEventFunc<RequestCtx>>> {
self.after_rel_update_handlers.get(rel_name)
}
pub(crate) fn before_node_delete(
&self,
type_name: &str,
) -> Option<&Vec<BeforeMutationEventFunc<RequestCtx>>> {
self.before_delete_handlers.get(type_name)
}
pub(crate) fn before_rel_delete(
&self,
rel_name: &str,
) -> Option<&Vec<BeforeMutationEventFunc<RequestCtx>>> {
self.before_delete_handlers.get(rel_name)
}
pub(crate) fn after_node_delete(
&self,
type_name: &str,
) -> Option<&Vec<AfterNodeEventFunc<RequestCtx>>> {
self.after_node_delete_handlers.get(type_name)
}
pub(crate) fn after_rel_delete(
&self,
rel_name: &str,
) -> Option<&Vec<AfterRelEventFunc<RequestCtx>>> {
self.after_rel_delete_handlers.get(rel_name)
}
}
impl<RequestCtx: RequestContext> Default for EventHandlerBag<RequestCtx> {
fn default() -> EventHandlerBag<RequestCtx> {
EventHandlerBag {
before_engine_build_handlers: vec![],
before_request_handlers: vec![],
after_request_handlers: vec![],
before_create_handlers: HashMap::new(),
after_node_create_handlers: HashMap::new(),
after_rel_create_handlers: HashMap::new(),
before_read_handlers: HashMap::new(),
after_node_read_handlers: HashMap::new(),
after_rel_read_handlers: HashMap::new(),
before_update_handlers: HashMap::new(),
after_node_update_handlers: HashMap::new(),
after_rel_update_handlers: HashMap::new(),
before_delete_handlers: HashMap::new(),
after_node_delete_handlers: HashMap::new(),
after_rel_delete_handlers: HashMap::new(),
}
}
}
pub struct EventFacade<'a, RequestCtx>
where
RequestCtx: RequestContext,
{
op: CrudOperation,
context: &'a GraphQLContext<RequestCtx>,
transaction: &'a mut <<<RequestCtx as RequestContext>::DBEndpointType as DatabaseEndpoint>::PoolType as DatabasePool>::TransactionType,
info: &'a Info,
}
impl<'a, RequestCtx> EventFacade<'a, RequestCtx>
where
RequestCtx: RequestContext,
{
pub(crate) fn new(
op: CrudOperation,
context: &'a GraphQLContext<RequestCtx>,
transaction: &'a mut <<<RequestCtx as RequestContext>::DBEndpointType as DatabaseEndpoint>::PoolType as DatabasePool>::TransactionType,
info: &'a Info,
) -> Self {
Self {
op,
context,
transaction,
info,
}
}
pub fn op(&self) -> &CrudOperation {
&self.op
}
pub fn context(&self) -> &'a GraphQLContext<RequestCtx> {
self.context
}
pub async fn read_nodes(
&mut self,
type_name: &str,
input: impl TryInto<Value>,
partition_key_opt: Option<&Value>,
) -> Result<Vec<Node<RequestCtx>>, Error> {
let mut info = self.info.clone();
info.name = "Query".to_string();
let mut sg = SuffixGenerator::new();
let node_var =
NodeQueryVar::new(Some(type_name.to_string()), "node".to_string(), sg.suffix());
let query_fragment = visit_node_query_input::<RequestCtx>(
&node_var,
Some(input.try_into().map_err(|_e| Error::TypeConversionFailed {
src: "".to_string(),
dst: "".to_string(),
})?),
&Info::new(format!("{}QueryInput", type_name), info.type_defs()),
partition_key_opt,
&mut sg,
self.transaction,
)
.await?;
let results = self
.transaction
.read_nodes(&node_var, query_fragment, partition_key_opt, &info)
.await;
results
}
pub async fn create_node(
&mut self,
type_name: &str,
input: impl TryInto<Value>,
partition_key_opt: Option<&Value>,
) -> Result<Node<RequestCtx>, Error> {
let mut sg = SuffixGenerator::new();
let node_var =
NodeQueryVar::new(Some(type_name.to_string()), "node".to_string(), sg.suffix());
let result = visit_node_create_mutation_input(
&node_var,
input.try_into().map_err(|_e| Error::TypeConversionFailed {
src: "".to_string(),
dst: "".to_string(),
})?,
&Info::new(
format!("{}CreateMutationInput", type_name),
self.info.type_defs(),
),
partition_key_opt,
&mut sg,
self.transaction,
self.context(),
)
.await;
result
}
pub async fn update_node(
&mut self,
type_name: &str,
input: impl TryInto<Value>,
partition_key_opt: Option<&Value>,
) -> Result<Vec<Node<RequestCtx>>, Error> {
let mut sg = SuffixGenerator::new();
let node_var =
NodeQueryVar::new(Some(type_name.to_string()), "node".to_string(), sg.suffix());
let result = visit_node_update_input(
&node_var,
input.try_into().map_err(|_e| Error::TypeConversionFailed {
src: "".to_string(),
dst: "".to_string(),
})?,
&Info::new(format!("{}UpdateInput", type_name), self.info.type_defs()),
partition_key_opt,
&mut sg,
self.transaction,
self.context(),
)
.await;
result
}
pub async fn delete_node(
&mut self,
type_name: &str,
input: impl TryInto<Value>,
partition_key_opt: Option<&Value>,
) -> Result<i32, Error> {
let mut sg = SuffixGenerator::new();
let node_var =
NodeQueryVar::new(Some(type_name.to_string()), "node".to_string(), sg.suffix());
let result = visit_node_delete_input(
&node_var,
input.try_into().map_err(|_e| Error::TypeConversionFailed {
src: "".to_string(),
dst: "".to_string(),
})?,
&Info::new(format!("{}DeleteInput", type_name), self.info.type_defs()),
partition_key_opt,
&mut sg,
self.transaction,
self.context(),
)
.await;
result
}
pub async fn read_rels(
&mut self,
src_node_label: &str,
rel_label: &str,
input: impl TryInto<Value>,
partition_key_opt: Option<&Value>,
) -> Result<Vec<Rel<RequestCtx>>, Error> {
let input_value_opt = Some(input.try_into().map_err(|_e| Error::TypeConversionFailed {
src: "TryInto<Value>".to_string(),
dst: "Value".to_string(),
})?);
let mut sg = SuffixGenerator::new();
let rel_suffix = sg.suffix();
let dst_suffix = sg.suffix();
let src_var = NodeQueryVar::new(
Some(src_node_label.to_string()),
"src".to_string(),
sg.suffix(),
);
let dst_var = NodeQueryVar::new(None, "dst".to_string(), dst_suffix);
let rel_var = RelQueryVar::new(rel_label.to_string(), rel_suffix, src_var, dst_var);
let info = Info::new(
src_node_label.to_string()
+ &*((&rel_label.to_string().to_title_case())
.split_whitespace()
.collect::<String>())
+ "QueryInput",
self.info.type_defs(),
);
let query_fragment = visit_rel_query_input::<RequestCtx>(
None,
&rel_var,
input_value_opt,
&info,
partition_key_opt,
&mut sg,
self.transaction,
)
.await?;
let results = self
.transaction
.read_rels(query_fragment, &rel_var, partition_key_opt)
.await?;
Ok(results)
}
}