//! MongoDB connection wrapper with typed collection accessors. use mongodb::{bson::doc, Client, Collection}; use super::Error; use crate::models::{ChatMessage, ChatSession, OrgBillingRecord, OrgSettings, UserPreferences}; /// Thin wrapper around [`mongodb::Database`] that provides typed /// collection accessors for the application's domain models. #[derive(Clone, Debug)] pub struct Database { inner: mongodb::Database, } impl Database { /// Connect to MongoDB, select the given database, and verify /// connectivity with a `ping` command. /// /// # Arguments /// /// * `uri` - MongoDB connection string (e.g. `mongodb://localhost:27017`) /// * `db_name` - Database name to use /// /// # Errors /// /// Returns `Error::DatabaseError` if the client cannot be created /// or the ping fails. pub async fn connect(uri: &str, db_name: &str) -> Result { let client = Client::with_uri_str(uri).await?; let db = client.database(db_name); // Verify the connection is alive. db.run_command(doc! { "ping": 1 }).await?; Ok(Self { inner: db }) } /// Collection for per-user preferences (theme, custom topics, etc.). pub fn user_preferences(&self) -> Collection { self.inner.collection("user_preferences") } /// Collection for organisation-level settings. pub fn org_settings(&self) -> Collection { self.inner.collection("org_settings") } /// Collection for per-cycle billing records. pub fn org_billing(&self) -> Collection { self.inner.collection("org_billing") } /// Collection for persisted chat sessions (sidebar listing). pub fn chat_sessions(&self) -> Collection { self.inner.collection("chat_sessions") } /// Collection for individual chat messages within sessions. pub fn chat_messages(&self) -> Collection { self.inner.collection("chat_messages") } /// Raw BSON document collection for queries that need manual /// `_id` → `String` conversion (avoids `ObjectId` deserialization issues). pub fn raw_collection(&self, name: &str) -> Collection { self.inner.collection(name) } }