#![cfg(feature = "sqlite")]
use autumn_web::config::DatabaseConfig;
use autumn_web::db::{RuntimeConnection, create_pool};
use autumn_web::reexports::{diesel, diesel_async};
use diesel::QueryableByName;
use diesel_async::RunQueryDsl as _;
use diesel_async::pooled_connection::deadpool::Pool;
type SqlitePool = Pool<RuntimeConnection>;
mod schema {
autumn_web::reexports::diesel::table! {
casc_posts (id) {
id -> Int8,
title -> Text,
}
}
autumn_web::reexports::diesel::table! {
casc_comments (id) {
id -> Int8,
post_id -> Int8,
body -> Text,
}
}
}
use schema::{casc_comments, casc_posts};
#[autumn_web::model(table = "casc_posts")]
pub struct CascPost {
#[id]
pub id: i64,
pub title: String,
}
#[autumn_web::model(table = "casc_comments")]
pub struct CascComment {
#[id]
pub id: i64,
pub post_id: i64,
pub body: String,
}
#[autumn_web::repository(CascComment, table = "casc_comments")]
pub trait CascCommentRepository {}
#[autumn_web::repository(
CascPost,
table = "casc_posts",
dependent(PgCascCommentRepository, fk = "post_id", on_delete = destroy)
)]
pub trait CascPostRepository {}
#[derive(QueryableByName)]
struct CountRow {
#[diesel(sql_type = autumn_web::reexports::diesel::sql_types::BigInt)]
n: i64,
}
async fn count(pool: &SqlitePool, sql: &str) -> i64 {
let mut conn = pool.get().await.expect("checkout a sqlite connection");
diesel::sql_query(sql)
.get_result::<CountRow>(&mut *conn)
.await
.expect("count query")
.n
}
async fn boot_pool() -> SqlitePool {
let config = DatabaseConfig {
url: Some("sqlite://file:casc_destroy?mode=memory&cache=shared".to_string()),
primary_pool_size: Some(1),
..Default::default()
};
let pool: SqlitePool = create_pool(&config)
.expect("sqlite pool builds via build_sqlite_pool")
.expect("a url is configured");
{
let mut conn = pool.get().await.expect("checkout a sqlite connection");
diesel::sql_query(
"CREATE TABLE casc_posts (\
id INTEGER PRIMARY KEY AUTOINCREMENT, \
title TEXT NOT NULL\
)",
)
.execute(&mut *conn)
.await
.expect("create casc_posts table");
diesel::sql_query(
"CREATE TABLE casc_comments (\
id INTEGER PRIMARY KEY AUTOINCREMENT, \
post_id BIGINT NOT NULL REFERENCES casc_posts(id), \
body TEXT NOT NULL\
)",
)
.execute(&mut *conn)
.await
.expect("create casc_comments table");
}
pool
}
#[tokio::test]
async fn deleting_parent_destroys_dependent_children_on_sqlite() {
let pool = boot_pool().await;
{
let mut conn = pool.get().await.expect("checkout a sqlite connection");
diesel::sql_query("INSERT INTO casc_posts (id, title) VALUES (1, 'hello'), (2, 'other')")
.execute(&mut *conn)
.await
.expect("seed posts");
diesel::sql_query(
"INSERT INTO casc_comments (id, post_id, body) VALUES \
(1, 1, 'a'), (2, 1, 'b'), (3, 1, 'c'), (4, 2, 'keep')",
)
.execute(&mut *conn)
.await
.expect("seed comments");
}
assert_eq!(
count(
&pool,
"SELECT COUNT(*) AS n FROM casc_comments WHERE post_id = 1"
)
.await,
3
);
let repo = PgCascPostRepository::with_pool_untracked(pool.clone());
repo.delete_by_id(1)
.await
.expect("destroy cascade must succeed on SQLite (no FOR UPDATE syntax error)");
assert_eq!(
count(&pool, "SELECT COUNT(*) AS n FROM casc_posts WHERE id = 1").await,
0
);
assert_eq!(
count(
&pool,
"SELECT COUNT(*) AS n FROM casc_comments WHERE post_id = 1"
)
.await,
0
);
assert_eq!(
count(&pool, "SELECT COUNT(*) AS n FROM casc_posts WHERE id = 2").await,
1
);
assert_eq!(
count(
&pool,
"SELECT COUNT(*) AS n FROM casc_comments WHERE post_id = 2"
)
.await,
1
);
}