//! Notification CRUD operations on `MessageRepo`. use chrono::Utc; use uuid::Uuid; use crate::ImksResult; use crate::models::message_notification::MessageNotification; use super::message_repo::MessageRepo; use super::pagination::{CursorPage, clamp_limit}; impl MessageRepo { /// Create a notification for a user triggered by a message. pub async fn create_notification( &self, message_id: Uuid, channel_id: Uuid, user_id: Uuid, reason: &str, delivery_channel: Option<&str>, ) -> ImksResult { let id = Uuid::now_v7(); let now = Utc::now(); sqlx::query_as::<_, MessageNotification>( r#" INSERT INTO message_notification ( id, message_id, channel_id, user_id, reason, status, delivery_channel, created_at ) VALUES ($1, $2, $3, $4, $5, 'pending', $6, $7) RETURNING * "#, ) .bind(id) .bind(message_id) .bind(channel_id) .bind(user_id) .bind(reason) .bind(delivery_channel) .bind(now) .fetch_one(self.pool()) .await .map_err(Into::into) } /// Mark a notification as read. pub async fn mark_notification_read(&self, notification_id: Uuid) -> ImksResult<()> { let now = Utc::now(); sqlx::query( r#" UPDATE message_notification SET status = 'read', read_at = $1 WHERE id = $2 "#, ) .bind(now) .bind(notification_id) .execute(self.pool()) .await?; Ok(()) } /// Mark all of a user's notifications as read. pub async fn mark_all_notifications_read(&self, user_id: Uuid) -> ImksResult { let now = Utc::now(); let result = sqlx::query( r#" UPDATE message_notification SET status = 'read', read_at = $1 WHERE user_id = $2 AND status != 'read' "#, ) .bind(now) .bind(user_id) .execute(self.pool()) .await?; Ok(result.rows_affected()) } /// List notifications for a user, newest first. pub async fn list_notifications( &self, user_id: Uuid, before: Option, limit: Option, ) -> ImksResult> { let effective_limit = clamp_limit(limit); let fetch_limit = effective_limit + 1; let rows = match before { Some(cursor) => { sqlx::query_as::<_, MessageNotification>( r#" SELECT * FROM message_notification WHERE user_id = $1 AND id < $2 ORDER BY id DESC LIMIT $3 "#, ) .bind(user_id) .bind(cursor) .bind(fetch_limit) .fetch_all(self.pool()) .await? } None => { sqlx::query_as::<_, MessageNotification>( r#" SELECT * FROM message_notification WHERE user_id = $1 ORDER BY id DESC LIMIT $2 "#, ) .bind(user_id) .bind(fetch_limit) .fetch_all(self.pool()) .await? } }; Ok(CursorPage::from_raw(rows, effective_limit, |n| n.id)) } /// Get unread notification count for a user. pub async fn get_unread_notification_count(&self, user_id: Uuid) -> ImksResult { let count: i64 = sqlx::query_scalar( r#" SELECT COUNT(*)::BIGINT FROM message_notification WHERE user_id = $1 AND status = 'pending' "#, ) .bind(user_id) .fetch_one(self.pool()) .await?; Ok(count) } }