diff --git a/Cargo.toml b/Cargo.toml index 5c155e8..d4cca84 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ edition.workspace = true description = "Entity CRUD and change tracking for SQL databases with SQLx" [workspace.package] -version = "0.3.6" +version = "0.3.7" edition = "2021" [dependencies] diff --git a/sqlx-record-derive/src/lib.rs b/sqlx-record-derive/src/lib.rs index 966d9d3..bc7c4da 100644 --- a/sqlx-record-derive/src/lib.rs +++ b/sqlx-record-derive/src/lib.rs @@ -1106,40 +1106,31 @@ fn generate_update_impl( /// Bind all form values to query in correct order. /// Handles both simple values and expression values, respecting expression precedence. + /// Uses Value enum for proper type handling of Option fields. pub fn bind_all_values<'q>(&'q self, mut query: sqlx::query::Query<'q, #db, #db_args>) -> sqlx::query::Query<'q, #db, #db_args> { - #( - // Expression takes precedence over simple value - if let Some(expr) = self._exprs.get(#db_names) { - let (_, expr_values) = expr.build_sql(#db_names, 1); - for value in expr_values { - query = ::sqlx_record::prelude::bind_value_owned(query, value); - } - } else if let Some(ref value) = self.#field_idents { - query = query.bind(value); - } - )* + // Use update_stmt_with_values to get properly converted values + // This handles nested Options (Option>) correctly + let (_, values) = self.update_stmt_with_values(); + for value in values { + query = ::sqlx_record::prelude::bind_value_owned(query, value); + } query } - /// Legacy binding method - only binds simple Option values (ignores expressions). + /// Legacy binding method - binds values through the Value enum for proper type handling. /// For backward compatibility. New code should use bind_all_values(). pub fn bind_form_values<'q>(&'q self, mut query: sqlx::query::Query<'q, #db, #db_args>) -> sqlx::query::Query<'q, #db, #db_args> { - if self._exprs.is_empty() { - // No expressions, use simple binding - #( - if let Some(ref value) = self.#field_idents { - query = query.bind(value); - } - )* - query - } else { - // Has expressions, use full binding - self.bind_all_values(query) + // Always use Value-based binding to properly handle Option fields + // This ensures nested Options (Option>) are unwrapped correctly + let (_, values) = self.update_stmt_with_values(); + for value in values { + query = ::sqlx_record::prelude::bind_value_owned(query, value); } + query } /// Check if this form uses any expressions diff --git a/src/value.rs b/src/value.rs index 7552c03..7c52857 100644 --- a/src/value.rs +++ b/src/value.rs @@ -256,6 +256,7 @@ impl UpdateExpr { pub type SqlValue = Value; // MySQL supports unsigned integers natively +// Note: UUID is bound as bytes for BINARY(16) column compatibility #[cfg(feature = "mysql")] macro_rules! bind_value { ($query:expr, $value: expr) => {{