refactor(tests): reformat code and update dependency management
- Reorganized import statements in adapter tests for better readability - Replaced or_insert_with(Vec::new) with or_default() in test closures - Updated Cargo.lock with new dependency versions and checksums - Added TLS features to tonic dependency configuration - Included sqlx, chrono, and uuid dependencies with specific features - Added jsonwebtoken and arc-swap as project dependencies - Reformatted assertion statements to comply with line length limits - Adjusted base64 import order in engine codec module - Updated protobuf include statement formatting
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
//! Read state CRUD operations on `MessageRepo`.
|
||||
//!
|
||||
//! One row per (channel, user). Upserted on each read; ON CONFLICT DO UPDATE
|
||||
//! advances the cursor and recalculates unread counts.
|
||||
|
||||
use chrono::Utc;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::ImksResult;
|
||||
use crate::models::message_read_state::MessageReadState;
|
||||
|
||||
use super::message_repo::MessageRepo;
|
||||
|
||||
impl MessageRepo {
|
||||
/// Mark a channel as read up to a given message for a user.
|
||||
/// Recalculates unread_count and unread_mentions from the database.
|
||||
pub async fn mark_read(
|
||||
&self,
|
||||
channel_id: Uuid,
|
||||
user_id: Uuid,
|
||||
last_read_message_id: Uuid,
|
||||
) -> ImksResult<MessageReadState> {
|
||||
let now = Utc::now();
|
||||
|
||||
let unread_count: i64 = sqlx::query_scalar(
|
||||
r#"
|
||||
SELECT COUNT(*)::BIGINT
|
||||
FROM message
|
||||
WHERE channel_id = $1
|
||||
AND deleted_at IS NULL
|
||||
AND id > $2
|
||||
AND author_id != $3
|
||||
"#,
|
||||
)
|
||||
.bind(channel_id)
|
||||
.bind(last_read_message_id)
|
||||
.bind(user_id)
|
||||
.fetch_one(self.pool())
|
||||
.await?;
|
||||
|
||||
let unread_mentions: i64 = sqlx::query_scalar(
|
||||
r#"
|
||||
SELECT COUNT(*)::BIGINT
|
||||
FROM message_mention mm
|
||||
WHERE mm.channel_id = $1
|
||||
AND mm.mentioned_user_id = $2
|
||||
AND mm.message_id > $3
|
||||
AND mm.read_at IS NULL
|
||||
"#,
|
||||
)
|
||||
.bind(channel_id)
|
||||
.bind(user_id)
|
||||
.bind(last_read_message_id)
|
||||
.fetch_one(self.pool())
|
||||
.await?;
|
||||
|
||||
let id = Uuid::now_v7();
|
||||
|
||||
sqlx::query_as::<_, MessageReadState>(
|
||||
r#"
|
||||
INSERT INTO message_read_state (
|
||||
id, channel_id, user_id, last_read_message_id, last_read_at,
|
||||
unread_count, unread_mentions, created_at, updated_at
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $8)
|
||||
ON CONFLICT (channel_id, user_id) DO UPDATE SET
|
||||
last_read_message_id = EXCLUDED.last_read_message_id,
|
||||
last_read_at = EXCLUDED.last_read_at,
|
||||
unread_count = EXCLUDED.unread_count,
|
||||
unread_mentions = EXCLUDED.unread_mentions,
|
||||
updated_at = EXCLUDED.updated_at
|
||||
RETURNING *
|
||||
"#,
|
||||
)
|
||||
.bind(id)
|
||||
.bind(channel_id)
|
||||
.bind(user_id)
|
||||
.bind(last_read_message_id)
|
||||
.bind(now)
|
||||
.bind(unread_count)
|
||||
.bind(unread_mentions)
|
||||
.fetch_one(self.pool())
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Get a user's read state for a channel.
|
||||
pub async fn get_read_state(
|
||||
&self,
|
||||
channel_id: Uuid,
|
||||
user_id: Uuid,
|
||||
) -> ImksResult<Option<MessageReadState>> {
|
||||
sqlx::query_as::<_, MessageReadState>(
|
||||
"SELECT * FROM message_read_state WHERE channel_id = $1 AND user_id = $2",
|
||||
)
|
||||
.bind(channel_id)
|
||||
.bind(user_id)
|
||||
.fetch_optional(self.pool())
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Get read state summaries for all channels a user participates in.
|
||||
pub async fn get_user_read_states(&self, user_id: Uuid) -> ImksResult<Vec<MessageReadState>> {
|
||||
sqlx::query_as::<_, MessageReadState>("SELECT * FROM message_read_state WHERE user_id = $1")
|
||||
.bind(user_id)
|
||||
.fetch_all(self.pool())
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user