impl crate::FromRow for {{ model_name }} {
    fn from_row(row: &crate::Row) -> nautilus_core::Result<Self> {
{%- for field in scalar_fields %}
{%- if field.is_pk %}
        // PK field — always required
        let {{ field.name }} = row
            .get("{{ field.db_name }}")
            .or_else(|| row.get("{{ table_name }}__{{ field.db_name }}"))
            .ok_or_else(|| nautilus_core::Error::TypeError(
                "missing required PK column '{{ field.db_name }}' ({{ field.name }})".to_string()
            ))
            .and_then(nautilus_core::FromValue::from_value)?;
{%- else %}
        // Scalar field — None when not selected (projection)
        let {{ field.name }}: Option<{{ field.rust_type }}> = row
            .get("{{ field.db_name }}")
            .or_else(|| row.get("{{ table_name }}__{{ field.db_name }}"))
            .and_then(|v| match v {
                nautilus_core::Value::Null => None,
                other => nautilus_core::FromValue::from_value(other).ok(),
            });
{%- endif %}

{%- endfor %}

        // Decode relation fields from JSON (if included via .include())
{%- for rel in relations %}
{%- if rel.is_array %}
        let {{ rel.field_name }} = row.get("{{ rel.field_name }}_json")
            .map(|v| match v {
                nautilus_core::Value::Null => vec![],
                other => decode_relation_json_ref::<Vec<{{ rel.target_model }}>>(other)
                    .unwrap_or_default(),
            })
            .unwrap_or_default();
{%- else %}
        let {{ rel.field_name }} = row.get("{{ rel.field_name }}_json")
            .and_then(|v| decode_relation_json_ref::<{{ rel.target_model }}>(v).map(Box::new));
{%- endif %}
{%- endfor %}

        Ok({{ model_name }} {
{%- for field in scalar_fields %}
            {{ field.name }},
{%- endfor %}
{%- for field in relation_fields %}
            {{ field.name }},
{%- endfor %}
        })
    }
}
