use git2::Signature;
use serde::{Deserialize, Serialize};
use sled::transaction::TransactionalTree;
use std::ops::Deref;
use time::OffsetDateTime;
#[derive(Serialize, Deserialize, Debug)]
pub struct Commit {
pub summary: String,
pub message: String,
pub author: Author,
pub committer: Author,
pub hash: Vec<u8>,
}
impl From<git2::Commit<'_>> for Commit {
fn from(commit: git2::Commit<'_>) -> Self {
Commit {
summary: commit
.summary()
.map(ToString::to_string)
.unwrap_or_default(),
message: commit.body().map(ToString::to_string).unwrap_or_default(),
committer: commit.committer().into(),
author: commit.author().into(),
hash: commit.id().as_bytes().to_vec(),
}
}
}
impl Commit {
pub fn insert(&self, database: &TransactionalTree, id: usize) {
database
.insert(&id.to_be_bytes(), bincode::serialize(self).unwrap())
.unwrap();
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Author {
pub name: String,
pub email: String,
pub time: OffsetDateTime,
}
impl From<git2::Signature<'_>> for Author {
fn from(author: Signature<'_>) -> Self {
Self {
name: author.name().map(ToString::to_string).unwrap_or_default(),
email: author.email().map(ToString::to_string).unwrap_or_default(),
time: OffsetDateTime::from_unix_timestamp(author.when().seconds()).unwrap(),
}
}
}
pub struct CommitTree(sled::Tree);
impl Deref for CommitTree {
type Target = sled::Tree;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl CommitTree {
pub(super) fn new(tree: sled::Tree) -> Self {
Self(tree)
}
pub fn fetch_latest(&self, amount: usize, offset: usize) -> Vec<Commit> {
let (latest_key, _) = self.last().unwrap().unwrap();
let mut latest_key_bytes = [0; std::mem::size_of::<usize>()];
latest_key_bytes.copy_from_slice(&latest_key);
let end = usize::from_be_bytes(latest_key_bytes).saturating_sub(offset);
let start = end.saturating_sub(amount);
self.range(start.to_be_bytes()..end.to_be_bytes())
.rev()
.map(|res| {
let (_, value) = res?;
let details = bincode::deserialize(&value).unwrap();
Ok(details)
})
.collect::<Result<Vec<_>, sled::Error>>()
.unwrap()
}
}