diff --git a/backend/clippy.toml b/backend/clippy.toml index 11b23ad..10ce8e1 100644 --- a/backend/clippy.toml +++ b/backend/clippy.toml @@ -1,27 +1,16 @@ -# Clippy configuration +# Clippy configuration for Normogen backend +# This configuration fine-tunes Clippy lints for our project -# Allow certain warnings for development -ambiguous-glob-reexports = "allow" -cast-lossless = "allow" -doc-markdown = "warn" -empty-structs-with-brackets = "warn" -explicit-auto-deref = "warn" -if-then-some-else-none = "warn" -match-wildcard-for-single-variants = "warn" -missing-errors-doc = "warn" -missing-panics-doc = "warn" -missing-safety-doc = "warn" -semicolon-if-nothing-returned = "warn" -unreadable-literal = "warn" -unused-self = "warn" -used-underscore-binding = "warn" +# Cognitive complexity threshold (default is already quite high) +cognitive-complexity-threshold = 30 -# Deny certain lints -missing-docs-in-private-items = "warn" -unwrap-used = "warn" -expect-used = "warn" -indexing-slicing = "warn" -panic = "deny" -unimplemented = "warn" -todo = "warn" -unreachable = "warn" +# Documentation threshold - accept common technical terms +doc-valid-idents = [ + "MongoDB", + "JWT", + "API", + "JSON", + "OAuth", + "HTTP", + "URL", +] diff --git a/backend/src/db/init.rs b/backend/src/db/init.rs index 15a8bd3..45afd12 100644 --- a/backend/src/db/init.rs +++ b/backend/src/db/init.rs @@ -1,9 +1,4 @@ -use mongodb::{ - Client, - Collection, - bson::doc, - IndexModel, -}; +use mongodb::{bson::doc, Client, Collection, IndexModel}; use anyhow::Result; @@ -25,13 +20,17 @@ impl DatabaseInitializer { // Create users collection and index { let collection: Collection = db.collection("users"); - + // Create email index using the builder pattern let index = IndexModel::builder() .keys(doc! { "email": 1 }) - .options(mongodb::options::IndexOptions::builder().unique(true).build()) + .options( + mongodb::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), @@ -41,37 +40,37 @@ impl DatabaseInitializer { // Create families collection and indexes { let collection: Collection = db.collection("families"); - - let index1 = IndexModel::builder() - .keys(doc! { "userId": 1 }) - .build(); - - let index2 = IndexModel::builder() - .keys(doc! { "familyId": 1 }) - .build(); - + + 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), + Err(e) => println!( + "Warning: Failed to create index on families.familyId: {}", + e + ), } } // Create profiles collection and index { let collection: Collection = db.collection("profiles"); - - let index = IndexModel::builder() - .keys(doc! { "familyId": 1 }) - .build(); - + + 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), + Err(e) => println!( + "Warning: Failed to create index on profiles.familyId: {}", + e + ), } } @@ -102,11 +101,9 @@ impl DatabaseInitializer { // Create shares collection and index { let collection: Collection = db.collection("shares"); - - let index = IndexModel::builder() - .keys(doc! { "familyId": 1 }) - .build(); - + + 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), @@ -116,15 +113,22 @@ impl DatabaseInitializer { // Create refresh_tokens collection and index { let collection: Collection = db.collection("refresh_tokens"); - + let index = IndexModel::builder() .keys(doc! { "token": 1 }) - .options(mongodb::options::IndexOptions::builder().unique(true).build()) + .options( + mongodb::options::IndexOptions::builder() + .unique(true) + .build(), + ) .build(); - + match collection.create_index(index, None).await { Ok(_) => println!("✓ Created index on refresh_tokens.token"), - Err(e) => println!("Warning: Failed to create index on refresh_tokens.token: {}", e), + Err(e) => println!( + "Warning: Failed to create index on refresh_tokens.token: {}", + e + ), } } diff --git a/backend/src/db/mod.rs b/backend/src/db/mod.rs index 51a0e3d..b6cbde0 100644 --- a/backend/src/db/mod.rs +++ b/backend/src/db/mod.rs @@ -1,18 +1,18 @@ +use anyhow::Result; use mongodb::{Client, Database}; use std::env; -use anyhow::Result; -pub mod user; +pub mod appointment; pub mod family; -pub mod profile; pub mod health_data; pub mod lab_result; pub mod medication; -pub mod appointment; -pub mod share; pub mod permission; +pub mod profile; +pub mod share; +pub mod user; -pub mod init; // Database initialization module +pub mod init; // Database initialization module mod mongodb_impl; @@ -21,9 +21,9 @@ pub use mongodb_impl::MongoDb; pub async fn create_database() -> Result { let mongo_uri = env::var("MONGODB_URI").expect("MONGODB_URI must be set"); let db_name = env::var("DATABASE_NAME").expect("DATABASE_NAME must be set"); - + let client = Client::with_uri_str(&mongo_uri).await?; let database = client.database(&db_name); - + Ok(database) } diff --git a/backend/src/services/openfda_service.rs b/backend/src/services/openfda_service.rs index b9af959..0b5574d 100644 --- a/backend/src/services/openfda_service.rs +++ b/backend/src/services/openfda_service.rs @@ -2,7 +2,7 @@ use reqwest::Client; use serde::{Deserialize, Serialize}; use std::collections::HashMap; -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "lowercase")] pub enum InteractionSeverity { Mild, @@ -31,57 +31,70 @@ impl OpenFDAService { base_url: "https://api.fda.gov/drug/event.json".to_string(), } } - - /// Check interactions between multiple medications + + /// Check for interactions between multiple drugs pub async fn check_interactions( &self, - medications: &[String], + drugs: &[String], ) -> Result, Box> { let mut interactions = Vec::new(); - - // Check all pairs - for i in 0..medications.len() { - for j in (i + 1)..medications.len() { - if let Some(interaction) = self - .check_pair_interaction(&medications[i], &medications[j]) - .await - { + + // Check each pair of drugs + for i in 0..drugs.len() { + for j in (i + 1)..drugs.len() { + if let Some(interaction) = self.check_pair(&drugs[i], &drugs[j]).await { interactions.push(interaction); } } } - + Ok(interactions) } - - /// Check interaction between two specific drugs - async fn check_pair_interaction( - &self, - drug1: &str, - drug2: &str, - ) -> Option { + + /// Check for interaction between a specific pair of drugs + async fn check_pair(&self, drug1: &str, drug2: &str) -> Option { // For MVP, use a hardcoded database of known interactions // In production, you would: // 1. Query OpenFDA drug event endpoint // 2. Use a professional interaction database // 3. Integrate with user-provided data - - let pair = format!( - "{}+{}", - drug1.to_lowercase(), - drug2.to_lowercase() - ); - + + let pair = format!("{}+{}", drug1.to_lowercase(), drug2.to_lowercase()); + // Known severe interactions (for demonstration) - let known_interactions = [ - ("warfarin+aspirin", InteractionSeverity::Severe, "Increased risk of bleeding"), - ("warfarin+ibuprofen", InteractionSeverity::Severe, "Increased risk of bleeding"), - ("acetaminophen+alcohol", InteractionSeverity::Severe, "Increased risk of liver damage"), - ("ssri+maoi", InteractionSeverity::Severe, "Serotonin syndrome risk"), - ("digoxin+verapamil", InteractionSeverity::Moderate, "Increased digoxin levels"), - ("acei+arb", InteractionSeverity::Moderate, "Increased risk of hyperkalemia"), + let known_interactions = vec![ + ( + "warfarin+aspirin", + InteractionSeverity::Severe, + "Increased risk of bleeding", + ), + ( + "warfarin+ibuprofen", + InteractionSeverity::Severe, + "Increased risk of bleeding", + ), + ( + "acetaminophen+alcohol", + InteractionSeverity::Severe, + "Increased risk of liver damage", + ), + ( + "ssri+maoi", + InteractionSeverity::Severe, + "Serotonin syndrome risk", + ), + ( + "digoxin+verapamil", + InteractionSeverity::Moderate, + "Increased digoxin levels", + ), + ( + "acei+arb", + InteractionSeverity::Moderate, + "Increased risk of hyperkalemia", + ), ]; - + for (known_pair, severity, desc) in known_interactions { if pair.contains(known_pair) || known_pair.contains(&pair) { return Some(DrugInteraction { @@ -92,10 +105,10 @@ impl OpenFDAService { }); } } - + None } - + /// Query OpenFDA for drug event reports async fn query_drug_events( &self, @@ -103,10 +116,9 @@ impl OpenFDAService { ) -> Result> { let query = format!( "{}?search=patient.drug.medicinalproduct:{}&limit=10", - self.base_url, - drug_name + self.base_url, drug_name ); - + let response = self .client .get(&query) @@ -114,7 +126,7 @@ impl OpenFDAService { .await? .json::() .await?; - + Ok(response) } } @@ -128,7 +140,7 @@ impl Default for OpenFDAService { #[cfg(test)] mod tests { use super::*; - + #[tokio::test] async fn test_check_warfarin_aspirin() { let service = OpenFDAService::new(); @@ -136,7 +148,7 @@ mod tests { .check_interactions(&["warfarin".to_string(), "aspirin".to_string()]) .await .unwrap(); - + assert!(!interactions.is_empty()); assert_eq!(interactions[0].severity, InteractionSeverity::Severe); }