Skip to main content

koprogo_api/application/ports/
user_role_repository.rs

1use crate::domain::entities::UserRoleAssignment;
2use async_trait::async_trait;
3use std::collections::HashMap;
4use uuid::Uuid;
5
6#[async_trait]
7pub trait UserRoleRepository: Send + Sync {
8    async fn create(&self, assignment: &UserRoleAssignment) -> Result<UserRoleAssignment, String>;
9    async fn list_for_user(&self, user_id: Uuid) -> Result<Vec<UserRoleAssignment>, String>;
10    async fn list_for_users(
11        &self,
12        user_ids: &[Uuid],
13    ) -> Result<HashMap<Uuid, Vec<UserRoleAssignment>>, String>;
14    async fn replace_all(
15        &self,
16        user_id: Uuid,
17        assignments: &[UserRoleAssignment],
18    ) -> Result<(), String>;
19    async fn find_by_id(&self, id: Uuid) -> Result<Option<UserRoleAssignment>, String>;
20    async fn set_primary_role(
21        &self,
22        user_id: Uuid,
23        role_id: Uuid,
24    ) -> Result<UserRoleAssignment, String>;
25    /// Delete a single role assignment by id.
26    ///
27    /// Story B0bis — gap fill for Story 3.1: the CRUD REST endpoint
28    /// `DELETE /users/{user_id}/role-assignments/{id}` revokes a single row
29    /// without rewriting the whole set. Returns `true` if a row was deleted,
30    /// `false` if no row matched.
31    async fn delete_by_id(&self, id: Uuid) -> Result<bool, String>;
32}
33
34#[cfg(test)]
35pub use tests::MockUserRoleRepo;
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40    use mockall::mock;
41
42    mock! {
43        pub UserRoleRepo {}
44
45        #[async_trait]
46        impl UserRoleRepository for UserRoleRepo {
47            async fn create(&self, assignment: &UserRoleAssignment) -> Result<UserRoleAssignment, String>;
48            async fn list_for_user(&self, user_id: Uuid) -> Result<Vec<UserRoleAssignment>, String>;
49            async fn list_for_users(
50                &self,
51                user_ids: &[Uuid],
52            ) -> Result<HashMap<Uuid, Vec<UserRoleAssignment>>, String>;
53            async fn replace_all(
54                &self,
55                user_id: Uuid,
56                assignments: &[UserRoleAssignment],
57            ) -> Result<(), String>;
58            async fn find_by_id(&self, id: Uuid) -> Result<Option<UserRoleAssignment>, String>;
59            async fn set_primary_role(
60                &self,
61                user_id: Uuid,
62                role_id: Uuid,
63            ) -> Result<UserRoleAssignment, String>;
64            async fn delete_by_id(&self, id: Uuid) -> Result<bool, String>;
65        }
66    }
67}