Merge pull request #567 from diesel-rs/sg-insert-option-into-not-null

Allow inserting `Option<T>` into columns where the type is not nullable
This commit is contained in:
Sean Griffin 2017-01-04 12:48:10 -05:00 committed by GitHub
commit 54a99472ed
6 changed files with 44 additions and 6 deletions

View File

@ -17,6 +17,11 @@ for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/
* The `persistable` module has been renamed to `insertable`.
### Fixed
* `#[derive(Insertable)]` allows fields of type `Option<T>` to be used with
columns that are not null if they have a default value.
## [0.9.1] - 2016-12-09
### Fixed

View File

@ -40,3 +40,7 @@ pub type NotBetween<Lhs, Rhs> = super::predicates::NotBetween<Lhs,
pub use super::predicates::{IsNull, IsNotNull, Asc, Desc};
#[doc(inline)]
pub use super::array_comparison::EqAny;
#[doc(hidden)]
pub type AsNullableExpr<Item, TargetExpr> = AsExprOf<Item,
<SqlTypeOf<TargetExpr> as types::IntoNullable>::Nullable>;

View File

@ -5,6 +5,7 @@ use expression::Expression;
use result::QueryResult;
use query_builder::{QueryBuilder, BuildQueryResult};
use query_source::{Table, Column};
use types::IntoNullable;
/// Represents that a structure can be used to to insert a new row into the
/// database. This is automatically implemented for `&[T]` and `&Vec<T>` for
@ -32,7 +33,8 @@ pub trait InsertValues<DB: Backend> {
#[derive(Debug, Copy, Clone)]
pub enum ColumnInsertValue<Col, Expr> where
Col: Column,
Expr: Expression<SqlType=Col::SqlType>,
Col::SqlType: IntoNullable,
Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>,
{
Expression(Col, Expr),
Default(Col),

View File

@ -163,7 +163,7 @@ macro_rules! impl_Insertable {
($(
$crate::insertable::ColumnInsertValue<
$table_name::$column_name,
$crate::expression::helper_types::AsExpr<
$crate::expression::helper_types::AsNullableExpr<
&'insert $field_ty,
$table_name::$column_name,
>,
@ -173,7 +173,7 @@ macro_rules! impl_Insertable {
type Values = ($(
$crate::insertable::ColumnInsertValue<
$table_name::$column_name,
$crate::expression::helper_types::AsExpr<
$crate::expression::helper_types::AsNullableExpr<
&'insert $field_ty,
$table_name::$column_name,
>,
@ -184,6 +184,7 @@ macro_rules! impl_Insertable {
fn values(self) -> Self::Values {
use $crate::expression::{AsExpression, Expression};
use $crate::insertable::ColumnInsertValue;
use $crate::types::IntoNullable;
let $self_to_columns = *self;
($(
Insertable_column_expr!($table_name::$column_name, $column_name, $field_kind)
@ -222,7 +223,7 @@ macro_rules! Insertable_column_expr {
($column:path, $field_access:expr, regular) => {
ColumnInsertValue::Expression(
$column,
AsExpression::<<$column as Expression>::SqlType>
AsExpression::<<<$column as Expression>::SqlType as IntoNullable>::Nullable>
::as_expression($field_access),
)
};

View File

@ -111,7 +111,8 @@ macro_rules! tuple_impls {
DB: Backend + SupportsDefaultKeyword,
Tab: Table,
$($T: Column<Table=Tab>,)+
$($ST: Expression<SqlType=$T::SqlType> + QueryFragment<DB>,)+
$($T::SqlType: IntoNullable,)+
$($ST: Expression<SqlType=<$T::SqlType as IntoNullable>::Nullable> + QueryFragment<DB>,)+
{
fn column_names(&self, out: &mut DB::QueryBuilder) -> BuildQueryResult {
$(
@ -158,7 +159,8 @@ macro_rules! tuple_impls {
for ($(ColumnInsertValue<$T, $ST>,)+) where
Tab: Table,
$($T: Column<Table=Tab>,)+
$($ST: Expression<SqlType=$T::SqlType> + QueryFragment<::sqlite::Sqlite>,)+
$($T::SqlType: IntoNullable,)+
$($ST: Expression<SqlType=<$T::SqlType as IntoNullable>::Nullable> + QueryFragment<::sqlite::Sqlite>,)+
{
#[allow(unused_assignments)]
fn column_names(&self, out: &mut ::sqlite::SqliteQueryBuilder) -> BuildQueryResult {

View File

@ -215,3 +215,27 @@ fn derive_identifiable_with_composite_pk() {
assert_eq!((&2, &3), foo1.id());
assert_eq!((&6, &7), foo2.id());
}
#[test]
fn derive_insertable_with_option_for_not_null_field_with_default() {
#[derive(Insertable)]
#[table_name="users"]
struct NewUser {
id: Option<i32>,
name: &'static str,
}
let conn = connection();
let data = vec![
NewUser { id: None, name: "Jim" },
NewUser { id: Some(123), name: "Bob" },
];
assert_eq!(Ok(2), insert(&data).into(users::table).execute(&conn));
let users = users::table.load::<User>(&conn).unwrap();
let jim = users.iter().find(|u| u.name == "Jim");
let bob = users.iter().find(|u| u.name == "Bob");
assert!(jim.is_some());
assert_eq!(Some(&User::new(123, "Bob")), bob);
}