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,116 @@
|
||||
//! Message write operations — insert, update body, soft delete.
|
||||
//!
|
||||
//! All mutations use parameterized queries and return the affected row(s).
|
||||
|
||||
use chrono::Utc;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::ImksResult;
|
||||
use crate::models::message::{Message, new_message_id};
|
||||
|
||||
use super::message_repo::MessageRepo;
|
||||
|
||||
/// Input payload for creating a new message.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CreateMessageInput {
|
||||
/// Target channel UUID.
|
||||
pub channel_id: Uuid,
|
||||
/// Author (user) UUID — extracted from JWT `sub` claim.
|
||||
pub author_id: Uuid,
|
||||
/// Thread this message belongs to (`None` = top-level).
|
||||
pub thread_id: Option<Uuid>,
|
||||
/// Direct reply reference (`None` = not a reply).
|
||||
pub reply_to_message_id: Option<Uuid>,
|
||||
/// Discriminator: `"text"`, `"system"`, `"event"`, `"article"`.
|
||||
pub message_type: String,
|
||||
/// Plain text or markdown body.
|
||||
pub body: String,
|
||||
/// Extensible metadata (flags, locale, etc.).
|
||||
pub metadata: Option<serde_json::Value>,
|
||||
/// Whether this is a system/bot-generated message.
|
||||
pub system: bool,
|
||||
}
|
||||
|
||||
impl MessageRepo {
|
||||
/// Insert a new message row and return it.
|
||||
///
|
||||
/// The message ID is a fresh UUID v7 (time-ordered).
|
||||
pub async fn create(&self, input: &CreateMessageInput) -> ImksResult<Message> {
|
||||
let id = new_message_id();
|
||||
let now = Utc::now();
|
||||
|
||||
let row = sqlx::query_as::<_, Message>(
|
||||
r#"
|
||||
INSERT INTO message (
|
||||
id, channel_id, author_id, thread_id, reply_to_message_id,
|
||||
message_type, body, metadata, pinned, system,
|
||||
edited_at, deleted_at, created_at, updated_at
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5,
|
||||
$6, $7, $8, FALSE, $9,
|
||||
NULL, NULL, $10, $10
|
||||
)
|
||||
RETURNING *
|
||||
"#,
|
||||
)
|
||||
.bind(id)
|
||||
.bind(input.channel_id)
|
||||
.bind(input.author_id)
|
||||
.bind(input.thread_id)
|
||||
.bind(input.reply_to_message_id)
|
||||
.bind(&input.message_type)
|
||||
.bind(&input.body)
|
||||
.bind(&input.metadata)
|
||||
.bind(input.system)
|
||||
.bind(now)
|
||||
.fetch_one(self.pool())
|
||||
.await?;
|
||||
|
||||
Ok(row)
|
||||
}
|
||||
|
||||
/// Update the body of an existing message. Sets `edited_at` and `updated_at`.
|
||||
///
|
||||
/// Returns the updated row, or an error if the message is not found or deleted.
|
||||
pub async fn update_body(&self, message_id: Uuid, new_body: &str) -> ImksResult<Message> {
|
||||
let now = Utc::now();
|
||||
|
||||
let row = sqlx::query_as::<_, Message>(
|
||||
r#"
|
||||
UPDATE message
|
||||
SET body = $1, edited_at = $2, updated_at = $2
|
||||
WHERE id = $3 AND deleted_at IS NULL
|
||||
RETURNING *
|
||||
"#,
|
||||
)
|
||||
.bind(new_body)
|
||||
.bind(now)
|
||||
.bind(message_id)
|
||||
.fetch_optional(self.pool())
|
||||
.await?
|
||||
.ok_or_else(|| crate::ImksError::NotFound(format!("message {message_id}")))?;
|
||||
|
||||
Ok(row)
|
||||
}
|
||||
|
||||
/// Soft-delete a message by setting `deleted_at`.
|
||||
///
|
||||
/// Returns `Ok(())` even if the message was already deleted.
|
||||
pub async fn soft_delete(&self, message_id: Uuid) -> ImksResult<()> {
|
||||
let now = Utc::now();
|
||||
|
||||
sqlx::query(
|
||||
r#"
|
||||
UPDATE message
|
||||
SET deleted_at = $1, updated_at = $1
|
||||
WHERE id = $2 AND deleted_at IS NULL
|
||||
"#,
|
||||
)
|
||||
.bind(now)
|
||||
.bind(message_id)
|
||||
.execute(self.pool())
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user