#![allow(dead_code)]
#![allow(unused_imports)]
prax_orm::prax_schema!("prax/schema.prax");
use prax_query::dialect::SqlDialect;
use prax_query::error::QueryError;
use prax_query::filter::FilterValue;
use prax_query::row::FromRow;
use prax_query::traits::{BoxFuture, Model as ModelTrait, QueryEngine};
#[derive(Clone)]
struct MockEngine;
impl QueryEngine for MockEngine {
fn dialect(&self) -> &dyn SqlDialect {
&prax_query::dialect::Postgres
}
fn query_many<T: ModelTrait + FromRow + Send + 'static>(
&self,
_sql: &str,
_params: Vec<FilterValue>,
) -> BoxFuture<'_, prax_query::error::QueryResult<Vec<T>>> {
Box::pin(async { Ok(Vec::new()) })
}
fn query_one<T: ModelTrait + FromRow + Send + 'static>(
&self,
_sql: &str,
_params: Vec<FilterValue>,
) -> BoxFuture<'_, prax_query::error::QueryResult<T>> {
Box::pin(async { Err(QueryError::not_found("test")) })
}
fn query_optional<T: ModelTrait + FromRow + Send + 'static>(
&self,
_sql: &str,
_params: Vec<FilterValue>,
) -> BoxFuture<'_, prax_query::error::QueryResult<Option<T>>> {
Box::pin(async { Ok(None) })
}
fn execute_insert<T: ModelTrait + FromRow + Send + 'static>(
&self,
_sql: &str,
_params: Vec<FilterValue>,
) -> BoxFuture<'_, prax_query::error::QueryResult<T>> {
Box::pin(async { Err(QueryError::not_found("test")) })
}
fn execute_update<T: ModelTrait + FromRow + Send + 'static>(
&self,
_sql: &str,
_params: Vec<FilterValue>,
) -> BoxFuture<'_, prax_query::error::QueryResult<Vec<T>>> {
Box::pin(async { Ok(Vec::new()) })
}
fn execute_delete(
&self,
_sql: &str,
_params: Vec<FilterValue>,
) -> BoxFuture<'_, prax_query::error::QueryResult<u64>> {
Box::pin(async { Ok(0) })
}
fn execute_raw(
&self,
_sql: &str,
_params: Vec<FilterValue>,
) -> BoxFuture<'_, prax_query::error::QueryResult<u64>> {
Box::pin(async { Ok(0) })
}
fn count(
&self,
_sql: &str,
_params: Vec<FilterValue>,
) -> BoxFuture<'_, prax_query::error::QueryResult<u64>> {
Box::pin(async { Ok(0) })
}
}
struct AppClient {
user: user::Client<MockEngine>,
}
impl AppClient {
fn new() -> Self {
Self {
user: user::Client::new(MockEngine),
}
}
}
#[test]
fn create_macro_compiles_with_data_and_select() {
let client = AppClient::new();
let now = ::chrono::Utc::now();
let op = prax_orm::create!(client.user, {
data: { email: "a@x.com", name: "Alice", age: 30, active: true, created_at: @(now) },
select: { id: true, email: true },
});
let (sql, params) = op.build_sql(&prax_query::dialect::Postgres);
assert!(sql.contains("INSERT INTO User"), "got: {sql}");
assert!(sql.contains("RETURNING id, email"), "got: {sql}");
assert!(!params.is_empty());
}
#[test]
fn create_macro_compiles_without_optional_fields() {
let client = AppClient::new();
let now = ::chrono::Utc::now();
let op = prax_orm::create!(client.user, {
data: { email: "b@x.com", active: true, created_at: @(now) },
});
let (sql, _params) = op.build_sql(&prax_query::dialect::Postgres);
assert!(sql.contains("INSERT INTO User"), "got: {sql}");
assert!(sql.contains("RETURNING *"));
}
#[test]
fn update_macro_compiles_plain_set() {
let client = AppClient::new();
let op = prax_orm::update!(client.user, {
where: { id: 1 },
data: { name: "Renamed" },
});
let (sql, _params) = op.build_sql(&prax_query::dialect::Postgres);
assert!(sql.contains("UPDATE User SET"), "got: {sql}");
assert!(sql.contains("name = $1"), "got: {sql}");
assert!(sql.contains("WHERE"), "got: {sql}");
}
#[test]
fn update_macro_compiles_with_increment() {
let client = AppClient::new();
let op = prax_orm::update!(client.user, {
where: { id: 1 },
data: { age: { increment: 1 } },
});
let (sql, _params) = op.build_sql(&prax_query::dialect::Postgres);
assert!(sql.contains("UPDATE User SET"), "got: {sql}");
assert!(sql.contains("age = age + $1"), "got: {sql}");
}
#[test]
fn update_macro_compiles_with_unset() {
let client = AppClient::new();
let op = prax_orm::update!(client.user, {
where: { id: 1 },
data: { name: { unset: true } },
});
let (sql, _params) = op.build_sql(&prax_query::dialect::Postgres);
assert!(sql.contains("name = NULL"), "got: {sql}");
}
#[test]
fn update_macro_compiles_mixed_ops() {
let client = AppClient::new();
let op = prax_orm::update!(client.user, {
where: { id: 42 },
data: {
name: "Bob",
age: { increment: 1 },
},
select: { id: true, age: true },
});
let (sql, _params) = op.build_sql(&prax_query::dialect::Postgres);
assert!(sql.contains("name = $1"), "got: {sql}");
assert!(sql.contains("age = age + $2"), "got: {sql}");
assert!(sql.contains("RETURNING id, age"), "got: {sql}");
}
#[test]
fn upsert_macro_compiles_full_form() {
let client = AppClient::new();
let now = ::chrono::Utc::now();
let op = prax_orm::upsert!(client.user, {
where: { email: "a@x.com" },
create: { email: "a@x.com", name: "Alice", active: true, created_at: @(now) },
update: { name: { set: "Renamed" } },
select: { id: true, email: true },
});
let (sql, _params) = op.build_sql(&prax_query::dialect::Postgres);
assert!(sql.contains("INSERT INTO User"), "got: {sql}");
assert!(sql.contains("ON CONFLICT (\"email\")"), "got: {sql}");
assert!(sql.contains("DO UPDATE SET"), "got: {sql}");
assert!(sql.contains("RETURNING id, email"), "got: {sql}");
}
#[test]
fn upsert_macro_supports_atomic_update_op() {
let client = AppClient::new();
let now = ::chrono::Utc::now();
let op = prax_orm::upsert!(client.user, {
where: { id: 1 },
create: { email: "b@x.com", active: true, created_at: @(now) },
update: { age: { increment: 1 } },
});
let (sql, _params) = op.build_sql(&prax_query::dialect::Postgres);
assert!(sql.contains("ON CONFLICT (\"id\")"), "got: {sql}");
assert!(sql.contains("age = age + $"), "got: {sql}");
}
#[test]
fn create_many_macro_compiles_with_two_rows() {
let client = AppClient::new();
let now = ::chrono::Utc::now();
let op = prax_orm::create_many!(client.user, {
data: [
{ email: "a@x.com", name: "Alice", active: true, created_at: @(now) },
{ email: "b@x.com", name: "Bob", active: true, created_at: @(now) },
],
});
let (sql, params) = op.build_sql(&prax_query::dialect::Postgres);
assert!(sql.contains("INSERT INTO User"), "got: {sql}");
assert!(sql.contains("VALUES ($1, $2, $3, $4)"), "got: {sql}");
assert_eq!(params.len(), 8);
}
#[test]
fn create_many_macro_supports_skip_duplicates() {
let client = AppClient::new();
let now = ::chrono::Utc::now();
let op = prax_orm::create_many!(client.user, {
data: [
{ email: "a@x.com", active: true, created_at: @(now) },
],
skip_duplicates: true,
});
let (sql, _params) = op.build_sql(&prax_query::dialect::Postgres);
assert!(sql.contains("ON CONFLICT DO NOTHING"), "got: {sql}");
}
#[test]
fn update_many_macro_compiles_with_non_unique_where() {
let client = AppClient::new();
let op = prax_orm::update_many!(client.user, {
where: { active: false },
data: { active: true },
});
let (sql, _params) = op.build_sql(&prax_query::dialect::Postgres);
assert!(sql.contains("UPDATE User SET"), "got: {sql}");
assert!(sql.contains("active = $1"), "got: {sql}");
assert!(sql.contains("WHERE"), "got: {sql}");
}
#[test]
fn update_many_macro_supports_arithmetic_op() {
let client = AppClient::new();
let op = prax_orm::update_many!(client.user, {
where: { active: true },
data: { age: { increment: 1 } },
});
let (sql, _params) = op.build_sql(&prax_query::dialect::Postgres);
assert!(sql.contains("age = age + $1"), "got: {sql}");
}
#[test]
fn create_data_supports_spread_from_value() {
let client = AppClient::new();
let now = ::chrono::Utc::now();
let base = user::UserCreateInput {
email: "a@x.com".into(),
name: Some("Alice".into()),
age: None,
active: Some(true),
created_at: now,
};
let op = prax_orm::create!(client.user, {
data: {
..base,
email: "alice@x.com",
},
});
let (sql, params) = op.build_sql(&prax_query::dialect::Postgres);
assert!(sql.contains("INSERT INTO User"), "got: {sql}");
let has_alice = params
.iter()
.any(|v| matches!(v, prax_query::filter::FilterValue::String(s) if s == "alice@x.com"));
assert!(has_alice, "expected email override; got: {params:?}");
}
#[test]
fn update_macro_round_trips_through_select_returning_shape() {
let client = AppClient::new();
let op = prax_orm::update!(client.user, {
where: { email: "alice@x.com" },
data: {
name: "Renamed",
age: { increment: 1 },
},
select: { id: true, name: true, age: true },
});
let (sql, params) = op.build_sql(&prax_query::dialect::Postgres);
assert!(sql.contains("UPDATE User SET"), "got: {sql}");
assert!(sql.contains("RETURNING id, name, age"), "got: {sql}");
assert_eq!(params.len(), 3, "got: {params:?}");
}