From 986ede8ceb15ec7fc0fc78ce747679bf6ca1bcc6 Mon Sep 17 00:00:00 2001
From: Georg Semmler <github@weiznich.de>
Date: Thu, 5 Dec 2024 11:10:55 +0100
Subject: [PATCH] Address review comments

This commit adds documentation, a changelog entry and a test to the new
feature
---
 CHANGELOG.md                         |  1 +
 diesel_derives/src/lib.rs            |  2 ++
 diesel_derives/tests/as_changeset.rs | 37 ++++++++++++++++++++++++++++
 3 files changed, 40 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index a410e44d83c0..b006453871c5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,7 @@ Increasing the minimal supported Rust version will always be coupled at least wi
 * Added `limit()` and `offset()` DSL to combination clauses such as `UNION`
 * Fixed `#[derive(Identifiable)]` ignoring attribute `#[diesel(serialize_as)]` on primary keys
 * Added embedded struct support for `AsChangeset` via `#[diesel(embed)]`
+* Added a `#[diesel(skip_update)]` attribute for the `AsChangeset` derive to skip updating a field present in the struct
 * Support for libsqlite3-sys 0.30.0
 * Add support for built-in PostgreSQL range operators and functions
 * Support for postgres multirange type
diff --git a/diesel_derives/src/lib.rs b/diesel_derives/src/lib.rs
index 3b53aca5527b..8659d2d3d11b 100644
--- a/diesel_derives/src/lib.rs
+++ b/diesel_derives/src/lib.rs
@@ -111,6 +111,8 @@ mod valid_grouping;
 ///    the actual field type.
 /// * `#[diesel(treat_none_as_null = true/false)]`, overrides the container-level
 ///   `treat_none_as_null` attribute for the current field.
+/// * `#[diesel(skip_update)]`, skips updating this field. Useful for working with
+///    generated columns.
 #[cfg_attr(
     all(not(feature = "without-deprecated"), feature = "with-deprecated"),
     proc_macro_derive(
diff --git a/diesel_derives/tests/as_changeset.rs b/diesel_derives/tests/as_changeset.rs
index 6c1802592fdd..0d8823c875fa 100644
--- a/diesel_derives/tests/as_changeset.rs
+++ b/diesel_derives/tests/as_changeset.rs
@@ -891,3 +891,40 @@ fn embedded_struct() {
     let actual = users::table.order(users::id).load(connection);
     assert_eq!(Ok(expected), actual);
 }
+
+#[test]
+fn skip_update() {
+    let connection = &mut connection_with_sean_and_tess_in_users_table();
+
+    #[derive(AsChangeset)]
+    #[diesel(table_name = users)]
+    #[diesel(primary_key(name))]
+    #[allow(dead_code)]
+    struct UserForm<'a> {
+        #[diesel(skip_update)]
+        name: &'a str,
+        hair_color: &'a str,
+        r#type: &'a str,
+        #[diesel(skip_update)]
+        non_existing: i32,
+    }
+
+    diesel::update(users::table.find(1))
+        .set(UserForm {
+            name: "John",
+            hair_color: "green",
+            r#type: "admin",
+            non_existing: 42,
+        })
+        .execute(connection)
+        .unwrap();
+
+    let res = users::table
+        .find(1)
+        .first::<(i32, String, Option<String>, Option<String>)>(connection)
+        .unwrap();
+
+    assert_eq!(res.1, "Sean");
+    assert_eq!(res.2, Some("green".into()));
+    assert_eq!(res.3, Some("admin".into()));
+}