Skip to content

Commit

Permalink
Add update mutation
Browse files Browse the repository at this point in the history
  • Loading branch information
karatakis committed Jul 28, 2023
1 parent df9a215 commit 36a0400
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 26 deletions.
28 changes: 16 additions & 12 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ use crate::{
ActiveEnumBuilder, ActiveEnumFilterInputBuilder, BuilderContext, ConnectionObjectBuilder,
CursorInputBuilder, EdgeObjectBuilder, EntityCreateBatchMutationBuilder,
EntityCreateOneMutationBuilder, EntityInputBuilder, EntityObjectBuilder,
EntityQueryFieldBuilder, FilterInputBuilder, FilterTypesMapHelper, OffsetInputBuilder,
OrderByEnumBuilder, OrderInputBuilder, PageInfoObjectBuilder, PageInputBuilder,
PaginationInfoObjectBuilder, PaginationInputBuilder,
EntityQueryFieldBuilder, EntityUpdateMutationBuilder, FilterInputBuilder, FilterTypesMapHelper,
OffsetInputBuilder, OrderByEnumBuilder, OrderInputBuilder, PageInfoObjectBuilder,
PageInputBuilder, PaginationInfoObjectBuilder, PaginationInputBuilder,
};

/// The Builder is used to create the Schema for GraphQL
Expand Down Expand Up @@ -107,28 +107,32 @@ impl Builder {
context: self.context,
};

if self.context.entity_input.unified {
let entity_input_object = entity_input_builder.insert_input_object::<T>();
self.inputs.push(entity_input_object);
} else {
let entity_insert_input_object = entity_input_builder.insert_input_object::<T>();
let entity_update_input_object = entity_input_builder.update_input_object::<T>();
self.inputs
.extend(vec![entity_insert_input_object, entity_update_input_object]);
}
let entity_insert_input_object = entity_input_builder.insert_input_object::<T>();
let entity_update_input_object = entity_input_builder.update_input_object::<T>();
self.inputs
.extend(vec![entity_insert_input_object, entity_update_input_object]);

// create one mutation
let entity_create_one_mutation_builder = EntityCreateOneMutationBuilder {
context: self.context,
};
let create_one_mutation = entity_create_one_mutation_builder.to_field::<T, A>();
self.mutations.push(create_one_mutation);

// create batch mutation
let entity_create_batch_mutation_builder: EntityCreateBatchMutationBuilder =
EntityCreateBatchMutationBuilder {
context: self.context,
};
let create_batch_mutation = entity_create_batch_mutation_builder.to_field::<T, A>();
self.mutations.push(create_batch_mutation);

// update mutation
let entity_update_mutation_builder = EntityUpdateMutationBuilder {
context: self.context,
};
let update_mutation = entity_update_mutation_builder.to_field::<T, A>();
self.mutations.push(update_mutation);
}

/// used to register a new enumeration to the builder context
Expand Down
7 changes: 4 additions & 3 deletions src/builder_context.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::{
ActiveEnumConfig, ActiveEnumFilterInputConfig, ConnectionObjectConfig, CursorInputConfig,
EdgeObjectConfig, EntityCreateBatchMutationConfig, EntityCreateOneMutationConfig,
EntityInputConfig, EntityObjectConfig, EntityQueryFieldConfig, FilterInputConfig,
OffsetInputConfig, OrderByEnumConfig, OrderInputConfig, PageInfoObjectConfig, PageInputConfig,
PaginationInfoObjectConfig, PaginationInputConfig,
EntityInputConfig, EntityObjectConfig, EntityQueryFieldConfig, EntityUpdateMutationConfig,
FilterInputConfig, OffsetInputConfig, OrderByEnumConfig, OrderInputConfig,
PageInfoObjectConfig, PageInputConfig, PaginationInfoObjectConfig, PaginationInputConfig,
};

