/// Internal Update builder for {{ model_name }} — use `{{ delegate_name }}::update(args)` instead.
pub(crate) struct {{ update_name }}<E: crate::Executor> {
    client: crate::Client<E>,
    filter: Option<nautilus_core::Expr>,
    require_filter: bool,
    /// Column-value assignments collected from `set_data`.
    assignments: Vec<(nautilus_core::ColumnMarker, nautilus_core::Value)>,
}

impl<E> {{ update_name }}<E>
where
    E: crate::Executor,
    for<'a> E::Row<'a>: Into<crate::Row>,
{
    pub(crate) fn new(client: crate::Client<E>) -> Self {
        {{ update_name }} {
            client,
            filter: None,
            require_filter: true,
            assignments: Vec::with_capacity({{ create_fields | length }}),
        }
    }

    /// Set WHERE filter.
    #[must_use]
    pub(crate) fn where_(mut self, expr: nautilus_core::Expr) -> Self {
        self.filter = Some(expr);
        self
    }

    /// Update all rows (removes the safety guard that requires a filter).
    #[must_use]
    pub(crate) fn all(mut self) -> Self {
        self.require_filter = false;
        self
    }

    /// Load field assignments from a structured update-input value.
    ///
    /// Only fields that are `Some(…)` in `data` are included in the SET
    /// clause; `None` fields are intentionally skipped (left unchanged).
    /// For nullable fields a `Some(None)` sets the column to NULL.
    #[must_use]
    pub(crate) fn set_data(mut self, data: {{ model_name }}UpdateInput) -> Self {
{%- for field in create_fields %}
        if let Some(outer) = data.{{ field.name }} {
{%- if field.is_optional %}
            let val = match outer {
                Some(v) => nautilus_core::Value::from(v),
                None => nautilus_core::Value::Null,
            };
{%- else %}
            let val = nautilus_core::Value::from(outer);
{%- endif %}
            self.assignments.push((
                nautilus_core::ColumnMarker::from_static("{{ table_name }}", "{{ field.db_name }}"),
                val,
            ));
        }
{%- endfor %}
        self
    }

    /// Execute the update, returning affected rows via `RETURNING`.
    ///
    /// Returns an empty `Vec` for databases that do not support `RETURNING`
    /// (e.g. MySQL).  Returns an empty `Vec` without touching the database
    /// when no assignments have been loaded via `set_data`.
    pub(crate) async fn exec(self) -> nautilus_core::Result<Vec<{{ model_name }}>> {
        use nautilus_core::*;
        use std::convert::Into;

        if self.assignments.is_empty() {
            return Ok(vec![]);
        }

        if self.require_filter && self.filter.is_none() {
            return Err(Error::InvalidQuery(
                "Update requires a WHERE filter — call `.all()` to update every row.".to_string(),
            ));
        }

        let mut builder = Update::table("{{ table_name }}")
            .with_capacity(UpdateCapacity {
                assignments: self.assignments.len(),
                returning: usize::from(self.client.dialect().supports_returning()) * {{ all_scalar_fields | length }},
            })
            .assignments(self.assignments);
        if let Some(filter) = self.filter {
            builder = builder.filter(filter);
        }

        let supports_returning = self.client.dialect().supports_returning();
        if supports_returning {
            let returning_cols = vec![
{%- for field in all_scalar_fields %}
                ColumnMarker::from_static("{{ table_name }}", "{{ field.db_name }}"),
{%- endfor %}
            ];
            builder = builder.returning(returning_cols);
        }

        let update = builder.build()?;
        let sql = self.client.dialect().render_update_owned(update)?;

        let rows = crate::execute_all(self.client.executor(), &sql)
            .await
            .map_err(|e| Error::Other(e.to_string()))?;

        let mut results = Vec::with_capacity(rows.len());
        for row in rows {
            let row: crate::Row = row.into();
            results.push(decode_model_row_with_hints(
                row,
                all_scalar_decode_slots(),
                all_scalar_value_hints(),
            )?);
        }

        Ok(results)
    }
}
