gitdataai/lib/git/graphql/mod.rs
2026-05-30 01:38:40 +08:00

192 lines
5.1 KiB
Rust

pub mod blob;
pub mod branch;
pub mod cache_helper;
pub mod commit;
pub mod tag;
pub mod tree;
use std::path::PathBuf;
use actix_web::{HttpResponse, web};
use cache::AppCache;
use db::database::AppDatabase;
use juniper::{
EmptyMutation, EmptySubscription, FieldResult, RootNode, graphql_object,
};
use serde_json::json;
use crate::{
bare::GitBare,
graphql::{
blob::{BlobResult, resolve_blob, resolve_blob_size},
branch::{
BranchGql, BranchSummaryGql, resolve_branch,
resolve_branch_summary, resolve_branches, resolve_head_branch,
},
commit::{
CommitGql, CommitSummaryGql, resolve_commit,
resolve_commit_history, resolve_commit_summary,
},
tag::{
TagGql, TagSummaryGql, resolve_tag, resolve_tag_summary,
resolve_tags,
},
tree::{TreeEntryGql, TreeInfoGql, resolve_tree, resolve_tree_entries},
},
};
type Schema = RootNode<
GraphqlQuery,
EmptyMutation<GraphqlContext>,
EmptySubscription<GraphqlContext>,
>;
fn schema() -> Schema {
Schema::new(
GraphqlQuery,
EmptyMutation::<GraphqlContext>::new(),
EmptySubscription::<GraphqlContext>::new(),
)
}
pub async fn graphql_handle(
path: web::Path<(String, String)>,
state: web::Data<crate::http::HttpAppState>,
body: web::Json<juniper::http::GraphQLRequest>,
) -> HttpResponse {
let (wk, repo_name) = path.into_inner();
let repo = match state.git_state.repo(wk, repo_name).await {
Ok(repo) => repo,
Err(err) => {
return HttpResponse::InternalServerError().json(json!({
"message": err.to_string()
}));
}
};
let ctx = GraphqlContext {
repo: GitBare {
bare_dir: PathBuf::from(&repo.repo.storage_path),
},
cache: state.git_state.cache.clone(),
db: state.git_state.db.clone(),
};
let schema = schema();
let response = body.execute(&schema, &ctx).await;
let status_code = if response.is_ok() { 200 } else { 400 };
HttpResponse::build(
actix_web::http::StatusCode::from_u16(status_code).unwrap(),
)
.content_type("application/json")
.json(response)
}
#[derive(Clone)]
pub struct GraphqlContext {
pub repo: GitBare,
pub cache: AppCache,
pub db: AppDatabase,
}
impl juniper::Context for GraphqlContext {}
pub struct GraphqlQuery;
fn to_field_error(e: anyhow::Error) -> juniper::FieldError {
juniper::FieldError::new(e.to_string(), juniper::Value::null())
}
#[graphql_object]
#[graphql(context = GraphqlContext)]
impl GraphqlQuery {
fn api_version() -> &'static str {
env!("CARGO_PKG_VERSION")
}
async fn head_branch(ctx: &GraphqlContext) -> FieldResult<BranchGql> {
resolve_head_branch(ctx).await.map_err(to_field_error)
}
async fn branches(ctx: &GraphqlContext) -> FieldResult<Vec<BranchGql>> {
resolve_branches(ctx).await.map_err(to_field_error)
}
async fn branch(
ctx: &GraphqlContext,
name: String,
) -> FieldResult<BranchGql> {
resolve_branch(ctx, name).await.map_err(to_field_error)
}
async fn branch_summary(
ctx: &GraphqlContext,
) -> FieldResult<BranchSummaryGql> {
resolve_branch_summary(ctx).await.map_err(to_field_error)
}
async fn tags(ctx: &GraphqlContext) -> FieldResult<Vec<TagGql>> {
resolve_tags(ctx).await.map_err(to_field_error)
}
async fn tag(ctx: &GraphqlContext, name: String) -> FieldResult<TagGql> {
resolve_tag(ctx, name).await.map_err(to_field_error)
}
async fn tag_summary(ctx: &GraphqlContext) -> FieldResult<TagSummaryGql> {
resolve_tag_summary(ctx).await.map_err(to_field_error)
}
async fn commit(
ctx: &GraphqlContext,
oid: String,
) -> FieldResult<CommitGql> {
resolve_commit(ctx, oid).await.map_err(to_field_error)
}
async fn commit_history(
ctx: &GraphqlContext,
limit: Option<i32>,
skip: Option<i32>,
sort: Option<String>,
) -> FieldResult<Vec<CommitGql>> {
resolve_commit_history(ctx, limit, skip, sort)
.await
.map_err(to_field_error)
}
async fn commit_summary(
ctx: &GraphqlContext,
) -> FieldResult<CommitSummaryGql> {
resolve_commit_summary(ctx).await.map_err(to_field_error)
}
async fn tree(
ctx: &GraphqlContext,
oid: String,
) -> FieldResult<TreeInfoGql> {
resolve_tree(ctx, oid).await.map_err(to_field_error)
}
async fn tree_entries(
ctx: &GraphqlContext,
tree_oid: String,
) -> FieldResult<Vec<TreeEntryGql>> {
resolve_tree_entries(ctx, tree_oid)
.await
.map_err(to_field_error)
}
async fn blob_size(ctx: &GraphqlContext, oid: String) -> FieldResult<i32> {
resolve_blob_size(ctx, oid).await.map_err(to_field_error)
}
async fn blob(
ctx: &GraphqlContext,
oid: String,
) -> FieldResult<BlobResult> {
resolve_blob(ctx, oid).await.map_err(to_field_error)
}
}