#![allow(dead_code)]
use serde::{Deserialize, Serialize};
use umbral_core::db;
#[derive(Debug, Clone, sqlx::FromRow, Serialize, Deserialize, umbral::orm::Model)]
#[umbral(table = "ci_handle")]
pub struct Handle {
pub id: i64,
#[umbral(case_insensitive, unique)]
pub name: String,
}
async fn boot() {
let settings = umbral::Settings::from_env().expect("figment defaults");
let dir = std::env::temp_dir();
let path = dir.join(format!("umbral_ci_field_{}.db", std::process::id()));
let _ = std::fs::remove_file(&path);
let url = format!("sqlite://{}?mode=rwc", path.display());
let pool = db::connect_sqlite(&url).await.expect("file-backed sqlite");
umbral::App::builder()
.settings(settings)
.database("default", pool)
.model::<Handle>()
.build()
.expect("App::build");
let mig = tempfile::tempdir().expect("migration dir");
let mig_path = mig.path().to_path_buf();
std::mem::forget(mig);
umbral::migrate::make_in(&mig_path).await.expect("make");
umbral::migrate::run_in(&mig_path).await.expect("run");
}
#[tokio::test]
async fn case_insensitive_unique_lookup_and_preserved_casing() {
boot().await;
Handle::objects()
.create(Handle {
id: 0,
name: "Dalmas".to_string(),
})
.await
.expect("first insert");
let dup = Handle::objects()
.create(Handle {
id: 0,
name: "dalmas".to_string(),
})
.await;
assert!(
matches!(
dup,
Err(umbral::orm::write::WriteError::UniqueViolation { .. })
),
"`dalmas` must collide with the stored `Dalmas` on a case-insensitive UNIQUE; got {dup:?}"
);
for probe in ["DALMAS", "dalmas", "DaLmAs"] {
let found = Handle::objects()
.filter(handle::NAME.eq(probe))
.first()
.await
.expect("query")
.unwrap_or_else(|| panic!("case-insensitive lookup for `{probe}` must find the row"));
assert_eq!(
found.name, "Dalmas",
"the stored casing must be preserved, not folded"
);
}
}