use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct HookConfig {
pub pre_migrate_sql: String,
pub post_migrate_sql: String,
}
impl HookConfig {
pub fn new(pre: impl Into<String>, post: impl Into<String>) -> Self {
Self {
pre_migrate_sql: pre.into(),
post_migrate_sql: post.into(),
}
}
pub fn has_pre_hook(&self) -> bool {
!self.pre_migrate_sql.trim().is_empty()
}
pub fn has_post_hook(&self) -> bool {
!self.post_migrate_sql.trim().is_empty()
}
pub fn is_active(&self) -> bool {
self.has_pre_hook() || self.has_post_hook()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum HookOutcome {
NotConfigured,
Ok { path: String, duration_ms: u64 },
Failed { path: String, error: String },
}
impl HookOutcome {
pub fn is_ok(&self) -> bool {
matches!(self, HookOutcome::NotConfigured | HookOutcome::Ok { .. })
}
pub fn is_failed(&self) -> bool {
matches!(self, HookOutcome::Failed { .. })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn hook_config_defaults_no_hooks() {
let cfg = HookConfig::default();
assert!(!cfg.has_pre_hook());
assert!(!cfg.has_post_hook());
assert!(!cfg.is_active());
}
#[test]
fn hook_config_with_pre_hook() {
let cfg = HookConfig::new("db/hooks/pre_migrate.sql", "");
assert!(cfg.has_pre_hook());
assert!(!cfg.has_post_hook());
assert!(cfg.is_active());
}
#[test]
fn hook_outcome_not_configured_is_ok() {
let outcome = HookOutcome::NotConfigured;
assert!(outcome.is_ok());
assert!(!outcome.is_failed());
}
#[test]
fn hook_outcome_failed_is_not_ok() {
let outcome = HookOutcome::Failed {
path: "pre.sql".to_string(),
error: "syntax error".to_string(),
};
assert!(!outcome.is_ok());
assert!(outcome.is_failed());
}
}