#![cfg(feature = "sqlite")]
use autumn_web::config::DatabaseConfig;
use autumn_web::db::{RuntimeConnection, create_pool};
use autumn_web::reexports::{diesel, diesel_async};
use diesel::sql_types::{BigInt, Integer, Text};
use diesel_async::pooled_connection::deadpool::Pool;
use diesel_async::{AsyncConnection as _, RunQueryDsl as _};
type SqlitePool = Pool<RuntimeConnection>;
#[derive(diesel::QueryableByName)]
struct NameRow {
#[diesel(sql_type = Text)]
name: String,
}
#[derive(diesel::QueryableByName)]
struct CountRow {
#[diesel(sql_type = BigInt)]
n: i64,
}
#[derive(diesel::QueryableByName)]
struct ForeignKeysRow {
#[diesel(sql_type = Integer)]
foreign_keys: i32,
}
#[tokio::test]
async fn read_only_sqlite_pool_builds_and_serves_reads() {
let tmp = tempfile::TempDir::new().expect("temp dir");
let db_path = tmp.path().join("reference.db");
{
let mut seed = RuntimeConnection::establish(&db_path.display().to_string())
.await
.expect("establish a raw read-write sqlite connection");
diesel::sql_query("CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT NOT NULL)")
.execute(&mut seed)
.await
.expect("create table t");
diesel::sql_query("INSERT INTO t (id, name) VALUES (1, 'alpha')")
.execute(&mut seed)
.await
.expect("insert seed row");
}
let ro_url = format!("sqlite://file:{}?mode=ro", db_path.display());
let config = DatabaseConfig {
url: Some(ro_url),
primary_pool_size: Some(4),
..Default::default()
};
let pool: SqlitePool = create_pool(&config)
.expect("read-only sqlite pool builds via build_sqlite_pool")
.expect("a url is configured");
let mut conn = pool
.get()
.await
.expect("checkout a read-only pooled connection — custom_setup must not fail on WAL");
let rows: Vec<NameRow> = diesel::sql_query("SELECT name FROM t WHERE id = 1")
.load(&mut *conn)
.await
.expect("read from the read-only pool");
assert_eq!(
rows.into_iter().next().expect("one row").name,
"alpha",
"a read-only pool must serve committed reads"
);
let fk: Vec<ForeignKeysRow> = diesel::sql_query("PRAGMA foreign_keys")
.load(&mut *conn)
.await
.expect("read foreign_keys pragma");
assert_eq!(
fk.into_iter()
.next()
.expect("foreign_keys row")
.foreign_keys,
1,
"the non-writing foreign_keys pragma must still be applied read-only"
);
let write = diesel::sql_query("INSERT INTO t (id, name) VALUES (2, 'beta')")
.execute(&mut *conn)
.await;
assert!(
write.is_err(),
"a write against a read-only sqlite pool must be rejected"
);
let count: Vec<CountRow> = diesel::sql_query("SELECT COUNT(*) AS n FROM t")
.load(&mut *conn)
.await
.expect("count rows");
assert_eq!(
count.into_iter().next().expect("count row").n,
1,
"a rejected write must not have been committed to the read-only database"
);
}