use db::sqlx; use serde::{Deserialize, Serialize}; use session::Session; use utoipa::ToSchema; use crate::{AppService, Pagination, error::AppError}; #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] pub struct ContributorDto { pub name: String, pub email: String, #[schema(value_type = Option)] pub user_id: Option, pub commit_count: i64, } impl AppService { pub async fn git_repo_contributors( &self, ctx: &Session, wk_name: &str, repo_name: &str, pagination: Pagination, ) -> Result, AppError> { let repo = self.git_require_member(ctx, wk_name, repo_name).await?; let offset = pagination.offset() as i64; let limit = pagination.limit() as i64; let rows = sqlx::query_as::<_, (String, String, Option, Option)>( "SELECT rc.name, rc.email, rc.user, COUNT(rco.id)::bigint AS commit_count \ FROM repo_committer rc \ LEFT JOIN repo_commit rco ON rc.id = rco.author \ WHERE rc.repo = $1 \ GROUP BY rc.id, rc.name, rc.email, rc.user \ ORDER BY commit_count DESC \ OFFSET $2 LIMIT $3", ) .bind(repo.id) .bind(offset) .bind(limit) .fetch_all(self.db.reader()) .await .map_err(|e| AppError::DatabaseError(e.to_string()))?; Ok(rows .into_iter() .map(|(name, email, user_id, commit_count)| ContributorDto { name, email, user_id, commit_count: commit_count.unwrap_or(0), }) .collect()) } }