juniper_eager_loading/
macros.rs

1/// This macro will implement [`LoadFrom`][] for Diesel models using the Postgres backend.
2///
3/// It'll use an [`= ANY`] which is only supported by Postgres.
4///
5/// [`LoadFrom`]: trait.LoadFrom.html
6/// [`= ANY`]: http://docs.diesel.rs/diesel/expression_methods/trait.ExpressionMethods.html#method.eq_any
7///
8/// # Example usage
9///
10/// ```
11/// #[macro_use]
12/// extern crate diesel;
13///
14/// use diesel::pg::PgConnection;
15/// use diesel::prelude::*;
16/// use juniper_eager_loading::impl_load_from_for_diesel_pg;
17/// #
18/// # fn main() {}
19///
20/// table! {
21///     users (id) {
22///         id -> Integer,
23///     }
24/// }
25///
26/// table! {
27///     companies (id) {
28///         id -> Integer,
29///     }
30/// }
31///
32/// table! {
33///     employments (id) {
34///         id -> Integer,
35///         user_id -> Integer,
36///         company_id -> Integer,
37///     }
38/// }
39///
40/// #[derive(Queryable)]
41/// struct User {
42///     id: i32,
43/// }
44///
45/// #[derive(Queryable)]
46/// struct Company {
47///     id: i32,
48/// }
49///
50/// #[derive(Queryable)]
51/// struct Employment {
52///     id: i32,
53///     user_id: i32,
54///     company_id: i32,
55/// }
56///
57/// struct Context {
58///     db: PgConnection,
59/// }
60///
61/// impl Context {
62///     // The macro assumes this method exists
63///     fn db(&self) -> &PgConnection {
64///         &self.db
65///     }
66/// }
67///
68/// impl_load_from_for_diesel_pg! {
69///     (
70///         error = diesel::result::Error,
71///         context = Context,
72///     ) => {
73///         i32 -> (users, User),
74///         i32 -> (companies, Company),
75///         i32 -> (employments, Employment),
76///
77///         User.id -> (employments.user_id, Employment),
78///         Company.id -> (employments.company_id, Employment),
79///
80///         Employment.company_id -> (companies.id, Company),
81///         Employment.user_id -> (users.id, User),
82///     }
83/// }
84/// ```
85///
86/// # Syntax
87///
88/// First you specify your error and connection type with
89///
90/// ```text
91/// (
92///     error = diesel::result::Error,
93///     context = Context,
94/// ) => {
95///     // ...
96/// }
97/// ```
98///
99/// Then you define each model type you want to implement [`LoadFrom`] for and which columns and
100/// tables to use. There are two possible syntaxes for different purposes.
101///
102/// ```text
103/// i32 -> (users, User),
104/// ```
105///
106/// The first syntax implements `LoadFrom<i32> for User`, meaning from a `Vec<i32>` we can load a
107/// `Vec<User>`. It just takes the id type, the table, and the model struct.
108///
109/// ```text
110/// User.id -> (employments.user_id, Employment),
111/// ```
112///
113/// This syntax is required when using [`HasMany`][] and [`HasManyThrough`][]. In this case it
114/// implements `LoadFrom<User> for Employment`, meaning from a `Vec<User>` we can get
115/// `Vec<Employment>`. It does this by loading the users, mapping the list to the user ids,
116/// then finding the employments with those ids.
117///
118/// [`HasMany`]: trait.HasMany.html
119/// [`HasManyThrough`]: trait.HasManyThrough.html
120///
121/// # `Context::db`
122///
123/// It is required that your context type has a method called `db` which returns a reference to a
124/// Diesel connection that can be passed to `.load(_)`.
125///
126/// Example:
127///
128/// ```rust,ignore
129/// struct Context {
130///     db: PgConnection,
131/// }
132///
133/// impl Context {
134///     fn db(&self) -> &PgConnection {
135///         &self.db
136///     }
137/// }
138///
139/// // Whatever the method returns has to work with Diesel's `load` method
140/// users::table
141///     .filter(users::id.eq(any(user_ids)))
142///     .load::<User>(ctx.db())
143/// ```
144///
145/// # What gets generated
146///
147/// The two syntaxes generates code like this:
148///
149/// ```
150/// # #[macro_use]
151/// # extern crate diesel;
152/// # use diesel::pg::PgConnection;
153/// # use diesel::prelude::*;
154/// # use juniper_eager_loading::impl_load_from_for_diesel_pg;
155/// # fn main() {}
156/// # table! {
157/// #     users (id) {
158/// #         id -> Integer,
159/// #     }
160/// # }
161/// # table! {
162/// #     companies (id) {
163/// #         id -> Integer,
164/// #     }
165/// # }
166/// # table! {
167/// #     employments (id) {
168/// #         id -> Integer,
169/// #         user_id -> Integer,
170/// #         company_id -> Integer,
171/// #     }
172/// # }
173/// # #[derive(Queryable)]
174/// # struct User {
175/// #     id: i32,
176/// # }
177/// # #[derive(Queryable)]
178/// # struct Company {
179/// #     id: i32,
180/// # }
181/// # #[derive(Queryable)]
182/// # struct Employment {
183/// #     id: i32,
184/// #     user_id: i32,
185/// #     company_id: i32,
186/// # }
187/// # struct Context { db: PgConnection }
188/// # impl Context {
189/// #     fn db(&self) -> &PgConnection {
190/// #         &self.db
191/// #     }
192/// # }
193///
194/// // i32 -> (users, User),
195/// impl juniper_eager_loading::LoadFrom<i32> for User {
196///     type Error = diesel::result::Error;
197///     type Context = Context;
198///
199///     fn load(ids: &[i32], field_args: &(), ctx: &Self::Context) -> Result<Vec<Self>, Self::Error> {
200///         use diesel::pg::expression::dsl::any;
201///
202///         users::table
203///             .filter(users::id.eq(any(ids)))
204///             .load::<User>(ctx.db())
205///             .map_err(From::from)
206///     }
207/// }
208///
209/// // User.id -> (employments.user_id, Employment),
210/// impl juniper_eager_loading::LoadFrom<User> for Employment {
211///     type Error = diesel::result::Error;
212///     type Context = Context;
213///
214///     fn load(froms: &[User], field_args: &(), ctx: &Self::Context) -> Result<Vec<Self>, Self::Error> {
215///         use diesel::pg::expression::dsl::any;
216///
217///         let from_ids = froms.iter().map(|other| other.id).collect::<Vec<_>>();
218///         employments::table
219///             .filter(employments::user_id.eq(any(from_ids)))
220///             .load(ctx.db())
221///             .map_err(From::from)
222///     }
223/// }
224/// ```
225#[macro_export]
226macro_rules! impl_load_from_for_diesel_pg {
227    ( $($token:tt)* ) => {
228        $crate::proc_macros::impl_load_from_for_diesel_pg!($($token)*);
229    }
230}
231
232/// This macro will implement [`LoadFrom`][] for Diesel models using the MySQL backend.
233///
234/// For more details see [`impl_load_from_for_diesel_pg`][].
235///
236/// [`impl_load_from_for_diesel_pg`]: macro.impl_load_from_for_diesel_pg.html
237/// [`LoadFrom`]: trait.LoadFrom.html
238///
239/// # Example usage
240///
241/// ```
242/// #[macro_use]
243/// extern crate diesel;
244///
245/// use diesel::mysql::MysqlConnection;
246/// use diesel::prelude::*;
247/// use juniper_eager_loading::impl_load_from_for_diesel_mysql;
248/// #
249/// # fn main() {}
250///
251/// table! {
252///     users (id) {
253///         id -> Integer,
254///     }
255/// }
256///
257/// table! {
258///     companies (id) {
259///         id -> Integer,
260///     }
261/// }
262///
263/// table! {
264///     employments (id) {
265///         id -> Integer,
266///         user_id -> Integer,
267///         company_id -> Integer,
268///     }
269/// }
270///
271/// #[derive(Queryable)]
272/// struct User {
273///     id: i32,
274/// }
275///
276/// #[derive(Queryable)]
277/// struct Company {
278///     id: i32,
279/// }
280///
281/// #[derive(Queryable)]
282/// struct Employment {
283///     id: i32,
284///     user_id: i32,
285///     company_id: i32,
286/// }
287///
288/// struct Context {
289///     db: MysqlConnection,
290/// }
291///
292/// impl Context {
293///     // The macro assumes this method exists
294///     fn db(&self) -> &MysqlConnection {
295///         &self.db
296///     }
297/// }
298///
299/// impl_load_from_for_diesel_mysql! {
300///     (
301///         error = diesel::result::Error,
302///         context = Context,
303///     ) => {
304///         i32 -> (users, User),
305///         i32 -> (companies, Company),
306///         i32 -> (employments, Employment),
307///
308///         User.id -> (employments.user_id, Employment),
309///         Company.id -> (employments.company_id, Employment),
310///
311///         Employment.company_id -> (companies.id, Company),
312///         Employment.user_id -> (users.id, User),
313///     }
314/// }
315/// ```
316#[macro_export]
317macro_rules! impl_load_from_for_diesel_mysql {
318    ( $($token:tt)* ) => {
319        $crate::proc_macros::impl_load_from_for_diesel_mysql!($($token)*);
320    }
321}
322
323/// This macro will implement [`LoadFrom`][] for Diesel models using the SQLite backend.
324///
325/// For more details see [`impl_load_from_for_diesel_pg`][].
326///
327/// [`impl_load_from_for_diesel_pg`]: macro.impl_load_from_for_diesel_pg.html
328/// [`LoadFrom`]: trait.LoadFrom.html
329///
330/// # Example usage
331///
332/// ```
333/// #[macro_use]
334/// extern crate diesel;
335///
336/// use diesel::sqlite::SqliteConnection;
337/// use diesel::prelude::*;
338/// use juniper_eager_loading::impl_load_from_for_diesel_sqlite;
339/// #
340/// # fn main() {}
341///
342/// table! {
343///     users (id) {
344///         id -> Integer,
345///     }
346/// }
347///
348/// table! {
349///     companies (id) {
350///         id -> Integer,
351///     }
352/// }
353///
354/// table! {
355///     employments (id) {
356///         id -> Integer,
357///         user_id -> Integer,
358///         company_id -> Integer,
359///     }
360/// }
361///
362/// #[derive(Queryable)]
363/// struct User {
364///     id: i32,
365/// }
366///
367/// #[derive(Queryable)]
368/// struct Company {
369///     id: i32,
370/// }
371///
372/// #[derive(Queryable)]
373/// struct Employment {
374///     id: i32,
375///     user_id: i32,
376///     company_id: i32,
377/// }
378///
379/// struct Context {
380///     db: SqliteConnection,
381/// }
382///
383/// impl Context {
384///     // The macro assumes this method exists
385///     fn db(&self) -> &SqliteConnection {
386///         &self.db
387///     }
388/// }
389///
390/// impl_load_from_for_diesel_sqlite! {
391///     (
392///         error = diesel::result::Error,
393///         context = Context,
394///     ) => {
395///         i32 -> (users, User),
396///         i32 -> (companies, Company),
397///         i32 -> (employments, Employment),
398///
399///         User.id -> (employments.user_id, Employment),
400///         Company.id -> (employments.company_id, Employment),
401///
402///         Employment.company_id -> (companies.id, Company),
403///         Employment.user_id -> (users.id, User),
404///     }
405/// }
406/// ```
407#[macro_export]
408macro_rules! impl_load_from_for_diesel_sqlite {
409    ( $($token:tt)* ) => {
410        $crate::proc_macros::impl_load_from_for_diesel_sqlite!($($token)*);
411    }
412}