#![allow(dead_code)] use mongodb::{bson::doc, options::IndexOptions, Collection, IndexModel}; use anyhow::Result; /// Creates required collections and indexes. Best-effort by design: index /// creation failures are logged as warnings and do not abort startup, matching /// the existing swallow-on-warning style. Safe to run repeatedly (idempotent). pub struct DatabaseInitializer { db: mongodb::Database, } impl DatabaseInitializer { pub fn new(db: mongodb::Database) -> Self { Self { db } } pub async fn initialize(&self) -> Result<()> { println!("[MongoDB] Initializing database collections and indexes..."); // Create users collection and index { let collection: Collection = self.db.collection("users"); // Create email index using the builder pattern let index = IndexModel::builder() .keys(doc! { "email": 1 }) .options(IndexOptions::builder().unique(true).build()) .build(); match collection.create_index(index, None).await { Ok(_) => println!("✓ Created index on users.email"), Err(e) => println!("Warning: Failed to create index on users.email: {}", e), } } // Create families collection and indexes { let collection: Collection = self.db.collection("families"); let index1 = IndexModel::builder().keys(doc! { "userId": 1 }).build(); let index2 = IndexModel::builder().keys(doc! { "familyId": 1 }).build(); match collection.create_index(index1, None).await { Ok(_) => println!("✓ Created index on families.userId"), Err(e) => println!("Warning: Failed to create index on families.userId: {}", e), } match collection.create_index(index2, None).await { Ok(_) => println!("✓ Created index on families.familyId"), Err(e) => println!( "Warning: Failed to create index on families.familyId: {}", e ), } } // Create profiles collection and index { let collection: Collection = self.db.collection("profiles"); let index = IndexModel::builder().keys(doc! { "familyId": 1 }).build(); match collection.create_index(index, None).await { Ok(_) => println!("✓ Created index on profiles.familyId"), Err(e) => println!( "Warning: Failed to create index on profiles.familyId: {}", e ), } } // Create health_data collection { let _collection: Collection = self.db.collection("health_data"); println!("✓ Created health_data collection"); } // Create lab_results collection { let _collection: Collection = self.db.collection("lab_results"); println!("✓ Created lab_results collection"); } // Create medications collection { let _collection: Collection = self.db.collection("medications"); println!("✓ Created medications collection"); } // Create appointments collection { let _collection: Collection = self.db.collection("appointments"); println!("✓ Created appointments collection"); } // Create shares collection and index { let collection: Collection = self.db.collection("shares"); let index = IndexModel::builder().keys(doc! { "familyId": 1 }).build(); match collection.create_index(index, None).await { Ok(_) => println!("✓ Created index on shares.familyId"), Err(e) => println!("Warning: Failed to create index on shares.familyId: {}", e), } } // Create refresh_tokens collection and indexes. // - unique index on tokenHash (the only thing we ever look tokens up by) // - TTL index on expiresAt so expired tokens are auto-deleted by Mongo { let collection: Collection = self.db.collection("refresh_tokens"); let unique_index = IndexModel::builder() .keys(doc! { "tokenHash": 1 }) .options(IndexOptions::builder().unique(true).build()) .build(); // TTL: documents are deleted once their `expiresAt` timestamp passes. // With expireAfterSeconds=0, Mongo removes each doc exactly when the // datetime stored in `expiresAt` is reached. let ttl_index = IndexModel::builder() .keys(doc! { "expiresAt": 1 }) .options( IndexOptions::builder() .expire_after(std::time::Duration::from_secs(0)) .build(), ) .build(); match collection.create_index(unique_index, None).await { Ok(_) => println!("✓ Created unique index on refresh_tokens.tokenHash"), Err(e) => println!( "Warning: Failed to create index on refresh_tokens.tokenHash: {}", e ), } match collection.create_index(ttl_index, None).await { Ok(_) => println!("✓ Created TTL index on refresh_tokens.expiresAt"), Err(e) => println!( "Warning: Failed to create TTL index on refresh_tokens.expiresAt: {}", e ), } } println!("[MongoDB] Database initialization complete"); Ok(()) } }