rs_auth_postgres/
verification.rs1use async_trait::async_trait;
2use sqlx::Row;
3
4use rs_auth_core::error::AuthError;
5use rs_auth_core::store::VerificationStore;
6use rs_auth_core::types::{NewVerification, Verification};
7
8use crate::db::AuthDb;
9
10#[async_trait]
11impl VerificationStore for AuthDb {
12 async fn create_verification(
13 &self,
14 verification: NewVerification,
15 ) -> Result<Verification, AuthError> {
16 sqlx::query(
17 r#"
18 INSERT INTO verifications (identifier, token_hash, expires_at)
19 VALUES ($1, $2, $3)
20 RETURNING id, identifier, token_hash, expires_at, created_at, updated_at
21 "#,
22 )
23 .bind(verification.identifier)
24 .bind(verification.token_hash)
25 .bind(verification.expires_at)
26 .fetch_one(&self.pool)
27 .await
28 .map(|row| Verification {
29 id: row.get("id"),
30 identifier: row.get("identifier"),
31 token_hash: row.get("token_hash"),
32 expires_at: row.get("expires_at"),
33 created_at: row.get("created_at"),
34 updated_at: row.get("updated_at"),
35 })
36 .map_err(|error| AuthError::Store(error.to_string()))
37 }
38
39 async fn find_by_identifier(
40 &self,
41 identifier: &str,
42 ) -> Result<Option<Verification>, AuthError> {
43 sqlx::query(
44 r#"
45 SELECT id, identifier, token_hash, expires_at, created_at, updated_at
46 FROM verifications
47 WHERE identifier = $1
48 "#,
49 )
50 .bind(identifier)
51 .fetch_optional(&self.pool)
52 .await
53 .map(|row| {
54 row.map(|row| Verification {
55 id: row.get("id"),
56 identifier: row.get("identifier"),
57 token_hash: row.get("token_hash"),
58 expires_at: row.get("expires_at"),
59 created_at: row.get("created_at"),
60 updated_at: row.get("updated_at"),
61 })
62 })
63 .map_err(|error| AuthError::Store(error.to_string()))
64 }
65
66 async fn find_by_token_hash(
67 &self,
68 token_hash: &str,
69 ) -> Result<Option<Verification>, AuthError> {
70 sqlx::query(
71 r#"
72 SELECT id, identifier, token_hash, expires_at, created_at, updated_at
73 FROM verifications
74 WHERE token_hash = $1
75 "#,
76 )
77 .bind(token_hash)
78 .fetch_optional(&self.pool)
79 .await
80 .map(|row| {
81 row.map(|row| Verification {
82 id: row.get("id"),
83 identifier: row.get("identifier"),
84 token_hash: row.get("token_hash"),
85 expires_at: row.get("expires_at"),
86 created_at: row.get("created_at"),
87 updated_at: row.get("updated_at"),
88 })
89 })
90 .map_err(|error| AuthError::Store(error.to_string()))
91 }
92
93 async fn delete_verification(&self, id: i64) -> Result<(), AuthError> {
94 sqlx::query(r#"DELETE FROM verifications WHERE id = $1"#)
95 .bind(id)
96 .execute(&self.pool)
97 .await
98 .map(|_| ())
99 .map_err(|error| AuthError::Store(error.to_string()))
100 }
101
102 async fn delete_by_identifier(&self, identifier: &str) -> Result<(), AuthError> {
103 sqlx::query(r#"DELETE FROM verifications WHERE identifier = $1"#)
104 .bind(identifier)
105 .execute(&self.pool)
106 .await
107 .map(|_| ())
108 .map_err(|error| AuthError::Store(error.to_string()))
109 }
110
111 async fn delete_expired(&self) -> Result<u64, AuthError> {
112 sqlx::query(r#"DELETE FROM verifications WHERE expires_at < now()"#)
113 .execute(&self.pool)
114 .await
115 .map(|result| result.rows_affected())
116 .map_err(|error| AuthError::Store(error.to_string()))
117 }
118}