#![allow(dead_code)]
use domain_key::{Domain, Key, KeyDomain, KeyParseError};
use std::borrow::Cow;
use std::collections::HashMap;
#[derive(Debug)]
struct UserDomain;
impl Domain for UserDomain {
const DOMAIN_NAME: &'static str = "user";
}
impl KeyDomain for UserDomain {
const MAX_LENGTH: usize = 32;
fn validate_domain_rules(key: &str) -> Result<(), KeyParseError> {
if key.starts_with("admin_") && !key.ends_with("_verified") {
return Err(KeyParseError::domain_error(
Self::DOMAIN_NAME,
"Admin users must have '_verified' suffix",
));
}
Ok(())
}
}
#[derive(Debug)]
struct ProductDomain;
impl Domain for ProductDomain {
const DOMAIN_NAME: &'static str = "product";
}
impl KeyDomain for ProductDomain {
const MAX_LENGTH: usize = 48;
const HAS_CUSTOM_NORMALIZATION: bool = true;
fn normalize_domain(key: Cow<'_, str>) -> Cow<'_, str> {
if key
.chars()
.any(|c| c.is_ascii_uppercase() || c == '-' || c == ' ')
{
let normalized = key.to_ascii_lowercase().replace(['-', ' '], "_");
Cow::Owned(normalized)
} else {
key
}
}
}
#[derive(Debug)]
struct OrderDomain;
impl Domain for OrderDomain {
const DOMAIN_NAME: &'static str = "order";
}
impl KeyDomain for OrderDomain {
const MAX_LENGTH: usize = 36;
fn validate_domain_rules(key: &str) -> Result<(), KeyParseError> {
if key.len() == 36 && key.chars().filter(|&c| c == '-').count() == 4 {
Ok(())
} else {
Err(KeyParseError::domain_error(
Self::DOMAIN_NAME,
"Order IDs must be in UUID format",
))
}
}
}
#[derive(Debug)]
struct CartDomain;
impl Domain for CartDomain {
const DOMAIN_NAME: &'static str = "cart";
}
impl KeyDomain for CartDomain {
const MAX_LENGTH: usize = 64;
}
type UserKey = Key<UserDomain>;
type ProductKey = Key<ProductDomain>;
type OrderKey = Key<OrderDomain>;
type CartKey = Key<CartDomain>;
#[derive(Debug, Clone)]
struct User {
id: UserKey,
name: String,
email: String,
}
#[derive(Debug, Clone)]
struct Product {
id: ProductKey,
name: String,
price: u32, }
#[derive(Debug, Clone)]
struct Order {
id: OrderKey,
user_id: UserKey,
items: Vec<(ProductKey, u32)>, total: u32,
}
#[derive(Debug, Clone)]
struct Cart {
id: CartKey,
user_id: UserKey,
items: HashMap<ProductKey, u32>, }
struct ECommerceService {
users: HashMap<UserKey, User>,
products: HashMap<ProductKey, Product>,
orders: HashMap<OrderKey, Order>,
carts: HashMap<CartKey, Cart>,
}
impl ECommerceService {
fn new() -> Self {
Self {
users: HashMap::new(),
products: HashMap::new(),
orders: HashMap::new(),
carts: HashMap::new(),
}
}
fn add_user(&mut self, name: String, email: String) -> Result<UserKey, KeyParseError> {
let user_id = UserKey::new(format!("user_{}", self.users.len() + 1))?;
let user = User {
id: user_id.clone(),
name,
email,
};
self.users.insert(user_id.clone(), user);
Ok(user_id)
}
fn add_product(&mut self, name: String, price: u32) -> Result<ProductKey, KeyParseError> {
let product_id = ProductKey::new(format!("PRODUCT-{}", name.replace(' ', "-")))?;
let product = Product {
id: product_id.clone(),
name,
price,
};
self.products.insert(product_id.clone(), product);
Ok(product_id)
}
fn create_cart(&mut self, user_id: UserKey) -> Result<CartKey, KeyParseError> {
let cart_id = CartKey::from_parts(&["cart", user_id.as_str()], "_")?;
let cart = Cart {
id: cart_id.clone(),
user_id,
items: HashMap::new(),
};
self.carts.insert(cart_id.clone(), cart);
Ok(cart_id)
}
fn add_to_cart(
&mut self,
cart_id: &CartKey,
product_id: ProductKey,
quantity: u32,
) -> Result<(), Box<dyn std::error::Error>> {
let cart = self.carts.get_mut(cart_id).ok_or("Cart not found")?;
*cart.items.entry(product_id).or_insert(0) += quantity;
Ok(())
}
fn create_order(&mut self, cart_id: &CartKey) -> Result<OrderKey, Box<dyn std::error::Error>> {
let cart = self.carts.get(cart_id).ok_or("Cart not found")?;
if cart.items.is_empty() {
return Err("Cannot create order from empty cart".into());
}
let order_id = OrderKey::new("550e8400-e29b-41d4-a716-446655440000")?;
let mut total = 0;
let items: Vec<(ProductKey, u32)> = cart
.items
.iter()
.map(|(product_id, &quantity)| {
if let Some(product) = self.products.get(product_id) {
total += product.price * quantity;
}
(product_id.clone(), quantity)
})
.collect();
let order = Order {
id: order_id.clone(),
user_id: cart.user_id.clone(),
items,
total,
};
self.orders.insert(order_id.clone(), order);
self.carts.get_mut(cart_id).unwrap().items.clear();
Ok(order_id)
}
fn get_user_orders(&self, user_id: &UserKey) -> Vec<&Order> {
self.orders
.values()
.filter(|order| &order.user_id == user_id)
.collect()
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== E-commerce Domain Example ===\n");
let mut service = ECommerceService::new();
let alice_id =
service.add_user("Alice Johnson".to_string(), "alice@example.com".to_string())?;
let bob_id = service.add_user("Bob Smith".to_string(), "bob@example.com".to_string())?;
println!("Created users:");
println!(" Alice ID: {}", alice_id.as_str());
println!(" Bob ID: {}", bob_id.as_str());
let laptop_id = service.add_product("Gaming Laptop".to_string(), 129_999)?; let mouse_id = service.add_product("wireless-mouse".to_string(), 4999)?;
println!("\nCreated products:");
println!(" Laptop ID: {} (normalized)", laptop_id.as_str());
println!(" Mouse ID: {} (normalized)", mouse_id.as_str());
let alice_cart = service.create_cart(alice_id.clone())?;
println!("\nCreated cart: {}", alice_cart.as_str());
service.add_to_cart(&alice_cart.clone(), laptop_id.clone(), 1)?;
service.add_to_cart(&alice_cart.clone(), mouse_id, 2)?;
println!("Added items to Alice's cart");
let order_id = service.create_order(&alice_cart)?;
println!("Created order: {}", order_id.as_str());
let alice_orders = service.get_user_orders(&alice_id);
println!("\nAlice's orders:");
for order in alice_orders {
println!(
" Order {}: ${:.2} ({} items)",
order.id.as_str(),
f64::from(order.total) / 100.0,
order.items.len()
);
}
println!("\n🛡️ Type safety demonstration:");
println!(" User key domain: {}", alice_id.domain());
println!(" Product key domain: {}", laptop_id.domain());
println!(" Order key domain: {}", order_id.domain());
println!("\n✅ E-commerce example completed successfully!");
Ok(())
}