1use crate::{DbPool, error::DbError, sql};
13
14pub async fn get_or_create_instance_id(pool: &DbPool) -> Result<String, DbError> {
34 let candidate = uuid::Uuid::new_v4().to_string();
35 sqlx::query(sql!(
36 "INSERT INTO db_instance (id, instance_id) VALUES (1, ?) ON CONFLICT (id) DO NOTHING"
37 ))
38 .bind(&candidate)
39 .execute(pool)
40 .await?;
41 sqlx::query_scalar(sql!("SELECT instance_id FROM db_instance WHERE id = 1"))
42 .fetch_one(pool)
43 .await
44 .map_err(Into::into)
45}
46
47#[cfg(test)]
48mod tests {
49 use super::*;
50 use crate::{DbConfig, run_migrations};
51
52 async fn setup_pool() -> DbPool {
53 let pool = DbConfig {
54 url: ":memory:".to_string(),
55 max_connections: 1,
56 pool_size: 1,
57 }
58 .connect()
59 .await
60 .expect("connect");
61 run_migrations(&pool).await.expect("migrate");
62 pool
63 }
64
65 #[tokio::test]
66 async fn generates_and_persists_id() {
67 let pool = setup_pool().await;
68 let id1 = get_or_create_instance_id(&pool).await.expect("first call");
69 assert!(!id1.is_empty());
70 let id2 = get_or_create_instance_id(&pool).await.expect("second call");
71 assert_eq!(id1, id2, "instance id must be stable across calls");
72 }
73
74 #[tokio::test]
75 async fn distinct_pools_get_distinct_ids() {
76 let pool_a = setup_pool().await;
77 let pool_b = setup_pool().await;
78 let id_a = get_or_create_instance_id(&pool_a).await.expect("pool a");
79 let id_b = get_or_create_instance_id(&pool_b).await.expect("pool b");
80 assert_ne!(id_a, id_b, "distinct databases must get distinct ids");
81 }
82}