Skip to content

Commit

Permalink
add skip_insertion attribute for Insertable derive macro
Browse files Browse the repository at this point in the history
  • Loading branch information
formlogic-kirk committed Nov 29, 2023
1 parent bc263af commit 0ffbed6
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 0 deletions.
3 changes: 3 additions & 0 deletions diesel_derives/src/attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub struct AttributeSpanWrapper<T> {

pub enum FieldAttr {
Embed(Ident),
SkipInsertion(Ident),

ColumnName(Ident, SqlIdentifier),
SqlType(Ident, TypePath),
Expand Down Expand Up @@ -123,6 +124,7 @@ impl Parse for FieldAttr {

match &*name_str {
"embed" => Ok(FieldAttr::Embed(name)),
"skip_insertion" => Ok(FieldAttr::SkipInsertion(name)),

"column_name" => Ok(FieldAttr::ColumnName(
name,
Expand Down Expand Up @@ -173,6 +175,7 @@ impl MySpanned for FieldAttr {
fn span(&self) -> Span {
match self {
FieldAttr::Embed(ident)
| FieldAttr::SkipInsertion(ident)
| FieldAttr::ColumnName(ident, _)
| FieldAttr::SqlType(ident, _)
| FieldAttr::TreatNoneAsNull(ident, _)
Expand Down
17 changes: 17 additions & 0 deletions diesel_derives/src/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub struct Field {
pub select_expression: Option<AttributeSpanWrapper<Expr>>,
pub select_expression_type: Option<AttributeSpanWrapper<Type>>,
pub embed: Option<AttributeSpanWrapper<bool>>,
pub skip_insertion: Option<AttributeSpanWrapper<bool>>,
}

impl Field {
Expand All @@ -30,6 +31,7 @@ impl Field {
let mut serialize_as = None;
let mut deserialize_as = None;
let mut embed = None;
let mut skip_insertion = None;
let mut select_expression = None;
let mut select_expression_type = None;
let mut treat_none_as_default_value = None;
Expand Down Expand Up @@ -102,6 +104,13 @@ impl Field {
ident_span,
})
}
FieldAttr::SkipInsertion(_) => {
skip_insertion = Some(AttributeSpanWrapper {
item: true,
attribute_span,
ident_span,
})
}
}
}

Expand All @@ -128,6 +137,7 @@ impl Field {
select_expression,
select_expression_type,
embed,
skip_insertion,
})
}

Expand Down Expand Up @@ -157,6 +167,13 @@ impl Field {
pub(crate) fn embed(&self) -> bool {
self.embed.as_ref().map(|a| a.item).unwrap_or(false)
}

pub(crate) fn skip_insertion(&self) -> bool {
self.skip_insertion
.as_ref()
.map(|a| a.item)
.unwrap_or(false)
}
}

pub enum FieldName {
Expand Down
4 changes: 4 additions & 0 deletions diesel_derives/src/insertable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ fn derive_into_single_table(
let mut ref_field_assign = Vec::with_capacity(model.fields().len());

for field in model.fields() {
// skip this field while generating the insertion
if let true = field.skip_insertion() {
continue;
}
// Use field-level attr. with fallback to the struct-level one.
let treat_none_as_default_value = match &field.treat_none_as_default_value {
Some(attr) => {
Expand Down
41 changes: 41 additions & 0 deletions diesel_tests/tests/insert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,47 @@ fn insert_returning_count_returns_number_of_rows_inserted() {
assert_eq!(1, second_count);
}

#[test]
#[cfg(not(any(feature = "mysql", feature = "sqlite")))]
fn insert_with_generated_column() {
use crate::schema::user_with_last_names::table as users;
#[derive(Debug, Queryable, Insertable, Selectable, Default)]
struct UserWithLastName {
id: i32,
first_name: String,
last_name: String,
#[diesel(skip_insertion)]
full_name: String,
}

let connection = &mut connection();
diesel::sql_query(
"CREATE TABLE user_with_last_names (
id SERIAL PRIMARY KEY,
first_name VARCHAR NOT NULL,
last_name VARCHAR NOT NULL,
full_NAME VARCHAR GENERATED ALWAYS AS (first_name || ' ' || last_name) STORED
)",
)
.execute(connection)
.unwrap();
let new_users: &[_] = &[UserWithLastName {
first_name: "Sean".to_string(),
last_name: "Black".to_string(),
..Default::default()
}];
let count = insert_into(users)
.values(new_users)
.execute(connection)
.unwrap();

assert_eq!(1, count);

let sean_black: UserWithLastName = users.first(connection).unwrap();

assert_eq!("Sean Black", sean_black.full_name.as_str());
}

#[derive(Insertable)]
#[diesel(table_name = users)]
struct BaldUser {
Expand Down
9 changes: 9 additions & 0 deletions diesel_tests/tests/schema/pg_schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,15 @@ table! {
}
}

table! {
user_with_last_names (id) {
id -> Int4,
first_name -> Varchar,
last_name -> Varchar,
full_name -> Varchar,
}
}

table! {
with_keywords (fn_) {
#[sql_name = "fn"]
Expand Down

0 comments on commit 0ffbed6

Please sign in to comment.