pub trait ToSql<A, DB: Backend>: Debug {
// Required method
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> Result;
}Expand description
Serializes a single value to be sent to the database.
The output is sent as a bind parameter, and the data must be written in the expected format for the given backend.
When possible, implementations of this trait should prefer using an existing
implementation, rather than writing to out directly. (For example, if you
are implementing this for an enum, which is represented as an integer in the
database, you should use i32::to_sql(x, out) instead of writing to out
yourself.)
Any types which implement this trait should also
#[derive(AsExpression)].
§Backend specific details
- For PostgreSQL, the bytes will be sent using the binary protocol, not text.
- For SQLite, all implementations should be written in terms of an existing
ToSqlimplementation. - For MySQL, the expected bytes will depend on the return value of
type_metadatafor the given SQL type. SeeMysqlTypefor details. - For third party backends, consult that backend’s documentation.
§Examples
Most implementations of this trait will be defined in terms of an existing implementation.
#[repr(i32)]
#[derive(Debug, Clone, Copy, AsExpression)]
#[diesel(sql_type = Integer)]
pub enum MyEnum {
A = 1,
B = 2,
}
impl<DB> ToSql<Integer, DB> for MyEnum
where
DB: Backend,
i32: ToSql<Integer, DB>,
{
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> serialize::Result {
match self {
MyEnum::A => 1.to_sql(out),
MyEnum::B => 2.to_sql(out),
}
}
}Example of creating a custom type mapping based on a MySQL enum type
This is designed to reuse the SQL type definition generated by diesel-cli
pub mod sql_types {
#[derive(diesel::sql_types::SqlType)]
#[diesel(mysql_type(name = "Enum"))]
pub struct PostEnum; //<- generated by diesel cli
}
#[derive(Debug, AsExpression, PartialEq, Clone)]
#[diesel(sql_type = sql_types::PostEnum)]
pub enum Post {
FirstValue,
SecondValue,
}
impl ToSql<sql_types::PostEnum, diesel::mysql::Mysql> for Post {
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, diesel::mysql::Mysql>) -> serialize::Result {
match *self {
// these string values need to match the labels used in your
// enum definition in SQL. So this expects that you defined the
/// relevant enum type as`ENUM('one', 'two')` in your `CREATE TABLE` statement
Post::FirstValue => out.write_all(b"one")?,
Post::SecondValue => out.write_all(b"two")?,
}
Ok(IsNull::No)
}
}Using temporary values as part of the ToSql implementation requires additional
work.
Backends using RawBytesBindCollector as BindCollector copy the serialized values as part
of Write implementation. This includes the Mysql and the Pg backend provided by diesel.
This means existing ToSql implementations can be used even with
temporary values. For these it is required to call
Output::reborrow to shorten the lifetime of the Output type correspondingly.
#[repr(i32)]
#[derive(Debug, Clone, Copy, AsExpression)]
#[diesel(sql_type = Integer)]
pub enum MyEnum {
A = 1,
B = 2,
}
impl ToSql<Integer, diesel::pg::Pg> for MyEnum
where
i32: ToSql<Integer, diesel::pg::Pg>,
{
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, diesel::pg::Pg>) -> serialize::Result {
let v = *self as i32;
<i32 as ToSql<Integer, diesel::pg::Pg>>::to_sql(&v, &mut out.reborrow())
}
}For any other backend the Output::set_value method provides a way to
set the output value directly. Checkout the documentation of the corresponding
BindCollector::Buffer type for provided From<T> implementations for a list
of accepted types. For the Sqlite backend see SqliteBindValue.
#[repr(i32)]
#[derive(Debug, Clone, Copy, AsExpression)]
#[diesel(sql_type = Integer)]
pub enum MyEnum {
A = 1,
B = 2,
}
impl ToSql<Integer, diesel::sqlite::Sqlite> for MyEnum
where
i32: ToSql<Integer, diesel::sqlite::Sqlite>,
{
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, diesel::sqlite::Sqlite>) -> serialize::Result {
out.set_value(*self as i32);
Ok(IsNull::No)
}
}