Merge pull request #1175 from zed-industries/users-api

Antonio Scandurra created

Allow specifying `query`, `limit` and `page` when hitting `/api/users`

Change summary

crates/collab/src/api.rs | 21 +++++++++++++++++++--
crates/collab/src/db.rs  | 20 ++++++++++++--------
2 files changed, 31 insertions(+), 10 deletions(-)

Detailed changes

crates/collab/src/api.rs 🔗

@@ -71,8 +71,25 @@ pub async fn validate_api_token<B>(req: Request<B>, next: Next<B>) -> impl IntoR
     Ok::<_, Error>(next.run(req).await)
 }
 
-async fn get_users(Extension(app): Extension<Arc<AppState>>) -> Result<Json<Vec<User>>> {
-    let users = app.db.get_all_users().await?;
+#[derive(Debug, Deserialize)]
+struct GetUsersQueryParams {
+    query: Option<String>,
+    page: Option<u32>,
+    limit: Option<u32>,
+}
+
+async fn get_users(
+    Query(params): Query<GetUsersQueryParams>,
+    Extension(app): Extension<Arc<AppState>>,
+) -> Result<Json<Vec<User>>> {
+    let limit = params.limit.unwrap_or(100);
+    let users = if let Some(query) = params.query {
+        app.db.fuzzy_search_users(&query, limit).await?
+    } else {
+        app.db
+            .get_all_users(params.page.unwrap_or(0), limit)
+            .await?
+    };
     Ok(Json(users))
 }
 

crates/collab/src/db.rs 🔗

@@ -17,8 +17,8 @@ pub trait Db: Send + Sync {
         email_address: Option<&str>,
         admin: bool,
     ) -> Result<UserId>;
+    async fn get_all_users(&self, page: u32, limit: u32) -> Result<Vec<User>>;
     async fn create_users(&self, users: Vec<(String, String, usize)>) -> Result<Vec<UserId>>;
-    async fn get_all_users(&self) -> Result<Vec<User>>;
     async fn fuzzy_search_users(&self, query: &str, limit: u32) -> Result<Vec<User>>;
     async fn get_user_by_id(&self, id: UserId) -> Result<Option<User>>;
     async fn get_users_by_ids(&self, ids: Vec<UserId>) -> Result<Vec<User>>;
@@ -142,6 +142,15 @@ impl Db for PostgresDb {
             .map(UserId)?)
     }
 
+    async fn get_all_users(&self, page: u32, limit: u32) -> Result<Vec<User>> {
+        let query = "SELECT * FROM users ORDER BY github_login ASC LIMIT $1 OFFSET $2";
+        Ok(sqlx::query_as(query)
+            .bind(limit)
+            .bind(page * limit)
+            .fetch_all(&self.pool)
+            .await?)
+    }
+  
     async fn create_users(&self, users: Vec<(String, String, usize)>) -> Result<Vec<UserId>> {
         let mut query = QueryBuilder::new(
             "INSERT INTO users (github_login, email_address, admin, invite_code, invite_count)",
@@ -177,11 +186,6 @@ impl Db for PostgresDb {
             .collect())
     }
 
-    async fn get_all_users(&self) -> Result<Vec<User>> {
-        let query = "SELECT * FROM users ORDER BY github_login ASC";
-        Ok(sqlx::query_as(query).fetch_all(&self.pool).await?)
-    }
-
     async fn fuzzy_search_users(&self, name_query: &str, limit: u32) -> Result<Vec<User>> {
         let like_string = fuzzy_like_string(name_query);
         let query = "
@@ -1765,11 +1769,11 @@ pub mod tests {
             }
         }
 
-        async fn create_users(&self, _users: Vec<(String, String, usize)>) -> Result<Vec<UserId>> {
+        async fn get_all_users(&self, _page: u32, _limit: u32) -> Result<Vec<User>> {
             unimplemented!()
         }
 
-        async fn get_all_users(&self) -> Result<Vec<User>> {
+        async fn create_users(&self, _users: Vec<(String, String, usize)>) -> Result<Vec<UserId>> {
             unimplemented!()
         }