Skip to content

Commit 5f9478d

Browse files
committed
Fix wundergraph_example to compile with the mysql backend
This requires some manual `HandleInsert` + `HandleBatchInsert` impls because the default provided one only works with integer primary keys, because there is no way to generally receive the last inserted primary key value using mysql. Interestingly we cannot derive `Insertable` then anymore because of an error about conflicting impls with the wild card impl in wundergraph itself. I think that's because rustc will not use associated types to see if an impl actual is conflicting or not.
1 parent 52759f9 commit 5f9478d

File tree

1 file changed

+187
-4
lines changed

1 file changed

+187
-4
lines changed

wundergraph_example/src/mutations.rs

Lines changed: 187 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@ use super::Friend;
99
use super::Hero;
1010
use super::HomeWorld;
1111
use super::Species;
12+
use diesel::prelude::*;
1213
use juniper::*;
14+
use wundergraph::query_builder::mutations::{HandleBatchInsert, HandleInsert};
15+
use wundergraph::query_builder::selection::LoadingHandler;
16+
use wundergraph::{QueryModifier, WundergraphContext};
1317

1418
#[derive(Insertable, GraphQLInputObject, Clone, Debug)]
1519
#[table_name = "heros"]
@@ -56,20 +60,199 @@ pub struct HomeWorldChangeset {
5660
name: Option<String>,
5761
}
5862

59-
#[derive(Insertable, GraphQLInputObject, Debug, Copy, Clone)]
60-
#[table_name = "friends"]
63+
#[cfg_attr(not(feature = "mysql"), derive(Insertable))]
64+
#[derive(GraphQLInputObject, Debug, Copy, Clone)]
65+
#[cfg_attr(not(feature = "mysql"), table_name = "friends")]
6166
pub struct NewFriend {
6267
hero_id: i32,
6368
friend_id: i32,
6469
}
6570

66-
#[derive(Insertable, GraphQLInputObject, Debug, Copy, Clone)]
67-
#[table_name = "appears_in"]
71+
impl<Ctx> HandleInsert<Friend, NewFriend, diesel::mysql::Mysql, Ctx> for friends::table
72+
where
73+
Ctx: WundergraphContext + QueryModifier<Friend, diesel::mysql::Mysql> + 'static,
74+
Ctx::Connection: Connection<Backend = diesel::mysql::Mysql>,
75+
{
76+
fn handle_insert(
77+
selection: Option<&'_ [Selection<'_, wundergraph::scalar::WundergraphScalarValue>]>,
78+
executor: &Executor<'_, Ctx, wundergraph::scalar::WundergraphScalarValue>,
79+
insertable: NewFriend,
80+
) -> ExecutionResult<wundergraph::scalar::WundergraphScalarValue> {
81+
let ctx = executor.context();
82+
let conn = ctx.get_connection();
83+
let look_ahead = executor.look_ahead();
84+
85+
conn.transaction(|| {
86+
diesel::insert_into(friends::table)
87+
.values((
88+
friends::hero_id.eq(insertable.hero_id),
89+
friends::friend_id.eq(insertable.friend_id),
90+
))
91+
.execute(conn)?;
92+
93+
let query = <Friend as LoadingHandler<diesel::mysql::Mysql, Ctx>>::build_query(
94+
&[],
95+
&look_ahead,
96+
)?
97+
.filter(
98+
friends::hero_id
99+
.eq(insertable.hero_id)
100+
.and(friends::friend_id.eq(insertable.friend_id)),
101+
)
102+
.limit(1);
103+
104+
let items = Friend::load(&look_ahead, selection, executor, query)?;
105+
Ok(items.into_iter().next().unwrap_or(Value::Null))
106+
})
107+
}
108+
}
109+
110+
impl<Ctx> HandleBatchInsert<Friend, NewFriend, diesel::mysql::Mysql, Ctx> for friends::table
111+
where
112+
Ctx: WundergraphContext + QueryModifier<Friend, diesel::mysql::Mysql> + 'static,
113+
Ctx::Connection: Connection<Backend = diesel::mysql::Mysql>,
114+
{
115+
fn handle_batch_insert(
116+
selection: Option<&'_ [Selection<'_, wundergraph::scalar::WundergraphScalarValue>]>,
117+
executor: &Executor<'_, Ctx, wundergraph::scalar::WundergraphScalarValue>,
118+
insertable: Vec<NewFriend>,
119+
) -> ExecutionResult<wundergraph::scalar::WundergraphScalarValue> {
120+
let ctx = executor.context();
121+
let conn = ctx.get_connection();
122+
let look_ahead = executor.look_ahead();
123+
124+
conn.transaction(|| {
125+
{
126+
let insert_values = insertable
127+
.iter()
128+
.map(|NewFriend { hero_id, friend_id }| {
129+
(
130+
friends::hero_id.eq(hero_id),
131+
friends::friend_id.eq(friend_id),
132+
)
133+
})
134+
.collect::<Vec<_>>();
135+
diesel::insert_into(friends::table)
136+
.values(insert_values)
137+
.execute(conn)?;
138+
}
139+
140+
let mut query = <Friend as LoadingHandler<diesel::mysql::Mysql, Ctx>>::build_query(
141+
&[],
142+
&look_ahead,
143+
)?;
144+
145+
for NewFriend { hero_id, friend_id } in insertable {
146+
query = query.or_filter(
147+
friends::hero_id
148+
.eq(hero_id)
149+
.and(friends::friend_id.eq(friend_id)),
150+
)
151+
}
152+
153+
let items = Friend::load(&look_ahead, selection, executor, query)?;
154+
Ok(Value::list(items))
155+
})
156+
}
157+
}
158+
159+
#[cfg_attr(not(feature = "mysql"), derive(Insertable))]
160+
#[derive(GraphQLInputObject, Debug, Copy, Clone)]
161+
#[cfg_attr(not(feature = "mysql"), table_name = "appears_in")]
68162
pub struct NewAppearsIn {
69163
hero_id: i32,
70164
episode: Episode,
71165
}
72166