pub mod guards;
Expand Down Expand Up @@ -43,6 +43,7 @@ pub struct BuilderContext {

pub entity_create_one_mutation: EntityCreateOneMutationConfig,
pub entity_create_batch_mutation: EntityCreateBatchMutationConfig,
pub entity_update_mutation: EntityUpdateMutationConfig,
pub entity_input: EntityInputConfig,

pub guards: GuardsConfig,
Expand Down
16 changes: 5 additions & 11 deletions src/inputs/entity_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ use crate::{BuilderContext, EntityObjectBuilder, SeaResult, TypesMapHelper};

/// The configuration structure of EntityInputBuilder
pub struct EntityInputConfig {
/// if true both insert and update are the same input object
pub unified: bool,
/// suffix that is appended on insert input objects
pub insert_suffix: String,
/// names of "{entity}.{column}" you want to skip the insert input to be generated
Expand All @@ -22,7 +20,6 @@ pub struct EntityInputConfig {
impl std::default::Default for EntityInputConfig {
fn default() -> Self {
EntityInputConfig {
unified: true,
insert_suffix: "InsertInput".into(),
insert_skips: Vec::new(),
update_suffix: "UpdateInput".into(),
Expand Down Expand Up @@ -56,9 +53,6 @@ impl EntityInputBuilder {
T: EntityTrait,
<T as EntityTrait>::Model: Sync,
{
if self.context.entity_input.unified {
return self.insert_type_name::<T>();
}
let entity_object_builder = EntityObjectBuilder {
context: self.context,
};
Expand All @@ -67,12 +61,12 @@ impl EntityInputBuilder {
}

/// used to produce the SeaORM entity input object
fn input_object<T>(&self, insert: bool) -> InputObject
fn input_object<T>(&self, is_insert: bool) -> InputObject
where
T: EntityTrait,
<T as EntityTrait>::Model: Sync,
{
let name = if insert {
let name = if is_insert {
self.insert_type_name::<T>()
} else {
self.update_type_name::<T>()
Expand All @@ -90,7 +84,7 @@ impl EntityInputBuilder {

let full_name = format!("{}.{}", entity_object_builder.type_name::<T>(), column_name);

let skip = if insert {
let skip = if is_insert {
self.context.entity_input.insert_skips.contains(&full_name)
} else {
self.context.entity_input.update_skips.contains(&full_name)
Expand All @@ -110,7 +104,7 @@ impl EntityInputBuilder {
None => return object,
};

let graphql_type = if column_def.is_null() {
let graphql_type = if column_def.is_null() || !is_insert {
TypeRef::named(type_name)
} else {
TypeRef::named_nn(type_name)
Expand All @@ -135,7 +129,7 @@ impl EntityInputBuilder {
T: EntityTrait,
<T as EntityTrait>::Model: Sync,
{
self.input_object::<T>(self.context.entity_input.unified)
self.input_object::<T>(false)
}

pub fn parse_object<T>(
Expand Down
130 changes: 130 additions & 0 deletions src/mutation/entity_update_mutation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
use async_graphql::dynamic::{Field, FieldFuture, FieldValue, InputValue, TypeRef};
use sea_orm::{
ActiveModelTrait, DatabaseConnection, EntityTrait, IntoActiveModel, QueryFilter,
TransactionTrait,
};

use crate::{
get_filter_conditions, prepare_active_model, BuilderContext, EntityInputBuilder,
EntityObjectBuilder, EntityQueryFieldBuilder, FilterInputBuilder,
};

/// The configuration structure of EntityUpdateMutationBuilder
pub struct EntityUpdateMutationConfig {
/// suffix that is appended on update mutations
pub mutation_suffix: String,

/// name for `data` field
pub data_field: String,

/// name for `filter` field
pub filter_field: String,
}

impl std::default::Default for EntityUpdateMutationConfig {
fn default() -> Self {
Self {
mutation_suffix: "Update".into(),
data_field: "data".into(),
filter_field: "filter".into(),
}
}
}

/// This builder produces the update mutation for an entity
pub struct EntityUpdateMutationBuilder {
pub context: &'static BuilderContext,
}

impl EntityUpdateMutationBuilder {
/// used to get mutation name for a SeaORM entity
pub fn type_name<T>(&self) -> String
where
T: EntityTrait,
<T as EntityTrait>::Model: Sync,
{
let entity_query_field_builder = EntityQueryFieldBuilder {
context: self.context,
};
format!(
"{}{}",
entity_query_field_builder.type_name::<T>(),
self.context.entity_update_mutation.mutation_suffix
)
}

/// used to get the update mutation field for a SeaORM entity
/// used to get the create mutation field for a SeaORM entity
pub fn to_field<T, A>(&self) -> Field
where
T: EntityTrait,
<T as EntityTrait>::Model: Sync,
<T as EntityTrait>::Model: IntoActiveModel<A>,
A: ActiveModelTrait<Entity = T> + sea_orm::ActiveModelBehavior + std::marker::Send,
{
let entity_input_builder = EntityInputBuilder {
context: self.context,
};
let entity_filter_input_builder = FilterInputBuilder {
context: self.context,
};
let entity_object_builder = EntityObjectBuilder {
context: self.context,
};
let object_name: String = entity_object_builder.type_name::<T>();

let context = self.context;

Field::new(
self.type_name::<T>(),
TypeRef::named_nn_list_nn(entity_object_builder.basic_type_name::<T>()),
move |ctx| {
FieldFuture::new(async move {
let db = ctx.data::<DatabaseConnection>()?;
let transaction = db.begin().await?;

let entity_input_builder = EntityInputBuilder { context };
let entity_object_builder = EntityObjectBuilder { context };

let filters = ctx.args.get(&context.entity_update_mutation.filter_field);
let filter_condition = get_filter_conditions::<T>(context, filters);
println!("{:?}", filter_condition);

let value_accessor = ctx
.args
.get(&context.entity_create_one_mutation.data_field)
.unwrap();
let input_object = &value_accessor.object()?;
let active_model = prepare_active_model::<T, A>(
&entity_input_builder,
&entity_object_builder,
input_object,
)?;

T::update_many()
.set(active_model)
.filter(filter_condition.clone())
.exec(&transaction)
.await?;

let result: Vec<T::Model> =
T::find().filter(filter_condition).all(&transaction).await?;

transaction.commit().await?;

Ok(Some(FieldValue::list(
result.into_iter().map(FieldValue::owned_any),
)))
})
},
)
.argument(InputValue::new(
&context.entity_update_mutation.data_field,
TypeRef::named_nn(entity_input_builder.update_type_name::<T>()),
))
.argument(InputValue::new(
&context.entity_update_mutation.filter_field,
TypeRef::named(entity_filter_input_builder.type_name(&object_name)),
))
}
}
3 changes: 3 additions & 0 deletions src/mutation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ pub use entity_create_one_mutation::*;

pub mod entity_create_batch_mutation;
pub use entity_create_batch_mutation::*;

pub mod entity_update_mutation;
pub use entity_update_mutation::*;

0 comments on commit 36a0400

Please sign in to comment.