koprogo_api/infrastructure/database/repositories/
poll_vote_repository_impl.rs1use crate::application::ports::PollVoteRepository;
2use crate::domain::entities::PollVote;
3use crate::infrastructure::database::pool::DbPool;
4use async_trait::async_trait;
5use serde_json;
6use sqlx::Row;
7use uuid::Uuid;
8
9pub struct PostgresPollVoteRepository {
10 pool: DbPool,
11}
12
13impl PostgresPollVoteRepository {
14 pub fn new(pool: DbPool) -> Self {
15 Self { pool }
16 }
17
18 fn row_to_poll_vote(&self, row: &sqlx::postgres::PgRow) -> Result<PollVote, String> {
20 let selected_ids_json: serde_json::Value = row
22 .try_get("selected_option_ids")
23 .map_err(|e| format!("Failed to get selected_option_ids: {}", e))?;
24
25 let selected_ids: Vec<Uuid> = serde_json::from_value(selected_ids_json)
26 .map_err(|e| format!("Failed to deserialize selected_option_ids: {}", e))?;
27
28 Ok(PollVote {
29 id: row
30 .try_get("id")
31 .map_err(|e| format!("Failed to get id: {}", e))?,
32 poll_id: row
33 .try_get("poll_id")
34 .map_err(|e| format!("Failed to get poll_id: {}", e))?,
35 owner_id: row
36 .try_get("owner_id")
37 .map_err(|e| format!("Failed to get owner_id: {}", e))?,
38 building_id: row
39 .try_get("building_id")
40 .map_err(|e| format!("Failed to get building_id: {}", e))?,
41 selected_option_ids: selected_ids,
42 rating_value: row
43 .try_get("rating_value")
44 .map_err(|e| format!("Failed to get rating_value: {}", e))?,
45 open_text: row
46 .try_get("open_text")
47 .map_err(|e| format!("Failed to get open_text: {}", e))?,
48 voted_at: row
49 .try_get("voted_at")
50 .map_err(|e| format!("Failed to get voted_at: {}", e))?,
51 ip_address: row
52 .try_get("ip_address")
53 .map_err(|e| format!("Failed to get ip_address: {}", e))?,
54 })
55 }
56}
57
58#[async_trait]
59impl PollVoteRepository for PostgresPollVoteRepository {
60 async fn create(&self, vote: &PollVote) -> Result<PollVote, String> {
61 let selected_ids_json = serde_json::to_value(&vote.selected_option_ids)
63 .map_err(|e| format!("Failed to serialize selected_option_ids: {}", e))?;
64
65 sqlx::query(
66 r#"
67 INSERT INTO poll_votes (
68 id, poll_id, owner_id, building_id, selected_option_ids,
69 rating_value, open_text, voted_at, ip_address
70 )
71 VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
72 "#,
73 )
74 .bind(vote.id)
75 .bind(vote.poll_id)
76 .bind(vote.owner_id)
77 .bind(vote.building_id)
78 .bind(selected_ids_json)
79 .bind(vote.rating_value)
80 .bind(&vote.open_text)
81 .bind(vote.voted_at)
82 .bind(&vote.ip_address)
83 .execute(&self.pool)
84 .await
85 .map_err(|e| format!("Failed to insert poll vote: {}", e))?;
86
87 Ok(vote.clone())
88 }
89
90 async fn find_by_id(&self, id: Uuid) -> Result<Option<PollVote>, String> {
91 let row = sqlx::query(
92 r#"
93 SELECT * FROM poll_votes WHERE id = $1
94 "#,
95 )
96 .bind(id)
97 .fetch_optional(&self.pool)
98 .await
99 .map_err(|e| format!("Failed to fetch poll vote: {}", e))?;
100
101 match row {
102 Some(r) => Ok(Some(self.row_to_poll_vote(&r)?)),
103 None => Ok(None),
104 }
105 }
106
107 async fn find_by_poll(&self, poll_id: Uuid) -> Result<Vec<PollVote>, String> {
108 let rows = sqlx::query(
109 r#"
110 SELECT * FROM poll_votes
111 WHERE poll_id = $1
112 ORDER BY voted_at DESC
113 "#,
114 )
115 .bind(poll_id)
116 .fetch_all(&self.pool)
117 .await
118 .map_err(|e| format!("Failed to fetch poll votes: {}", e))?;
119
120 rows.iter()
121 .map(|row| self.row_to_poll_vote(row))
122 .collect::<Result<Vec<PollVote>, String>>()
123 }
124
125 async fn find_by_poll_and_owner(
126 &self,
127 poll_id: Uuid,
128 owner_id: Uuid,
129 ) -> Result<Option<PollVote>, String> {
130 let row = sqlx::query(
131 r#"
132 SELECT * FROM poll_votes
133 WHERE poll_id = $1 AND owner_id = $2
134 LIMIT 1
135 "#,
136 )
137 .bind(poll_id)
138 .bind(owner_id)
139 .fetch_optional(&self.pool)
140 .await
141 .map_err(|e| format!("Failed to fetch poll vote: {}", e))?;
142
143 match row {
144 Some(r) => Ok(Some(self.row_to_poll_vote(&r)?)),
145 None => Ok(None),
146 }
147 }
148
149 async fn find_by_owner(&self, owner_id: Uuid) -> Result<Vec<PollVote>, String> {
150 let rows = sqlx::query(
151 r#"
152 SELECT * FROM poll_votes
153 WHERE owner_id = $1
154 ORDER BY voted_at DESC
155 "#,
156 )
157 .bind(owner_id)
158 .fetch_all(&self.pool)
159 .await
160 .map_err(|e| format!("Failed to fetch poll votes: {}", e))?;
161
162 rows.iter()
163 .map(|row| self.row_to_poll_vote(row))
164 .collect::<Result<Vec<PollVote>, String>>()
165 }
166
167 async fn delete(&self, id: Uuid) -> Result<bool, String> {
168 let result = sqlx::query(
169 r#"
170 DELETE FROM poll_votes WHERE id = $1
171 "#,
172 )
173 .bind(id)
174 .execute(&self.pool)
175 .await
176 .map_err(|e| format!("Failed to delete poll vote: {}", e))?;
177
178 Ok(result.rows_affected() > 0)
179 }
180}