mod common;
use qbrs::dialect::Postgres;
use qbrs::expr::{ExprMethods, Text};
use qbrs::select::select;
use qbrs::statement::Statement;
use qbrs::{Table, prepare};
use qbrs_sqlx::{LoadExt, PreparedExt, StreamExt as _};
#[derive(Table)]
#[table(name = "users_prepare_test")]
#[allow(dead_code)]
struct Users {
#[column(primary_key, generated)]
id: i64,
email: String,
}
prepare! {
struct ByEmail { email: Text }
}
#[tokio::test]
async fn prepared_query_reused_across_different_params() {
let (pool, guard) = common::test_pool("qbrs_test_prepare").await;
sqlx::query("DROP TABLE IF EXISTS users_prepare_test")
.execute(&pool)
.await
.expect("drop table");
sqlx::query(
"CREATE TABLE users_prepare_test (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
email TEXT NOT NULL
)",
)
.execute(&pool)
.await
.expect("create table");
let ids: Vec<i64> = qbrs::insert::insert(users::Table)
.values(UsersInsert::builder().email("ada@example.com").build())
.values(UsersInsert::builder().email("dan@example.com").build())
.returning(users::id)
.load(&pool)
.await
.expect("seed users");
assert_eq!(ids.len(), 2);
let query = select(users::id)
.from(users::Table)
.filter(users::email.eq(ByEmail::email()))
.prepare::<ByEmail, _>(Postgres);
let ada: Vec<i64> = query
.load(
&pool,
ByEmail {
email: "ada@example.com".to_string(),
},
)
.await
.expect("load for ada");
assert_eq!(ada, vec![ids[0]]);
let dan: Vec<i64> = query
.load(
&pool,
ByEmail {
email: "dan@example.com".to_string(),
},
)
.await
.expect("load for dan");
assert_eq!(dan, vec![ids[1]]);
let twice = select(users::id)
.from(users::Table)
.filter(users::email.eq(ByEmail::email()))
.filter(users::email.gte(ByEmail::email()))
.prepare::<ByEmail, _>(Postgres);
let (sql, params) = twice
.resolve(ByEmail {
email: "ada@example.com".to_string(),
})
.expect("every placeholder resolved");
assert!(
sql.ends_with(
r#"WHERE ("users_prepare_test"."email" = $1) AND ("users_prepare_test"."email" >= $1)"#
),
"{sql}"
);
assert_eq!(params.len(), 1);
let ada_again: Vec<i64> = twice
.load(
&pool,
ByEmail {
email: "ada@example.com".to_string(),
},
)
.await
.expect("load through a placeholder named twice");
assert_eq!(ada_again, vec![ids[0]]);
let mut streamed = query
.stream(
&pool,
ByEmail {
email: "dan@example.com".to_string(),
},
)
.expect("open the prepared stream");
let mut streamed_ids = Vec::new();
while let Some(id) = streamed.next().await {
streamed_ids.push(id.expect("decode a streamed row"));
}
drop(streamed);
assert_eq!(streamed_ids, vec![ids[1]]);
sqlx::query("DROP TABLE users_prepare_test")
.execute(&pool)
.await
.expect("cleanup");
common::shutdown(pool, guard).await;
}