Skip to content

Commit 03ec1d9

Browse files
authored
Merge pull request diesel-rs#1983 from diesel-rs/sg-sql-function-proc
Change `sql_function!` to be a proc macro
2 parents 64faade + c2ba306 commit 03ec1d9

11 files changed

Lines changed: 321 additions & 788 deletions

File tree

diesel/src/expression/count.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ sql_function! {
1515
///
1616
/// ```rust
1717
/// # #[macro_use] extern crate diesel;
18-
/// # include!("../../doctest_setup.rs");
18+
/// # include!("../doctest_setup.rs");
1919
/// # use diesel::dsl::*;
2020
/// #
2121
/// # fn main() {

diesel/src/expression/functions/mod.rs

Lines changed: 3 additions & 334 deletions
Original file line numberDiff line numberDiff line change
@@ -1,292 +1,3 @@
1-
#[macro_export]
2-
#[doc(hidden)]
3-
macro_rules! __diesel_sql_function_body {
4-
// Entry point with type arguments. Pull out the rest of the body.
5-
(
6-
data = (
7-
meta = $meta:tt,
8-
fn_name = $fn_name:tt,
9-
),
10-
type_args = $type_args:tt,
11-
type_args_with_bounds = $type_args_with_bounds:tt,
12-
unparsed_tokens = (
13-
$args:tt -> $return_type:ty $(;)*
14-
),
15-
) => {
16-
__diesel_sql_function_body! {
17-
meta = $meta,
18-
fn_name = $fn_name,
19-
type_args = $type_args,
20-
type_args_with_bounds = $type_args_with_bounds,
21-
args = $args,
22-
return_type = $return_type,
23-
}
24-
};
25-
26-
// Entry point. We need to search the meta items for our special attributes
27-
(
28-
meta = $meta:tt,
29-
fn_name = $fn_name:ident,
30-
$($rest:tt)*
31-
) => {
32-
__diesel_sql_function_body! {
33-
aggregate = no,
34-
sql_name = stringify!($fn_name),
35-
unchecked_meta = $meta,
36-
meta = (),
37-
fn_name = $fn_name,
38-
$($rest)*
39-
}
40-
};
41-
42-
// Found #[aggregate]
43-
(
44-
aggregate = $aggregate:tt,
45-
sql_name = $sql_name:expr,
46-
unchecked_meta = (#[aggregate] $($unchecked:tt)*),
47-
meta = $meta:tt,
48-
$($rest:tt)*
49-
) => {
50-
__diesel_sql_function_body! {
51-
aggregate = yes,
52-
sql_name = $sql_name,
53-
unchecked_meta = ($($unchecked)*),
54-
meta = $meta,
55-
$($rest)*
56-
}
57-
};
58-
59-
// Found #[sql_name].
60-
(
61-
aggregate = $aggregate:tt,
62-
sql_name = $ignored:expr,
63-
unchecked_meta = (#[sql_name = $sql_name:expr] $($unchecked:tt)*),
64-
meta = $meta:tt,
65-
$($rest:tt)*
66-
) => {
67-
__diesel_sql_function_body! {
68-
aggregate = $aggregate,
69-
sql_name = $sql_name,
70-
unchecked_meta = ($($unchecked)*),
71-
meta = $meta,
72-
$($rest)*
73-
}
74-
};
75-
76-
// Didn't find a special attribute
77-
(
78-
aggregate = $aggregate:tt,
79-
sql_name = $sql_name:expr,
80-
unchecked_meta = (#$checked:tt $($unchecked:tt)*),
81-
meta = ($($meta:tt)*),
82-
$($rest:tt)*
83-
) => {
84-
__diesel_sql_function_body! {
85-
aggregate = $aggregate,
86-
sql_name = $sql_name,
87-
unchecked_meta = ($($unchecked)*),
88-
meta = ($($meta)* #$checked),
89-
$($rest)*
90-
}
91-
};
92-
93-
// Done searching for special attributes
94-
(
95-
aggregate = $aggregate:tt,
96-
sql_name = $sql_name:expr,
97-
unchecked_meta = (),
98-
meta = ($($meta:tt)*),
99-
fn_name = $fn_name:ident,
100-
type_args = ($($type_args:ident,)*),
101-
type_args_with_bounds = ($($type_args_bounds:tt)*),
102-
args = ($($arg_name:ident: $arg_type:ty),*),
103-
return_type = $return_type:ty,
104-
) => {
105-
$($meta)*
106-
#[allow(non_camel_case_types)]
107-
pub fn $fn_name<$($type_args_bounds)* $($arg_name),*>($($arg_name: $arg_name),*)
108-
-> $fn_name::HelperType<$($type_args,)* $($arg_name),*>
109-
where
110-
$($arg_name: $crate::expression::AsExpression<$arg_type>),+
111-
{
112-
$fn_name::$fn_name {
113-
$($arg_name: $arg_name.as_expression(),)+
114-
$($type_args: ::std::marker::PhantomData,)*
115-
}
116-
}
117-
118-
#[doc(hidden)]
119-
#[allow(non_camel_case_types, non_snake_case, unused_imports)]
120-
pub(crate) mod $fn_name {
121-
use super::*;
122-
use $crate::sql_types::*;
123-
124-
#[derive(Debug, Clone, Copy, QueryId, DieselNumericOps)]
125-
pub struct $fn_name<$($type_args,)* $($arg_name),*> {
126-
$(pub(in super) $arg_name: $arg_name,)*
127-
$(pub(in super) $type_args: ::std::marker::PhantomData<$type_args>,)*
128-
}
129-
130-
pub type HelperType<$($type_args,)* $($arg_name),*> = $fn_name<
131-
$($type_args,)*
132-
$(
133-
<$arg_name as $crate::expression::AsExpression<$arg_type>>::Expression
134-
),*
135-
>;
136-
137-
impl<$($type_args_bounds)* $($arg_name),*>
138-
$crate::expression::Expression
139-
for $fn_name<$($type_args,)* $($arg_name),*>
140-
where
141-
($($arg_name),*): $crate::expression::Expression,
142-
{
143-
type SqlType = $return_type;
144-
}
145-
146-
impl<$($type_args_bounds)* $($arg_name),*, DB>
147-
$crate::query_builder::QueryFragment<DB>
148-
for $fn_name<$($type_args,)* $($arg_name),*>
149-
where
150-
DB: $crate::backend::Backend,
151-
for<'a> ($(&'a $arg_name),*): $crate::query_builder::QueryFragment<DB>,
152-
{
153-
fn walk_ast(&self, mut out: $crate::query_builder::AstPass<DB>) -> $crate::result::QueryResult<()> {
154-
out.push_sql(concat!($sql_name, "("));
155-
$crate::query_builder::QueryFragment::walk_ast(
156-
&($(&self.$arg_name),*), out.reborrow())?;
157-
out.push_sql(")");
158-
Ok(())
159-
}
160-
}
161-
162-
impl<$($type_args_bounds)* $($arg_name),*, QS>
163-
$crate::expression::SelectableExpression<QS>
164-
for $fn_name<$($type_args,)* $($arg_name),*>
165-
where
166-
$($arg_name: $crate::expression::SelectableExpression<QS>,)*
167-
Self: $crate::expression::AppearsOnTable<QS>,
168-
{
169-
}
170-
171-
impl<$($type_args_bounds)* $($arg_name),*, QS>
172-
$crate::expression::AppearsOnTable<QS>
173-
for $fn_name<$($type_args,)* $($arg_name),*>
174-
where
175-
$($arg_name: $crate::expression::AppearsOnTable<QS>,)*
176-
Self: $crate::expression::Expression,
177-
{
178-
}
179-
180-
static_cond! {
181-
if $aggregate == no {
182-
impl<$($type_args_bounds)* $($arg_name),*>
183-
$crate::expression::NonAggregate
184-
for $fn_name<$($type_args,)* $($arg_name),*>
185-
where
186-
$($arg_name: $crate::expression::NonAggregate,)*
187-
Self: $crate::expression::Expression,
188-
{
189-
}
190-
}
191-
}
192-
193-
__diesel_sqlite_register_fn! {
194-
type_args = ($($type_args)*),
195-
aggregate = $aggregate,
196-
fn_name = $fn_name,
197-
args = ($($arg_name,)+),
198-
sql_args = ($($arg_type,)+),
199-
ret = $return_type,
200-
}
201-
}
202-
}
203-
}
204-
205-
#[macro_export]
206-
#[doc(hidden)]
207-
#[cfg(feature = "sqlite")]
208-
macro_rules! __diesel_sqlite_register_fn {
209-
// We can't handle generic functions for SQLite
210-
(
211-
type_args = ($($type_args:tt)+),
212-
$($rest:tt)*
213-
) => {
214-
};
215-
216-
// We don't currently support aggregate functions for SQLite
217-
(
218-
type_args = $ignored:tt,
219-
aggregate = yes,
220-
$($rest:tt)*
221-
) => {
222-
};
223-
224-
(
225-
type_args = (),
226-
aggregate = no,
227-
fn_name = $fn_name:ident,
228-
args = ($($args:ident,)+),
229-
sql_args = $sql_args:ty,
230-
ret = $ret:ty,
231-
) => {
232-
#[allow(dead_code)]
233-
/// Registers an implementation for this function on the given connection
234-
///
235-
/// This function must be called for every `SqliteConnection` before
236-
/// this SQL function can be used on SQLite. The implementation must be
237-
/// deterministic (returns the same result given the same arguments). If
238-
/// the function is nondeterministic, call
239-
/// `register_nondeterministic_impl` instead.
240-
pub fn register_impl<F, Ret, $($args,)+>(
241-
conn: &$crate::SqliteConnection,
242-
f: F,
243-
) -> $crate::QueryResult<()>
244-
where
245-
F: Fn($($args,)+) -> Ret + Send + 'static,
246-
($($args,)+): $crate::deserialize::Queryable<$sql_args, $crate::sqlite::Sqlite>,
247-
Ret: $crate::serialize::ToSql<$ret, $crate::sqlite::Sqlite>,
248-
{
249-
conn.register_sql_function::<$sql_args, $ret, _, _, _>(
250-
stringify!($fn_name),
251-
true,
252-
move |($($args,)+)| f($($args),+),
253-
)
254-
}
255-
256-
#[allow(dead_code)]
257-
/// Registers an implementation for this function on the given connection
258-
///
259-
/// This function must be called for every `SqliteConnection` before
260-
/// this SQL function can be used on SQLite.
261-
/// `register_nondeterministic_impl` should only be used if your
262-
/// function can return different results with the same arguments (e.g.
263-
/// `random`). If your function is deterministic, you should call
264-
/// `register_impl` instead.
265-
pub fn register_nondeterministic_impl<F, Ret, $($args,)+>(
266-
conn: &$crate::SqliteConnection,
267-
mut f: F,
268-
) -> $crate::QueryResult<()>
269-
where
270-
F: FnMut($($args,)+) -> Ret + Send + 'static,
271-
($($args,)+): $crate::deserialize::Queryable<$sql_args, $crate::sqlite::Sqlite>,
272-
Ret: $crate::serialize::ToSql<$ret, $crate::sqlite::Sqlite>,
273-
{
274-
conn.register_sql_function::<$sql_args, $ret, _, _, _>(
275-
stringify!($fn_name),
276-
false,
277-
move |($($args,)+)| f($($args),+),
278-
)
279-
}
280-
};
281-
}
282-
283-
#[macro_export]
284-
#[doc(hidden)]
285-
#[cfg(not(feature = "sqlite"))]
286-
macro_rules! __diesel_sqlite_register_fn {
287-
($($token:tt)*) => {};
288-
}
289-
2901
#[macro_export]
2912
/// Declare a sql function for use in your code.
2923
///
@@ -452,51 +163,9 @@ macro_rules! __diesel_sqlite_register_fn {
452163
/// # }
453164
/// ```
454165
macro_rules! sql_function {
455-
($(#$meta:tt)* fn $fn_name:ident $args:tt $(;)*) => {
456-
sql_function!($(#$meta)* fn $fn_name $args -> ());
457-
};
458-
459-
($(#$meta:tt)* fn $fn_name:ident $args:tt -> $return_type:ty $(;)*) => {
460-
sql_function!($(#$meta)* fn $fn_name <> $args -> $return_type);
461-
};
462-
463-
(
464-
$(#$meta:tt)*
465-
fn $fn_name:ident
466-
<
467-
$($tokens:tt)*
468-
) => {
469-
__diesel_parse_type_args!(
470-
data = (
471-
meta = ($(#$meta)*),
472-
fn_name = $fn_name,
473-
),
474-
callback = __diesel_sql_function_body,
475-
tokens = ($($tokens)*),
476-
);
477-
};
478-
479-
($fn_name:ident, $struct_name:ident, $args:tt -> $return_type:ty) => {
480-
sql_function!($fn_name, $struct_name, $args -> $return_type, "");
481-
};
482-
483-
($fn_name:ident, $struct_name:ident, $args:tt -> $return_type:ty, $docs:expr) => {
484-
sql_function!($fn_name, $struct_name, $args -> $return_type, $docs, "");
485-
};
486-
487-
($fn_name:ident, $struct_name:ident, ($($arg_name:ident: $arg_type:ty),*)) => {
488-
sql_function!($fn_name, $struct_name, ($($arg_name: $arg_type),*) -> ());
489-
};
490-
491-
(
492-
$fn_name:ident,
493-
$struct_name:ident,
494-
$args:tt -> $return_type:ty,
495-
$docs:expr,
496-
$helper_ty_docs:expr
497-
) => {
498-
sql_function_body!($fn_name, $struct_name, $args -> $return_type, $docs, $helper_ty_docs);
499-
};
166+
($($args:tt)*) => {
167+
sql_function_proc! { $($args)* }
168+
}
500169
}
501170

502171
#[macro_export]

0 commit comments

Comments
 (0)