use crate::errors::{ErrorKind, NitriteError, NitriteResult};
use crate::migration::{InstructionSet, InstructionType};
use std::any::Any;
use std::collections::VecDeque;
use std::sync::atomic::AtomicBool;
use std::sync::{Arc, Mutex};
type AnyArg = Arc<dyn Any + Send + Sync>;
type MigrateFn = Box<dyn Fn(&InstructionSet) -> NitriteResult<()> + Send + Sync>;
#[derive(Clone)]
pub struct MigrationStep {
pub instruction_type: InstructionType,
pub collection_name: Option<String>,
pub entity_name: Option<String>,
pub key: Option<String>,
pub arguments: MigrationArguments,
}
impl std::fmt::Debug for MigrationStep {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MigrationStep")
.field("instruction_type", &self.instruction_type)
.field("collection_name", &self.collection_name)
.field("entity_name", &self.entity_name)
.field("key", &self.key)
.field("arguments", &"<arguments>")
.finish()
}
}
#[derive(Clone)]
pub enum MigrationArguments {
None,
Single(Arc<dyn Any + Send + Sync>),
Double(Arc<dyn Any + Send + Sync>, Arc<dyn Any + Send + Sync>),
Triple(Arc<dyn Any + Send + Sync>, Arc<dyn Any + Send + Sync>, Arc<dyn Any + Send + Sync>),
Quad(Arc<dyn Any + Send + Sync>, Arc<dyn Any + Send + Sync>, Arc<dyn Any + Send + Sync>, Arc<dyn Any + Send + Sync>),
Multiple(Vec<Arc<dyn Any + Send + Sync>>),
}
impl std::fmt::Debug for MigrationArguments {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MigrationArguments::None => write!(f, "None"),
MigrationArguments::Single(_) => write!(f, "Single(<value>)"),
MigrationArguments::Double(_, _) => write!(f, "Double(<value>, <value>)"),
MigrationArguments::Triple(_, _, _) => write!(f, "Triple(<value>, <value>, <value>)"),
MigrationArguments::Quad(_, _, _, _) => write!(f, "Quad(<value>, <value>, <value>, <value>)"),
MigrationArguments::Multiple(_) => write!(f, "Multiple(<values>)"),
}
}
}
impl MigrationArguments {
pub fn as_single<T: Any + Send + Sync + Clone + 'static>(&self) -> NitriteResult<T> {
match self {
MigrationArguments::Single(arg) => {
arg.downcast_ref::<T>()
.cloned()
.ok_or_else(|| NitriteError::new(
"Failed to downcast single argument",
ErrorKind::ValidationError,
))
}
_ => Err(NitriteError::new(
"Expected single argument",
ErrorKind::ValidationError,
)),
}
}
pub fn as_double<T1, T2>(&self) -> NitriteResult<(T1, T2)>
where
T1: Any + Send + Sync + Clone + 'static,
T2: Any + Send + Sync + Clone + 'static,
{
match self {
MigrationArguments::Double(arg1, arg2) => {
let a = arg1.downcast_ref::<T1>()
.cloned()
.ok_or_else(|| NitriteError::new(
"Failed to downcast first argument",
ErrorKind::ValidationError,
))?;
let b = arg2.downcast_ref::<T2>()
.cloned()
.ok_or_else(|| NitriteError::new(
"Failed to downcast second argument",
ErrorKind::ValidationError,
))?;
Ok((a, b))
}
_ => Err(NitriteError::new(
"Expected double arguments",
ErrorKind::ValidationError,
)),
}
}
pub fn as_triple<T1, T2, T3>(&self) -> NitriteResult<(T1, T2, T3)>
where
T1: Any + Send + Sync + Clone + 'static,
T2: Any + Send + Sync + Clone + 'static,
T3: Any + Send + Sync + Clone + 'static,
{
match self {
MigrationArguments::Triple(arg1, arg2, arg3) => {
let a = arg1.downcast_ref::<T1>()
.cloned()
.ok_or_else(|| NitriteError::new(
"Failed to downcast first argument",
ErrorKind::ValidationError,
))?;
let b = arg2.downcast_ref::<T2>()
.cloned()
.ok_or_else(|| NitriteError::new(
"Failed to downcast second argument",
ErrorKind::ValidationError,
))?;
let c = arg3.downcast_ref::<T3>()
.cloned()
.ok_or_else(|| NitriteError::new(
"Failed to downcast third argument",
ErrorKind::ValidationError,
))?;
Ok((a, b, c))
}
_ => Err(NitriteError::new(
"Expected triple arguments",
ErrorKind::ValidationError,
)),
}
}
pub fn as_quad<T1, T2, T3, T4>(&self) -> NitriteResult<(T1, T2, T3, T4)>
where
T1: Any + Send + Sync + Clone + 'static,
T2: Any + Send + Sync + Clone + 'static,
T3: Any + Send + Sync + Clone + 'static,
T4: Any + Send + Sync + Clone + 'static,
{
match self {
MigrationArguments::Quad(arg1, arg2, arg3, arg4) => {
let a = arg1.downcast_ref::<T1>()
.cloned()
.ok_or_else(|| NitriteError::new(
"Failed to downcast first argument",
ErrorKind::ValidationError,
))?;
let b = arg2.downcast_ref::<T2>()
.cloned()
.ok_or_else(|| NitriteError::new(
"Failed to downcast second argument",
ErrorKind::ValidationError,
))?;
let c = arg3.downcast_ref::<T3>()
.cloned()
.ok_or_else(|| NitriteError::new(
"Failed to downcast third argument",
ErrorKind::ValidationError,
))?;
let d = arg4.downcast_ref::<T4>()
.cloned()
.ok_or_else(|| NitriteError::new(
"Failed to downcast fourth argument",
ErrorKind::ValidationError,
))?;
Ok((a, b, c, d))
}
_ => Err(NitriteError::new(
"Expected quad arguments",
ErrorKind::ValidationError,
)),
}
}
pub fn as_multiple<T: Any + Send + Sync + Clone + 'static>(&self) -> NitriteResult<Vec<T>> {
match self {
MigrationArguments::Multiple(args) => {
args.iter()
.map(|arg| {
arg.downcast_ref::<T>()
.cloned()
.ok_or_else(|| NitriteError::new(
"Failed to downcast argument in multiple",
ErrorKind::ValidationError,
))
})
.collect()
}
_ => Err(NitriteError::new(
"Expected multiple arguments",
ErrorKind::ValidationError,
)),
}
}
pub fn as_any_single(&self) -> NitriteResult<Arc<dyn Any + Send + Sync>> {
match self {
MigrationArguments::Single(arg) => Ok(Arc::clone(arg)),
_ => Err(NitriteError::new(
"Expected single argument",
ErrorKind::ValidationError,
)),
}
}
pub fn as_any_double(&self) -> NitriteResult<(Arc<dyn Any + Send + Sync>, Arc<dyn Any + Send + Sync>)> {
match self {
MigrationArguments::Double(arg1, arg2) => Ok((Arc::clone(arg1), Arc::clone(arg2))),
_ => Err(NitriteError::new(
"Expected double arguments",
ErrorKind::ValidationError,
)),
}
}
pub fn as_any_triple(&self) -> NitriteResult<(AnyArg, AnyArg, AnyArg)> {
match self {
MigrationArguments::Triple(arg1, arg2, arg3) => Ok((Arc::clone(arg1), Arc::clone(arg2), Arc::clone(arg3))),
_ => Err(NitriteError::new(
"Expected triple arguments",
ErrorKind::ValidationError,
)),
}
}
pub fn as_any_multiple(&self) -> NitriteResult<Vec<Arc<dyn Any + Send + Sync>>> {
match self {
MigrationArguments::Multiple(args) => Ok(args.iter().map(Arc::clone).collect()),
_ => Err(NitriteError::new(
"Expected multiple arguments",
ErrorKind::ValidationError,
)),
}
}
pub fn arg_count(&self) -> usize {
match self {
MigrationArguments::None => 0,
MigrationArguments::Single(_) => 1,
MigrationArguments::Double(_, _) => 2,
MigrationArguments::Triple(_, _, _) => 3,
MigrationArguments::Quad(_, _, _, _) => 4,
MigrationArguments::Multiple(args) => args.len(),
}
}
}
#[derive(Debug, Clone)]
pub struct Migration {
inner: Arc<MigrationInner>,
}
impl Migration {
pub fn new(from_version: u32, to_version: u32, migrate: impl Fn(&InstructionSet) -> NitriteResult<()> + Send + Sync + 'static) -> Self {
Migration {
inner: Arc::new(MigrationInner {
from_version,
to_version,
migration_steps: Mutex::new(VecDeque::new()),
executed: AtomicBool::new(false),
migrate: Box::new(migrate),
}),
}
}
pub fn from_version(&self) -> u32 {
self.inner.from_version
}
pub fn to_version(&self) -> u32 {
self.inner.to_version
}
pub fn steps(&self) -> NitriteResult<Vec<MigrationStep>> {
let executed = self.inner.executed.load(std::sync::atomic::Ordering::SeqCst);
if !executed {
self.execute()?;
}
let steps = self.inner.migration_steps.lock()
.map_err(|_| NitriteError::new("Failed to acquire lock on migration_steps", ErrorKind::ValidationError))?;
Ok(steps.iter().cloned().collect())
}
pub(crate) fn execute(&self) -> NitriteResult<()> {
let steps = self.get_all_steps()?;
let instruction_set = InstructionSet::new(steps);
(self.inner.migrate)(&instruction_set)?;
let new_steps = instruction_set.get_steps()?;
let mut migration_steps = self.inner.migration_steps.lock()
.map_err(|_| NitriteError::new("Failed to acquire lock on migration_steps", ErrorKind::ValidationError))?;
migration_steps.clear();
for step in new_steps {
migration_steps.push_back(step);
}
self.inner.executed.store(true, std::sync::atomic::Ordering::SeqCst);
Ok(())
}
pub(crate) fn add_step(&self, step: MigrationStep) -> NitriteResult<()> {
let mut steps = self.inner.migration_steps.lock()
.map_err(|_| NitriteError::new("Failed to acquire lock on migration_steps", ErrorKind::ValidationError))?;
steps.push_back(step);
Ok(())
}
pub(crate) fn get_all_steps(&self) -> NitriteResult<Vec<MigrationStep>> {
let steps = self.inner.migration_steps.lock()
.map_err(|_| NitriteError::new("Failed to acquire lock on migration_steps", ErrorKind::ValidationError))?;
Ok(steps.iter().cloned().collect())
}
}
pub struct MigrationInner {
from_version: u32,
to_version: u32,
migration_steps: Mutex<VecDeque<MigrationStep>>,
executed: AtomicBool,
migrate: MigrateFn,
}
impl std::fmt::Debug for MigrationInner {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MigrationInner")
.field("from_version", &self.from_version)
.field("to_version", &self.to_version)
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_migration_step_creation() {
let step = MigrationStep {
instruction_type: InstructionType::AddUser,
collection_name: Some("users".to_string()),
entity_name: Some("User".to_string()),
key: Some("id".to_string()),
arguments: MigrationArguments::None,
};
assert_eq!(step.instruction_type, InstructionType::AddUser);
assert_eq!(step.collection_name, Some("users".to_string()));
assert_eq!(step.entity_name, Some("User".to_string()));
assert_eq!(step.key, Some("id".to_string()));
}
#[test]
fn test_migration_step_with_no_optional_fields() {
let step = MigrationStep {
instruction_type: InstructionType::CustomInstruction,
collection_name: None,
entity_name: None,
key: None,
arguments: MigrationArguments::None,
};
assert_eq!(step.collection_name, None);
assert_eq!(step.entity_name, None);
assert_eq!(step.key, None);
}
#[test]
fn test_migration_step_clone() {
let step = MigrationStep {
instruction_type: InstructionType::DropCollection,
collection_name: Some("test".to_string()),
entity_name: None,
key: None,
arguments: MigrationArguments::None,
};
let cloned = step.clone();
assert_eq!(cloned.instruction_type, step.instruction_type);
assert_eq!(cloned.collection_name, step.collection_name);
}
#[test]
fn test_migration_step_debug_format() {
let step = MigrationStep {
instruction_type: InstructionType::AddUser,
collection_name: Some("col".to_string()),
entity_name: None,
key: None,
arguments: MigrationArguments::None,
};
let debug_str = format!("{:?}", step);
assert!(debug_str.contains("MigrationStep"));
assert!(debug_str.contains("AddUser"));
}
#[test]
fn test_migration_arguments_none() {
let args = MigrationArguments::None;
assert_eq!(args.arg_count(), 0);
}
#[test]
fn test_migration_arguments_none_debug() {
let args = MigrationArguments::None;
let debug_str = format!("{:?}", args);
assert_eq!(debug_str, "None");
}
#[test]
fn test_migration_arguments_none_as_single_error() {
let args = MigrationArguments::None;
let result: NitriteResult<String> = args.as_single();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_none_as_double_error() {
let args = MigrationArguments::None;
let result: NitriteResult<(String, String)> = args.as_double();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_none_as_triple_error() {
let args = MigrationArguments::None;
let result: NitriteResult<(String, String, String)> = args.as_triple();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_none_as_quad_error() {
let args = MigrationArguments::None;
let result: NitriteResult<(String, String, String, String)> = args.as_quad();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_none_as_multiple_error() {
let args = MigrationArguments::None;
let result: NitriteResult<Vec<String>> = args.as_multiple();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_none_as_any_single_error() {
let args = MigrationArguments::None;
let result = args.as_any_single();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_none_as_any_double_error() {
let args = MigrationArguments::None;
let result = args.as_any_double();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_none_as_any_triple_error() {
let args = MigrationArguments::None;
let result = args.as_any_triple();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_none_as_any_multiple_error() {
let args = MigrationArguments::None;
let result = args.as_any_multiple();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_single_creation() {
let value = Arc::new("test" as &str);
let args = MigrationArguments::Single(value);
assert_eq!(args.arg_count(), 1);
}
#[test]
fn test_migration_arguments_single_as_single_success() {
let value = Arc::new("test".to_string());
let args = MigrationArguments::Single(value);
let result: NitriteResult<String> = args.as_single();
assert!(result.is_ok());
assert_eq!(result.unwrap(), "test".to_string());
}
#[test]
fn test_migration_arguments_single_as_single_type_mismatch() {
let value = Arc::new(42i32);
let args = MigrationArguments::Single(value);
let result: NitriteResult<String> = args.as_single();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_single_as_double_error() {
let value = Arc::new("test".to_string());
let args = MigrationArguments::Single(value);
let result: NitriteResult<(String, String)> = args.as_double();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_single_debug() {
let value = Arc::new("test".to_string());
let args = MigrationArguments::Single(value);
let debug_str = format!("{:?}", args);
assert_eq!(debug_str, "Single(<value>)");
}
#[test]
fn test_migration_arguments_single_as_any_single_success() {
let value = Arc::new("test".to_string());
let args = MigrationArguments::Single(value.clone());
let result = args.as_any_single();
assert!(result.is_ok());
}
#[test]
fn test_migration_arguments_single_clone() {
let value = Arc::new("test".to_string());
let args = MigrationArguments::Single(value);
let cloned = args.clone();
assert_eq!(cloned.arg_count(), 1);
}
#[test]
fn test_migration_arguments_double_creation() {
let arg1 = Arc::new("first".to_string());
let arg2 = Arc::new("second".to_string());
let args = MigrationArguments::Double(arg1, arg2);
assert_eq!(args.arg_count(), 2);
}
#[test]
fn test_migration_arguments_double_as_double_success() {
let arg1 = Arc::new("first".to_string());
let arg2 = Arc::new("second".to_string());
let args = MigrationArguments::Double(arg1, arg2);
let result: NitriteResult<(String, String)> = args.as_double();
assert!(result.is_ok());
let (a, b) = result.unwrap();
assert_eq!(a, "first".to_string());
assert_eq!(b, "second".to_string());
}
#[test]
fn test_migration_arguments_double_as_double_first_type_mismatch() {
let arg1 = Arc::new(42i32);
let arg2 = Arc::new("second".to_string());
let args = MigrationArguments::Double(arg1, arg2);
let result: NitriteResult<(String, String)> = args.as_double();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_double_as_double_second_type_mismatch() {
let arg1 = Arc::new("first".to_string());
let arg2 = Arc::new(42i32);
let args = MigrationArguments::Double(arg1, arg2);
let result: NitriteResult<(String, String)> = args.as_double();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_double_as_triple_error() {
let arg1 = Arc::new("first".to_string());
let arg2 = Arc::new("second".to_string());
let args = MigrationArguments::Double(arg1, arg2);
let result: NitriteResult<(String, String, String)> = args.as_triple();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_double_debug() {
let arg1 = Arc::new("first".to_string());
let arg2 = Arc::new("second".to_string());
let args = MigrationArguments::Double(arg1, arg2);
let debug_str = format!("{:?}", args);
assert_eq!(debug_str, "Double(<value>, <value>)");
}
#[test]
fn test_migration_arguments_double_as_any_double_success() {
let arg1 = Arc::new("first".to_string());
let arg2 = Arc::new("second".to_string());
let args = MigrationArguments::Double(arg1.clone(), arg2.clone());
let result = args.as_any_double();
assert!(result.is_ok());
}
#[test]
fn test_migration_arguments_triple_creation() {
let arg1 = Arc::new("first".to_string());
let arg2 = Arc::new("second".to_string());
let arg3 = Arc::new("third".to_string());
let args = MigrationArguments::Triple(arg1, arg2, arg3);
assert_eq!(args.arg_count(), 3);
}
#[test]
fn test_migration_arguments_triple_as_triple_success() {
let arg1 = Arc::new("first".to_string());
let arg2 = Arc::new("second".to_string());
let arg3 = Arc::new("third".to_string());
let args = MigrationArguments::Triple(arg1, arg2, arg3);
let result: NitriteResult<(String, String, String)> = args.as_triple();
assert!(result.is_ok());
let (a, b, c) = result.unwrap();
assert_eq!(a, "first".to_string());
assert_eq!(b, "second".to_string());
assert_eq!(c, "third".to_string());
}
#[test]
fn test_migration_arguments_triple_as_triple_first_type_mismatch() {
let arg1 = Arc::new(42i32);
let arg2 = Arc::new("second".to_string());
let arg3 = Arc::new("third".to_string());
let args = MigrationArguments::Triple(arg1, arg2, arg3);
let result: NitriteResult<(String, String, String)> = args.as_triple();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_triple_as_triple_second_type_mismatch() {
let arg1 = Arc::new("first".to_string());
let arg2 = Arc::new(42i32);
let arg3 = Arc::new("third".to_string());
let args = MigrationArguments::Triple(arg1, arg2, arg3);
let result: NitriteResult<(String, String, String)> = args.as_triple();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_triple_as_triple_third_type_mismatch() {
let arg1 = Arc::new("first".to_string());
let arg2 = Arc::new("second".to_string());
let arg3 = Arc::new(42i32);
let args = MigrationArguments::Triple(arg1, arg2, arg3);
let result: NitriteResult<(String, String, String)> = args.as_triple();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_triple_as_quad_error() {
let arg1 = Arc::new("first".to_string());
let arg2 = Arc::new("second".to_string());
let arg3 = Arc::new("third".to_string());
let args = MigrationArguments::Triple(arg1, arg2, arg3);
let result: NitriteResult<(String, String, String, String)> = args.as_quad();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_triple_debug() {
let arg1 = Arc::new("first".to_string());
let arg2 = Arc::new("second".to_string());
let arg3 = Arc::new("third".to_string());
let args = MigrationArguments::Triple(arg1, arg2, arg3);
let debug_str = format!("{:?}", args);
assert_eq!(debug_str, "Triple(<value>, <value>, <value>)");
}
#[test]
fn test_migration_arguments_triple_as_any_triple_success() {
let arg1 = Arc::new("first".to_string());
let arg2 = Arc::new("second".to_string());
let arg3 = Arc::new("third".to_string());
let args = MigrationArguments::Triple(arg1.clone(), arg2.clone(), arg3.clone());
let result = args.as_any_triple();
assert!(result.is_ok());
}
#[test]
fn test_migration_arguments_quad_creation() {
let arg1 = Arc::new("first".to_string());
let arg2 = Arc::new("second".to_string());
let arg3 = Arc::new("third".to_string());
let arg4 = Arc::new("fourth".to_string());
let args = MigrationArguments::Quad(arg1, arg2, arg3, arg4);
assert_eq!(args.arg_count(), 4);
}
#[test]
fn test_migration_arguments_quad_as_quad_success() {
let arg1 = Arc::new("first".to_string());
let arg2 = Arc::new("second".to_string());
let arg3 = Arc::new("third".to_string());
let arg4 = Arc::new("fourth".to_string());
let args = MigrationArguments::Quad(arg1, arg2, arg3, arg4);
let result: NitriteResult<(String, String, String, String)> = args.as_quad();
assert!(result.is_ok());
let (a, b, c, d) = result.unwrap();
assert_eq!(a, "first".to_string());
assert_eq!(b, "second".to_string());
assert_eq!(c, "third".to_string());
assert_eq!(d, "fourth".to_string());
}
#[test]
fn test_migration_arguments_quad_as_quad_first_type_mismatch() {
let arg1 = Arc::new(42i32);
let arg2 = Arc::new("second".to_string());
let arg3 = Arc::new("third".to_string());
let arg4 = Arc::new("fourth".to_string());
let args = MigrationArguments::Quad(arg1, arg2, arg3, arg4);
let result: NitriteResult<(String, String, String, String)> = args.as_quad();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_quad_as_quad_second_type_mismatch() {
let arg1 = Arc::new("first".to_string());
let arg2 = Arc::new(42i32);
let arg3 = Arc::new("third".to_string());
let arg4 = Arc::new("fourth".to_string());
let args = MigrationArguments::Quad(arg1, arg2, arg3, arg4);
let result: NitriteResult<(String, String, String, String)> = args.as_quad();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_quad_as_quad_third_type_mismatch() {
let arg1 = Arc::new("first".to_string());
let arg2 = Arc::new("second".to_string());
let arg3 = Arc::new(42i32);
let arg4 = Arc::new("fourth".to_string());
let args = MigrationArguments::Quad(arg1, arg2, arg3, arg4);
let result: NitriteResult<(String, String, String, String)> = args.as_quad();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_quad_as_quad_fourth_type_mismatch() {
let arg1 = Arc::new("first".to_string());
let arg2 = Arc::new("second".to_string());
let arg3 = Arc::new("third".to_string());
let arg4 = Arc::new(42i32);
let args = MigrationArguments::Quad(arg1, arg2, arg3, arg4);
let result: NitriteResult<(String, String, String, String)> = args.as_quad();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_quad_as_multiple_error() {
let arg1 = Arc::new("first".to_string());
let arg2 = Arc::new("second".to_string());
let arg3 = Arc::new("third".to_string());
let arg4 = Arc::new("fourth".to_string());
let args = MigrationArguments::Quad(arg1, arg2, arg3, arg4);
let result: NitriteResult<Vec<String>> = args.as_multiple();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_quad_debug() {
let arg1 = Arc::new("first".to_string());
let arg2 = Arc::new("second".to_string());
let arg3 = Arc::new("third".to_string());
let arg4 = Arc::new("fourth".to_string());
let args = MigrationArguments::Quad(arg1, arg2, arg3, arg4);
let debug_str = format!("{:?}", args);
assert_eq!(debug_str, "Quad(<value>, <value>, <value>, <value>)");
}
#[test]
fn test_migration_arguments_multiple_empty() {
let args = MigrationArguments::Multiple(vec![]);
assert_eq!(args.arg_count(), 0);
}
#[test]
fn test_migration_arguments_multiple_single_item() {
let arg = Arc::new("value".to_string());
let args = MigrationArguments::Multiple(vec![arg]);
assert_eq!(args.arg_count(), 1);
}
#[test]
fn test_migration_arguments_multiple_multiple_items() {
let args_vec = vec![
Arc::new("first".to_string()) as Arc<dyn Any + Send + Sync>,
Arc::new("second".to_string()) as Arc<dyn Any + Send + Sync>,
Arc::new("third".to_string()) as Arc<dyn Any + Send + Sync>,
];
let args = MigrationArguments::Multiple(args_vec);
assert_eq!(args.arg_count(), 3);
}
#[test]
fn test_migration_arguments_multiple_as_multiple_success() {
let args_vec = vec![
Arc::new("first".to_string()) as Arc<dyn Any + Send + Sync>,
Arc::new("second".to_string()) as Arc<dyn Any + Send + Sync>,
];
let args = MigrationArguments::Multiple(args_vec);
let result: NitriteResult<Vec<String>> = args.as_multiple();
assert!(result.is_ok());
let values = result.unwrap();
assert_eq!(values.len(), 2);
assert_eq!(values[0], "first".to_string());
assert_eq!(values[1], "second".to_string());
}
#[test]
fn test_migration_arguments_multiple_as_multiple_type_mismatch() {
let args_vec = vec![
Arc::new(42i32) as Arc<dyn Any + Send + Sync>,
];
let args = MigrationArguments::Multiple(args_vec);
let result: NitriteResult<Vec<String>> = args.as_multiple();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_multiple_as_single_error() {
let args_vec = vec![
Arc::new("value".to_string()) as Arc<dyn Any + Send + Sync>,
];
let args = MigrationArguments::Multiple(args_vec);
let result: NitriteResult<String> = args.as_single();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_multiple_debug() {
let args_vec = vec![
Arc::new("first".to_string()) as Arc<dyn Any + Send + Sync>,
];
let args = MigrationArguments::Multiple(args_vec);
let debug_str = format!("{:?}", args);
assert_eq!(debug_str, "Multiple(<values>)");
}
#[test]
fn test_migration_arguments_multiple_as_any_multiple_success() {
let args_vec = vec![
Arc::new("first".to_string()) as Arc<dyn Any + Send + Sync>,
Arc::new("second".to_string()) as Arc<dyn Any + Send + Sync>,
];
let args = MigrationArguments::Multiple(args_vec);
let result = args.as_any_multiple();
assert!(result.is_ok());
assert_eq!(result.unwrap().len(), 2);
}
#[test]
fn test_migration_new() {
let migration = Migration::new(1, 2, |_| Ok(()));
assert_eq!(migration.from_version(), 1);
assert_eq!(migration.to_version(), 2);
}
#[test]
fn test_migration_from_version() {
let migration = Migration::new(5, 10, |_| Ok(()));
assert_eq!(migration.from_version(), 5);
}
#[test]
fn test_migration_to_version() {
let migration = Migration::new(3, 7, |_| Ok(()));
assert_eq!(migration.to_version(), 7);
}
#[test]
fn test_migration_add_step() {
let migration = Migration::new(1, 2, |_| Ok(()));
let step = MigrationStep {
instruction_type: InstructionType::AddUser,
collection_name: None,
entity_name: None,
key: None,
arguments: MigrationArguments::None,
};
let result = migration.add_step(step);
assert!(result.is_ok());
}
#[test]
fn test_migration_get_all_steps() {
let migration = Migration::new(1, 2, |_| Ok(()));
let step = MigrationStep {
instruction_type: InstructionType::ChangePassword,
collection_name: None,
entity_name: None,
key: None,
arguments: MigrationArguments::None,
};
migration.add_step(step).unwrap();
let steps = migration.get_all_steps().unwrap();
assert_eq!(steps.len(), 1);
assert_eq!(steps[0].instruction_type, InstructionType::ChangePassword);
}
#[test]
fn test_migration_get_all_steps_multiple() {
let migration = Migration::new(1, 2, |_| Ok(()));
for i in 0..3 {
let step = MigrationStep {
instruction_type: if i == 0 { InstructionType::AddUser } else { InstructionType::ChangePassword },
collection_name: None,
entity_name: None,
key: None,
arguments: MigrationArguments::None,
};
migration.add_step(step).unwrap();
}
let steps = migration.get_all_steps().unwrap();
assert_eq!(steps.len(), 3);
}
#[test]
fn test_migration_execute_success() {
let migration = Migration::new(1, 2, |_| Ok(()));
let result = migration.execute();
assert!(result.is_ok());
}
#[test]
fn test_migration_execute_with_error() {
let migration = Migration::new(1, 2, |_| {
Err(NitriteError::new("Test error", ErrorKind::ValidationError))
});
let result = migration.execute();
assert!(result.is_err());
}
#[test]
fn test_migration_steps_lazy_execution() {
let executed = Arc::new(Mutex::new(false));
let executed_clone = executed.clone();
let migration = Migration::new(1, 2, move |_| {
*executed_clone.lock().unwrap() = true;
Ok(())
});
let result = migration.steps();
assert!(result.is_ok());
assert!(*executed.lock().unwrap());
}
#[test]
fn test_migration_steps_cached() {
let call_count = Arc::new(Mutex::new(0));
let call_count_clone = call_count.clone();
let migration = Migration::new(1, 2, move |_| {
*call_count_clone.lock().unwrap() += 1;
Ok(())
});
let _ = migration.steps();
let _ = migration.steps();
assert_eq!(*call_count.lock().unwrap(), 1);
}
#[test]
fn test_migration_steps_with_steps() {
let migration = Migration::new(1, 2, |_| Ok(()));
let step = MigrationStep {
instruction_type: InstructionType::DropCollection,
collection_name: Some("users".to_string()),
entity_name: None,
key: None,
arguments: MigrationArguments::None,
};
migration.add_step(step).unwrap();
let steps = migration.steps().unwrap();
assert_eq!(steps.len(), 1);
assert_eq!(steps[0].instruction_type, InstructionType::DropCollection);
assert_eq!(steps[0].collection_name, Some("users".to_string()));
}
#[test]
fn test_migration_steps_returns_error() {
let migration = Migration::new(1, 2, |_| {
Err(NitriteError::new("Exec error", ErrorKind::ValidationError))
});
let result = migration.steps();
assert!(result.is_err());
}
#[test]
fn test_migration_clone() {
let migration = Migration::new(1, 2, |_| Ok(()));
let cloned = Migration {
inner: Arc::clone(&migration.inner),
};
assert_eq!(cloned.from_version(), 1);
assert_eq!(cloned.to_version(), 2);
}
#[test]
fn test_migration_debug() {
let migration = Migration::new(1, 2, |_| Ok(()));
let debug_str = format!("{:?}", migration);
assert!(debug_str.contains("Migration"));
}
#[test]
fn test_migration_inner_debug() {
let migration = Migration::new(3, 4, |_| Ok(()));
let debug_str = format!("{:?}", migration);
assert!(debug_str.contains("3") || debug_str.contains("4"));
}
#[test]
fn test_migration_arguments_single_with_integer() {
let value = Arc::new(42i32);
let args = MigrationArguments::Single(value);
let result: NitriteResult<i32> = args.as_single();
assert!(result.is_ok());
assert_eq!(result.unwrap(), 42);
}
#[test]
fn test_migration_arguments_double_with_mixed_types() {
let arg1 = Arc::new("text".to_string());
let arg2 = Arc::new(100i32);
let args = MigrationArguments::Double(arg1, arg2);
let result: NitriteResult<(String, i32)> = args.as_double();
assert!(result.is_ok());
let (text, num) = result.unwrap();
assert_eq!(text, "text".to_string());
assert_eq!(num, 100);
}
#[test]
fn test_migration_arguments_clone() {
let none_args = MigrationArguments::None;
let cloned_none = none_args.clone();
assert_eq!(cloned_none.arg_count(), 0);
let single_args = MigrationArguments::Single(Arc::new("test".to_string()));
let cloned_single = single_args.clone();
assert_eq!(cloned_single.arg_count(), 1);
}
#[test]
fn test_migration_step_with_all_fields() {
let step = MigrationStep {
instruction_type: InstructionType::CustomInstruction,
collection_name: Some("col".to_string()),
entity_name: Some("Entity".to_string()),
key: Some("id".to_string()),
arguments: MigrationArguments::Double(
Arc::new("arg1".to_string()),
Arc::new("arg2".to_string()),
),
};
assert_eq!(step.collection_name, Some("col".to_string()));
assert_eq!(step.entity_name, Some("Entity".to_string()));
assert_eq!(step.key, Some("id".to_string()));
assert_eq!(step.arguments.arg_count(), 2);
}
#[test]
fn test_migration_arguments_single_as_triple_error() {
let value = Arc::new("test".to_string());
let args = MigrationArguments::Single(value);
let result: NitriteResult<(String, String, String)> = args.as_triple();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_single_as_quad_error() {
let value = Arc::new("test".to_string());
let args = MigrationArguments::Single(value);
let result: NitriteResult<(String, String, String, String)> = args.as_quad();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_double_as_single_error() {
let arg1 = Arc::new("first".to_string());
let arg2 = Arc::new("second".to_string());
let args = MigrationArguments::Double(arg1, arg2);
let result: NitriteResult<String> = args.as_single();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_triple_as_double_error() {
let arg1 = Arc::new("first".to_string());
let arg2 = Arc::new("second".to_string());
let arg3 = Arc::new("third".to_string());
let args = MigrationArguments::Triple(arg1, arg2, arg3);
let result: NitriteResult<(String, String)> = args.as_double();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_quad_as_single_error() {
let arg1 = Arc::new("first".to_string());
let arg2 = Arc::new("second".to_string());
let arg3 = Arc::new("third".to_string());
let arg4 = Arc::new("fourth".to_string());
let args = MigrationArguments::Quad(arg1, arg2, arg3, arg4);
let result: NitriteResult<String> = args.as_single();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_quad_as_triple_error() {
let arg1 = Arc::new("first".to_string());
let arg2 = Arc::new("second".to_string());
let arg3 = Arc::new("third".to_string());
let arg4 = Arc::new("fourth".to_string());
let args = MigrationArguments::Quad(arg1, arg2, arg3, arg4);
let result: NitriteResult<(String, String, String)> = args.as_triple();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_multiple_as_double_error() {
let args_vec = vec![
Arc::new("first".to_string()) as Arc<dyn Any + Send + Sync>,
Arc::new("second".to_string()) as Arc<dyn Any + Send + Sync>,
];
let args = MigrationArguments::Multiple(args_vec);
let result: NitriteResult<(String, String)> = args.as_double();
assert!(result.is_err());
}
#[test]
fn test_migration_arguments_multiple_partial_match() {
let args_vec = vec![
Arc::new("first".to_string()) as Arc<dyn Any + Send + Sync>,
Arc::new(42i32) as Arc<dyn Any + Send + Sync>,
Arc::new("third".to_string()) as Arc<dyn Any + Send + Sync>,
];
let args = MigrationArguments::Multiple(args_vec);
let result: NitriteResult<Vec<String>> = args.as_multiple();
assert!(result.is_err());
}
}