diff --git a/crates/collab/src/api.rs b/crates/collab/src/api.rs index db6bef4661..6440e8cb30 100644 --- a/crates/collab/src/api.rs +++ b/crates/collab/src/api.rs @@ -1,6 +1,6 @@ use crate::{ auth, - db::{User, UserId}, + db::{ProjectId, User, UserId}, rpc::{self, ResultExt}, AppState, Error, Result, }; @@ -16,6 +16,7 @@ use axum::{ }; use axum_extra::response::ErasedJson; use serde::{Deserialize, Serialize}; +use serde_json::json; use std::sync::Arc; use time::OffsetDateTime; use tower::ServiceBuilder; @@ -37,6 +38,7 @@ pub fn routes(rpc_server: &Arc, state: Arc) -> Router, + Extension(app): Extension>, +) -> Result { + let extensions = app + .db + .get_project_extensions(ProjectId::from_proto(params.project_id)) + .await?; + Ok(ErasedJson::pretty(json!({ "extensions": extensions }))) +} + #[derive(Deserialize)] struct CreateAccessTokenQueryParams { public_key: String, diff --git a/crates/collab/src/db.rs b/crates/collab/src/db.rs index f49910d719..e4555ed856 100644 --- a/crates/collab/src/db.rs +++ b/crates/collab/src/db.rs @@ -46,7 +46,7 @@ pub trait Db: Send + Sync { /// Unregisters a project for the given project id. async fn unregister_project(&self, project_id: ProjectId) -> Result<()>; - /// Create a new project for the given user. + /// Update file counts by extension for the given project and worktree. async fn update_worktree_extensions( &self, project_id: ProjectId, @@ -54,6 +54,12 @@ pub trait Db: Send + Sync { extensions: HashMap, ) -> Result<()>; + /// Get the file counts on the given project keyed by their worktree and extension. + async fn get_project_extensions( + &self, + project_id: ProjectId, + ) -> Result>>; + /// Record which users have been active in which projects during /// a given period of time. async fn record_project_activity( @@ -501,6 +507,37 @@ impl Db for PostgresDb { Ok(()) } + async fn get_project_extensions( + &self, + project_id: ProjectId, + ) -> Result>> { + #[derive(Clone, Debug, Default, FromRow, Serialize, PartialEq)] + struct WorktreeExtension { + worktree_id: i32, + extension: String, + count: i32, + } + + let query = " + SELECT worktree_id, extension, count + FROM worktree_extensions + WHERE project_id = $1 + "; + let counts = sqlx::query_as::<_, WorktreeExtension>(query) + .bind(&project_id) + .fetch_all(&self.pool) + .await?; + + let mut extension_counts = HashMap::default(); + for count in counts { + extension_counts + .entry(count.worktree_id as u64) + .or_insert(HashMap::default()) + .insert(count.extension, count.count as usize); + } + Ok(extension_counts) + } + async fn record_project_activity( &self, time_period: Range, @@ -2173,6 +2210,13 @@ pub mod tests { Ok(()) } + async fn get_project_extensions( + &self, + _project_id: ProjectId, + ) -> Result>> { + unimplemented!() + } + async fn record_project_activity( &self, _period: Range,