use bsql::Pool;
async fn pool() -> Pool {
Pool::connect("postgres://bsql:bsql@localhost/bsql_test")
.await
.expect("Failed to connect to test database. Is PostgreSQL running?")
}
#[tokio::test]
async fn singleflight_fetch_one_works() {
let pool = pool().await;
let id = 1i32;
let user = bsql::query!("SELECT id, login FROM users WHERE id = $id: i32")
.fetch_one(&pool)
.await
.unwrap();
let r = user.get().unwrap();
assert_eq!(r.id, 1);
assert_eq!(r.login, "alice");
}
#[tokio::test]
async fn singleflight_fetch_all_works() {
let pool = pool().await;
let users = bsql::query!("SELECT id, login FROM users ORDER BY id")
.fetch_all(&pool)
.await
.unwrap();
assert!(users.len() >= 2);
assert_eq!(users[0].login, "alice");
}
#[tokio::test]
async fn concurrent_identical_queries_all_succeed() {
use std::sync::Arc;
let pool = Arc::new(pool().await);
let mut handles = Vec::new();
for _ in 0..10 {
let pool = Arc::clone(&pool);
handles.push(tokio::spawn(async move {
bsql::query!("SELECT id, login FROM users ORDER BY id")
.fetch_all(pool.as_ref())
.await
}));
}
for handle in handles {
let users = handle.await.expect("task panicked").unwrap();
assert!(users.len() >= 2);
assert_eq!(users[0].login, "alice");
}
}
#[tokio::test]
async fn parameterized_query_works_with_singleflight() {
let pool = pool().await;
let id = 1i32;
let user = bsql::query!("SELECT id, login FROM users WHERE id = $id: i32")
.fetch_one(&pool)
.await
.unwrap();
assert_eq!(user.get().unwrap().id, 1);
let id = 2i32;
let user = bsql::query!("SELECT id, login FROM users WHERE id = $id: i32")
.fetch_one(&pool)
.await
.unwrap();
assert_eq!(user.get().unwrap().id, 2);
}
#[tokio::test]
async fn transaction_queries_are_not_coalesced() {
let pool = pool().await;
let mut txn = pool.begin().await.unwrap();
let users = bsql::query!("SELECT id, login FROM users ORDER BY id")
.fetch_all(&mut txn)
.await
.unwrap();
assert!(users.len() >= 2);
txn.rollback().await.unwrap();
}
#[tokio::test]
async fn pool_connection_queries_not_coalesced() {
let pool = pool().await;
let mut conn = pool.acquire().await.unwrap();
let users = bsql::query!("SELECT id, login FROM users ORDER BY id")
.fetch_all(&mut conn)
.await
.unwrap();
assert!(users.len() >= 2);
}
#[tokio::test]
async fn execute_not_affected_by_singleflight() {
let pool = pool().await;
let desc = "singleflight-test-desc";
let id = 1i32;
let affected = bsql::query!("UPDATE tickets SET description = $desc: &str WHERE id = $id: i32")
.execute(&pool)
.await
.unwrap();
assert_eq!(affected, 1);
}
#[tokio::test]
async fn queries_work_after_concurrent_burst() {
use std::sync::Arc;
let pool = Arc::new(pool().await);
let mut handles = Vec::new();
for _ in 0..20 {
let pool = Arc::clone(&pool);
handles.push(tokio::spawn(async move {
bsql::query!("SELECT id, login FROM users ORDER BY id")
.fetch_all(pool.as_ref())
.await
}));
}
for handle in handles {
let result = handle.await.expect("task panicked");
if let Ok(users) = &result {
assert!(users.len() >= 2);
}
}
let id = 1i32;
let user = bsql::query!("SELECT id, login FROM users WHERE id = $id: i32")
.fetch_one(pool.as_ref())
.await
.unwrap();
let r = user.get().unwrap();
assert_eq!(r.id, 1);
assert_eq!(r.login, "alice");
}
#[tokio::test]
async fn singleflight_fetch_optional_works() {
let pool = pool().await;
let id = 1i32;
let user = bsql::query!("SELECT id, login FROM users WHERE id = $id: i32")
.fetch_optional(&pool)
.await
.unwrap();
assert!(user.is_some());
assert_eq!(user.unwrap().get().unwrap().login, "alice");
}
#[tokio::test]
async fn different_queries_are_independent() {
use std::sync::Arc;
let pool = Arc::new(pool().await);
let pool1 = Arc::clone(&pool);
let h1 = tokio::spawn(async move {
bsql::query!("SELECT id, login FROM users ORDER BY id")
.fetch_all(pool1.as_ref())
.await
});
let pool2 = Arc::clone(&pool);
let h2 = tokio::spawn(async move {
bsql::query!("SELECT id FROM tickets ORDER BY id")
.fetch_all(pool2.as_ref())
.await
});
let users = h1.await.expect("task panicked").unwrap();
let tickets = h2.await.expect("task panicked").unwrap();
assert!(users.len() >= 2);
assert!(!tickets.is_empty());
}