use std::{collections::HashSet, ops::Deref};
use git2::Signature;
use serde::{Deserialize, Serialize};
use sled::IVec;
use yoke::{Yoke, Yokeable};
use crate::database::schema::{commit::Author, Yoked};
#[derive(Serialize, Deserialize, Debug, Yokeable)]
pub struct Tag<'a> {
#[serde(borrow)]
pub tagger: Option<Author<'a>>,
}
impl<'a> Tag<'a> {
pub fn new(tagger: Option<&'a Signature<'_>>) -> Self {
Self {
tagger: tagger.map(Into::into),
}
}
pub fn insert(&self, batch: &TagTree, name: &str) -> Result<(), anyhow::Error> {
batch.insert(name.as_bytes(), bincode::serialize(self)?)?;
Ok(())
}
}
pub struct TagTree(sled::Tree);
impl Deref for TagTree {
type Target = sled::Tree;
fn deref(&self) -> &Self::Target {
&self.0
}
}
pub type YokedTag = Yoked<Tag<'static>>;
impl TagTree {
pub(super) fn new(tree: sled::Tree) -> Self {
Self(tree)
}
pub fn remove(&self, name: &str) -> Result<bool, sled::Error> {
self.0.remove(name).map(|v| v.is_some())
}
pub fn list(&self) -> HashSet<String> {
self.iter()
.keys()
.filter_map(Result::ok)
.map(|v| String::from_utf8_lossy(&v).into_owned())
.collect()
}
pub fn fetch_all(&self) -> Vec<(String, YokedTag)> {
let mut res = self
.iter()
.map(|res| {
let (name, value) = res?;
let name = String::from_utf8_lossy(&name)
.strip_prefix("refs/tags/")
.unwrap()
.to_string();
let value = Box::new(value);
Ok((
name,
Yoke::try_attach_to_cart(value, |data: &IVec| bincode::deserialize(data))
.unwrap(),
))
})
.collect::<Result<Vec<(String, YokedTag)>, sled::Error>>()
.unwrap();
res.sort_unstable_by(|a, b| {
let a_tagger = a.1.get().tagger.as_ref().map(|v| v.time);
let b_tagger = b.1.get().tagger.as_ref().map(|v| v.time);
b_tagger.cmp(&a_tagger)
});
res
}
}