1
use std::collections::BTreeMap;
2

            
3
use serde::{Deserialize, Serialize};
4
use serde_json::json;
5
use thiserror::Error;
6

            
7
use crate::core::{
8
    protocol::request_validation::ValidationError,
9
    types::{DbOrUser, MySQLUser},
10
};
11

            
12
pub type CreateUsersRequest = Vec<MySQLUser>;
13

            
14
pub type CreateUsersResponse = BTreeMap<MySQLUser, Result<(), CreateUserError>>;
15

            
16
#[derive(Error, Debug, Clone, PartialEq, Serialize, Deserialize)]
17
pub enum CreateUserError {
18
    #[error("Validation error: {0}")]
19
    ValidationError(#[from] ValidationError),
20

            
21
    #[error("User already exists")]
22
    UserAlreadyExists,
23

            
24
    #[error("MySQL error: {0}")]
25
    MySqlError(String),
26
}
27

            
28
pub fn print_create_users_output_status(output: &CreateUsersResponse) {
29
    for (username, result) in output {
30
        match result {
31
            Ok(()) => {
32
                println!("User '{username}' created successfully.");
33
            }
34
            Err(err) => {
35
                eprintln!("{}", err.to_error_message(username));
36
                eprintln!("Skipping...");
37
            }
38
        }
39
        println!();
40
    }
41
}
42

            
43
pub fn print_create_users_output_status_json(output: &CreateUsersResponse) {
44
    let value = output
45
        .iter()
46
        .map(|(name, result)| match result {
47
            Ok(()) => (name.to_string(), json!({ "status": "success" })),
48
            Err(err) => (
49
                name.to_string(),
50
                json!({
51
                  "status": "error",
52
                  "type": err.error_type(),
53
                  "error": err.to_error_message(name),
54
                }),
55
            ),
56
        })
57
        .collect::<serde_json::Map<_, _>>();
58
    println!(
59
        "{}",
60
        serde_json::to_string_pretty(&value)
61
            .unwrap_or("Failed to serialize result to JSON".to_string())
62
    );
63
}
64

            
65
impl CreateUserError {
66
    #[must_use]
67
    pub fn to_error_message(&self, username: &MySQLUser) -> String {
68
        match self {
69
            CreateUserError::ValidationError(err) => {
70
                err.to_error_message(&DbOrUser::User(username.clone()))
71
            }
72
            CreateUserError::UserAlreadyExists => {
73
                format!("User '{username}' already exists.")
74
            }
75
            CreateUserError::MySqlError(err) => {
76
                format!("MySQL error: {err}")
77
            }
78
        }
79
    }
80

            
81
    #[must_use]
82
    pub fn error_type(&self) -> String {
83
        match self {
84
            CreateUserError::ValidationError(err) => err.error_type(),
85
            CreateUserError::UserAlreadyExists => "user-already-exists".to_string(),
86
            CreateUserError::MySqlError(_) => "mysql-error".to_string(),
87
        }
88
    }
89
}
90

            
91
#[cfg(test)]
92
mod tests {
93
    use super::*;
94

            
95
    #[test]
96
1
    fn test_serialize_deserialize_request() {
97
1
        let request: CreateUsersRequest = vec!["alice".into(), "bob".into(), "charlie".into()];
98

            
99
1
        let json = serde_json::to_string_pretty(&request).unwrap();
100
1
        println!("Serialized request:\n{}", json);
101

            
102
1
        let deserialized: CreateUsersRequest = serde_json::from_str(&json).unwrap();
103
1
        assert_eq!(request, deserialized);
104
1
    }
105

            
106
    #[test]
107
1
    fn test_serialize_deserialize_response() {
108
1
        let response: CreateUsersResponse = BTreeMap::from([
109
1
            ("alice".into(), Ok(())),
110
1
            ("bob".into(), Err(CreateUserError::UserAlreadyExists)),
111
1
            (
112
1
                "charlie".into(),
113
1
                Err(CreateUserError::MySqlError("Some MySQL error".into())),
114
1
            ),
115
1
        ]);
116

            
117
1
        let json = serde_json::to_string_pretty(&response).unwrap();
118
1
        println!("Serialized response:\n{}", json);
119

            
120
1
        let deserialized: CreateUsersResponse = serde_json::from_str(&json).unwrap();
121
1
        assert_eq!(response, deserialized);
122
1
    }
123
}