// rocie - An enterprise grocery management system // // Copyright (C) 2026 Benedikt Peetz // SPDX-License-Identifier: GPL-3.0-or-later // // This file is part of Rocie. // // You should have received a copy of the License along with this program. // If not, see . use serde::{Deserialize, Serialize}; use sqlx::query; use uuid::Uuid; use crate::storage::sql::{ insert::{Operations, Transactionable}, user::{PasswordHash, User, UserId}, }; #[derive(Debug, Deserialize, Serialize)] pub(crate) enum Operation { RegisterUser { id: UserId, name: String, description: Option, password_hash: PasswordHash, }, } impl Transactionable for Operation { type ApplyError = apply::Error; type UndoError = undo::Error; async fn apply(self, txn: &mut sqlx::SqliteConnection) -> Result<(), apply::Error> { match self { Operation::RegisterUser { id, name, description, password_hash, } => { let password_hash = password_hash.to_string(); query!( " INSERT INTO users (id, name, password_hash, description) VALUES (?,?,?,?) ", id, name, password_hash, description, ) .execute(txn) .await?; } } Ok(()) } async fn undo(self, txn: &mut sqlx::SqliteConnection) -> Result<(), undo::Error> { match self { Operation::RegisterUser { id, name, description, password_hash, } => { let password_hash = password_hash.to_string(); query!( " DELETE FROM users WHERE id = ? AND name = ? AND description = ? AND password_hash = ?; ", id, name, description, password_hash, ) .execute(txn) .await?; } } Ok(()) } } pub(crate) mod undo { #[derive(thiserror::Error, Debug)] pub(crate) enum Error { #[error("Failed to execute undo sql statments: {0}")] SqlError(#[from] sqlx::Error), } } pub(crate) mod apply { #[derive(thiserror::Error, Debug)] pub(crate) enum Error { #[error("Failed to execute apply sql statments: {0}")] SqlError(#[from] sqlx::Error), } } impl User { pub(crate) fn register( name: String, password_hash: PasswordHash, description: Option, ops: &mut Operations, ) -> Self { let id = UserId::from(Uuid::new_v4()); ops.push(Operation::RegisterUser { id, name: name.clone(), description: description.clone(), password_hash: password_hash.clone(), }); Self { id, name, description, password_hash, } } }