use sqlx::Row;
use super::builder::QueryBuilder;
use crate::error::ModelResult;
use crate::model::Model;
impl<M: Model> QueryBuilder<M> {
pub async fn get(self, pool: &sqlx::Pool<sqlx::Postgres>) -> ModelResult<Vec<M>> {
let sql = self.to_sql();
let rows = sqlx::query(&sql).fetch_all(pool).await?;
let mut models = Vec::new();
for row in rows {
models.push(M::from_row(&row)?);
}
Ok(models)
}
pub async fn chunk<F>(
self,
pool: &sqlx::Pool<sqlx::Postgres>,
chunk_size: i64,
mut callback: F,
) -> ModelResult<()>
where
F: FnMut(Vec<M>) -> Result<(), crate::error::ModelError>,
{
let mut offset = 0;
loop {
let chunk_query = self.clone().limit(chunk_size).offset(offset);
let chunk = chunk_query.get(pool).await?;
if chunk.is_empty() {
break;
}
callback(chunk)?;
offset += chunk_size;
}
Ok(())
}
pub async fn get_raw(
self,
pool: &sqlx::Pool<sqlx::Postgres>,
) -> ModelResult<Vec<serde_json::Value>> {
let sql = self.to_sql();
let rows = sqlx::query(&sql).fetch_all(pool).await?;
let mut results = Vec::new();
for row in rows {
let mut json_row = serde_json::Map::new();
for i in 0..row.len() {
if let Ok(column) = row.try_get::<Option<String>, _>(i) {
let column_name = format!("column_{}", i); json_row.insert(
column_name,
serde_json::Value::String(column.unwrap_or_default()),
);
}
}
results.push(serde_json::Value::Object(json_row));
}
Ok(results)
}
pub async fn first(self, pool: &sqlx::Pool<sqlx::Postgres>) -> ModelResult<Option<M>> {
let query = self.limit(1);
let mut results = query.get(pool).await?;
Ok(results.pop())
}
pub async fn first_or_fail(self, pool: &sqlx::Pool<sqlx::Postgres>) -> ModelResult<M> {
self.first(pool)
.await?
.ok_or_else(|| crate::error::ModelError::NotFound(M::table_name().to_string()))
}
pub async fn count(mut self, pool: &sqlx::Pool<sqlx::Postgres>) -> ModelResult<i64> {
self.select_fields = vec!["COUNT(*)".to_string()];
let sql = self.to_sql();
let row = sqlx::query(&sql).fetch_one(pool).await?;
let count: i64 = row.try_get(0)?;
Ok(count)
}
pub async fn aggregate(
self,
pool: &sqlx::Pool<sqlx::Postgres>,
) -> ModelResult<Option<serde_json::Value>> {
let sql = self.to_sql();
let row_opt = sqlx::query(&sql).fetch_optional(pool).await?;
if let Some(row) = row_opt {
if let Ok(result) = row.try_get::<Option<i64>, _>(0) {
return Ok(Some(serde_json::Value::Number(serde_json::Number::from(
result.unwrap_or(0),
))));
} else if let Ok(result) = row.try_get::<Option<f64>, _>(0) {
return Ok(Some(
serde_json::Number::from_f64(result.unwrap_or(0.0))
.map(serde_json::Value::Number)
.unwrap_or(serde_json::Value::Null),
));
} else if let Ok(result) = row.try_get::<Option<String>, _>(0) {
return Ok(Some(serde_json::Value::String(result.unwrap_or_default())));
}
}
Ok(None)
}
}