Skip to main content

better_auth_core/adapters/
database.rs

1use async_trait::async_trait;
2use chrono::{DateTime, Utc};
3use std::collections::HashMap;
4use std::sync::{Arc, Mutex};
5use uuid::Uuid;
6
7use crate::error::{AuthError, AuthResult};
8use crate::types::{
9    Account, CreateAccount, CreateSession, CreateUser, CreateVerification, Session, UpdateUser,
10    User, Verification,
11};
12
13/// Database adapter trait for persistence
14#[async_trait]
15pub trait DatabaseAdapter: Send + Sync {
16    // User operations
17    async fn create_user(&self, user: CreateUser) -> AuthResult<User>;
18    async fn get_user_by_id(&self, id: &str) -> AuthResult<Option<User>>;
19    async fn get_user_by_email(&self, email: &str) -> AuthResult<Option<User>>;
20    async fn get_user_by_username(&self, username: &str) -> AuthResult<Option<User>>;
21    async fn update_user(&self, id: &str, update: UpdateUser) -> AuthResult<User>;
22    async fn delete_user(&self, id: &str) -> AuthResult<()>;
23
24    // Session operations
25    async fn create_session(&self, session: CreateSession) -> AuthResult<Session>;
26    async fn get_session(&self, token: &str) -> AuthResult<Option<Session>>;
27    async fn get_user_sessions(&self, user_id: &str) -> AuthResult<Vec<Session>>;
28    async fn update_session_expiry(&self, token: &str, expires_at: DateTime<Utc>)
29    -> AuthResult<()>;
30    async fn delete_session(&self, token: &str) -> AuthResult<()>;
31    async fn delete_user_sessions(&self, user_id: &str) -> AuthResult<()>;
32    async fn delete_expired_sessions(&self) -> AuthResult<usize>;
33
34    // Account operations (for OAuth)
35    async fn create_account(&self, account: CreateAccount) -> AuthResult<Account>;
36    async fn get_account(
37        &self,
38        provider: &str,
39        provider_account_id: &str,
40    ) -> AuthResult<Option<Account>>;
41    async fn get_user_accounts(&self, user_id: &str) -> AuthResult<Vec<Account>>;
42    async fn delete_account(&self, id: &str) -> AuthResult<()>;
43
44    // Verification token operations
45    async fn create_verification(
46        &self,
47        verification: CreateVerification,
48    ) -> AuthResult<Verification>;
49    async fn get_verification(
50        &self,
51        identifier: &str,
52        value: &str,
53    ) -> AuthResult<Option<Verification>>;
54    async fn get_verification_by_value(&self, value: &str) -> AuthResult<Option<Verification>>;
55    async fn delete_verification(&self, id: &str) -> AuthResult<()>;
56    async fn delete_expired_verifications(&self) -> AuthResult<usize>;
57}
58
59/// In-memory database adapter for testing and development
60pub struct MemoryDatabaseAdapter {
61    users: Arc<Mutex<HashMap<String, User>>>,
62    sessions: Arc<Mutex<HashMap<String, Session>>>,
63    accounts: Arc<Mutex<HashMap<String, Account>>>,
64    verifications: Arc<Mutex<HashMap<String, Verification>>>,
65    email_index: Arc<Mutex<HashMap<String, String>>>, // email -> user_id
66    username_index: Arc<Mutex<HashMap<String, String>>>, // username -> user_id
67}
68
69impl MemoryDatabaseAdapter {
70    pub fn new() -> Self {
71        Self {
72            users: Arc::new(Mutex::new(HashMap::new())),
73            sessions: Arc::new(Mutex::new(HashMap::new())),
74            accounts: Arc::new(Mutex::new(HashMap::new())),
75            verifications: Arc::new(Mutex::new(HashMap::new())),
76            email_index: Arc::new(Mutex::new(HashMap::new())),
77            username_index: Arc::new(Mutex::new(HashMap::new())),
78        }
79    }
80}
81
82impl Default for MemoryDatabaseAdapter {
83    fn default() -> Self {
84        Self::new()
85    }
86}
87
88#[async_trait]
89impl DatabaseAdapter for MemoryDatabaseAdapter {
90    async fn create_user(&self, create_user: CreateUser) -> AuthResult<User> {
91        let mut users = self.users.lock().unwrap();
92        let mut email_index = self.email_index.lock().unwrap();
93        let mut username_index = self.username_index.lock().unwrap();
94
95        let id = create_user.id.unwrap_or_else(|| Uuid::new_v4().to_string());
96
97        // Check if email already exists
98        if let Some(email) = &create_user.email
99            && email_index.contains_key(email)
100        {
101            return Err(AuthError::config("Email already exists"));
102        }
103
104        // Check if username already exists
105        if let Some(username) = &create_user.username
106            && username_index.contains_key(username)
107        {
108            return Err(AuthError::conflict(
109                "A user with this username already exists",
110            ));
111        }
112
113        let now = Utc::now();
114        let user = User {
115            id: id.clone(),
116            name: create_user.name,
117            email: create_user.email.clone(),
118            email_verified: create_user.email_verified.unwrap_or(false),
119            image: create_user.image,
120            created_at: now,
121            updated_at: now,
122            username: create_user.username.clone(),
123            display_username: create_user.display_username,
124            two_factor_enabled: false,
125            role: create_user.role,
126            banned: false,
127            ban_reason: None,
128            ban_expires: None,
129            metadata: create_user.metadata.unwrap_or_default(),
130        };
131
132        users.insert(id.clone(), user.clone());
133
134        if let Some(email) = &create_user.email {
135            email_index.insert(email.clone(), id.clone());
136        }
137
138        if let Some(username) = &create_user.username {
139            username_index.insert(username.clone(), id);
140        }
141
142        Ok(user)
143    }
144
145    async fn get_user_by_id(&self, id: &str) -> AuthResult<Option<User>> {
146        let users = self.users.lock().unwrap();
147        Ok(users.get(id).cloned())
148    }
149
150    async fn get_user_by_email(&self, email: &str) -> AuthResult<Option<User>> {
151        let email_index = self.email_index.lock().unwrap();
152        let users = self.users.lock().unwrap();
153
154        if let Some(user_id) = email_index.get(email) {
155            Ok(users.get(user_id).cloned())
156        } else {
157            Ok(None)
158        }
159    }
160
161    async fn get_user_by_username(&self, username: &str) -> AuthResult<Option<User>> {
162        let username_index = self.username_index.lock().unwrap();
163        let users = self.users.lock().unwrap();
164
165        if let Some(user_id) = username_index.get(username) {
166            Ok(users.get(user_id).cloned())
167        } else {
168            Ok(None)
169        }
170    }
171
172    async fn update_user(&self, id: &str, update: UpdateUser) -> AuthResult<User> {
173        let mut users = self.users.lock().unwrap();
174        let mut email_index = self.email_index.lock().unwrap();
175        let mut username_index = self.username_index.lock().unwrap();
176
177        let user = users.get_mut(id).ok_or(AuthError::UserNotFound)?;
178
179        // Update email index if email changed
180        if let Some(new_email) = &update.email {
181            if let Some(old_email) = &user.email {
182                email_index.remove(old_email);
183            }
184            email_index.insert(new_email.clone(), id.to_string());
185            user.email = Some(new_email.clone());
186        }
187
188        if let Some(name) = update.name {
189            user.name = Some(name);
190        }
191
192        if let Some(image) = update.image {
193            user.image = Some(image);
194        }
195
196        if let Some(email_verified) = update.email_verified {
197            user.email_verified = email_verified;
198        }
199
200        if let Some(ref username) = update.username {
201            // Update username index
202            if let Some(old_username) = &user.username {
203                username_index.remove(old_username);
204            }
205            username_index.insert(username.clone(), id.to_string());
206            user.username = Some(username.clone());
207        }
208
209        if let Some(display_username) = update.display_username {
210            user.display_username = Some(display_username);
211        }
212
213        if let Some(role) = update.role {
214            user.role = Some(role);
215        }
216
217        if let Some(banned) = update.banned {
218            user.banned = banned;
219        }
220
221        if let Some(ban_reason) = update.ban_reason {
222            user.ban_reason = Some(ban_reason);
223        }
224
225        if let Some(ban_expires) = update.ban_expires {
226            user.ban_expires = Some(ban_expires);
227        }
228
229        if let Some(two_factor_enabled) = update.two_factor_enabled {
230            user.two_factor_enabled = two_factor_enabled;
231        }
232
233        if let Some(metadata) = update.metadata {
234            user.metadata = metadata;
235        }
236
237        user.updated_at = Utc::now();
238
239        Ok(user.clone())
240    }
241
242    async fn delete_user(&self, id: &str) -> AuthResult<()> {
243        let mut users = self.users.lock().unwrap();
244        let mut email_index = self.email_index.lock().unwrap();
245        let mut username_index = self.username_index.lock().unwrap();
246
247        if let Some(user) = users.remove(id) {
248            if let Some(email) = &user.email {
249                email_index.remove(email);
250            }
251            if let Some(username) = &user.username {
252                username_index.remove(username);
253            }
254        }
255
256        Ok(())
257    }
258
259    async fn create_session(&self, create_session: CreateSession) -> AuthResult<Session> {
260        let mut sessions = self.sessions.lock().unwrap();
261
262        let token = format!("session_{}", Uuid::new_v4());
263        let now = Utc::now();
264        let session = Session {
265            id: Uuid::new_v4().to_string(),
266            expires_at: create_session.expires_at,
267            token: token.clone(),
268            created_at: now,
269            updated_at: now,
270            ip_address: create_session.ip_address,
271            user_agent: create_session.user_agent,
272            user_id: create_session.user_id,
273            impersonated_by: create_session.impersonated_by,
274            active_organization_id: create_session.active_organization_id,
275            active: true,
276        };
277
278        sessions.insert(token, session.clone());
279        Ok(session)
280    }
281
282    async fn get_session(&self, token: &str) -> AuthResult<Option<Session>> {
283        let sessions = self.sessions.lock().unwrap();
284        Ok(sessions.get(token).cloned())
285    }
286
287    async fn get_user_sessions(&self, user_id: &str) -> AuthResult<Vec<Session>> {
288        let sessions = self.sessions.lock().unwrap();
289        Ok(sessions
290            .values()
291            .filter(|session| session.user_id == user_id && session.active)
292            .cloned()
293            .collect())
294    }
295
296    async fn update_session_expiry(
297        &self,
298        token: &str,
299        expires_at: DateTime<Utc>,
300    ) -> AuthResult<()> {
301        let mut sessions = self.sessions.lock().unwrap();
302        if let Some(session) = sessions.get_mut(token) {
303            session.expires_at = expires_at;
304        }
305        Ok(())
306    }
307
308    async fn delete_session(&self, token: &str) -> AuthResult<()> {
309        let mut sessions = self.sessions.lock().unwrap();
310        sessions.remove(token);
311        Ok(())
312    }
313
314    async fn delete_user_sessions(&self, user_id: &str) -> AuthResult<()> {
315        let mut sessions = self.sessions.lock().unwrap();
316        sessions.retain(|_, session| session.user_id != user_id);
317        Ok(())
318    }
319
320    async fn delete_expired_sessions(&self) -> AuthResult<usize> {
321        let mut sessions = self.sessions.lock().unwrap();
322        let now = Utc::now();
323        let initial_count = sessions.len();
324
325        sessions.retain(|_, session| session.expires_at > now && session.active);
326
327        Ok(initial_count - sessions.len())
328    }
329
330    async fn create_account(&self, create_account: CreateAccount) -> AuthResult<Account> {
331        let mut accounts = self.accounts.lock().unwrap();
332
333        let now = Utc::now();
334        let account = Account {
335            id: Uuid::new_v4().to_string(),
336            account_id: create_account.account_id,
337            provider_id: create_account.provider_id,
338            user_id: create_account.user_id,
339            access_token: create_account.access_token,
340            refresh_token: create_account.refresh_token,
341            id_token: create_account.id_token,
342            access_token_expires_at: create_account.access_token_expires_at,
343            refresh_token_expires_at: create_account.refresh_token_expires_at,
344            scope: create_account.scope,
345            password: create_account.password,
346            created_at: now,
347            updated_at: now,
348        };
349
350        accounts.insert(account.id.clone(), account.clone());
351        Ok(account)
352    }
353
354    async fn get_account(
355        &self,
356        provider: &str,
357        provider_account_id: &str,
358    ) -> AuthResult<Option<Account>> {
359        let accounts = self.accounts.lock().unwrap();
360        Ok(accounts
361            .values()
362            .find(|acc| acc.provider_id == provider && acc.account_id == provider_account_id)
363            .cloned())
364    }
365
366    async fn get_user_accounts(&self, user_id: &str) -> AuthResult<Vec<Account>> {
367        let accounts = self.accounts.lock().unwrap();
368        Ok(accounts
369            .values()
370            .filter(|acc| acc.user_id == user_id)
371            .cloned()
372            .collect())
373    }
374
375    async fn delete_account(&self, id: &str) -> AuthResult<()> {
376        let mut accounts = self.accounts.lock().unwrap();
377        accounts.remove(id);
378        Ok(())
379    }
380
381    async fn create_verification(
382        &self,
383        create_verification: CreateVerification,
384    ) -> AuthResult<Verification> {
385        let mut verifications = self.verifications.lock().unwrap();
386
387        let now = Utc::now();
388        let verification = Verification {
389            id: Uuid::new_v4().to_string(),
390            identifier: create_verification.identifier,
391            value: create_verification.value.clone(),
392            expires_at: create_verification.expires_at,
393            created_at: now,
394            updated_at: now,
395        };
396
397        verifications.insert(verification.id.clone(), verification.clone());
398        Ok(verification)
399    }
400
401    async fn get_verification(
402        &self,
403        identifier: &str,
404        value: &str,
405    ) -> AuthResult<Option<Verification>> {
406        let verifications = self.verifications.lock().unwrap();
407        let now = Utc::now();
408
409        Ok(verifications
410            .values()
411            .find(|v| v.identifier == identifier && v.value == value && v.expires_at > now)
412            .cloned())
413    }
414
415    async fn get_verification_by_value(&self, value: &str) -> AuthResult<Option<Verification>> {
416        let verifications = self.verifications.lock().unwrap();
417        let now = Utc::now();
418
419        Ok(verifications
420            .values()
421            .find(|v| v.value == value && v.expires_at > now)
422            .cloned())
423    }
424
425    async fn delete_verification(&self, id: &str) -> AuthResult<()> {
426        let mut verifications = self.verifications.lock().unwrap();
427        verifications.remove(id);
428        Ok(())
429    }
430
431    async fn delete_expired_verifications(&self) -> AuthResult<usize> {
432        let mut verifications = self.verifications.lock().unwrap();
433        let now = Utc::now();
434        let initial_count = verifications.len();
435
436        verifications.retain(|_, verification| verification.expires_at > now);
437
438        Ok(initial_count - verifications.len())
439    }
440}
441
442#[cfg(feature = "sqlx-postgres")]
443pub mod sqlx_adapter {
444    use super::*;
445    use sqlx::PgPool;
446
447    pub struct SqlxAdapter {
448        pool: PgPool,
449    }
450
451    impl SqlxAdapter {
452        pub async fn new(database_url: &str) -> Result<Self, sqlx::Error> {
453            let pool = PgPool::connect(database_url).await?;
454            Ok(Self { pool })
455        }
456
457        /// Create adapter with custom pool configuration
458        pub async fn with_config(
459            database_url: &str,
460            config: PoolConfig,
461        ) -> Result<Self, sqlx::Error> {
462            let pool = sqlx::postgres::PgPoolOptions::new()
463                .max_connections(config.max_connections)
464                .min_connections(config.min_connections)
465                .acquire_timeout(config.acquire_timeout)
466                .idle_timeout(config.idle_timeout)
467                .max_lifetime(config.max_lifetime)
468                .connect(database_url)
469                .await?;
470            Ok(Self { pool })
471        }
472
473        pub fn from_pool(pool: PgPool) -> Self {
474            Self { pool }
475        }
476
477        /// Test database connection
478        pub async fn test_connection(&self) -> Result<(), sqlx::Error> {
479            sqlx::query("SELECT 1").execute(&self.pool).await?;
480            Ok(())
481        }
482
483        /// Get connection pool statistics
484        pub fn pool_stats(&self) -> PoolStats {
485            PoolStats {
486                size: self.pool.size(),
487                idle: self.pool.num_idle(),
488            }
489        }
490
491        /// Close the connection pool
492        pub async fn close(&self) {
493            self.pool.close().await;
494        }
495    }
496
497    /// Database connection pool configuration
498    #[derive(Debug, Clone)]
499    pub struct PoolConfig {
500        pub max_connections: u32,
501        pub min_connections: u32,
502        pub acquire_timeout: std::time::Duration,
503        pub idle_timeout: Option<std::time::Duration>,
504        pub max_lifetime: Option<std::time::Duration>,
505    }
506
507    impl Default for PoolConfig {
508        fn default() -> Self {
509            Self {
510                max_connections: 10,
511                min_connections: 0,
512                acquire_timeout: std::time::Duration::from_secs(30),
513                idle_timeout: Some(std::time::Duration::from_secs(600)), // 10 minutes
514                max_lifetime: Some(std::time::Duration::from_secs(1800)), // 30 minutes
515            }
516        }
517    }
518
519    /// Connection pool statistics
520    #[derive(Debug, Clone)]
521    pub struct PoolStats {
522        pub size: u32,
523        pub idle: usize,
524    }
525
526    #[async_trait]
527    impl DatabaseAdapter for SqlxAdapter {
528        async fn create_user(&self, create_user: CreateUser) -> AuthResult<User> {
529            let id = create_user.id.unwrap_or_else(|| Uuid::new_v4().to_string());
530            let now = Utc::now();
531
532            let user = sqlx::query_as::<_, User>(
533                r#"
534                INSERT INTO users (id, email, name, image, email_verified, created_at, updated_at, metadata)
535                VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
536                RETURNING id, email, name, image, email_verified, created_at, updated_at, metadata
537                "#
538            )
539            .bind(&id)
540            .bind(&create_user.email)
541            .bind(&create_user.name)
542            .bind(&create_user.image)
543            .bind(false)
544            .bind(&now)
545            .bind(&now)
546            .bind(sqlx::types::Json(create_user.metadata.unwrap_or_default()))
547            .fetch_one(&self.pool)
548            .await?;
549
550            Ok(user)
551        }
552
553        async fn get_user_by_id(&self, id: &str) -> AuthResult<Option<User>> {
554            let user = sqlx::query_as::<_, User>(
555                r#"
556                SELECT id, email, name, image, email_verified, created_at, updated_at, metadata
557                FROM users WHERE id = $1
558                "#,
559            )
560            .bind(id)
561            .fetch_optional(&self.pool)
562            .await?;
563
564            Ok(user)
565        }
566
567        async fn get_user_by_email(&self, email: &str) -> AuthResult<Option<User>> {
568            let user = sqlx::query_as::<_, User>(
569                r#"
570                SELECT id, email, name, image, email_verified, created_at, updated_at, metadata
571                FROM users WHERE email = $1
572                "#,
573            )
574            .bind(email)
575            .fetch_optional(&self.pool)
576            .await?;
577
578            Ok(user)
579        }
580
581        async fn get_user_by_username(&self, username: &str) -> AuthResult<Option<User>> {
582            let user = sqlx::query_as::<_, User>(
583                r#"
584                SELECT id, email, name, image, email_verified, created_at, updated_at, metadata
585                FROM users WHERE username = $1
586                "#,
587            )
588            .bind(username)
589            .fetch_optional(&self.pool)
590            .await?;
591
592            Ok(user)
593        }
594
595        async fn update_user(&self, id: &str, update: UpdateUser) -> AuthResult<User> {
596            let mut query = sqlx::QueryBuilder::new("UPDATE users SET updated_at = NOW()");
597            let mut has_updates = false;
598
599            if let Some(email) = &update.email {
600                query.push(", email = ");
601                query.push_bind(email);
602                has_updates = true;
603            }
604
605            if let Some(name) = &update.name {
606                query.push(", name = ");
607                query.push_bind(name);
608                has_updates = true;
609            }
610
611            if let Some(image) = &update.image {
612                query.push(", image = ");
613                query.push_bind(image);
614                has_updates = true;
615            }
616
617            if let Some(email_verified) = update.email_verified {
618                query.push(", email_verified = ");
619                query.push_bind(email_verified);
620                has_updates = true;
621            }
622
623            if let Some(metadata) = &update.metadata {
624                query.push(", metadata = ");
625                query.push_bind(sqlx::types::Json(metadata.clone()));
626                has_updates = true;
627            }
628
629            if !has_updates {
630                // If no updates, just return the current user
631                return self
632                    .get_user_by_id(id)
633                    .await?
634                    .ok_or(AuthError::UserNotFound);
635            }
636
637            query.push(" WHERE id = ");
638            query.push_bind(id);
639            query.push(" RETURNING id, email, name, image, email_verified, created_at, updated_at, metadata");
640
641            let user = query.build_query_as::<User>().fetch_one(&self.pool).await?;
642
643            Ok(user)
644        }
645
646        async fn delete_user(&self, id: &str) -> AuthResult<()> {
647            sqlx::query("DELETE FROM users WHERE id = $1")
648                .bind(id)
649                .execute(&self.pool)
650                .await?;
651
652            Ok(())
653        }
654
655        async fn create_session(&self, create_session: CreateSession) -> AuthResult<Session> {
656            let id = Uuid::new_v4().to_string();
657            let token = format!("session_{}", Uuid::new_v4());
658            let now = Utc::now();
659
660            let session = sqlx::query_as::<_, Session>(
661                r#"
662                INSERT INTO sessions (id, user_id, token, expires_at, created_at, ip_address, user_agent, active)
663                VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
664                RETURNING id, user_id, token, expires_at, created_at, ip_address, user_agent, active
665                "#
666            )
667            .bind(&id)
668            .bind(&create_session.user_id)
669            .bind(&token)
670            .bind(&create_session.expires_at)
671            .bind(&now)
672            .bind(&create_session.ip_address)
673            .bind(&create_session.user_agent)
674            .bind(true)
675            .fetch_one(&self.pool)
676            .await?;
677
678            Ok(session)
679        }
680
681        async fn get_session(&self, token: &str) -> AuthResult<Option<Session>> {
682            let session = sqlx::query_as::<_, Session>(
683                r#"
684                SELECT id, user_id, token, expires_at, created_at, updated_at, ip_address, user_agent, active, impersonated_by, active_organization_id
685                FROM sessions 
686                WHERE token = $1 AND active = true
687                "#
688            )
689            .bind(token)
690            .fetch_optional(&self.pool)
691            .await?;
692
693            Ok(session)
694        }
695
696        async fn get_user_sessions(&self, user_id: &str) -> AuthResult<Vec<Session>> {
697            let sessions = sqlx::query_as::<_, Session>(
698                r#"
699                SELECT id, user_id, token, expires_at, created_at, updated_at, ip_address, user_agent, active, impersonated_by, active_organization_id
700                FROM sessions 
701                WHERE user_id = $1 AND active = true
702                ORDER BY created_at DESC
703                "#
704            )
705            .bind(user_id)
706            .fetch_all(&self.pool)
707            .await?;
708
709            Ok(sessions)
710        }
711
712        async fn update_session_expiry(
713            &self,
714            token: &str,
715            expires_at: DateTime<Utc>,
716        ) -> AuthResult<()> {
717            sqlx::query(
718                r#"
719                UPDATE sessions 
720                SET expires_at = $1 
721                WHERE token = $2 AND active = true
722                "#,
723            )
724            .bind(&expires_at)
725            .bind(token)
726            .execute(&self.pool)
727            .await?;
728
729            Ok(())
730        }
731
732        async fn delete_session(&self, token: &str) -> AuthResult<()> {
733            sqlx::query("DELETE FROM sessions WHERE token = $1")
734                .bind(token)
735                .execute(&self.pool)
736                .await?;
737
738            Ok(())
739        }
740
741        async fn delete_user_sessions(&self, user_id: &str) -> AuthResult<()> {
742            sqlx::query("DELETE FROM sessions WHERE user_id = $1")
743                .bind(user_id)
744                .execute(&self.pool)
745                .await?;
746
747            Ok(())
748        }
749
750        async fn delete_expired_sessions(&self) -> AuthResult<usize> {
751            let result =
752                sqlx::query("DELETE FROM sessions WHERE expires_at < NOW() OR active = false")
753                    .execute(&self.pool)
754                    .await?;
755
756            Ok(result.rows_affected() as usize)
757        }
758
759        async fn create_account(&self, create_account: CreateAccount) -> AuthResult<Account> {
760            let id = Uuid::new_v4().to_string();
761            let now = Utc::now();
762
763            let account = sqlx::query_as::<_, Account>(
764                r#"
765                INSERT INTO accounts (id, account_id, provider_id, user_id, access_token, refresh_token, id_token, access_token_expires_at, refresh_token_expires_at, scope, password, created_at, updated_at)
766                VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
767                RETURNING *
768                "#
769            )
770            .bind(&id)
771            .bind(&create_account.account_id)
772            .bind(&create_account.provider_id)
773            .bind(&create_account.user_id)
774            .bind(&create_account.access_token)
775            .bind(&create_account.refresh_token)
776            .bind(&create_account.id_token)
777            .bind(&create_account.access_token_expires_at)
778            .bind(&create_account.refresh_token_expires_at)
779            .bind(&create_account.scope)
780            .bind(&create_account.password)
781            .bind(&now)
782            .bind(&now)
783            .fetch_one(&self.pool)
784            .await?;
785
786            Ok(account)
787        }
788
789        async fn get_account(
790            &self,
791            provider: &str,
792            provider_account_id: &str,
793        ) -> AuthResult<Option<Account>> {
794            let account = sqlx::query_as::<_, Account>(
795                r#"
796                SELECT *
797                FROM accounts 
798                WHERE provider_id = $1 AND account_id = $2
799                "#,
800            )
801            .bind(provider)
802            .bind(provider_account_id)
803            .fetch_optional(&self.pool)
804            .await?;
805
806            Ok(account)
807        }
808
809        async fn get_user_accounts(&self, user_id: &str) -> AuthResult<Vec<Account>> {
810            let accounts = sqlx::query_as::<_, Account>(
811                r#"
812                SELECT id, user_id, provider, provider_account_id, access_token, refresh_token, expires_at, token_type, scope, created_at
813                FROM accounts 
814                WHERE user_id = $1
815                ORDER BY created_at DESC
816                "#
817            )
818            .bind(user_id)
819            .fetch_all(&self.pool)
820            .await?;
821
822            Ok(accounts)
823        }
824
825        async fn delete_account(&self, id: &str) -> AuthResult<()> {
826            sqlx::query("DELETE FROM accounts WHERE id = $1")
827                .bind(id)
828                .execute(&self.pool)
829                .await?;
830
831            Ok(())
832        }
833
834        async fn create_verification(
835            &self,
836            create_verification: CreateVerification,
837        ) -> AuthResult<Verification> {
838            let id = Uuid::new_v4().to_string();
839            let now = Utc::now();
840
841            let verification = sqlx::query_as::<_, Verification>(
842                r#"
843                INSERT INTO verifications (id, identifier, value, expires_at, created_at, updated_at)
844                VALUES ($1, $2, $3, $4, $5, $6)
845                RETURNING *
846                "#
847            )
848            .bind(&id)
849            .bind(&create_verification.identifier)
850            .bind(&create_verification.value)
851            .bind(&create_verification.expires_at)
852            .bind(&now)
853            .bind(&now)
854            .fetch_one(&self.pool)
855            .await?;
856
857            Ok(verification)
858        }
859
860        async fn get_verification(
861            &self,
862            identifier: &str,
863            value: &str,
864        ) -> AuthResult<Option<Verification>> {
865            let verification = sqlx::query_as::<_, Verification>(
866                r#"
867                SELECT *
868                FROM verifications 
869                WHERE identifier = $1 AND value = $2 AND expires_at > NOW()
870                "#,
871            )
872            .bind(identifier)
873            .bind(value)
874            .fetch_optional(&self.pool)
875            .await?;
876
877            Ok(verification)
878        }
879
880        async fn get_verification_by_value(&self, value: &str) -> AuthResult<Option<Verification>> {
881            let verification = sqlx::query_as::<_, Verification>(
882                r#"
883                SELECT *
884                FROM verifications 
885                WHERE value = $1 AND expires_at > NOW()
886                "#,
887            )
888            .bind(value)
889            .fetch_optional(&self.pool)
890            .await?;
891
892            Ok(verification)
893        }
894
895        async fn delete_verification(&self, id: &str) -> AuthResult<()> {
896            sqlx::query("DELETE FROM verifications WHERE id = $1")
897                .bind(id)
898                .execute(&self.pool)
899                .await?;
900
901            Ok(())
902        }
903
904        async fn delete_expired_verifications(&self) -> AuthResult<usize> {
905            let result = sqlx::query("DELETE FROM verifications WHERE expires_at < NOW()")
906                .execute(&self.pool)
907                .await?;
908
909            Ok(result.rows_affected() as usize)
910        }
911    }
912}
913
914#[cfg(feature = "sqlx-postgres")]
915pub use sqlx_adapter::SqlxAdapter;