use eyre::Context;
use rusqlite::OptionalExtension;
use tracing::instrument;
use crate::git::{NonZeroOid, Repo};
use crate::tui::Effects;
pub struct MergeBaseDb<'conn> {
conn: &'conn rusqlite::Connection,
}
impl std::fmt::Debug for MergeBaseDb<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<MergeBaseDb>")
}
}
#[instrument]
fn init_tables(conn: &rusqlite::Connection) -> eyre::Result<()> {
conn.execute(
"
CREATE TABLE IF NOT EXISTS merge_base_oids (
lhs_oid TEXT NOT NULL,
rhs_oid TEXT NOT NULL,
merge_base_oid TEXT,
UNIQUE (lhs_oid, rhs_oid)
)
",
rusqlite::params![],
)
.wrap_err("Creating tables")?;
Ok(())
}
impl<'conn> MergeBaseDb<'conn> {
#[instrument]
pub fn new(conn: &'conn rusqlite::Connection) -> eyre::Result<Self> {
init_tables(conn).wrap_err("Initializing tables")?;
Ok(MergeBaseDb { conn })
}
#[instrument]
pub fn get_merge_base_oid(
&self,
effects: &Effects,
repo: &Repo,
lhs_oid: NonZeroOid,
rhs_oid: NonZeroOid,
) -> eyre::Result<Option<NonZeroOid>> {
let (_effects, _progress) =
effects.start_operation(crate::tui::OperationType::GetMergeBase);
let (lhs_oid, rhs_oid) = if lhs_oid < rhs_oid {
(lhs_oid, rhs_oid)
} else {
(rhs_oid, lhs_oid)
};
let merge_base_oid: Option<Option<String>> = self
.conn
.query_row_named(
"
SELECT merge_base_oid
FROM merge_base_oids
WHERE lhs_oid = :lhs_oid
AND rhs_oid = :rhs_oid
",
rusqlite::named_params! {
":lhs_oid": lhs_oid.to_string(),
":rhs_oid": rhs_oid.to_string(),
},
|row| row.get("merge_base_oid"),
)
.optional()
.wrap_err("Querying merge-base DB")?;
match merge_base_oid {
Some(Some(merge_base_oid)) => {
let merge_base_oid: NonZeroOid =
merge_base_oid.parse().wrap_err("Parsing merge-base OID")?;
Ok(Some(merge_base_oid))
}
Some(None) => Ok(None),
None => {
let merge_base_oid = repo.find_merge_base(lhs_oid, rhs_oid)?;
self.conn
.execute_named(
"
INSERT INTO merge_base_oids VALUES (
:lhs_oid,
:rhs_oid,
:merge_base_oid
)",
rusqlite::named_params! {
":lhs_oid": &lhs_oid.to_string(),
":rhs_oid": &rhs_oid.to_string(),
":merge_base_oid": &merge_base_oid.map(|oid| oid.to_string()),
},
)
.wrap_err("Caching merge-base OID")?;
Ok(merge_base_oid)
}
}
}
}