#![allow(dead_code)]
use derive_builder::Builder;
use es_entity::*;
use serde::{Deserialize, Serialize};
es_entity::entity_id! {
OrderId ,
OrderItemId
}
#[derive(EsEvent, Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
#[es_event(id = "OrderItemId")]
pub enum OrderItemEvent {
Initialized {
id: OrderItemId,
order_id: OrderId,
product_name: String,
quantity: i32,
price: f64,
},
QuantityUpdated {
quantity: i32,
},
}
#[derive(EsEntity, Builder)]
#[builder(pattern = "owned", build_fn(error = "EntityHydrationError"))]
pub struct OrderItem {
pub id: OrderItemId,
pub order_id: OrderId,
pub product_name: String,
pub quantity: i32,
pub price: f64,
events: EntityEvents<OrderItemEvent>,
}
impl OrderItem {
pub fn update_quantity(&mut self, quantity: i32) -> Idempotent<()> {
idempotency_guard!(
self.events.iter_all().rev(),
already_applied: OrderItemEvent::QuantityUpdated { quantity: q } if q == &quantity,
resets_on: OrderItemEvent::QuantityUpdated { .. }
);
self.quantity = quantity;
self.events
.push(OrderItemEvent::QuantityUpdated { quantity });
Idempotent::Executed(())
}
}
impl TryFromEvents<OrderItemEvent> for OrderItem {
fn try_from_events(events: EntityEvents<OrderItemEvent>) -> Result<Self, EntityHydrationError> {
let mut builder = OrderItemBuilder::default();
for event in events.iter_all() {
match event {
OrderItemEvent::Initialized {
id,
order_id,
product_name,
quantity,
price,
} => {
builder = builder
.id(*id)
.order_id(*order_id)
.product_name(product_name.clone())
.quantity(*quantity)
.price(*price);
}
OrderItemEvent::QuantityUpdated { quantity } => {
builder = builder.quantity(*quantity);
}
}
}
builder.events(events).build()
}
}
#[derive(Debug, Clone, Builder)]
pub struct NewOrderItem {
pub id: OrderItemId,
pub order_id: OrderId,
#[builder(setter(into))]
pub product_name: String,
pub quantity: i32,
pub price: f64,
}
impl NewOrderItem {
pub fn builder() -> NewOrderItemBuilder {
NewOrderItemBuilder::default()
}
}
impl IntoEvents<OrderItemEvent> for NewOrderItem {
fn into_events(self) -> EntityEvents<OrderItemEvent> {
EntityEvents::init(
self.id,
vec![OrderItemEvent::Initialized {
id: self.id,
order_id: self.order_id,
product_name: self.product_name,
quantity: self.quantity,
price: self.price,
}],
)
}
}
#[derive(EsEvent, Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
#[es_event(id = "OrderId")]
pub enum OrderEvent {
Initialized { id: OrderId },
}
#[derive(EsEntity, Builder)]
#[builder(pattern = "owned", build_fn(error = "EntityHydrationError"))]
pub struct Order {
pub id: OrderId,
events: EntityEvents<OrderEvent>,
#[es_entity(nested)]
#[builder(default)]
items: Nested<OrderItem>,
}
impl Order {
pub fn add_item(&mut self, item: NewOrderItem) {
self.items.add_new(item);
}
pub fn find_item_with_name(&self, product_name: &str) -> Option<&OrderItem> {
self.items
.find_persisted(|item| item.product_name == product_name)
}
pub fn n_items(&self) -> usize {
self.items.len_persisted()
}
pub fn update_item_quantity(&mut self, product_name: &str, quantity: i32) -> Idempotent<()> {
if let Some(item) = self
.items
.find_persisted_mut(|item| item.product_name == product_name)
{
item.update_quantity(quantity)
} else {
Idempotent::AlreadyApplied
}
}
}
impl TryFromEvents<OrderEvent> for Order {
fn try_from_events(events: EntityEvents<OrderEvent>) -> Result<Self, EntityHydrationError> {
let mut builder = OrderBuilder::default();
for event in events.iter_all() {
match event {
OrderEvent::Initialized { id } => builder = builder.id(*id),
}
}
builder.events(events).build()
}
}
#[derive(Debug, Clone, Builder)]
pub struct NewOrder {
pub id: OrderId,
}
impl NewOrder {
pub fn builder() -> NewOrderBuilder {
NewOrderBuilder::default()
}
}
impl IntoEvents<OrderEvent> for NewOrder {
fn into_events(self) -> EntityEvents<OrderEvent> {
EntityEvents::init(self.id, vec![OrderEvent::Initialized { id: self.id }])
}
}