Files
k-mood/crates/adapters/sqlite/src/repositories/entry/command.rs
Gabriel Kaszewski 95739892de
Some checks failed
CI / ci (push) Failing after 1m48s
init
2026-08-25 23:24:36 +02:00

204 lines
6.9 KiB
Rust

use sqlx::SqlitePool;
use domain::activity::ActivityId;
use domain::entry::{DateRange, MoodEntry, MoodEntryId};
use domain::errors::DomainError;
use domain::user::UserId;
use super::super::shared::db_err;
pub struct SqliteEntryCommandRepository {
pool: SqlitePool,
}
impl SqliteEntryCommandRepository {
pub fn new(pool: SqlitePool) -> Self {
Self { pool }
}
async fn save_relations(&self, entry: &MoodEntry) -> Result<(), DomainError> {
let entry_id = entry.id().value().to_string();
sqlx::query("DELETE FROM entry_activities WHERE entry_id = ?")
.bind(&entry_id)
.execute(&self.pool)
.await
.map_err(db_err)?;
for activity_id in entry.activities() {
sqlx::query("INSERT INTO entry_activities (entry_id, activity_id) VALUES (?, ?)")
.bind(&entry_id)
.bind(activity_id.value().to_string())
.execute(&self.pool)
.await
.map_err(db_err)?;
}
sqlx::query("DELETE FROM entry_photos WHERE entry_id = ?")
.bind(&entry_id)
.execute(&self.pool)
.await
.map_err(db_err)?;
for photo_id in entry.photos() {
sqlx::query("INSERT INTO entry_photos (entry_id, photo_id) VALUES (?, ?)")
.bind(&entry_id)
.bind(photo_id.value().to_string())
.execute(&self.pool)
.await
.map_err(db_err)?;
}
sqlx::query("DELETE FROM entry_voice_memos WHERE entry_id = ?")
.bind(&entry_id)
.execute(&self.pool)
.await
.map_err(db_err)?;
for voice_memo_id in entry.voice_memos() {
sqlx::query("INSERT INTO entry_voice_memos (entry_id, voice_memo_id) VALUES (?, ?)")
.bind(&entry_id)
.bind(voice_memo_id.value().to_string())
.execute(&self.pool)
.await
.map_err(db_err)?;
}
Ok(())
}
}
#[async_trait::async_trait]
impl domain::ports::MoodEntryCommandPort for SqliteEntryCommandRepository {
async fn save(&self, entry: &MoodEntry) -> Result<(), DomainError> {
sqlx::query(
"INSERT INTO mood_entries (id, user_id, mood, logged_at, content, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(id) DO UPDATE SET
mood = excluded.mood, logged_at = excluded.logged_at,
content = excluded.content, updated_at = excluded.updated_at"
)
.bind(entry.id().value().to_string())
.bind(entry.user_id().value().to_string())
.bind(entry.mood().value() as i32)
.bind(entry.logged_at().to_rfc3339())
.bind(entry.content().map(|c| c.value().to_string()))
.bind(entry.created_at().to_rfc3339())
.bind(entry.updated_at().to_rfc3339())
.execute(&self.pool)
.await
.map_err(db_err)?;
self.save_relations(entry).await
}
async fn save_batch(&self, entries: &[MoodEntry]) -> Result<(), DomainError> {
let mut tx = self.pool.begin().await.map_err(db_err)?;
for entry in entries {
let entry_id = entry.id().value().to_string();
sqlx::query(
"INSERT INTO mood_entries (id, user_id, mood, logged_at, content, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(id) DO UPDATE SET
mood = excluded.mood, logged_at = excluded.logged_at,
content = excluded.content, updated_at = excluded.updated_at"
)
.bind(&entry_id)
.bind(entry.user_id().value().to_string())
.bind(entry.mood().value() as i32)
.bind(entry.logged_at().to_rfc3339())
.bind(entry.content().map(|c| c.value().to_string()))
.bind(entry.created_at().to_rfc3339())
.bind(entry.updated_at().to_rfc3339())
.execute(&mut *tx)
.await
.map_err(db_err)?;
for activity_id in entry.activities() {
sqlx::query("INSERT INTO entry_activities (entry_id, activity_id) VALUES (?, ?)")
.bind(&entry_id)
.bind(activity_id.value().to_string())
.execute(&mut *tx)
.await
.map_err(db_err)?;
}
for photo_id in entry.photos() {
sqlx::query("INSERT INTO entry_photos (entry_id, photo_id) VALUES (?, ?)")
.bind(&entry_id)
.bind(photo_id.value().to_string())
.execute(&mut *tx)
.await
.map_err(db_err)?;
}
for voice_memo_id in entry.voice_memos() {
sqlx::query(
"INSERT INTO entry_voice_memos (entry_id, voice_memo_id) VALUES (?, ?)",
)
.bind(&entry_id)
.bind(voice_memo_id.value().to_string())
.execute(&mut *tx)
.await
.map_err(db_err)?;
}
}
tx.commit().await.map_err(db_err)?;
Ok(())
}
async fn delete(&self, id: &MoodEntryId) -> Result<(), DomainError> {
sqlx::query("DELETE FROM mood_entries WHERE id = ?")
.bind(id.value().to_string())
.execute(&self.pool)
.await
.map_err(db_err)?;
Ok(())
}
async fn delete_all_by_user(&self, user_id: &UserId) -> Result<(), DomainError> {
sqlx::query("DELETE FROM mood_entries WHERE user_id = ?")
.bind(user_id.value().to_string())
.execute(&self.pool)
.await
.map_err(db_err)?;
Ok(())
}
async fn delete_by_date_range(
&self,
user_id: &UserId,
range: &DateRange,
) -> Result<u64, DomainError> {
let result = sqlx::query(
"DELETE FROM mood_entries WHERE user_id = ? AND logged_at >= ? AND logged_at <= ?",
)
.bind(user_id.value().to_string())
.bind(range.start().to_rfc3339())
.bind(range.end().to_rfc3339())
.execute(&self.pool)
.await
.map_err(db_err)?;
Ok(result.rows_affected())
}
async fn replace_activity(
&self,
user_id: &UserId,
old_activity_id: &ActivityId,
new_activity_id: &ActivityId,
) -> Result<u64, DomainError> {
let result = sqlx::query(
"UPDATE entry_activities SET activity_id = ?
WHERE activity_id = ? AND entry_id IN (SELECT id FROM mood_entries WHERE user_id = ?)",
)
.bind(new_activity_id.value().to_string())
.bind(old_activity_id.value().to_string())
.bind(user_id.value().to_string())
.execute(&self.pool)
.await
.map_err(db_err)?;
Ok(result.rows_affected())
}
}