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 email = crate::models::normalise_email(email);
34        let deleted_status = UserStatus::Deleted.as_str();
35        let row = sqlx::query_as!(
36            User,
37            r#"
38            SELECT id, name, email, full_name, display_name, status, email_verified,
39                   roles, avatar_url, is_bot, is_scanner, created_at, updated_at
40            FROM users
41            WHERE email = $1 AND status != $2
42            "#,
43            email,
44            deleted_status
45        )
46        .fetch_optional(&*self.pool)
47        .await?;
48
49        Ok(row)
50    }
51
52    pub async fn find_by_name(&self, name: &str) -> Result<Option<User>> {
53        let deleted_status = UserStatus::Deleted.as_str();
54        let row = sqlx::query_as!(
55            User,
56            r#"
57            SELECT id, name, email, full_name, display_name, status, email_verified,
58                   roles, avatar_url, is_bot, is_scanner, created_at, updated_at
59            FROM users
60            WHERE name = $1 AND status != $2
61            "#,
62            name,
63            deleted_status
64        )
65        .fetch_optional(&*self.pool)
66        .await?;
67
68        Ok(row)
69    }
70
71    pub async fn find_by_role(&self, role: UserRole) -> Result<Vec<User>> {
72        let deleted_status = UserStatus::Deleted.as_str();
73        let rows = sqlx::query_as!(
74            User,
75            r#"
76            SELECT id, name, email, full_name, display_name, status, email_verified,
77                   roles, avatar_url, is_bot, is_scanner, created_at, updated_at
78            FROM users
79            WHERE $1 = ANY(roles) AND status != $2
80            ORDER BY created_at DESC
81            "#,
82            role.as_str(),
83            deleted_status
84        )
85        .fetch_all(&*self.pool)
86        .await?;
87
88        Ok(rows)
89    }
90
91    pub async fn find_first_user(&self) -> Result<Option<User>> {
92        let deleted_status = UserStatus::Deleted.as_str();
93        let row = sqlx::query_as!(
94            User,
95            r#"
96            SELECT id, name, email, full_name, display_name, status, email_verified,
97                   roles, avatar_url, is_bot, is_scanner, created_at, updated_at
98            FROM users
99            WHERE status != $1
100            ORDER BY created_at ASC
101            LIMIT 1
102            "#,
103            deleted_status
104        )
105        .fetch_optional(&*self.pool)
106        .await?;
107
108        Ok(row)
109    }
110
111    pub async fn find_first_admin(&self) -> Result<Option<User>> {
112        let deleted_status = UserStatus::Deleted.as_str();
113        let admin_role = UserRole::Admin.as_str();
114        let row = sqlx::query_as!(
115            User,
116            r#"
117            SELECT id, name, email, full_name, display_name, status, email_verified,
118                   roles, avatar_url, is_bot, is_scanner, created_at, updated_at
119            FROM users
120            WHERE $1 = ANY(roles) AND status != $2
121            ORDER BY created_at ASC
122            LIMIT 1
123            "#,
124            admin_role,
125            deleted_status
126        )
127        .fetch_optional(&*self.pool)
128        .await?;
129
130        Ok(row)
131    }
132
133    pub async fn find_authenticated_user(&self, user_id: &UserId) -> Result<Option<User>> {
134        let active_status = UserStatus::Active.as_str();
135        let row = sqlx::query_as!(
136            User,
137            r#"
138            SELECT id, name, email, full_name, display_name, status, email_verified,
139                   roles, avatar_url, is_bot, is_scanner, created_at, updated_at
140            FROM users
141            WHERE id = $1 AND status = $2
142            "#,
143            user_id.as_str(),
144            active_status
145        )
146        .fetch_optional(&*self.pool)
147        .await?;
148
149        Ok(row)
150    }
151}