use std::cell::OnceCell;
use rusqlite::{Statement, Transaction};
use crate::{Error, ForeignKeyCheckError, Result};
const PRAGMA_FK_CHECK: &str = "SELECT * FROM pragma_foreign_key_check;";
pub(crate) struct FKCheck<'conn> {
stmt: OnceCell<Statement<'conn>>,
}
impl<'conn> FKCheck<'conn> {
pub(crate) fn new() -> Self {
Self {
stmt: OnceCell::new(),
}
}
pub(crate) fn validate(&mut self, conn: &'conn Transaction) -> Result<()> {
if self.stmt.get().is_none() {
self.stmt
.set(
conn.prepare(PRAGMA_FK_CHECK)
.map_err(|e| crate::Error::with_sql(e, PRAGMA_FK_CHECK))?,
)
.expect("OnceCell was checked above and is empty");
}
let stmt = self
.stmt
.get_mut()
.expect("the OnceCell was initialize just above");
let fk_errors = stmt
.query_map([], |row| {
Ok(ForeignKeyCheckError {
table: row.get(0)?,
rowid: row.get(1)?,
parent: row.get(2)?,
fkid: row.get(3)?,
})
})
.map_err(|e| Error::with_sql(e, PRAGMA_FK_CHECK))?
.collect::<Result<Vec<_>, _>>()?;
if !fk_errors.is_empty() {
Err(crate::Error::ForeignKeyCheck(fk_errors))
} else {
Ok(())
}
}
}