use spg_sqlx::{SpgPool, SpgPoolExt};
use sqlx::Row;
async fn seeded() -> SpgPool {
let pool: SpgPool = SpgPool::connect_in_memory().await.unwrap();
sqlx::query(
"CREATE TABLE outbound (id INT NOT NULL, state TEXT NOT NULL, \
next_retry BIGINT NOT NULL)",
)
.execute(&pool)
.await
.unwrap();
sqlx::query("CREATE INDEX idx_outbound_retry ON outbound(next_retry)")
.execute(&pool)
.await
.unwrap();
for i in 0..200_i32 {
sqlx::query("INSERT INTO outbound VALUES ($1, $2, $3)")
.bind(i)
.bind("queued")
.bind(i64::from(i) * 60)
.execute(&pool)
.await
.unwrap();
}
pool
}
#[tokio::test]
async fn explain_reaches_the_engine_through_the_pool() {
let pool = seeded().await;
let rows = sqlx::query("EXPLAIN SELECT id FROM outbound WHERE next_retry = 600")
.fetch_all(&pool)
.await
.expect("EXPLAIN through SpgPool");
assert!(!rows.is_empty(), "EXPLAIN returned no rows");
let plan: Vec<String> = rows.iter().map(|r| r.get::<String, _>(0)).collect();
assert!(
plan.iter().any(|l| !l.trim().is_empty()),
"EXPLAIN returned only blank lines: {plan:?}"
);
}
#[tokio::test]
async fn the_plan_distinguishes_an_index_scan_from_a_full_scan() {
let pool = seeded().await;
let plan_of = |sql: &'static str| {
let pool = pool.clone();
async move {
sqlx::query(sql)
.fetch_all(&pool)
.await
.unwrap()
.iter()
.map(|r| r.get::<String, _>(0))
.collect::<Vec<_>>()
.join("\n")
}
};
let indexed = plan_of("EXPLAIN SELECT id FROM outbound WHERE next_retry = 600").await;
let scanned = plan_of("EXPLAIN SELECT id FROM outbound WHERE state = 'queued'").await;
assert_ne!(
indexed.to_lowercase(),
scanned.to_lowercase(),
"the same plan came back for an indexed predicate and an unindexed \
one, so the plan cannot answer which one a query got:\n{indexed}"
);
}