167+
impl<Ctx> HandleInsert<AppearsIn, NewAppearsIn, diesel::mysql::Mysql, Ctx> for appears_in::table
168+
where
169+
Ctx: WundergraphContext + QueryModifier<AppearsIn, diesel::mysql::Mysql> + 'static,
170+
Ctx::Connection: Connection<Backend = diesel::mysql::Mysql>,
171+
{
172+
fn handle_insert(
173+
selection: Option<&'_ [Selection<'_, wundergraph::scalar::WundergraphScalarValue>]>,
174+
executor: &Executor<'_, Ctx, wundergraph::scalar::WundergraphScalarValue>,
175+
insertable: NewAppearsIn,
176+
) -> ExecutionResult<wundergraph::scalar::WundergraphScalarValue> {
177+
let ctx = executor.context();
178+
let conn = ctx.get_connection();
179+
let look_ahead = executor.look_ahead();
180+
181+
conn.transaction(|| {
182+
diesel::insert_into(appears_in::table)
183+
.values((
184+
appears_in::hero_id.eq(insertable.hero_id),
185+
appears_in::episode.eq(insertable.episode),
186+
))
187+
.execute(conn)?;
188+
189+
let query = <AppearsIn as LoadingHandler<diesel::mysql::Mysql, Ctx>>::build_query(
190+
&[],
191+
&look_ahead,
192+
)?
193+
.filter(
194+
appears_in::hero_id
195+
.eq(insertable.hero_id)
196+
.and(appears_in::episode.eq(insertable.episode)),
197+
)
198+
.limit(1);
199+
200+
let items = AppearsIn::load(&look_ahead, selection, executor, query)?;
201+
Ok(items.into_iter().next().unwrap_or(Value::Null))
202+
})
203+
}
204+
}
205+
206+
impl<Ctx> HandleBatchInsert<AppearsIn, NewAppearsIn, diesel::mysql::Mysql, Ctx>
207+
for appears_in::table
208+
where
209+
Ctx: WundergraphContext + QueryModifier<AppearsIn, diesel::mysql::Mysql> + 'static,
210+
Ctx::Connection: Connection<Backend = diesel::mysql::Mysql>,
211+
{
212+
fn handle_batch_insert(
213+
selection: Option<&'_ [Selection<'_, wundergraph::scalar::WundergraphScalarValue>]>,
214+
executor: &Executor<'_, Ctx, wundergraph::scalar::WundergraphScalarValue>,
215+
insertable: Vec<NewAppearsIn>,
216+
) -> ExecutionResult<wundergraph::scalar::WundergraphScalarValue> {
217+
let ctx = executor.context();
218+
let conn = ctx.get_connection();
219+
let look_ahead = executor.look_ahead();
220+
221+
conn.transaction(|| {
222+
{
223+
let insert_values = insertable
224+
.iter()
225+
.map(|NewAppearsIn { hero_id, episode }| {
226+
(
227+
appears_in::hero_id.eq(hero_id),
228+
appears_in::episode.eq(episode),
229+
)
230+
})
231+
.collect::<Vec<_>>();
232+
diesel::insert_into(appears_in::table)
233+
.values(insert_values)
234+
.execute(conn)?;
235+
}
236+
237+
let mut query = <AppearsIn as LoadingHandler<diesel::mysql::Mysql, Ctx>>::build_query(
238+
&[],
239+
&look_ahead,
240+
)?;
241+
242+
for NewAppearsIn { hero_id, episode } in insertable {
243+
query = query.or_filter(
244+
appears_in::hero_id
245+
.eq(hero_id)
246+
.and(appears_in::episode.eq(episode)),
247+
)
248+
}
249+
250+
let items = AppearsIn::load(&look_ahead, selection, executor, query)?;
251+
Ok(Value::list(items))
252+
})
253+
}
254+
}
255+
73256
wundergraph::mutation_object! {
74257
/// Global mutation object for the schema
75258
Mutation {

0 commit comments

Comments
 (0)