use serde::{Deserialize, Serialize};
use std::fmt;
use std::hash::{Hash, Hasher};
use time::OffsetDateTime;
use utoipa::ToSchema;
use super::{MerkleHash, User};
use crate::config::UserConfig;
use crate::error::OxenError;
use crate::view::workspaces::WorkspaceCommit;
#[derive(Deserialize, Serialize, Debug, Clone, ToSchema)]
pub struct NewCommitBody {
pub message: String,
pub author: String,
pub email: String,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct NewCommit {
pub parent_ids: Vec<String>,
pub message: String,
pub author: String,
pub email: String,
#[serde(with = "time::serde::rfc3339")]
pub timestamp: OffsetDateTime,
}
impl NewCommit {
pub fn from_commit(commit: &Commit) -> NewCommit {
NewCommit {
parent_ids: commit.parent_ids.to_owned(),
message: commit.message.to_owned(),
author: commit.author.to_owned(),
email: commit.email.to_owned(),
timestamp: commit.timestamp.to_owned(),
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone, ToSchema)]
#[schema(
example = json!({
"id": "a1b2c3d4e5f67890abcdef1234567890",
"parent_ids": [
"f1e2d3c4b5a67890fedcba9876543210"
],
"message": "Refactor data loading pipeline.",
"author": "ox",
"email": "ox@example.com",
"timestamp": "2025-01-01T10:00:00Z"
})
)]
pub struct Commit {
pub id: String,
pub parent_ids: Vec<String>,
pub message: String,
pub author: String,
pub email: String,
#[serde(with = "time::serde::rfc3339")]
pub timestamp: OffsetDateTime,
}
impl From<Commit> for WorkspaceCommit {
fn from(val: Commit) -> Self {
WorkspaceCommit {
id: val.id,
message: val.message,
author: val.author,
email: val.email,
timestamp: val.timestamp,
}
}
}
impl fmt::Display for Commit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} -> '{}'", self.id, self.message)
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CommitWithSize {
pub id: String,
pub parent_ids: Vec<String>,
pub message: String,
pub author: String,
pub email: String,
#[serde(with = "time::serde::rfc3339")]
pub timestamp: OffsetDateTime,
pub size: u64,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CommitWithBranchName {
pub id: String,
pub parent_ids: Vec<String>,
pub message: String,
pub author: String,
pub email: String,
#[serde(with = "time::serde::rfc3339")]
pub timestamp: OffsetDateTime,
pub size: u64,
pub branch_name: String,
}
impl PartialEq for Commit {
fn eq(&self, other: &Commit) -> bool {
self.id == other.id
}
}
impl Eq for Commit {}
impl Hash for Commit {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}
impl std::error::Error for Commit {}
impl Commit {
pub fn from_new_and_id(new_commit: &NewCommit, id: String) -> Commit {
Commit {
id,
parent_ids: new_commit.parent_ids.to_owned(),
message: new_commit.message.to_owned(),
author: new_commit.author.to_owned(),
email: new_commit.email.to_owned(),
timestamp: new_commit.timestamp.to_owned(),
}
}
pub fn from_new_and_hash(new_commit: &NewCommit, hash: u128) -> Commit {
Commit {
id: format!("{hash:x}"),
parent_ids: new_commit.parent_ids.to_owned(),
message: new_commit.message.to_owned(),
author: new_commit.author.to_owned(),
email: new_commit.email.to_owned(),
timestamp: new_commit.timestamp.to_owned(),
}
}
pub fn from_with_size(commit: &CommitWithSize) -> Commit {
Commit {
id: commit.id.to_owned(),
parent_ids: commit.parent_ids.to_owned(),
message: commit.message.to_owned(),
author: commit.author.to_owned(),
email: commit.email.to_owned(),
timestamp: commit.timestamp.to_owned(),
}
}
pub fn from_with_branch_name(commit: &CommitWithBranchName) -> Commit {
Commit {
id: commit.id.to_owned(),
parent_ids: commit.parent_ids.to_owned(),
message: commit.message.to_owned(),
author: commit.author.to_owned(),
email: commit.email.to_owned(),
timestamp: commit.timestamp.to_owned(),
}
}
pub fn hash(&self) -> Result<MerkleHash, OxenError> {
self.id.parse()
}
pub fn to_uri_encoded(&self) -> String {
serde_url_params::to_string(&self).unwrap()
}
pub fn get_user(&self) -> User {
User {
name: self.author.to_owned(),
email: self.email.to_owned(),
}
}
}
impl CommitWithSize {
pub fn from_commit(commit: &Commit, size: u64) -> CommitWithSize {
CommitWithSize {
id: commit.id.to_owned(),
parent_ids: commit.parent_ids.to_owned(),
message: commit.message.to_owned(),
author: commit.author.to_owned(),
email: commit.email.to_owned(),
timestamp: commit.timestamp.to_owned(),
size,
}
}
}
impl CommitWithBranchName {
pub fn from_commit(commit: &Commit, size: u64, branch_name: String) -> CommitWithBranchName {
CommitWithBranchName {
id: commit.id.to_owned(),
parent_ids: commit.parent_ids.to_owned(),
message: commit.message.to_owned(),
author: commit.author.to_owned(),
email: commit.email.to_owned(),
timestamp: commit.timestamp.to_owned(),
size,
branch_name,
}
}
}
impl NewCommitBody {
pub fn from_config(cfg: &UserConfig, message: &str) -> NewCommitBody {
NewCommitBody {
message: message.to_string(),
author: cfg.name.clone(),
email: cfg.email.clone(),
}
}
}
#[derive(Serialize, Deserialize, Debug, ToSchema)]
#[schema(
example = json!({
"commit": {
"id": "a1b2c3d4e5f67890abcdef1234567890",
"parent_ids": [
"f1e2d3c4b5a67890fedcba9876543210"
],
"message": "Refactor data loading pipeline.",
"author": "ox",
"email": "ox@example.com",
"timestamp": "2025-01-01T10:00:00Z"
},
"num_entries": 12000,
"num_synced_files": 11950,
})
)]
pub struct CommitStats {
pub commit: Commit,
pub num_entries: usize, pub num_synced_files: usize, }
impl CommitStats {
pub fn is_synced(&self) -> bool {
self.num_entries == self.num_synced_files
}
}