Files
banner/tests/db_batch_upsert.rs

213 lines
5.7 KiB
Rust

mod helpers;
use banner::data::batch::batch_upsert_courses;
use sqlx::PgPool;
#[sqlx::test]
async fn test_batch_upsert_empty_slice(pool: PgPool) {
batch_upsert_courses(&[], &pool).await.unwrap();
let count: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM courses")
.fetch_one(&pool)
.await
.unwrap();
assert_eq!(count.0, 0);
}
#[sqlx::test]
async fn test_batch_upsert_inserts_new_courses(pool: PgPool) {
let courses = vec![
helpers::make_course("10001", "202510", "CS", "1083", "Intro to CS", 25, 30, 0, 5),
helpers::make_course(
"10002",
"202510",
"MAT",
"1214",
"Calculus I",
40,
45,
3,
10,
),
];
batch_upsert_courses(&courses, &pool).await.unwrap();
let rows: Vec<(String, String, String, String, i32, i32, i32, i32)> = sqlx::query_as(
"SELECT crn, subject, course_number, title, enrollment, max_enrollment, wait_count, wait_capacity
FROM courses ORDER BY crn",
)
.fetch_all(&pool)
.await
.unwrap();
assert_eq!(rows.len(), 2);
let (crn, subject, course_number, title, enrollment, max_enrollment, wait_count, wait_capacity) =
&rows[0];
assert_eq!(crn, "10001");
assert_eq!(subject, "CS");
assert_eq!(course_number, "1083");
assert_eq!(title, "Intro to CS");
assert_eq!(*enrollment, 25);
assert_eq!(*max_enrollment, 30);
assert_eq!(*wait_count, 0);
assert_eq!(*wait_capacity, 5);
let (crn, subject, ..) = &rows[1];
assert_eq!(crn, "10002");
assert_eq!(subject, "MAT");
}
#[sqlx::test]
async fn test_batch_upsert_updates_existing(pool: PgPool) {
let initial = vec![helpers::make_course(
"20001",
"202510",
"CS",
"3443",
"App Programming",
10,
35,
0,
5,
)];
batch_upsert_courses(&initial, &pool).await.unwrap();
// Upsert the same CRN+term with updated enrollment
let updated = vec![helpers::make_course(
"20001",
"202510",
"CS",
"3443",
"App Programming",
30,
35,
2,
5,
)];
batch_upsert_courses(&updated, &pool).await.unwrap();
let count: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM courses")
.fetch_one(&pool)
.await
.unwrap();
assert_eq!(count.0, 1, "upsert should not create a duplicate row");
let (enrollment, wait_count): (i32, i32) =
sqlx::query_as("SELECT enrollment, wait_count FROM courses WHERE crn = '20001'")
.fetch_one(&pool)
.await
.unwrap();
assert_eq!(enrollment, 30);
assert_eq!(wait_count, 2);
}
#[sqlx::test]
async fn test_batch_upsert_mixed_insert_and_update(pool: PgPool) {
let initial = vec![
helpers::make_course("30001", "202510", "CS", "1083", "Intro to CS", 10, 30, 0, 5),
helpers::make_course(
"30002",
"202510",
"CS",
"2073",
"Computer Architecture",
20,
30,
0,
5,
),
];
batch_upsert_courses(&initial, &pool).await.unwrap();
// Update both existing courses and add a new one
let mixed = vec![
helpers::make_course("30001", "202510", "CS", "1083", "Intro to CS", 15, 30, 1, 5),
helpers::make_course(
"30002",
"202510",
"CS",
"2073",
"Computer Architecture",
25,
30,
0,
5,
),
helpers::make_course(
"30003",
"202510",
"MAT",
"1214",
"Calculus I",
40,
45,
3,
10,
),
];
batch_upsert_courses(&mixed, &pool).await.unwrap();
let count: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM courses")
.fetch_one(&pool)
.await
.unwrap();
assert_eq!(count.0, 3, "should have 2 updated + 1 new = 3 total rows");
// Verify updated values
let (enrollment,): (i32,) =
sqlx::query_as("SELECT enrollment FROM courses WHERE crn = '30001'")
.fetch_one(&pool)
.await
.unwrap();
assert_eq!(enrollment, 15);
let (enrollment,): (i32,) =
sqlx::query_as("SELECT enrollment FROM courses WHERE crn = '30002'")
.fetch_one(&pool)
.await
.unwrap();
assert_eq!(enrollment, 25);
// Verify new row
let (subject,): (String,) = sqlx::query_as("SELECT subject FROM courses WHERE crn = '30003'")
.fetch_one(&pool)
.await
.unwrap();
assert_eq!(subject, "MAT");
}
#[sqlx::test]
async fn test_batch_upsert_unique_constraint_crn_term(pool: PgPool) {
// Same CRN, different term codes → should produce two separate rows
let courses = vec![
helpers::make_course("40001", "202510", "CS", "1083", "Intro to CS", 25, 30, 0, 5),
helpers::make_course("40001", "202520", "CS", "1083", "Intro to CS", 10, 30, 0, 5),
];
batch_upsert_courses(&courses, &pool).await.unwrap();
let count: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM courses WHERE crn = '40001'")
.fetch_one(&pool)
.await
.unwrap();
assert_eq!(
count.0, 2,
"same CRN with different term codes should be separate rows"
);
let rows: Vec<(String, i32)> = sqlx::query_as(
"SELECT term_code, enrollment FROM courses WHERE crn = '40001' ORDER BY term_code",
)
.fetch_all(&pool)
.await
.unwrap();
assert_eq!(rows[0].0, "202510");
assert_eq!(rows[0].1, 25);
assert_eq!(rows[1].0, "202520");
assert_eq!(rows[1].1, 10);
}