#[derive(Debug, thiserror::Error, Clone, PartialEq, Eq)]
#[error("`{association}` was lazily loaded on `{model}` which has strict_loading enabled")]
pub struct StrictLoadingViolation {
pub model: String,
pub association: String,
}
pub trait StrictLoading {
fn strict_loading(&self) -> bool;
fn set_strict_loading(&mut self, enabled: bool);
fn check_strict_loading(&self, association: &str) -> Result<(), StrictLoadingViolation> {
if self.strict_loading() {
let model = std::any::type_name::<Self>()
.rsplit("::")
.next()
.map_or_else(|| "unknown".to_owned(), str::to_owned);
return Err(StrictLoadingViolation {
model,
association: association.to_owned(),
});
}
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct StrictLoadingState {
enabled: bool,
}
impl StrictLoadingState {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn enabled() -> Self {
Self { enabled: true }
}
#[must_use]
pub fn is_enabled(&self) -> bool {
self.enabled
}
pub fn set(&mut self, enabled: bool) {
self.enabled = enabled;
}
}
impl StrictLoading for StrictLoadingState {
fn strict_loading(&self) -> bool {
self.is_enabled()
}
fn set_strict_loading(&mut self, enabled: bool) {
self.set(enabled);
}
}
#[cfg(test)]
mod tests {
use super::{StrictLoading, StrictLoadingState, StrictLoadingViolation};
#[test]
fn strict_loading_state_new_is_disabled_by_default() {
let state = StrictLoadingState::new();
assert!(!state.is_enabled());
assert!(!state.strict_loading());
}
#[test]
fn strict_loading_state_enabled_is_enabled() {
let state = StrictLoadingState::enabled();
assert!(state.is_enabled());
assert!(state.strict_loading());
}
#[test]
fn check_strict_loading_on_enabled_state_returns_violation() {
let state = StrictLoadingState::enabled();
let error = state
.check_strict_loading("comments")
.expect_err("enabled strict loading should reject lazy loads");
assert_eq!(
error,
StrictLoadingViolation {
model: "StrictLoadingState".to_owned(),
association: "comments".to_owned(),
}
);
}
#[test]
fn check_strict_loading_on_disabled_state_returns_ok() {
let state = StrictLoadingState::new();
assert!(state.check_strict_loading("comments").is_ok());
}
}