Skip to content

Instantly share code, notes, and snippets.

@p-alik
Last active June 6, 2020 05:24
Show Gist options
  • Save p-alik/fb53204bb75733268d918de1fa6804b8 to your computer and use it in GitHub Desktop.
Save p-alik/fb53204bb75733268d918de1fa6804b8 to your computer and use it in GitHub Desktop.
minimal MySql wundergraph::query_builder::mutations::insert::HandleInsert implementation
use diesel::associations::HasTable;
use diesel::backend::Backend;
use diesel::deserialize::FromSql;
use diesel::dsl::SqlTypeOf;
use diesel::expression::{Expression, NonAggregate, SelectableExpression};
use diesel::insertable::CanInsertInSingleQuery;
use diesel::mysql::Mysql;
use diesel::query_builder::{BoxedSelectStatement, QueryFragment};
use diesel::query_dsl::methods::{BoxedDsl, FilterDsl};
use diesel::r2d2::{ConnectionManager, Pool, PooledConnection};
use diesel::sql_types::{Bigint, HasSqlType, Integer};
use diesel::{
AppearsOnTable, Connection, EqAll, Identifiable, Insertable, MysqlConnection, RunQueryDsl,
Table,
};
use juniper::{http::GraphQLRequest, ExecutionResult, Executor, Selection, Value};
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;
use std::sync::Arc;
use wundergraph::query_builder::mutations::{HandleBatchInsert, HandleInsert};
use wundergraph::query_builder::selection::{
fields::WundergraphFieldList, filter::BuildFilter, order::BuildOrder, select::BuildSelect,
LoadingHandler, QueryModifier, SqlTypeOfPlaceholder,
};
use wundergraph::scalar::WundergraphScalarValue;
use wundergraph::{WundergraphContext, WundergraphEntity};
diesel::no_arg_sql_function!(LAST_INSERT_ID, Bigint);
table! {
comments (id) {
id -> Integer,
post -> Nullable<Integer>,
commenter -> Nullable<Integer>,
content -> Text,
}
}
allow_tables_to_appear_in_same_query!(comments,);
#[derive(Clone, Debug, Identifiable, WundergraphEntity)]
#[table_name = "comments"]
#[primary_key(id)]
pub struct Comment {
id: i32,
content: String,
}
wundergraph::query_object! {
Query {
Comment,
}
}
#[derive(Insertable, juniper::GraphQLInputObject, Clone, Debug)]
#[graphql(scalar = "WundergraphScalarValue")]
#[table_name = "comments"]
pub struct NewComment {
post: Option<i32>,
commenter: Option<i32>,
content: String,
}
impl<L, I, Ctx, T> HandleInsert<L, I, Mysql, Ctx> for comments::table
where
T: Table + HasTable<Table = T> + 'static,
T::FromClause: QueryFragment<Mysql>,
L: LoadingHandler<Mysql, Ctx, Table = T> + 'static,
L::FieldList: WundergraphFieldList<Mysql, L::PrimaryKeyIndex, T, Ctx>,
<L::Filter as BuildFilter<Mysql>>::Ret: AppearsOnTable<T>,
L::Columns: BuildOrder<T, Mysql>
+ BuildSelect<T, Mysql, SqlTypeOfPlaceholder<L::FieldList, Mysql, L::PrimaryKeyIndex, T, Ctx>>,
&'static L: Identifiable,
Ctx: WundergraphContext + QueryModifier<L, Mysql>,
Ctx::Connection: Connection<Backend = Mysql>,
I: Insertable<T>,
I::Values: QueryFragment<Mysql> + CanInsertInSingleQuery<Mysql>,
T: BoxedDsl<
'static,
Mysql,
Output = BoxedSelectStatement<'static, SqlTypeOf<<T as Table>::AllColumns>, T, Mysql>,
>,
<Ctx::Connection as Connection>::Backend: HasSqlType<SqlTypeOf<T::PrimaryKey>>
+ HasSqlType<SqlTypeOfPlaceholder<L::FieldList, Mysql, L::PrimaryKeyIndex, T, Ctx>>,
T::PrimaryKey: EqAll<i32>,
T::PrimaryKey: Expression<SqlType = Integer>,
T::PrimaryKey: QueryFragment<Mysql> + Default,
<T::PrimaryKey as EqAll<i32>>::Output:
SelectableExpression<T> + NonAggregate + QueryFragment<Mysql> + 'static,
i32: FromSql<Integer, Mysql>,
{
fn handle_insert(
selection: Option<&'_ [Selection<'_, WundergraphScalarValue>]>,
executor: &Executor<'_, Ctx, WundergraphScalarValue>,
insertable: I,
) -> ExecutionResult<WundergraphScalarValue> {
let ctx = executor.context();
let conn = ctx.get_connection();
conn.transaction(|| -> ExecutionResult<WundergraphScalarValue> {
let look_ahead = executor.look_ahead();
insertable.insert_into(T::table()).execute(conn)?;
let last_insert_id: i64 = diesel::select(LAST_INSERT_ID).first(conn)?;
let q = L::build_query(&[], &look_ahead)?;
let q = FilterDsl::filter(
q,
T::PrimaryKey::default().eq_all(i32::try_from(last_insert_id)?),
);
let items = L::load(&look_ahead, selection, executor, q)?;
Ok(items.into_iter().next().unwrap_or(Value::Null))
})
}
}
impl<L, I, DB, Ctx> HandleBatchInsert<L, I, DB, Ctx> for comments::table
where
L: LoadingHandler<Mysql, Ctx>,
DB: Backend,
Ctx: WundergraphContext + QueryModifier<L, Mysql>,
Ctx::Connection: Connection<Backend = Mysql>,
{
fn handle_batch_insert(
_selection: Option<&'_ [Selection<'_, WundergraphScalarValue>]>,
_executor: &Executor<'_, Ctx, WundergraphScalarValue>,
_insertable: Vec<I>,
) -> ExecutionResult<WundergraphScalarValue> {
unimplemented!()
}
}
#[derive(AsChangeset, Identifiable, juniper::GraphQLInputObject, Clone, Debug)]
#[graphql(scalar = "WundergraphScalarValue")]
#[table_name = "comments"]
#[primary_key(id)]
pub struct CommentChangeset {
id: i32,
content: String,
}
wundergraph::mutation_object! {
Mutation{
Comment(insert = NewComment, update = CommentChangeset, ),
}
}
pub type Schema<Connection> = juniper::RootNode<
'static,
Query<PooledConnection<ConnectionManager<Connection>>>,
Mutation<PooledConnection<ConnectionManager<Connection>>>,
WundergraphScalarValue,
>;
#[derive(Serialize, Deserialize, Debug)]
pub struct GraphQLData(GraphQLRequest<WundergraphScalarValue>);
#[derive(Clone)]
struct AppState {
schema: Arc<Schema<MysqlConnection>>,
pool: Arc<Pool<ConnectionManager<MysqlConnection>>>,
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment