#cqrs #pattern #adapter #command #query #context #bus

kti_cqrs_rs

Implementation of CQRS pattern in Rust

4 releases (breaking)

new 0.3.0 Dec 8, 2024
0.2.0 Mar 16, 2024
0.1.0 Mar 3, 2024
0.0.1 Nov 4, 2023

#15 in #bus

Download history 2/week @ 2024-08-11 5/week @ 2024-08-18 69/week @ 2024-08-25 28/week @ 2024-09-01 54/week @ 2024-09-08 11/week @ 2024-09-15 47/week @ 2024-09-22 6/week @ 2024-09-29 14/week @ 2024-10-06 41/week @ 2024-10-13 14/week @ 2024-10-20 1/week @ 2024-10-27

292 downloads per month
Used in kti_cqrs_provider_rs

MIT/Apache

10KB
140 lines

Implementation of CQRS pattern in Rust

Currently the crate contains only query & command handlers

Simple example (existed in repo)

#[cfg(test)]
mod tests {
  use std::{sync::Arc, time::Duration};

  use kti_cqrs_rs::core::bus::{command_bus::CommandBus, event_bus::EventBus, query_bus::QueryBus};
  use tokio::{sync::Mutex, time::sleep};

  use super::{
    adapters::{
      mutex_repository_adapter::MutexRepositoryAdapter, mutex_service_adapter::MutexServiceAdapter,
    },
    contexts::mutex_context::MutexContext,
    ports::mutex_service_port::MutexServicePort,
  };

  fn create_service() -> Box<dyn MutexServicePort> {
    let store = Arc::new(Mutex::new(vec![]));

    let query_repository = Box::new(MutexRepositoryAdapter::new(store.clone()));
    let command_repository = Box::new(MutexRepositoryAdapter::new(store));

    Box::new(MutexServiceAdapter::new(
      Arc::new(Mutex::new(MutexContext::new(
        query_repository,
        command_repository,
      ))),
      CommandBus,
      QueryBus,
      EventBus,
    ))
  }

  #[tokio::test]
  async fn should_be_empty_vector() {
    let service = create_service();

    let count = service.get_count().await.unwrap();

    assert_eq!(count, 0);
  }

  #[tokio::test]
  async fn should_be_one_element() {
    let service = create_service();

    service.add_element(1).await.unwrap();

    let count = service.get_count().await.unwrap();

    assert_eq!(count, 1);
  }

  #[tokio::test]
  async fn should_be_empty_after_remove() {
    let service = create_service();

    service.add_element(1).await.unwrap();
    service.remove_element(1).await.unwrap();

    let count = service.get_count().await.unwrap();

    assert_eq!(count, 0);
  }

  #[tokio::test]
  async fn should_be_error_on_remove_not_existed_element() {
    let service = create_service();

    let res = service.remove_element(1).await;

    assert!(res.is_err());
  }

  #[tokio::test]
  async fn should_be_updated_element() {
    let from_element = 1;
    let to_element = 2;
    let service = create_service();

    service.add_element(from_element).await.unwrap();
    service
      .update_element(from_element, to_element)
      .await
      .unwrap();

    let elements = service.get_elements().await.unwrap();

    let updated_element = elements.first().unwrap();

    assert_eq!(*updated_element, to_element);
  }

  #[tokio::test]
  async fn should_be_incremented_by_event() {
    let element = 43;
    let service = create_service();

    service.add_element_with_event(element).await.unwrap();

    sleep(Duration::from_secs(1)).await;

    let elements = service.get_elements().await.unwrap();

    let incremented_element = elements.first().unwrap();

    assert_eq!(*incremented_element, element + 1);
  }

  #[tokio::test]
  async fn should_be_failed_incremented_by_event() {
    let element = 42;
    let service = create_service();

    service.add_element_with_event(element).await.unwrap();

    sleep(Duration::from_secs(1)).await;

    let elements = service.get_elements().await.unwrap();

    let incremented_element = elements.first().unwrap();

    assert_eq!(*incremented_element, element);
  }

  #[tokio::test]
  async fn should_be_failed_increment_without_awaiting() {
    let element = 43;
    let service = create_service();

    service.add_element_with_event(element).await.unwrap();

    let elements = service.get_elements().await.unwrap();

    let incremented_element = elements.first().unwrap();

    assert_eq!(*incremented_element, element);
  }
}

Dependencies

~2.2–8MB
~64K SLoC