use polars::prelude::*;
use super::CommitRecord;
use crate::RpoError;
pub fn build(records: Vec<CommitRecord>) -> Result<DataFrame, RpoError> {
let n = records.len();
let mut sha = Vec::with_capacity(n);
let mut short_sha = Vec::with_capacity(n);
let mut author_name = Vec::with_capacity(n);
let mut author_email = Vec::with_capacity(n);
let mut canon_an = Vec::with_capacity(n);
let mut canon_ae = Vec::with_capacity(n);
let mut committer_name = Vec::with_capacity(n);
let mut committer_email = Vec::with_capacity(n);
let mut canon_cn = Vec::with_capacity(n);
let mut canon_ce = Vec::with_capacity(n);
let mut author_time = Vec::with_capacity(n);
let mut commit_time = Vec::with_capacity(n);
let mut parent_count = Vec::with_capacity(n);
let mut is_merge = Vec::with_capacity(n);
let mut subject = Vec::with_capacity(n);
let mut files_changed = Vec::with_capacity(n);
let mut insertions = Vec::with_capacity(n);
let mut deletions = Vec::with_capacity(n);
for r in records {
sha.push(r.sha);
short_sha.push(r.short_sha);
author_name.push(r.author_name);
author_email.push(r.author_email);
canon_an.push(r.canonical_author_name);
canon_ae.push(r.canonical_author_email);
committer_name.push(r.committer_name);
committer_email.push(r.committer_email);
canon_cn.push(r.canonical_committer_name);
canon_ce.push(r.canonical_committer_email);
author_time.push(r.author_time_ms);
commit_time.push(r.commit_time_ms);
parent_count.push(r.parent_count);
is_merge.push(r.is_merge);
subject.push(r.message_subject);
files_changed.push(r.files_changed);
insertions.push(r.insertions);
deletions.push(r.deletions);
}
let at = Column::new("author_time".into(), author_time).cast(&DataType::Datetime(
TimeUnit::Milliseconds,
Some(TimeZone::UTC),
))?;
let ct = Column::new("commit_time".into(), commit_time).cast(&DataType::Datetime(
TimeUnit::Milliseconds,
Some(TimeZone::UTC),
))?;
let df = DataFrame::new_infer_height(vec![
Column::new("sha".into(), sha),
Column::new("short_sha".into(), short_sha),
Column::new("author_name".into(), author_name),
Column::new("author_email".into(), author_email),
Column::new("canonical_author_name".into(), canon_an),
Column::new("canonical_author_email".into(), canon_ae),
Column::new("committer_name".into(), committer_name),
Column::new("committer_email".into(), committer_email),
Column::new("canonical_committer_name".into(), canon_cn),
Column::new("canonical_committer_email".into(), canon_ce),
at,
ct,
Column::new("parent_count".into(), parent_count),
Column::new("is_merge".into(), is_merge),
Column::new("message_subject".into(), subject),
Column::new("files_changed".into(), files_changed),
Column::new("insertions".into(), insertions),
Column::new("deletions".into(), deletions),
])?;
Ok(df)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::frames::CommitRecord;
fn record(sha: &str) -> CommitRecord {
CommitRecord {
sha: sha.into(),
short_sha: sha[..7].into(),
author_name: "A".into(),
author_email: "a@a".into(),
canonical_author_name: "A".into(),
canonical_author_email: "a@a".into(),
committer_name: "A".into(),
committer_email: "a@a".into(),
canonical_committer_name: "A".into(),
canonical_committer_email: "a@a".into(),
author_time_ms: 1_700_000_000_000,
commit_time_ms: 1_700_000_000_000,
parent_count: 1,
is_merge: false,
message_subject: "x".into(),
files_changed: 2,
insertions: 10,
deletions: 5,
}
}
#[test]
fn empty_input_produces_zero_row_frame() {
let df = build(vec![]).unwrap();
assert_eq!(df.height(), 0);
assert_eq!(df.width(), 18);
}
#[test]
fn single_record_roundtrips() {
let df = build(vec![record("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef")]).unwrap();
assert_eq!(df.height(), 1);
let sha_col = df.column("sha").unwrap();
assert_eq!(
sha_col.str().unwrap().get(0).unwrap(),
"deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
);
}
}