#![cfg(feature = "sqlite")]
use autumn_web::config::DatabaseConfig;
use autumn_web::db::{Db, DbState, RuntimeConnection, create_pool};
use autumn_web::reexports::{axum, diesel, diesel_async};
use axum::Router;
use axum::body::Body;
use axum::http::{Request, StatusCode};
use axum::routing::get;
use diesel_async::RunQueryDsl as _;
use diesel_async::pooled_connection::deadpool::Pool;
use tower::ServiceExt as _;
type SqlitePool = Pool<RuntimeConnection>;
#[derive(Clone)]
struct AppState {
pool: SqlitePool,
}
impl DbState for AppState {
fn pool(&self) -> Option<&SqlitePool> {
Some(&self.pool)
}
}
#[derive(diesel::QueryableByName)]
struct Greeting {
#[diesel(sql_type = diesel::sql_types::Text)]
message: String,
}
async fn greet(mut db: Db) -> Result<String, StatusCode> {
let rows: Vec<Greeting> = diesel::sql_query("SELECT message FROM greetings WHERE id = 1")
.load(&mut *db)
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
rows.into_iter()
.next()
.map(|g| g.message)
.ok_or(StatusCode::NOT_FOUND)
}
#[tokio::test]
async fn db_extractor_serves_a_sqlite_backed_request_with_200() {
let tmp = tempfile::TempDir::new().expect("temp dir");
let db_path = tmp.path().join("extractor.db");
let url = format!("sqlite://{}", db_path.display());
let config = DatabaseConfig {
url: Some(url),
..Default::default()
};
let pool: SqlitePool = create_pool(&config)
.expect("sqlite pool builds via the build_sqlite_pool path")
.expect("a url is configured");
{
let mut conn = pool.get().await.expect("checkout a sqlite connection");
diesel::sql_query("CREATE TABLE greetings (id INTEGER PRIMARY KEY, message TEXT NOT NULL)")
.execute(&mut *conn)
.await
.expect("create table on sqlite");
diesel::sql_query(
"INSERT INTO greetings (id, message) VALUES (1, 'hello via Db extractor')",
)
.execute(&mut *conn)
.await
.expect("seed row on sqlite");
}
let app: Router = Router::new()
.route("/greet", get(greet))
.with_state(AppState { pool });
let response = app
.oneshot(
Request::builder()
.uri("/greet")
.body(Body::empty())
.expect("build request"),
)
.await
.expect("router serves the request");
assert_eq!(
response.status(),
StatusCode::OK,
"the real `Db`-extractor route must be 200 under SQLite, not 503 from a \
Postgres-only `SET statement_timeout` in Db::checkout"
);
let body = axum::body::to_bytes(response.into_body(), usize::MAX)
.await
.expect("read body");
assert_eq!(
&body[..],
b"hello via Db extractor",
"response body is the row SELECTed through the Db extractor"
);
}