use std::{pin::Pin, sync::Arc}; use async_graphql::dynamic::{ Field, FieldFuture, FieldValue, InputValue, ResolverContext, TypeRef, ValueAccessor, }; use sea_orm::EntityTrait; use seaography::{BuilderContext, EntityObjectBuilder, FilterInputBuilder, GuardAction}; use crate::{app::AppContextTrait, errors::RecorderResult}; pub type FilterMutationFn = Arc< dyn for<'a> Fn( &ResolverContext<'a>, Arc, Option>, ) -> Pin< Box>>> + Send + 'a>, > + Send + Sync, >; pub fn generate_entity_filter_mutation_field( builder_context: &'static BuilderContext, field_name: N, type_ref: R, mutation_fn: FilterMutationFn, ) -> Field where T: EntityTrait, ::Model: Sync, N: Into, R: Into, { let entity_filter_input_builder = FilterInputBuilder { context: builder_context, }; let entity_object_builder = EntityObjectBuilder { context: builder_context, }; let object_name: String = entity_object_builder.type_name::(); let context = builder_context; let guard = builder_context.guards.entity_guards.get(&object_name); Field::new(field_name, type_ref, move |ctx| { let mutation_fn = mutation_fn.clone(); FieldFuture::new(async move { let guard_flag = if let Some(guard) = guard { (*guard)(&ctx) } else { GuardAction::Allow }; if let GuardAction::Block(reason) = guard_flag { return Err::, async_graphql::Error>(async_graphql::Error::new( reason.unwrap_or("Entity guard triggered.".into()), )); } let app_ctx = ctx.data::>()?; let filters = ctx.args.get(&context.entity_delete_mutation.filter_field); let result = mutation_fn(&ctx, app_ctx.clone(), filters) .await .map_err(async_graphql::Error::new_with_source)?; Ok(result) }) }) .argument(InputValue::new( &context.entity_delete_mutation.filter_field, TypeRef::named(entity_filter_input_builder.type_name(&object_name)), )) }