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

135 lines
3.2 KiB
Rust

use std::time::Duration;
use juniper::graphql_object;
use serde::{Deserialize, Serialize};
use crate::{
cmd::{
oid::ObjectId,
tree::{TreeEntry, TreeInfo, TreeKind},
},
graphql::{
GraphqlContext,
cache_helper::{IMMUTABLE_TTL, cache_key, cached_json},
},
};
const TREE_TTL: Duration = IMMUTABLE_TTL;
#[derive(Clone, Serialize, Deserialize)]
pub struct TreeInfoGql {
pub oid: String,
pub entry_count: i32,
pub is_empty: bool,
}
#[graphql_object(context = GraphqlContext)]
impl TreeInfoGql {
fn oid(&self) -> &str {
&self.oid
}
fn entry_count(&self) -> i32 {
self.entry_count
}
fn is_empty(&self) -> bool {
self.is_empty
}
}
impl From<TreeInfo> for TreeInfoGql {
fn from(info: TreeInfo) -> Self {
TreeInfoGql {
oid: info.oid.0,
entry_count: info.entry_count as i32,
is_empty: info.is_empty,
}
}
}
#[derive(Clone, Serialize, Deserialize)]
pub struct TreeEntryGql {
pub name: String,
pub oid: String,
pub kind: String,
pub filemode: i32,
pub is_binary: bool,
pub is_lfs: bool,
}
#[graphql_object(context = GraphqlContext)]
impl TreeEntryGql {
fn name(&self) -> &str {
&self.name
}
fn oid(&self) -> &str {
&self.oid
}
fn kind(&self) -> &str {
&self.kind
}
fn filemode(&self) -> i32 {
self.filemode
}
fn is_binary(&self) -> bool {
self.is_binary
}
fn is_lfs(&self) -> bool {
self.is_lfs
}
}
impl From<TreeEntry> for TreeEntryGql {
fn from(entry: TreeEntry) -> Self {
TreeEntryGql {
name: entry.name,
oid: entry.oid.0,
kind: match entry.kind {
TreeKind::Blob => "blob".to_string(),
TreeKind::Tree => "tree".to_string(),
TreeKind::LfsPointer => "lfs_pointer".to_string(),
},
filemode: entry.filemode as i32,
is_binary: entry.is_binary,
is_lfs: entry.is_lfs,
}
}
}
pub async fn resolve_tree(
ctx: &GraphqlContext,
oid: String,
) -> anyhow::Result<TreeInfoGql> {
let key = cache_key("query:git:tree", &[&oid]);
cached_json(&ctx.cache, &key, TREE_TTL, || {
let repo = ctx.repo.clone();
let oid_obj = ObjectId::new(&oid);
async move {
let info =
tokio::task::spawn_blocking(move || repo.resolve_tree(oid_obj))
.await?
.map_err(|e| anyhow::anyhow!(e))?;
Ok(TreeInfoGql::from(info))
}
})
.await
}
pub async fn resolve_tree_entries(
ctx: &GraphqlContext,
tree_oid: String,
) -> anyhow::Result<Vec<TreeEntryGql>> {
let key = cache_key("query:git:tree_entries", &[&tree_oid]);
cached_json(&ctx.cache, &key, TREE_TTL, || {
let repo = ctx.repo.clone();
let oid_obj = ObjectId::new(&tree_oid);
async move {
let entries =
tokio::task::spawn_blocking(move || repo.tree_entries(oid_obj))
.await?
.map_err(|e| anyhow::anyhow!(e))?;
Ok(entries.into_iter().map(TreeEntryGql::from).collect())
}
})
.await
}