123 lines
3.4 KiB
Rust
123 lines
3.4 KiB
Rust
use db::sqlx;
|
|
use serde::{Deserialize, Serialize};
|
|
use session::Session;
|
|
use utoipa::ToSchema;
|
|
|
|
use crate::{AppService, error::AppError};
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
|
|
pub struct RepoEmbedCardResponse {
|
|
// Repo basics
|
|
pub name: String,
|
|
pub description: Option<String>,
|
|
pub default_branch: String,
|
|
pub visibility: String,
|
|
pub size_bytes: i64,
|
|
pub is_archived: bool,
|
|
pub updated_at: String,
|
|
|
|
// Language
|
|
pub language: Option<String>,
|
|
|
|
// Stats
|
|
pub star_count: i64,
|
|
pub fork_count: i64,
|
|
|
|
// Topics
|
|
pub topics: Vec<String>,
|
|
}
|
|
|
|
impl AppService {
|
|
pub async fn repo_embed_card(
|
|
&self,
|
|
ctx: &Session,
|
|
wk_name: &str,
|
|
repo_name: &str,
|
|
) -> Result<RepoEmbedCardResponse, AppError> {
|
|
let repo = self.git_require_member(ctx, wk_name, repo_name).await?;
|
|
|
|
// Fetch language, topics, star count, fork count in parallel
|
|
let (lang, topics, star_count, fork_count) = tokio::try_join!(
|
|
self.git_repo_embed_language(repo.id),
|
|
self.git_repo_embed_topics(repo.id),
|
|
self.git_repo_embed_star_count(repo.id),
|
|
self.git_repo_embed_fork_count(repo.id),
|
|
)?;
|
|
|
|
Ok(RepoEmbedCardResponse {
|
|
name: repo.name,
|
|
description: repo.description,
|
|
default_branch: repo.default_branch,
|
|
visibility: repo.visibility,
|
|
size_bytes: repo.size_bytes,
|
|
is_archived: repo.is_archived,
|
|
updated_at: repo.updated_at.to_rfc3339(),
|
|
language: lang,
|
|
star_count,
|
|
fork_count,
|
|
topics,
|
|
})
|
|
}
|
|
|
|
async fn git_repo_embed_language(
|
|
&self,
|
|
repo_id: uuid::Uuid,
|
|
) -> Result<Option<String>, AppError> {
|
|
let row: Option<(String,)> = sqlx::query_as(
|
|
"SELECT language FROM repo_language WHERE repo = $1 ORDER BY bytes DESC LIMIT 1",
|
|
)
|
|
.bind(repo_id)
|
|
.fetch_optional(self.db.reader())
|
|
.await
|
|
.map_err(|e| AppError::DatabaseError(e.to_string()))?;
|
|
|
|
Ok(row.map(|r| r.0))
|
|
}
|
|
|
|
async fn git_repo_embed_topics(
|
|
&self,
|
|
repo_id: uuid::Uuid,
|
|
) -> Result<Vec<String>, AppError> {
|
|
let rows: Vec<(String,)> = sqlx::query_as(
|
|
"SELECT topic FROM repo_topic WHERE repo = $1 ORDER BY topic",
|
|
)
|
|
.bind(repo_id)
|
|
.fetch_all(self.db.reader())
|
|
.await
|
|
.map_err(|e| AppError::DatabaseError(e.to_string()))?;
|
|
|
|
Ok(rows.into_iter().map(|r| r.0).collect())
|
|
}
|
|
|
|
async fn git_repo_embed_star_count(
|
|
&self,
|
|
repo_id: uuid::Uuid,
|
|
) -> Result<i64, AppError> {
|
|
let row: (i64,) =
|
|
sqlx::query_as("SELECT COUNT(*) FROM repo_star WHERE repo = $1")
|
|
.bind(repo_id)
|
|
.fetch_one(self.db.reader())
|
|
.await
|
|
.map_err(|e| AppError::DatabaseError(e.to_string()))?;
|
|
|
|
Ok(row.0)
|
|
}
|
|
|
|
async fn git_repo_embed_fork_count(
|
|
&self,
|
|
repo_id: uuid::Uuid,
|
|
) -> Result<i64, AppError> {
|
|
let row: (i64,) = sqlx::query_as(
|
|
"SELECT COUNT(*) FROM repo_fork f \
|
|
INNER JOIN repo r ON r.id = f.repo AND r.deleted_at IS NULL \
|
|
WHERE f.source_repo = $1",
|
|
)
|
|
.bind(repo_id)
|
|
.fetch_one(self.db.reader())
|
|
.await
|
|
.map_err(|e| AppError::DatabaseError(e.to_string()))?;
|
|
|
|
Ok(row.0)
|
|
}
|
|
}
|