Skip to main content

systemprompt_users/repository/user/
find.rs

1//! User lookup queries.
2//!
3//! Copyright (c) systemprompt.io — Business Source License 1.1.
4//! See <https://systemprompt.io> for licensing details.
5
6use systemprompt_identifiers::UserId;
7
8use crate::error::Result;
9use crate::models::{User, UserRole, UserStatus};
10use crate::repository::UserRepository;
11
12impl UserRepository {
13    pub async fn find_by_id(&self, id: &UserId) -> Result<Option<User>> {
14        let deleted_status = UserStatus::Deleted.as_str();
15        let row = sqlx::query_as!(
16            User,
17            r#"
18            SELECT id, name, email, full_name, display_name, status, email_verified,
19                   roles, avatar_url, is_bot, is_scanner, created_at, updated_at
20            FROM users
21            WHERE id = $1 AND status != $2
22            "#,
23            id.as_str(),
24            deleted_status
25        )
26        .fetch_optional(&*self.pool)
27        .await?;
28
29        Ok(row)
30    }
31
32    pub async fn find_by_email(&self, email: &str) -> Result<Option<User>> {
33        let deleted_status = UserStatus::Deleted.as_str();
34        let row = sqlx::query_as!(
35            User,
36            r#"
37            SELECT id, name, email, full_name, display_name, status, email_verified,
38                   roles, avatar_url, is_bot, is_scanner, created_at, updated_at
39            FROM users
40            WHERE email = $1 AND status != $2
41            "#,
42            email,
43            deleted_status
44        )
45        .fetch_optional(&*self.pool)
46        .await?;
47
48        Ok(row)
49    }
50
51    pub async fn find_by_name(&self, name: &str) -> Result<Option<User>> {
52        let deleted_status = UserStatus::Deleted.as_str();
53        let row = sqlx::query_as!(
54            User,
55            r#"
56            SELECT id, name, email, full_name, display_name, status, email_verified,
57                   roles, avatar_url, is_bot, is_scanner, created_at, updated_at
58            FROM users
59            WHERE name = $1 AND status != $2
60            "#,
61            name,
62            deleted_status
63        )
64        .fetch_optional(&*self.pool)
65        .await?;
66
67        Ok(row)
68    }
69
70    pub async fn find_by_role(&self, role: UserRole) -> Result<Vec<User>> {
71        let deleted_status = UserStatus::Deleted.as_str();
72        let rows = sqlx::query_as!(
73            User,
74            r#"
75            SELECT id, name, email, full_name, display_name, status, email_verified,
76                   roles, avatar_url, is_bot, is_scanner, created_at, updated_at
77            FROM users
78            WHERE $1 = ANY(roles) AND status != $2
79            ORDER BY created_at DESC
80            "#,
81            role.as_str(),
82            deleted_status
83        )
84        .fetch_all(&*self.pool)
85        .await?;
86
87        Ok(rows)
88    }
89
90    pub async fn find_first_user(&self) -> Result<Option<User>> {
91        let deleted_status = UserStatus::Deleted.as_str();
92        let row = sqlx::query_as!(
93            User,
94            r#"
95            SELECT id, name, email, full_name, display_name, status, email_verified,
96                   roles, avatar_url, is_bot, is_scanner, created_at, updated_at
97            FROM users
98            WHERE status != $1
99            ORDER BY created_at ASC
100            LIMIT 1
101            "#,
102            deleted_status
103        )
104        .fetch_optional(&*self.pool)
105        .await?;
106
107        Ok(row)
108    }
109
110    pub async fn find_first_admin(&self) -> Result<Option<User>> {
111        let deleted_status = UserStatus::Deleted.as_str();
112        let admin_role = UserRole::Admin.as_str();
113        let row = sqlx::query_as!(
114            User,
115            r#"
116            SELECT id, name, email, full_name, display_name, status, email_verified,
117                   roles, avatar_url, is_bot, is_scanner, created_at, updated_at
118            FROM users
119            WHERE $1 = ANY(roles) AND status != $2
120            ORDER BY created_at ASC
121            LIMIT 1
122            "#,
123            admin_role,
124            deleted_status
125        )
126        .fetch_optional(&*self.pool)
127        .await?;
128
129        Ok(row)
130    }
131
132    pub async fn find_authenticated_user(&self, user_id: &UserId) -> Result<Option<User>> {
133        let active_status = UserStatus::Active.as_str();
134        let row = sqlx::query_as!(
135            User,
136            r#"
137            SELECT id, name, email, full_name, display_name, status, email_verified,
138                   roles, avatar_url, is_bot, is_scanner, created_at, updated_at
139            FROM users
140            WHERE id = $1 AND status = $2
141            "#,
142            user_id.as_str(),
143            active_status
144        )
145        .fetch_optional(&*self.pool)
146        .await?;
147
148        Ok(row)
149    }
150}