Skip to content

Commit 1c1002d

Browse files
committed
Merge #800: Add searching option to listing user profiles endpoint
da4ee5d refactor: [#799] more descriptive function comment and code cleanup (Mario) 67cafad fix: [#799] max number of results adjusted to page size (Mario) 9759a0c feat: [#799] get user profiles endpoint now supports searching (Mario) Pull request description: Resolves #799 ACKs for top commit: josecelano: ACK da4ee5d Tree-SHA512: f88ad5ee1b72fecf0d6492048135db7ba351426cdee515efd7eda0e4ee2e93007095cdf4f0efb2d6bde3481381eb62f6e72aae0d7fd0735747903275c67d0f8d
2 parents b6e4adf + da4ee5d commit 1c1002d

File tree

5 files changed

+44
-9
lines changed

5 files changed

+44
-9
lines changed

src/config/v2/api.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,6 @@ impl Api {
4545
}
4646

4747
fn default_max_user_profile_page_size() -> u8 {
48-
30
48+
100
4949
}
5050
}

src/databases/database.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,13 @@ pub trait Database: Sync + Send {
143143
/// Get `UserProfile` from `username`.
144144
async fn get_user_profile_from_username(&self, username: &str) -> Result<UserProfile, Error>;
145145

146-
/// Get all user profiles in a paginated form as `UserProfilesResponse`.
147-
async fn get_user_profiles_paginated(&self, offset: u64, page_size: u8) -> Result<UserProfilesResponse, Error>;
146+
/// Get all user profiles in a paginated and sorted form as `UserProfilesResponse` from `search`,`offset` and `page_size`.
147+
async fn get_user_profiles_search_paginated(
148+
&self,
149+
search: &Option<String>,
150+
offset: u64,
151+
page_size: u8,
152+
) -> Result<UserProfilesResponse, Error>;
148153

149154
/// Get `UserCompact` from `user_id`.
150155
async fn get_user_compact_from_id(&self, user_id: i64) -> Result<UserCompact, Error>;

src/databases/mysql.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -155,12 +155,23 @@ impl Database for Mysql {
155155
.map_err(|_| database::Error::UserNotFound)
156156
}
157157

158-
async fn get_user_profiles_paginated(&self, offset: u64, limit: u8) -> Result<UserProfilesResponse, database::Error> {
159-
let mut query_string = "SELECT * FROM torrust_user_profiles".to_string();
158+
async fn get_user_profiles_search_paginated(
159+
&self,
160+
search: &Option<String>,
161+
offset: u64,
162+
limit: u8,
163+
) -> Result<UserProfilesResponse, database::Error> {
164+
let user_name = match search {
165+
None => "%".to_string(),
166+
Some(v) => format!("%{v}%"),
167+
};
168+
169+
let mut query_string = "SELECT * FROM torrust_user_profiles WHERE username LIKE ?".to_string();
160170

161171
let count_query = format!("SELECT COUNT(*) as count FROM ({query_string}) AS count_table");
162172

163173
let count_result: Result<i64, database::Error> = query_as(&count_query)
174+
.bind(user_name.clone())
164175
.fetch_one(&self.pool)
165176
.await
166177
.map(|(v,)| v)
@@ -171,6 +182,7 @@ impl Database for Mysql {
171182
query_string = format!("{query_string} LIMIT ?, ?");
172183

173184
let res: Vec<UserProfile> = sqlx::query_as::<_, UserProfile>(&query_string)
185+
.bind(user_name.clone())
174186
.bind(i64::saturating_add_unsigned(0, offset))
175187
.bind(limit)
176188
.fetch_all(&self.pool)

src/databases/sqlite.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -156,12 +156,23 @@ impl Database for Sqlite {
156156
.map_err(|_| database::Error::UserNotFound)
157157
}
158158

159-
async fn get_user_profiles_paginated(&self, offset: u64, limit: u8) -> Result<UserProfilesResponse, database::Error> {
160-
let mut query_string = "SELECT * FROM torrust_user_profiles".to_string();
159+
async fn get_user_profiles_search_paginated(
160+
&self,
161+
search: &Option<String>,
162+
offset: u64,
163+
limit: u8,
164+
) -> Result<UserProfilesResponse, database::Error> {
165+
let user_name = match search {
166+
None => "%".to_string(),
167+
Some(v) => format!("%{v}%"),
168+
};
169+
170+
let mut query_string = "SELECT * FROM torrust_user_profiles WHERE username LIKE ?".to_string();
161171

162172
let count_query = format!("SELECT COUNT(*) as count FROM ({query_string}) AS count_table");
163173

164174
let count_result: Result<i64, database::Error> = query_as(&count_query)
175+
.bind(user_name.clone())
165176
.fetch_one(&self.pool)
166177
.await
167178
.map(|(v,)| v)
@@ -172,6 +183,7 @@ impl Database for Sqlite {
172183
query_string = format!("{query_string} LIMIT ?, ?");
173184

174185
let res: Vec<UserProfile> = sqlx::query_as::<_, UserProfile>(&query_string)
186+
.bind(user_name.clone())
175187
.bind(i64::saturating_add_unsigned(0, offset))
176188
.bind(limit)
177189
.fetch_all(&self.pool)

src/services/user.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,15 @@ fn no_email() -> String {
3636
pub struct ListingRequest {
3737
pub page_size: Option<u8>,
3838
pub page: Option<u32>,
39+
pub search: Option<String>,
3940
}
4041

4142
/// Internal specification for user profiles listings.
4243
#[derive(Debug, Deserialize)]
4344
pub struct ListingSpecification {
4445
pub offset: u64,
4546
pub page_size: u8,
47+
pub search: Option<String>,
4648
}
4749

4850
pub struct RegistrationService {
@@ -401,7 +403,11 @@ impl ListingService {
401403

402404
let offset = u64::from(page * u32::from(page_size));
403405

404-
ListingSpecification { offset, page_size }
406+
ListingSpecification {
407+
search: request.search.clone(),
408+
offset,
409+
page_size,
410+
}
405411
}
406412
}
407413

@@ -504,7 +510,7 @@ impl DbUserProfileRepository {
504510
/// It returns an error if there is a database error.
505511
pub async fn generate_listing(&self, specification: &ListingSpecification) -> Result<UserProfilesResponse, Error> {
506512
self.database
507-
.get_user_profiles_paginated(specification.offset, specification.page_size)
513+
.get_user_profiles_search_paginated(&specification.search, specification.offset, specification.page_size)
508514
.await
509515
}
510516
}

0 commit comments

Comments
 (0)