Skip to content

Commit

Permalink
Merge pull request #3862 from formlogic-kirk/skip_insertion
Browse files Browse the repository at this point in the history
add skip_insertion attribute for Insertable derive macro
  • Loading branch information
weiznich committed Dec 8, 2023
2 parents bc263af + d2054c2 commit ce16e91
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Increasing the minimal supported Rust version will always be coupled at least wi
* Added automatic usage of all sqlite `rowid` aliases when no explicit primary key is defined for `print-schema`
* Added a `#[dsl::auto_type]` attribute macro, allowing to infer type of query fragment functions
* Added the same type inference on `Selectable` derives, which allows skipping specifying `select_expression_type` most of the time, in turn enabling most queries to be written using just a `Selectable` derive.
* Added an optional `#[diesel(skip_insertion)]` field attribute to the `Insertable` derive macro, allowing fields which map to generated columns to be skipped during insertion.

### Changed

Expand Down
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 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
2 changes: 2 additions & 0 deletions diesel_derives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,8 @@ pub fn derive_identifiable(input: TokenStream) -> TokenStream {
/// the actual field type.
/// * `#[diesel(treat_none_as_default_value = true/false)]`, overrides the container-level
/// `treat_none_as_default_value` attribute for the current field.
/// * `#[diesel(skip_insertion)]`, skips insertion of this field. Useful for working with
/// generated columns.
///
/// # Examples
///
Expand Down
39 changes: 39 additions & 0 deletions diesel_tests/tests/insert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,45 @@ 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 {
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 (
first_name VARCHAR NOT NULL PRIMARY KEY,
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(),
full_name: "This field not inserted".to_string(),
}];
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
8 changes: 8 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,14 @@ table! {
}
}

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

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

0 comments on commit ce16e91

Please sign in to comment.