define_sql_function!() { /* proc-macro */ }
Expand description
Declare a sql function for use in your code.
Diesel only provides support for a very small number of SQL functions. This macro enables you to add additional functions from the SQL standard, as well as any custom functions your application might have.
This is a legacy variant of the [#[declare_sql_function]
] attribute macro, which
should be preferred instead. It will generate the same code as the attribute macro
and also it will accept the same syntax as the other macro.
The syntax for this macro is very similar to that of a normal Rust function,
except the argument and return types will be the SQL types being used.
Typically, these types will come from diesel::sql_types
This macro will generate two items. A function with the name that you’ve given, and a module with a helper type representing the return type of your function. For example, this invocation:
define_sql_function!(fn lower(x: Text) -> Text);
will generate this code:
pub fn lower<X>(x: X) -> lower<X> {
...
}
pub type lower<X> = ...;
Most attributes given to this macro will be put on the generated function (including doc comments).
§Adding Doc Comments
use diesel::sql_types::Text;
define_sql_function! {
/// Represents the `canon_crate_name` SQL function, created in
/// migration ....
fn canon_crate_name(a: Text) -> Text;
}
let target_name = "diesel";
crates.filter(canon_crate_name(name).eq(canon_crate_name(target_name)));
// This will generate the following SQL
// SELECT * FROM crates WHERE canon_crate_name(crates.name) = canon_crate_name($1)
§Special Attributes
There are a handful of special attributes that Diesel will recognize. They are:
#[aggregate]
- Indicates that this is an aggregate function, and that
NonAggregate
shouldn’t be implemented.
- Indicates that this is an aggregate function, and that
#[sql_name = "name"]
- The SQL to be generated is different from the Rust name of the function. This can be used to represent functions which can take many argument types, or to capitalize function names.
§Expanded Code
Expanded Code
§Input
define_sql_function! {
fn lower(input : Text) -> Text;
}
§Expanded Code
The macro expands the input to the following Rust code:
#[allow(non_camel_case_types)]
pub fn lower<input>(input: input) -> lower<input>
where
input: diesel::expression::AsExpression<Text>,
{
lower_utils::lower {
input: input.as_expression(),
}
}
#[allow(non_camel_case_types, non_snake_case)]
///The return type of [`lower()`](super::fn_name)
pub type lower<input> = lower_utils::lower<
<input as diesel::expression::AsExpression<Text>>::Expression,
>;
#[doc(hidden)]
#[allow(non_camel_case_types, non_snake_case, unused_imports)]
pub(crate) mod lower_utils {
use diesel::{self, QueryResult};
use diesel::expression::{
AsExpression, Expression, SelectableExpression, AppearsOnTable, ValidGrouping,
};
use diesel::query_builder::{QueryFragment, AstPass};
use diesel::sql_types::*;
use diesel::internal::sql_functions::*;
use super::*;
#[derive(Debug, Clone, Copy, diesel::query_builder::QueryId)]
#[derive(diesel::sql_types::DieselNumericOps)]
pub struct lower<input> {
pub(super) input: input,
}
///The return type of [`lower()`](super::fn_name)
pub type HelperType<input> = lower<<input as AsExpression<Text>>::Expression>;
impl<input> Expression for lower<input>
where
(input): Expression,
{
type SqlType = Text;
}
impl<input, __DieselInternal> SelectableExpression<__DieselInternal> for lower<input>
where
input: SelectableExpression<__DieselInternal>,
Self: AppearsOnTable<__DieselInternal>,
{}
impl<input, __DieselInternal> AppearsOnTable<__DieselInternal> for lower<input>
where
input: AppearsOnTable<__DieselInternal>,
Self: Expression,
{}
impl<input, __DieselInternal> FunctionFragment<__DieselInternal> for lower<input>
where
__DieselInternal: diesel::backend::Backend,
input: QueryFragment<__DieselInternal>,
{
const FUNCTION_NAME: &'static str = "lower";
#[allow(unused_assignments)]
fn walk_arguments<'__b>(
&'__b self,
mut out: AstPass<'_, '__b, __DieselInternal>,
) -> QueryResult<()> {
let mut needs_comma = false;
if !self.input.is_noop(out.backend())? {
if needs_comma {
out.push_sql(", ");
}
self.input.walk_ast(out.reborrow())?;
needs_comma = true;
}
Ok(())
}
}
impl<input, __DieselInternal> QueryFragment<__DieselInternal> for lower<input>
where
__DieselInternal: diesel::backend::Backend,
input: QueryFragment<__DieselInternal>,
{
fn walk_ast<'__b>(
&'__b self,
mut out: AstPass<'_, '__b, __DieselInternal>,
) -> QueryResult<()> {
out.push_sql(<Self as FunctionFragment<__DieselInternal>>::FUNCTION_NAME);
out.push_sql("(");
self.walk_arguments(out.reborrow())?;
out.push_sql(")");
Ok(())
}
}
#[derive(ValidGrouping)]
pub struct __Derived<input>(input);
impl<input, __DieselInternal> ValidGrouping<__DieselInternal> for lower<input>
where
__Derived<input>: ValidGrouping<__DieselInternal>,
{
type IsAggregate = <__Derived<
input,
> as ValidGrouping<__DieselInternal>>::IsAggregate;
}
use diesel::sqlite::{Sqlite, SqliteConnection};
use diesel::serialize::ToSql;
use diesel::deserialize::{FromSqlRow, StaticallySizedRow};
#[allow(dead_code)]
/// Registers an implementation for this function on the given connection
///
/// This function must be called for every `SqliteConnection` before
/// this SQL function can be used on SQLite. The implementation must be
/// deterministic (returns the same result given the same arguments). If
/// the function is nondeterministic, call
/// `register_nondeterministic_impl` instead.
pub fn register_impl<F, Ret, input>(
conn: &mut SqliteConnection,
f: F,
) -> QueryResult<()>
where
F: Fn(input) -> Ret + std::panic::UnwindSafe + Send + 'static,
(input,): FromSqlRow<(Text,), Sqlite> + StaticallySizedRow<(Text,), Sqlite>,
Ret: ToSql<Text, Sqlite>,
{
conn.register_sql_function::<
(Text,),
Text,
_,
_,
_,
>("lower", true, move |(input,)| f(input))
}
#[allow(dead_code)]
/// Registers an implementation for this function on the given connection
///
/// This function must be called for every `SqliteConnection` before
/// this SQL function can be used on SQLite.
/// `register_nondeterministic_impl` should only be used if your
/// function can return different results with the same arguments (e.g.
/// `random`). If your function is deterministic, you should call
/// `register_impl` instead.
pub fn register_nondeterministic_impl<F, Ret, input>(
conn: &mut SqliteConnection,
mut f: F,
) -> QueryResult<()>
where
F: FnMut(input) -> Ret + std::panic::UnwindSafe + Send + 'static,
(input,): FromSqlRow<(Text,), Sqlite> + StaticallySizedRow<(Text,), Sqlite>,
Ret: ToSql<Text, Sqlite>,
{
conn.register_sql_function::<
(Text,),
Text,
_,
_,
_,
>("lower", false, move |(input,)| f(input))
}
}