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 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 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 { 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> { 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 }