---
source: crates/nautilus-codegen/tests/snapshot_tests.rs
assertion_line: 37
expression: code
---
//! User model and associated builders.
use crate::{FromRow, Row};
use futures::stream::StreamExt;
fn all_scalar_value_hints() -> &'static [Option<crate::ValueHint>] {
&[
None,
None,
]
}
fn decode_model_row_with_hints(
row: crate::Row,
hints: &[Option<crate::ValueHint>],
) -> nautilus_core::Result<User> {
let row = crate::normalize_row_with_hints(row, hints)
.map_err(|e| nautilus_core::Error::Other(format!(
"Failed to normalize User row: {}",
e
)))?;
User::from_row(&row)
}
/// User model.
///
/// PK fields are always present. All other scalar fields are `Option<T>`:
/// they are `Some(value)` when the column was included in the query result
/// (default, or explicitly selected via `select`), and `None` when the
/// column was omitted through projection.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct User {
pub id: i32,
pub name: Option<String>,
}
impl User {
/// Column accessor for id.
pub fn id() -> nautilus_core::Column<i32> {
nautilus_core::Column::new("User", "id")
}
/// Column accessor for name.
pub fn name() -> nautilus_core::Column<String> {
nautilus_core::Column::new("User", "name")
}
/// Create a delegate for User queries.
pub fn nautilus<E>(client: &crate::Client<E>) -> UserDelegate<E>
where
E: crate::Executor,
for<'a> E::Row<'a>: Into<crate::Row>,
{
UserDelegate::new(client.clone())
}
}
impl crate::FromRow for User {
fn from_row(row: &crate::Row) -> nautilus_core::Result<Self> {
// PK field — always required
let id = row
.get("id")
.or_else(|| row.get("User__id"))
.ok_or_else(|| nautilus_core::Error::TypeError(
"missing required PK column 'id' (id)".to_string()
))
.and_then(nautilus_core::FromValue::from_value)?;
// Scalar field — None when not selected (projection)
let name: Option<String> = row
.get("name")
.or_else(|| row.get("User__name"))
.and_then(|v| match v {
nautilus_core::Value::Null => None,
other => nautilus_core::FromValue::from_value(other).ok(),
});
// Decode relation fields from JSON (if included via .include())
Ok(User {
id,
name,
})
}
}
/// Column accessors for User selections.
#[derive(Debug, Clone, Copy)]
pub struct UserColumns;
impl UserColumns {
pub fn id(&self) -> nautilus_core::Column<i32> {
nautilus_core::Column::new("User", "id")
}
pub fn name(&self) -> nautilus_core::Column<String> {
nautilus_core::Column::new("User", "name")
}
}
/// Structured input for creating a User record.
///
/// All fields are optional; unset fields are omitted from the INSERT.
#[derive(Debug, Default, Clone)]
pub struct UserCreateInput {
/// id column.
pub id: Option<i32>,
/// name column.
pub name: Option<String>,
}
impl UserCreateInput {
fn to_engine_data(&self) -> serde_json::Value {
let mut data = serde_json::Map::new();
if let Some(value) = &self.id {
data.insert(
"id".to_string(),
nautilus_core::Value::from(value.clone()).to_json_plain(),
);
}
if let Some(value) = &self.name {
data.insert(
"name".to_string(),
nautilus_core::Value::from(value.clone()).to_json_plain(),
);
}
serde_json::Value::Object(data)
}
}
/// Structured input for updating User records.
///
/// All fields are optional; only set fields are included in the UPDATE.
#[derive(Debug, Default, Clone)]
pub struct UserUpdateInput {
/// id column.
pub id: Option<i32>,
/// name column.
pub name: Option<String>,
}
impl UserUpdateInput {
fn to_engine_data(&self) -> serde_json::Value {
let mut data = serde_json::Map::new();
if let Some(value) = &self.id {
data.insert(
"id".to_string(),
nautilus_core::Value::from(value.clone()).to_json_plain(),
);
}
if let Some(value) = &self.name {
data.insert(
"name".to_string(),
nautilus_core::Value::from(value.clone()).to_json_plain(),
);
}
serde_json::Value::Object(data)
}
}
/// Structured arguments for updating User records.
#[derive(Debug, Default, Clone)]
pub struct UserUpdateArgs {
/// Optional WHERE filter — if `None`, all rows are updated.
pub where_: Option<nautilus_core::Expr>,
/// Fields to update.
pub data: UserUpdateInput,
}
/// Structured arguments for deleting User records.
#[derive(Debug, Default, Clone)]
pub struct UserDeleteArgs {
/// Optional WHERE filter — if `None`, all rows are deleted.
pub where_: Option<nautilus_core::Expr>,
}
/// Structured arguments for upserting a User record.
#[derive(Debug, Default, Clone)]
pub struct UserUpsertArgs {
/// WHERE filter used to look up the existing record (should target a unique field).
pub where_: Option<nautilus_core::Expr>,
/// Fields used when creating a new record (record not found).
pub create: UserCreateInput,
/// Fields applied when updating an existing record.
pub update: UserUpdateInput,
/// Whether to return the created/updated record (default: true).
pub return_data: bool,
}
/// Scalar fields on User that can be referenced in generated aggregate APIs.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum UserScalarField {
Id,
Name,
}
impl UserScalarField {
fn as_str(&self) -> &'static str {
match self {
Self::Id => "id",
Self::Name => "name",
}
}
}
/// Sort direction used by User `group_by()` ordering.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum UserSortOrder {
Asc,
Desc,
}
impl UserSortOrder {
fn as_str(&self) -> &'static str {
match self {
Self::Asc => "asc",
Self::Desc => "desc",
}
}
}
/// Structured arguments for counting User records.
#[derive(Debug, Default, Clone)]
pub struct UserCountArgs {
/// Optional WHERE filter.
pub where_: Option<nautilus_core::Expr>,
/// Limit the counted window.
pub take: Option<i32>,
/// Offset the counted window.
pub skip: Option<u32>,
/// Optional keyset cursor for paginated counts.
pub cursor: Option<std::collections::HashMap<String, nautilus_core::Value>>,
}
impl UserCountArgs {
fn to_engine_args(&self) -> nautilus_core::Result<Option<serde_json::Value>> {
let mut args = serde_json::Map::new();
if let Some(filter) = self.where_.as_ref() {
args.insert(
"where".to_string(),
nautilus_core::where_expr_to_protocol_json(filter)?,
);
}
if let Some(take) = self.take {
args.insert("take".to_string(), serde_json::Value::from(take));
}
if let Some(skip) = self.skip {
args.insert("skip".to_string(), serde_json::Value::from(skip));
}
if let Some(cursor) = self.cursor.as_ref() {
args.insert("cursor".to_string(), serialize_cursor_for_engine(cursor));
}
Ok((!args.is_empty()).then_some(serde_json::Value::Object(args)))
}
}
/// Select which COUNT aggregates to return from `UserDelegate::group_by`.
#[derive(Debug, Default, Clone)]
pub struct UserCountAggregateInput {
pub _all: bool,
pub id: bool,
pub name: bool,
}
impl UserCountAggregateInput {
fn to_json(&self) -> Option<serde_json::Value> {
let mut obj = serde_json::Map::new();
if self._all {
obj.insert("_all".to_string(), serde_json::Value::Bool(true));
}
if self.id {
obj.insert("id".to_string(), serde_json::Value::Bool(true));
}
if self.name {
obj.insert("name".to_string(), serde_json::Value::Bool(true));
}
(!obj.is_empty()).then_some(serde_json::Value::Object(obj))
}
}
/// Select which AVG aggregates to return from `UserDelegate::group_by`.
#[derive(Debug, Default, Clone)]
pub struct UserAvgAggregateInput {
pub id: bool,
}
impl UserAvgAggregateInput {
fn to_json(&self) -> Option<serde_json::Value> {
let mut obj = serde_json::Map::new();
if self.id {
obj.insert("id".to_string(), serde_json::Value::Bool(true));
}
(!obj.is_empty()).then_some(serde_json::Value::Object(obj))
}
}
/// Select which SUM aggregates to return from `UserDelegate::group_by`.
#[derive(Debug, Default, Clone)]
pub struct UserSumAggregateInput {
pub id: bool,
}
impl UserSumAggregateInput {
fn to_json(&self) -> Option<serde_json::Value> {
let mut obj = serde_json::Map::new();
if self.id {
obj.insert("id".to_string(), serde_json::Value::Bool(true));
}
(!obj.is_empty()).then_some(serde_json::Value::Object(obj))
}
}
/// Select which MIN aggregates to return from `UserDelegate::group_by`.
#[derive(Debug, Default, Clone)]
pub struct UserMinAggregateInput {
pub id: bool,
pub name: bool,
}
impl UserMinAggregateInput {
fn to_json(&self) -> Option<serde_json::Value> {
let mut obj = serde_json::Map::new();
if self.id {
obj.insert("id".to_string(), serde_json::Value::Bool(true));
}
if self.name {
obj.insert("name".to_string(), serde_json::Value::Bool(true));
}
(!obj.is_empty()).then_some(serde_json::Value::Object(obj))
}
}
/// Select which MAX aggregates to return from `UserDelegate::group_by`.
#[derive(Debug, Default, Clone)]
pub struct UserMaxAggregateInput {
pub id: bool,
pub name: bool,
}
impl UserMaxAggregateInput {
fn to_json(&self) -> Option<serde_json::Value> {
let mut obj = serde_json::Map::new();
if self.id {
obj.insert("id".to_string(), serde_json::Value::Bool(true));
}
if self.name {
obj.insert("name".to_string(), serde_json::Value::Bool(true));
}
(!obj.is_empty()).then_some(serde_json::Value::Object(obj))
}
}
/// One ORDER BY item for `UserDelegate::group_by()`.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UserGroupByOrderBy {
Field {
field: UserScalarField,
direction: UserSortOrder,
},
CountAll(UserSortOrder),
Count {
field: UserScalarField,
direction: UserSortOrder,
},
Avg {
field: UserScalarField,
direction: UserSortOrder,
},
Sum {
field: UserScalarField,
direction: UserSortOrder,
},
Min {
field: UserScalarField,
direction: UserSortOrder,
},
Max {
field: UserScalarField,
direction: UserSortOrder,
},
}
impl UserGroupByOrderBy {
fn to_json(&self) -> serde_json::Value {
match self {
Self::Field { field, direction } => {
let mut obj = serde_json::Map::new();
obj.insert(
field.as_str().to_string(),
serde_json::Value::String(direction.as_str().to_string()),
);
serde_json::Value::Object(obj)
}
Self::CountAll(direction) => {
let mut inner = serde_json::Map::new();
inner.insert(
"_all".to_string(),
serde_json::Value::String(direction.as_str().to_string()),
);
let mut outer = serde_json::Map::new();
outer.insert("_count".to_string(), serde_json::Value::Object(inner));
serde_json::Value::Object(outer)
}
Self::Count { field, direction } => {
let mut inner = serde_json::Map::new();
inner.insert(
field.as_str().to_string(),
serde_json::Value::String(direction.as_str().to_string()),
);
let mut outer = serde_json::Map::new();
outer.insert("_count".to_string(), serde_json::Value::Object(inner));
serde_json::Value::Object(outer)
}
Self::Avg { field, direction } => {
let mut inner = serde_json::Map::new();
inner.insert(
field.as_str().to_string(),
serde_json::Value::String(direction.as_str().to_string()),
);
let mut outer = serde_json::Map::new();
outer.insert("_avg".to_string(), serde_json::Value::Object(inner));
serde_json::Value::Object(outer)
}
Self::Sum { field, direction } => {
let mut inner = serde_json::Map::new();
inner.insert(
field.as_str().to_string(),
serde_json::Value::String(direction.as_str().to_string()),
);
let mut outer = serde_json::Map::new();
outer.insert("_sum".to_string(), serde_json::Value::Object(inner));
serde_json::Value::Object(outer)
}
Self::Min { field, direction } => {
let mut inner = serde_json::Map::new();
inner.insert(
field.as_str().to_string(),
serde_json::Value::String(direction.as_str().to_string()),
);
let mut outer = serde_json::Map::new();
outer.insert("_min".to_string(), serde_json::Value::Object(inner));
serde_json::Value::Object(outer)
}
Self::Max { field, direction } => {
let mut inner = serde_json::Map::new();
inner.insert(
field.as_str().to_string(),
serde_json::Value::String(direction.as_str().to_string()),
);
let mut outer = serde_json::Map::new();
outer.insert("_max".to_string(), serde_json::Value::Object(inner));
serde_json::Value::Object(outer)
}
}
}
}
/// Structured arguments for grouping User rows and computing aggregates.
#[derive(Debug, Default, Clone)]
pub struct UserGroupByArgs {
/// Logical field names to group by.
pub by: Vec<UserScalarField>,
/// Optional pre-group WHERE filter.
pub where_: Option<nautilus_core::Expr>,
/// Optional HAVING JSON object using the protocol aggregate shape.
pub having: Option<serde_json::Value>,
/// Limit the number of returned groups.
pub take: Option<i32>,
/// Offset the returned groups.
pub skip: Option<u32>,
/// COUNT aggregation selection.
pub count: Option<UserCountAggregateInput>,
/// AVG aggregation selection.
pub avg: Option<UserAvgAggregateInput>,
/// SUM aggregation selection.
pub sum: Option<UserSumAggregateInput>,
/// MIN aggregation selection.
pub min: Option<UserMinAggregateInput>,
/// MAX aggregation selection.
pub max: Option<UserMaxAggregateInput>,
/// ORDER BY items applied after grouping.
pub order_by: Vec<UserGroupByOrderBy>,
}
impl UserGroupByArgs {
fn to_engine_args(&self) -> nautilus_core::Result<serde_json::Value> {
let mut args = serde_json::Map::new();
args.insert(
"by".to_string(),
serde_json::Value::Array(
self.by
.iter()
.map(|field| serde_json::Value::String(field.as_str().to_string()))
.collect(),
),
);
if let Some(filter) = self.where_.as_ref() {
args.insert(
"where".to_string(),
nautilus_core::where_expr_to_protocol_json(filter)?,
);
}
if let Some(having) = self.having.as_ref() {
args.insert("having".to_string(), having.clone());
}
if let Some(take) = self.take {
args.insert("take".to_string(), serde_json::Value::from(take));
}
if let Some(skip) = self.skip {
args.insert("skip".to_string(), serde_json::Value::from(skip));
}
if let Some(count) = self.count.as_ref().and_then(UserCountAggregateInput::to_json) {
args.insert("count".to_string(), count);
}
if let Some(avg) = self.avg.as_ref().and_then(UserAvgAggregateInput::to_json) {
args.insert("avg".to_string(), avg);
}
if let Some(sum) = self.sum.as_ref().and_then(UserSumAggregateInput::to_json) {
args.insert("sum".to_string(), sum);
}
if let Some(min) = self.min.as_ref().and_then(UserMinAggregateInput::to_json) {
args.insert("min".to_string(), min);
}
if let Some(max) = self.max.as_ref().and_then(UserMaxAggregateInput::to_json) {
args.insert("max".to_string(), max);
}
if !self.order_by.is_empty() {
args.insert(
"orderBy".to_string(),
serde_json::Value::Array(
self.order_by
.iter()
.map(UserGroupByOrderBy::to_json)
.collect(),
),
);
}
Ok(serde_json::Value::Object(args))
}
}
/// Typed COUNT aggregates returned by `UserDelegate::group_by()`.
#[derive(Debug, Default, Clone, PartialEq)]
pub struct UserCountAggregateOutput {
pub _all: Option<i64>,
pub id: Option<i64>,
pub name: Option<i64>,
}
impl UserCountAggregateOutput {
fn from_json_object(
obj: &serde_json::Map<String, serde_json::Value>,
) -> nautilus_core::Result<Self> {
Ok(Self {
_all: decode_optional_group_by_json_value(obj, "_all")?,
id: decode_optional_group_by_json_value(obj, "id")?,
name: decode_optional_group_by_json_value(obj, "name")?,
})
}
}
/// Typed AVG aggregates returned by `UserDelegate::group_by()`.
#[derive(Debug, Default, Clone, PartialEq)]
pub struct UserAvgAggregateOutput {
pub id: Option<f64>,
}
impl UserAvgAggregateOutput {
fn from_json_object(
obj: &serde_json::Map<String, serde_json::Value>,
) -> nautilus_core::Result<Self> {
Ok(Self {
id: decode_optional_group_by_json_value(obj, "id")?,
})
}
}
/// Typed SUM aggregates returned by `UserDelegate::group_by()`.
#[derive(Debug, Default, Clone, PartialEq)]
pub struct UserSumAggregateOutput {
pub id: Option<i64>,
}
impl UserSumAggregateOutput {
fn from_json_object(
obj: &serde_json::Map<String, serde_json::Value>,
) -> nautilus_core::Result<Self> {
Ok(Self {
id: decode_optional_group_by_json_value(obj, "id")?,
})
}
}
/// Typed MIN aggregates returned by `UserDelegate::group_by()`.
#[derive(Debug, Default, Clone, PartialEq)]
pub struct UserMinAggregateOutput {
pub id: Option<i32>,
pub name: Option<String>,
}
impl UserMinAggregateOutput {
fn from_json_object(
obj: &serde_json::Map<String, serde_json::Value>,
) -> nautilus_core::Result<Self> {
Ok(Self {
id: decode_optional_group_by_json_value(obj, "id")?,
name: decode_optional_group_by_json_value(obj, "name")?,
})
}
}
/// Typed MAX aggregates returned by `UserDelegate::group_by()`.
#[derive(Debug, Default, Clone, PartialEq)]
pub struct UserMaxAggregateOutput {
pub id: Option<i32>,
pub name: Option<String>,
}
impl UserMaxAggregateOutput {
fn from_json_object(
obj: &serde_json::Map<String, serde_json::Value>,
) -> nautilus_core::Result<Self> {
Ok(Self {
id: decode_optional_group_by_json_value(obj, "id")?,
name: decode_optional_group_by_json_value(obj, "name")?,
})
}
}
/// One typed row returned by `UserDelegate::group_by()`.
#[derive(Debug, Default, Clone, PartialEq)]
pub struct UserGroupByOutput {
pub id: Option<i32>,
pub name: Option<String>,
pub _count: Option<UserCountAggregateOutput>,
pub _avg: Option<UserAvgAggregateOutput>,
pub _sum: Option<UserSumAggregateOutput>,
pub _min: Option<UserMinAggregateOutput>,
pub _max: Option<UserMaxAggregateOutput>,
}
impl UserGroupByOutput {
fn from_row(row: &crate::Row) -> nautilus_core::Result<Self> {
Ok(Self {
id: decode_optional_group_by_row_value(row, "id")?,
name: decode_optional_group_by_row_value(row, "name")?,
_count: decode_optional_group_by_object(row, "_count")?
.map(UserCountAggregateOutput::from_json_object)
.transpose()?,
_avg: decode_optional_group_by_object(row, "_avg")?
.map(UserAvgAggregateOutput::from_json_object)
.transpose()?,
_sum: decode_optional_group_by_object(row, "_sum")?
.map(UserSumAggregateOutput::from_json_object)
.transpose()?,
_min: decode_optional_group_by_object(row, "_min")?
.map(UserMinAggregateOutput::from_json_object)
.transpose()?,
_max: decode_optional_group_by_object(row, "_max")?
.map(UserMaxAggregateOutput::from_json_object)
.transpose()?,
})
}
}
fn serialize_cursor_for_engine(
cursor: &std::collections::HashMap<String, nautilus_core::Value>,
) -> serde_json::Value {
serde_json::Value::Object(
cursor
.iter()
.map(|(key, value)| (key.clone(), value.to_json_plain()))
.collect(),
)
}
fn decode_optional_group_by_row_value<T>(
row: &crate::Row,
key: &str,
) -> nautilus_core::Result<Option<T>>
where
T: nautilus_core::FromValue,
{
match row.get(key) {
Some(nautilus_core::Value::Null) | None => Ok(None),
Some(value) => <T as nautilus_core::FromValue>::from_value(value).map(Some),
}
}
fn decode_optional_group_by_object<'a>(
row: &'a crate::Row,
key: &str,
) -> nautilus_core::Result<Option<&'a serde_json::Map<String, serde_json::Value>>> {
match row.get(key) {
Some(nautilus_core::Value::Json(serde_json::Value::Object(obj))) => Ok(Some(obj)),
Some(nautilus_core::Value::Null) | None => Ok(None),
Some(other) => Err(nautilus_core::Error::TypeError(format!(
"expected object-valued aggregate '{}' in groupBy output, got {:?}",
key, other
))),
}
}
fn decode_optional_group_by_json_value<T>(
obj: &serde_json::Map<String, serde_json::Value>,
key: &str,
) -> nautilus_core::Result<Option<T>>
where
T: nautilus_core::FromValue,
{
match obj.get(key) {
Some(serde_json::Value::Null) | None => Ok(None),
Some(value) => <T as nautilus_core::FromValue>::from_value_owned(
crate::runtime::wire_value_to_core_value(key, value),
)
.map(Some),
}
}
fn serialize_update_filter_for_engine(
filter: Option<&nautilus_core::Expr>,
) -> nautilus_core::Result<Option<serde_json::Value>> {
let filter_json = match filter {
Some(expr) => match nautilus_core::where_expr_to_protocol_json(expr) {
Ok(value) => value,
Err(nautilus_core::Error::InvalidQuery(_)) => return Ok(None),
Err(err) => return Err(err),
},
None => return Ok(None),
};
Ok(Some(filter_json))
}
/// Delegate for User queries.
///
/// Obtained via `client.User` (or the model accessor). Each method
/// accepts a structured args object and executes the query immediately — no
/// extra `.exec()` call is needed.
pub struct UserDelegate<E: crate::Executor> {
client: crate::Client<E>,
}
impl<E> UserDelegate<E>
where
E: crate::Executor,
for<'a> E::Row<'a>: Into<crate::Row>,
{
pub(crate) fn new(client: crate::Client<E>) -> Self {
UserDelegate { client }
}
/// Find all User records matching `args`.
///
/// Executes immediately and returns a `Vec<User>`.
pub fn find_many(
&self,
args: nautilus_core::FindManyArgs,
) -> nautilus_core::Result<Vec<User>> {
let _c = self.client.clone();
tokio::task::block_in_place(|| tokio::runtime::Handle::current().block_on(async move {
if let Some(rows) =
crate::runtime::try_find_many_via_engine::<_, User>(
&_c,
"User",
&args,
)
.await?
{
return Ok(rows);
}
if !args.include.is_empty() {
return Err(nautilus_core::Error::InvalidQuery(
"include queries require the embedded engine path in the generated Rust client"
.to_string(),
));
}
let mut builder = UserFindMany::new(_c);
if let Some(filter) = args.where_ {
builder = builder.where_(filter);
}
for order in args.order_by {
builder = builder.order_by(order);
}
if let Some(take) = args.take {
builder = builder.take(take);
}
if let Some(skip) = args.skip {
builder = builder.skip(skip);
}
if !args.select.is_empty() {
let set: std::collections::HashSet<String> = args.select
.into_iter()
.filter_map(|(k, v)| if v { Some(k) } else { None })
.collect();
if !set.is_empty() {
builder = builder.select_fields(set);
}
}
if let Some(cursor) = args.cursor {
builder = builder.cursor(cursor);
}
if !args.distinct.is_empty() {
builder = builder.distinct(args.distinct);
}
builder.exec().await
}))
}
/// Find the first User record matching `args`, or `None`.
pub fn find_first(
&self,
args: nautilus_core::FindManyArgs,
) -> nautilus_core::Result<Option<User>> {
let args = nautilus_core::FindManyArgs { take: Some(1), ..args };
Ok(self.find_many(args)?.into_iter().next())
}
/// Find a single User record by a unique filter, or `None` if not found.
///
/// `args.where_` should reference a `@id` or `@unique` field for correct semantics.
pub fn find_unique(
&self,
args: nautilus_core::FindUniqueArgs,
) -> nautilus_core::Result<Option<User>> {
let find_args = nautilus_core::FindManyArgs {
where_: Some(args.where_),
take: Some(1),
select: args.select,
include: args.include,
..Default::default()
};
Ok(self.find_many(find_args)?.into_iter().next())
}
/// Find a single User record by a unique filter, or return `Error::NotFound`.
pub fn find_unique_or_throw(
&self,
args: nautilus_core::FindUniqueArgs,
) -> nautilus_core::Result<User> {
self.find_unique(args)?.ok_or_else(|| {
nautilus_core::Error::NotFound(
format!("No {} record found matching the given unique filter", "User")
)
})
}
/// Find the first User record matching `args`, or return `Error::NotFound`.
pub fn find_first_or_throw(
&self,
args: nautilus_core::FindManyArgs,
) -> nautilus_core::Result<User> {
self.find_first(args)?.ok_or_else(|| {
nautilus_core::Error::NotFound(
format!("No {} record found matching the given filter", "User")
)
})
}
/// Create a new User record.
///
/// Executes immediately and returns the created `User`.
pub fn create(
&self,
data: UserCreateInput,
) -> nautilus_core::Result<User> {
let _c = self.client.clone();
tokio::task::block_in_place(|| tokio::runtime::Handle::current().block_on(async move {
if let Some(record) =
crate::runtime::try_create_via_engine::<_, User>(
&_c,
"User",
data.to_engine_data(),
)
.await?
{
return Ok(record);
}
let mut builder = UserCreate::new(_c);
if let Some(value) = data.id {
builder = builder.id(value);
}
if let Some(value) = data.name {
builder = builder.name(value);
}
builder.exec().await
}))
}
/// Create multiple User records in a single batch.
///
/// Executes immediately and returns the created records.
pub fn create_many(
&self,
entries: Vec<UserCreateEntry>,
) -> nautilus_core::Result<Vec<User>> {
let _c = self.client.clone();
tokio::task::block_in_place(|| tokio::runtime::Handle::current().block_on(async move {
if entries.is_empty() {
return Ok(vec![]);
}
if let Some(rows) =
crate::runtime::try_create_many_via_engine::<_, User>(
&_c,
"User",
entries.iter().map(UserCreateEntry::to_engine_data).collect(),
)
.await?
{
return Ok(rows);
}
let mut builder = UserCreateMany::new(_c);
for entry in entries {
builder = builder.entry(entry);
}
builder.exec().await
}))
}
/// Update User records matching `args.where_`.
///
/// If `args.where_` is `None`, all rows are updated.
/// Executes immediately and returns the updated records.
pub fn update(
&self,
args: UserUpdateArgs,
) -> nautilus_core::Result<Vec<User>> {
let _c = self.client.clone();
tokio::task::block_in_place(|| tokio::runtime::Handle::current().block_on(async move {
let engine_data = args.data.to_engine_data();
let no_assignments = engine_data
.as_object()
.is_some_and(|data| data.is_empty());
if no_assignments {
return Ok(vec![]);
}
if let Some(filter_json) = serialize_update_filter_for_engine(args.where_.as_ref())? {
if let Some(rows) =
crate::runtime::try_update_via_engine::<_, User>(
&_c,
"User",
filter_json,
engine_data,
)
.await?
{
return Ok(rows);
}
}
let mut builder = UserUpdate::new(_c).set_data(args.data);
if let Some(filter) = args.where_ {
builder = builder.where_(filter);
} else {
builder = builder.all();
}
builder.exec().await
}))
}
/// Delete the first User record matching `args.where_`.
///
/// finds the first matching record and
/// deletes it by its primary key. Returns `Ok(None)` if no record matches.
pub fn delete(
&self,
args: UserDeleteArgs,
) -> nautilus_core::Result<Option<User>> {
// Find the first matching record to get its primary key
let record = self.find_first(nautilus_core::FindManyArgs {
where_: args.where_,
..Default::default()
})?;
let Some(record) = record else {
return Ok(None);
};
// Build a primary-key filter to delete exactly that one record
let pk_filter = nautilus_core::Expr::column("User__id").eq(nautilus_core::Expr::param(record.id.clone()));
let _c = self.client.clone();
tokio::task::block_in_place(|| tokio::runtime::Handle::current().block_on(async move {
UserDelete::new(_c).where_(pk_filter).exec().await?;
nautilus_core::Result::<()>::Ok(())
}))?;
Ok(Some(record))
}
/// Delete all User records matching `args.where_`.
///
/// If `args.where_` is `None`, all rows are deleted.
/// Executes immediately and returns the deleted records.
pub fn delete_many(
&self,
args: UserDeleteArgs,
) -> nautilus_core::Result<Vec<User>> {
let _c = self.client.clone();
tokio::task::block_in_place(|| tokio::runtime::Handle::current().block_on(async move {
let mut builder = UserDelete::new(_c);
if let Some(expr) = args.where_ {
builder = builder.where_(expr);
} else {
builder = builder.all();
}
builder.exec().await
}))
}
/// Count User records matching `args`.
pub fn count(
&self,
args: UserCountArgs,
) -> nautilus_core::Result<i64> {
let _c = self.client.clone();
tokio::task::block_in_place(|| tokio::runtime::Handle::current().block_on(async move {
if let Some(count) =
crate::runtime::try_count_via_engine(
&_c,
"User",
args.to_engine_args()?,
)
.await?
{
return Ok(count);
}
Err(nautilus_core::Error::InvalidQuery(
"count queries require the embedded engine path in the generated Rust client"
.to_string(),
))
}))
}
/// Group User rows and compute aggregates.
pub fn group_by(
&self,
args: UserGroupByArgs,
) -> nautilus_core::Result<Vec<UserGroupByOutput>> {
let _c = self.client.clone();
tokio::task::block_in_place(|| tokio::runtime::Handle::current().block_on(async move {
let engine_args = args.to_engine_args()?;
if let Some(rows) =
crate::runtime::try_group_by_rows_via_engine(
&_c,
"User",
engine_args,
)
.await?
{
let mut decoded = Vec::with_capacity(rows.len());
for row in &rows {
decoded.push(UserGroupByOutput::from_row(row)?);
}
return Ok(decoded);
}
Err(nautilus_core::Error::InvalidQuery(
"groupBy queries require the embedded engine path in the generated Rust client"
.to_string(),
))
}))
}
/// Execute a raw SQL string and return the result rows as generic maps.
///
/// The SQL is sent to the database as-is with no parameter binding.
/// Prefer `raw_stmt_query` when user-supplied values are involved to avoid
/// SQL injection.
pub fn raw_query(
&self,
sql: impl Into<String>,
) -> nautilus_core::Result<Vec<std::collections::HashMap<String, serde_json::Value>>> {
let _c = self.client.clone();
tokio::task::block_in_place(|| tokio::runtime::Handle::current().block_on(async move {
let sql_obj = nautilus_dialect::Sql { text: sql.into(), params: vec![] };
let stream = _c.executor().execute(&sql_obj);
futures::pin_mut!(stream);
let mut results: Vec<std::collections::HashMap<String, serde_json::Value>> = Vec::new();
while let Some(result) = stream.next().await {
let row: crate::Row = result
.map_err(|e| nautilus_core::Error::Other(e.to_string()))?
.into();
let map = row
.iter()
.map(|(name, val)| {
let json_val = val.to_json_plain();
(name.to_string(), json_val)
})
.collect();
results.push(map);
}
Ok(results)
}))
}
/// Execute a raw prepared-statement query with bound parameters.
///
/// Use `$1`, `$2`, … (PostgreSQL) or `?` (MySQL / SQLite) as placeholders.
/// Parameters are bound in the order they appear in the `params` slice.
pub fn raw_stmt_query(
&self,
sql: impl Into<String>,
params: Vec<nautilus_core::Value>,
) -> nautilus_core::Result<Vec<std::collections::HashMap<String, serde_json::Value>>> {
let _c = self.client.clone();
tokio::task::block_in_place(|| tokio::runtime::Handle::current().block_on(async move {
let sql_obj = nautilus_dialect::Sql { text: sql.into(), params };
let stream = _c.executor().execute(&sql_obj);
futures::pin_mut!(stream);
let mut results: Vec<std::collections::HashMap<String, serde_json::Value>> = Vec::new();
while let Some(result) = stream.next().await {
let row: crate::Row = result
.map_err(|e| nautilus_core::Error::Other(e.to_string()))?
.into();
let map = row
.iter()
.map(|(name, val)| {
let json_val = val.to_json_plain();
(name.to_string(), json_val)
})
.collect();
results.push(map);
}
Ok(results)
}))
}
/// Create or update a User record.
///
/// Looks up an existing record using `args.where_`. If found, updates it
/// with `args.data`; otherwise creates a new record with `args.data`.
/// Executes immediately and returns the created or updated `User`
/// (or `None` when `args.return_data` is `false`).
pub fn upsert(
&self,
args: UserUpsertArgs,
) -> nautilus_core::Result<Option<User>> {
let existing = self.find_first(nautilus_core::FindManyArgs {
where_: args.where_.clone(),
..Default::default()
})?;
if let Some(record) = existing {
let updated = self.update(UserUpdateArgs {
where_: args.where_,
data: args.update,
})?;
if !args.return_data {
return Ok(None);
}
Ok(Some(updated.into_iter().next().unwrap_or(record)))
} else {
let created = self.create(args.create)?;
if !args.return_data {
return Ok(None);
}
Ok(Some(created))
}
}
}
/// Internal FindMany builder for User - use `UserDelegate::find_many(args)` instead.
pub(crate) struct UserFindMany<E: crate::Executor, S = ()> {
client: crate::Client<E>,
filter: Option<nautilus_core::Expr>,
order_by: Vec<nautilus_core::OrderBy>,
/// Positive = forward pagination, negative = backward pagination.
take: Option<i32>,
skip: Option<u32>,
select: std::collections::HashSet<String>,
/// Cursor map: PK field name -> value for stable keyset pagination.
cursor: Option<std::collections::HashMap<String, nautilus_core::Value>>,
/// True when `take` was negative (backward pagination).
backward: bool,
/// Columns to deduplicate on (SELECT DISTINCT / DISTINCT ON).
distinct: Vec<String>,
_selection: std::marker::PhantomData<S>,
}
impl<E, S> UserFindMany<E, S>
where
E: crate::Executor,
for<'a> E::Row<'a>: Into<crate::Row>,
{
pub(crate) fn new(client: crate::Client<E>) -> Self {
UserFindMany {
client,
filter: None,
order_by: vec![],
take: None,
skip: None,
select: std::collections::HashSet::new(),
cursor: None,
backward: false,
distinct: vec![],
_selection: std::marker::PhantomData,
}
}
/// Add a WHERE filter.
#[must_use]
pub(crate) fn where_(mut self, expr: nautilus_core::Expr) -> Self {
self.filter = Some(expr);
self
}
/// Add ORDER BY clause.
#[must_use]
pub(crate) fn order_by(mut self, order: nautilus_core::OrderBy) -> Self {
self.order_by.push(order);
self
}
/// Limit the number of results.
///
/// Positive `n` paginates **forward**; negative `n` paginates **backward**
/// (flips ORDER BY and reverses the result slice in memory).
#[must_use]
pub(crate) fn take(mut self, n: i32) -> Self {
self.backward = n < 0;
self.take = Some(n);
self
}
/// Skip a number of results (OFFSET).
#[must_use]
pub(crate) fn skip(mut self, n: u32) -> Self {
self.skip = Some(n);
self
}
/// Set the cursor for stable keyset pagination.
///
/// The map must contain all primary-key fields of the model.
/// The cursor record is included in the result.
#[must_use]
pub(crate) fn cursor(
mut self,
map: std::collections::HashMap<String, nautilus_core::Value>,
) -> Self {
self.cursor = Some(map);
self
}
/// Specify columns to deduplicate on (SELECT DISTINCT / DISTINCT ON).
///
/// - **Postgres**: emits `DISTINCT ON (cols)` - the columns are automatically
/// prepended to `ORDER BY` before query execution.
/// - **SQLite / MySQL**: emits plain `SELECT DISTINCT` (full-row dedup;
/// combine with `select_fields` for column-level effect).
#[must_use]
pub(crate) fn distinct(mut self, columns: Vec<String>) -> Self {
self.distinct = columns;
self
}
/// Specify a field projection (only return the listed columns).
///
/// PK fields are always included regardless.
#[must_use]
pub(crate) fn select_fields(mut self, fields: std::collections::HashSet<String>) -> Self {
self.select = fields;
self
}
}
impl<E> UserFindMany<E, ()>
where
E: crate::Executor,
for<'a> E::Row<'a>: Into<crate::Row>,
{
/// Execute the query and return all rows.
pub(crate) async fn exec(self) -> nautilus_core::Result<Vec<User>> {
use nautilus_core::*;
let client = self.client;
let mut builder = Select::from_table("User");
let mut row_hints: Vec<Option<crate::ValueHint>> = Vec::new();
// Add scalar columns (PK columns always included; others filtered by select if active)
builder = builder.item(SelectItem::column(ColumnMarker::new("User", "id")));
row_hints.push(None);
if self.select.is_empty() || self.select.contains("name") {
builder = builder.item(SelectItem::column(ColumnMarker::new("User", "name")));
row_hints.push(None);
}
// Extract fields from self so we can mix borrows and moves freely.
let backward = self.backward;
let cursor = self.cursor;
let filter = self.filter;
let order_by = self.order_by;
let take = self.take;
let skip = self.skip;
let distinct = self.distinct;
// Auto-add distinct columns to ORDER BY so they appear first (required for
// Postgres DISTINCT ON; harmless for SQLite / MySQL which use plain DISTINCT).
if !distinct.is_empty() {
let existing_cols: std::collections::HashSet<&str> =
order_by.iter().map(|o| o.column.as_str()).collect();
for col in &distinct {
if !existing_cols.contains(col.as_str()) {
let dir = if backward { OrderDir::Desc } else { OrderDir::Asc };
builder = builder.order_by(col.clone(), dir);
}
}
}
// Cursor predicate
// Build an inclusive keyset WHERE clause from the cursor map and merge
// it with any caller-supplied filter.
let effective_filter = if let Some(ref cursor_map) = cursor {
// Static PK field (cursor-map-key, table__db_col) pairs - generated
// at code-generation time from the model's primary-key definition.
let pk_pairs: &[(&str, &str)] = &[
("id", "User__id"),
];
let cursor_pred =
nautilus_core::build_cursor_predicate(pk_pairs, cursor_map, backward)?;
// Auto-add any PK column that is not yet in order_by so that the
// keyset predicate is unambiguous.
let existing_cols: std::collections::HashSet<&str> =
order_by.iter().map(|o| o.column.as_str()).collect();
if !existing_cols.contains("id") {
let dir = if backward { OrderDir::Desc } else { OrderDir::Asc };
builder = builder.order_by("id".to_string(), dir);
}
Some(match filter {
Some(f) => f.and(cursor_pred),
None => cursor_pred,
})
} else {
filter
};
if let Some(f) = effective_filter {
builder = builder.filter(f);
}
// Apply ordering, flipping direction for backward pagination.
for order in order_by {
let dir = if backward {
match order.direction {
OrderDir::Asc => OrderDir::Desc,
OrderDir::Desc => OrderDir::Asc,
}
} else {
order.direction
};
builder = builder.order_by(order.column, dir);
}
// Apply take (absolute value; direction is handled by ORDER BY flip).
if let Some(n) = take {
builder = builder.take(n.saturating_abs());
}
if let Some(offset) = skip {
builder = builder.skip(offset);
}
// Apply distinct (SELECT DISTINCT / DISTINCT ON).
if !distinct.is_empty() {
builder = builder.distinct(distinct);
}
let select = builder.build()?;
let sql = client.dialect().render_select(&select)?;
let stream = client.executor().execute(&sql);
futures::pin_mut!(stream);
let mut results = Vec::new();
while let Some(result) = stream.next().await {
let row: crate::Row = result.map_err(|e| Error::Other(e.to_string()))?.into();
let decoded = decode_model_row_with_hints(row, &row_hints)?;
results.push(decoded);
}
// Backward pagination: DB returned rows in reversed order - restore natural order.
if backward {
results.reverse();
}
Ok(results)
}
}
/// Internal Create builder for User — use `UserDelegate::create(data)` instead.
pub(crate) struct UserCreate<E: crate::Executor> {
client: crate::Client<E>,
id: Option<i32>,
name: Option<String>,
}
impl<E> UserCreate<E>
where
E: crate::Executor,
for<'a> E::Row<'a>: Into<crate::Row>,
{
pub(crate) fn new(client: crate::Client<E>) -> Self {
UserCreate {
client,
id: None,
name: None,
}
}
/// Set id.
#[must_use]
pub(crate) fn id(mut self, value: impl Into<i32>) -> Self {
self.id = Some(value.into());
self
}
/// Set name.
#[must_use]
pub(crate) fn name(mut self, value: impl Into<String>) -> Self {
self.name = Some(value.into());
self
}
/// Execute the create query.
pub(crate) async fn exec(self) -> nautilus_core::Result<User> {
use nautilus_core::*;
let mut columns = Vec::new();
let mut values = Vec::new();
if let Some(value) = self.id {
columns.push(ColumnMarker::new("User", "id"));
values.push(Value::from(value));
}
if let Some(value) = self.name {
columns.push(ColumnMarker::new("User", "name"));
values.push(Value::from(value));
}
let mut builder = Insert::into_table("User")
.columns(columns)
.values(values);
let supports_returning = self.client.dialect().supports_returning();
if supports_returning {
let returning_cols = vec![
ColumnMarker::new("User", "id"),
ColumnMarker::new("User", "name"),
];
builder = builder.returning(returning_cols);
}
let insert = builder.build()?;
let sql = self.client.dialect().render_insert(&insert)?;
let stream = self.client.executor().execute(&sql);
futures::pin_mut!(stream);
let row: Row = stream
.next()
.await
.ok_or_else(|| Error::Other("INSERT returned no rows".to_string()))?
.map_err(|e| Error::Other(e.to_string()))?
.into();
decode_model_row_with_hints(row, all_scalar_value_hints())
}
}
/// Entry for creating User.
#[derive(Debug, Clone)]
pub struct UserCreateEntry {
pub id: i32,
pub name: String,
}
impl UserCreateEntry {
pub(crate) fn to_engine_data(&self) -> serde_json::Value {
let mut data = serde_json::Map::new();
data.insert(
"id".to_string(),
nautilus_core::Value::from(self.id.clone()).to_json_plain(),
);
data.insert(
"name".to_string(),
nautilus_core::Value::from(self.name.clone()).to_json_plain(),
);
serde_json::Value::Object(data)
}
}
/// Internal CreateMany builder for User — use `UserDelegate::create_many(entries)` instead.
pub(crate) struct UserCreateMany<E: crate::Executor> {
client: crate::Client<E>,
entries: Vec<UserCreateEntry>,
}
impl<E> UserCreateMany<E>
where
E: crate::Executor,
for<'a> E::Row<'a>: Into<crate::Row>,
{
pub(crate) fn new(client: crate::Client<E>) -> Self {
UserCreateMany {
client,
entries: vec![],
}
}
/// Add an entry to the batch.
#[must_use]
pub(crate) fn entry(mut self, entry: UserCreateEntry) -> Self {
self.entries.push(entry);
self
}
/// Execute the batch create using a single multi-row `INSERT`.
pub(crate) async fn exec(self) -> nautilus_core::Result<Vec<User>> {
use nautilus_core::*;
if self.entries.is_empty() {
return Ok(vec![]);
}
// MySQL does not support RETURNING — fall back to per-row inserts.
if !self.client.dialect().supports_returning() {
let mut results = Vec::with_capacity(self.entries.len());
for entry in self.entries {
let result = UserCreate::new(self.client.clone())
.id(entry.id)
.name(entry.name)
.exec().await?;
results.push(result);
}
return Ok(results);
}
let columns = vec![
ColumnMarker::new("User", "id"),
ColumnMarker::new("User", "name"),
];
let mut builder = Insert::into_table("User")
.columns(columns);
for entry in &self.entries {
let row = vec![
Value::from(entry.id.clone()),
Value::from(entry.name.clone()),
];
builder = builder.values(row);
}
let returning_cols = vec![
ColumnMarker::new("User", "id"),
ColumnMarker::new("User", "name"),
];
builder = builder.returning(returning_cols);
let insert = builder.build()?;
let sql = self.client.dialect().render_insert(&insert)?;
let stream = self.client.executor().execute(&sql);
futures::pin_mut!(stream);
let mut results = Vec::with_capacity(self.entries.len());
while let Some(result) = stream.next().await {
let row: crate::Row = result.map_err(|e| Error::Other(e.to_string()))?.into();
let decoded = decode_model_row_with_hints(row, all_scalar_value_hints())?;
results.push(decoded);
}
Ok(results)
}
}
/// Internal Update builder for User — use `UserDelegate::update(args)` instead.
pub(crate) struct UserUpdate<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> UserUpdate<E>
where
E: crate::Executor,
for<'a> E::Row<'a>: Into<crate::Row>,
{
pub(crate) fn new(client: crate::Client<E>) -> Self {
UserUpdate {
client,
filter: None,
require_filter: true,
assignments: Vec::new(),
}
}
/// 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: UserUpdateInput) -> Self {
if let Some(outer) = data.id {
let val = nautilus_core::Value::from(outer);
self.assignments.push((
nautilus_core::ColumnMarker::new("User", "id"),
val,
));
}
if let Some(outer) = data.name {
let val = nautilus_core::Value::from(outer);
self.assignments.push((
nautilus_core::ColumnMarker::new("User", "name"),
val,
));
}
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<User>> {
use nautilus_core::*;
use futures::StreamExt;
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("User");
for (col, val) in self.assignments {
builder = builder.set(col, val);
}
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![
ColumnMarker::new("User", "id"),
ColumnMarker::new("User", "name"),
];
builder = builder.returning(returning_cols);
}
let update = builder.build()?;
let sql = self.client.dialect().render_update(&update)?;
let stream = self.client.executor().execute(&sql);
futures::pin_mut!(stream);
let mut results = Vec::new();
while let Some(result) = stream.next().await {
let row: crate::Row = result.map_err(|e| Error::Other(e.to_string()))?.into();
results.push(decode_model_row_with_hints(row, all_scalar_value_hints())?);
}
Ok(results)
}
}
/// Internal Delete builder for User — use `UserDelegate::delete(filter)` instead.
pub(crate) struct UserDelete<E: crate::Executor> {
client: crate::Client<E>,
filter: Option<nautilus_core::Expr>,
require_filter: bool,
}
impl<E> UserDelete<E>
where
E: crate::Executor,
for<'a> E::Row<'a>: Into<crate::Row>,
{
pub(crate) fn new(client: crate::Client<E>) -> Self {
UserDelete {
client,
filter: None,
require_filter: true,
}
}
/// Set WHERE filter.
#[must_use]
pub(crate) fn where_(mut self, expr: nautilus_core::Expr) -> Self {
self.filter = Some(expr);
self
}
/// Delete all rows (removes the safety guard that requires a filter).
#[must_use]
pub(crate) fn all(mut self) -> Self {
self.require_filter = false;
self
}
/// Execute the delete, returning deleted rows via `RETURNING`.
///
/// Returns an empty `Vec` for databases that do not support `RETURNING`
/// (e.g. MySQL).
pub(crate) async fn exec(self) -> nautilus_core::Result<Vec<User>> {
use nautilus_core::*;
use futures::StreamExt;
if self.require_filter && self.filter.is_none() {
return Err(Error::InvalidQuery(
"Delete requires a WHERE filter — call `.all()` to delete every row.".to_string(),
));
}
let mut builder = Delete::from_table("User");
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![
ColumnMarker::new("User", "id"),
ColumnMarker::new("User", "name"),
];
builder = builder.returning(returning_cols);
}
let delete = builder.build()?;
let sql = self.client.dialect().render_delete(&delete)?;
let stream = self.client.executor().execute(&sql);
futures::pin_mut!(stream);
let mut results = Vec::new();
while let Some(result) = stream.next().await {
let row: crate::Row = result.map_err(|e| Error::Other(e.to_string()))?.into();
results.push(decode_model_row_with_hints(row, all_scalar_value_hints())?);
}
Ok(results)
}
}