| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| use crate::models::{generate_random_string, generate_random_strings, TestDataGenerator}; |
| use chrono::{DateTime, NaiveDateTime, Utc}; |
| use fory_derive::ForyObject; |
| use serde::{Deserialize, Serialize}; |
| use std::collections::HashMap; |
| |
| // Fory models |
| #[derive(ForyObject, Debug, Clone, PartialEq, Default)] |
| pub struct ForyProduct { |
| pub id: String, |
| pub name: String, |
| pub price: f64, |
| pub categories: Vec<String>, |
| pub attributes: HashMap<String, String>, |
| } |
| |
| #[derive(ForyObject, Debug, Clone, PartialEq)] |
| pub struct ForyOrderItem { |
| pub product: ForyProduct, |
| pub quantity: i32, |
| pub unit_price: f64, |
| pub customizations: HashMap<String, String>, |
| } |
| |
| #[derive(ForyObject, Debug, Clone, PartialEq, Default)] |
| pub struct ForyCustomer { |
| pub id: String, |
| pub name: String, |
| pub email: String, |
| pub phone_numbers: Vec<String>, |
| pub preferences: HashMap<String, String>, |
| pub member_since: NaiveDateTime, |
| } |
| |
| #[derive(ForyObject, Debug, Clone, PartialEq)] |
| pub struct ForyOrder { |
| pub id: String, |
| pub customer: ForyCustomer, |
| pub items: Vec<ForyOrderItem>, |
| pub total_amount: f64, |
| pub status: String, |
| pub order_date: NaiveDateTime, |
| pub metadata: HashMap<String, String>, |
| } |
| |
| #[derive(ForyObject, Debug, Clone, PartialEq)] |
| pub struct ECommerceData { |
| pub orders: Vec<ForyOrder>, |
| pub customers: Vec<ForyCustomer>, |
| pub products: Vec<ForyProduct>, |
| pub order_lookup: HashMap<String, ForyOrder>, |
| } |
| |
| // Serde models |
| #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] |
| pub struct SerdeProduct { |
| pub id: String, |
| pub name: String, |
| pub price: f64, |
| pub categories: Vec<String>, |
| pub attributes: HashMap<String, String>, |
| } |
| |
| #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] |
| pub struct SerdeOrderItem { |
| pub product: SerdeProduct, |
| pub quantity: i32, |
| pub unit_price: f64, |
| pub customizations: HashMap<String, String>, |
| } |
| |
| #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] |
| pub struct SerdeCustomer { |
| pub id: String, |
| pub name: String, |
| pub email: String, |
| pub phone_numbers: Vec<String>, |
| pub preferences: HashMap<String, String>, |
| pub member_since: DateTime<Utc>, |
| } |
| |
| #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] |
| pub struct SerdeOrder { |
| pub id: String, |
| pub customer: SerdeCustomer, |
| pub items: Vec<SerdeOrderItem>, |
| pub total_amount: f64, |
| pub status: String, |
| pub order_date: DateTime<Utc>, |
| pub metadata: HashMap<String, String>, |
| } |
| |
| #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] |
| pub struct SerdeECommerceData { |
| pub orders: Vec<SerdeOrder>, |
| pub customers: Vec<SerdeCustomer>, |
| pub products: Vec<SerdeProduct>, |
| pub order_lookup: HashMap<String, SerdeOrder>, |
| } |
| |
| impl TestDataGenerator for ECommerceData { |
| type Data = ECommerceData; |
| |
| fn generate_small() -> Self::Data { |
| let product = ForyProduct { |
| id: "prod_1".to_string(), |
| name: "Laptop".to_string(), |
| price: 999.99, |
| categories: vec!["Electronics".to_string(), "Computers".to_string()], |
| attributes: HashMap::from([ |
| ("brand".to_string(), "TechCorp".to_string()), |
| ("model".to_string(), "X1".to_string()), |
| ]), |
| }; |
| |
| let customer = ForyCustomer { |
| id: "cust_1".to_string(), |
| name: "John Doe".to_string(), |
| email: "john@example.com".to_string(), |
| phone_numbers: vec!["+1234567890".to_string()], |
| preferences: HashMap::from([ |
| ("language".to_string(), "en".to_string()), |
| ("currency".to_string(), "USD".to_string()), |
| ]), |
| member_since: DateTime::from_timestamp(1640995200, 0).unwrap().naive_utc(), |
| }; |
| |
| let order_item = ForyOrderItem { |
| product: product.clone(), |
| quantity: 1, |
| unit_price: 999.99, |
| customizations: HashMap::from([("color".to_string(), "black".to_string())]), |
| }; |
| |
| let order = ForyOrder { |
| id: "order_1".to_string(), |
| customer: customer.clone(), |
| items: vec![order_item], |
| total_amount: 999.99, |
| status: "completed".to_string(), |
| order_date: DateTime::from_timestamp(1640995200, 0).unwrap().naive_utc(), |
| metadata: HashMap::from([("payment_method".to_string(), "credit_card".to_string())]), |
| }; |
| |
| let mut order_lookup = HashMap::new(); |
| order_lookup.insert(order.id.clone(), order.clone()); |
| |
| ECommerceData { |
| orders: vec![order], |
| customers: vec![customer], |
| products: vec![product], |
| order_lookup, |
| } |
| } |
| |
| fn generate_medium() -> Self::Data { |
| let mut products = Vec::new(); |
| let mut customers = Vec::new(); |
| let mut orders = Vec::new(); |
| let mut order_lookup = HashMap::new(); |
| |
| // Generate 20 products |
| for i in 1..=20 { |
| let product = ForyProduct { |
| id: format!("prod_{}", i), |
| name: generate_random_string(30), |
| price: (i as f64) * 50.0, |
| categories: generate_random_strings(3, 15), |
| attributes: { |
| let mut map = HashMap::new(); |
| for j in 1..=5 { |
| map.insert(format!("attr_{}", j), generate_random_string(20)); |
| } |
| map |
| }, |
| }; |
| products.push(product); |
| } |
| |
| // Generate 10 customers |
| for i in 1..=10 { |
| let customer = ForyCustomer { |
| id: format!("cust_{}", i), |
| name: generate_random_string(40), |
| email: format!("user{}@example.com", i), |
| phone_numbers: generate_random_strings(2, 12), |
| preferences: { |
| let mut map = HashMap::new(); |
| for j in 1..=10 { |
| map.insert(format!("pref_{}", j), generate_random_string(15)); |
| } |
| map |
| }, |
| member_since: DateTime::from_timestamp(1640995200, 0).unwrap().naive_utc(), |
| }; |
| customers.push(customer); |
| } |
| |
| // Generate 15 orders |
| for i in 1..=15 { |
| let customer = customers[i % customers.len()].clone(); |
| let mut items = Vec::new(); |
| let mut total = 0.0; |
| |
| for j in 1..=3 { |
| let product = products[j % products.len()].clone(); |
| let quantity = ((j % 5) + 1) as i32; |
| let unit_price = product.price; |
| total += unit_price * quantity as f64; |
| |
| let item = ForyOrderItem { |
| product, |
| quantity, |
| unit_price, |
| customizations: { |
| let mut map = HashMap::new(); |
| for k in 1..=3 { |
| map.insert(format!("custom_{}", k), generate_random_string(10)); |
| } |
| map |
| }, |
| }; |
| items.push(item); |
| } |
| |
| let order = ForyOrder { |
| id: format!("order_{}", i), |
| customer, |
| items, |
| total_amount: total, |
| status: if i % 3 == 0 { |
| "pending".to_string() |
| } else { |
| "completed".to_string() |
| }, |
| order_date: DateTime::from_timestamp(1640995200, 0).unwrap().naive_utc(), |
| metadata: { |
| let mut map = HashMap::new(); |
| for k in 1..=5 { |
| map.insert(format!("meta_{}", k), generate_random_string(20)); |
| } |
| map |
| }, |
| }; |
| |
| order_lookup.insert(order.id.clone(), order.clone()); |
| orders.push(order); |
| } |
| |
| ECommerceData { |
| orders, |
| customers, |
| products, |
| order_lookup, |
| } |
| } |
| |
| fn generate_large() -> Self::Data { |
| let mut products = Vec::new(); |
| let mut customers = Vec::new(); |
| let mut orders = Vec::new(); |
| let mut order_lookup = HashMap::new(); |
| |
| // Generate 100 products |
| for i in 1..=100 { |
| let product = ForyProduct { |
| id: format!("prod_{}", i), |
| name: generate_random_string(50), |
| price: (i as f64) * 25.0, |
| categories: generate_random_strings(5, 20), |
| attributes: { |
| let mut map = HashMap::new(); |
| for j in 1..=10 { |
| map.insert(format!("attr_{}", j), generate_random_string(30)); |
| } |
| map |
| }, |
| }; |
| products.push(product); |
| } |
| |
| // Generate 50 customers |
| for i in 1..=50 { |
| let customer = ForyCustomer { |
| id: format!("cust_{}", i), |
| name: generate_random_string(60), |
| email: format!("user{}@example.com", i), |
| phone_numbers: generate_random_strings(3, 15), |
| preferences: { |
| let mut map = HashMap::new(); |
| for j in 1..=20 { |
| map.insert(format!("pref_{}", j), generate_random_string(25)); |
| } |
| map |
| }, |
| member_since: DateTime::from_timestamp(1640995200, 0).unwrap().naive_utc(), |
| }; |
| customers.push(customer); |
| } |
| |
| // Generate 100 orders |
| for i in 1..=100 { |
| let customer = customers[i % customers.len()].clone(); |
| let mut items = Vec::new(); |
| let mut total = 0.0; |
| |
| for j in 1..=5 { |
| let product = products[j % products.len()].clone(); |
| let quantity = ((j % 10) + 1) as i32; |
| let unit_price = product.price; |
| total += unit_price * quantity as f64; |
| |
| let item = ForyOrderItem { |
| product, |
| quantity, |
| unit_price, |
| customizations: { |
| let mut map = HashMap::new(); |
| for k in 1..=5 { |
| map.insert(format!("custom_{}", k), generate_random_string(20)); |
| } |
| map |
| }, |
| }; |
| items.push(item); |
| } |
| |
| let order = ForyOrder { |
| id: format!("order_{}", i), |
| customer, |
| items, |
| total_amount: total, |
| status: if i % 4 == 0 { |
| "pending".to_string() |
| } else { |
| "completed".to_string() |
| }, |
| order_date: DateTime::from_timestamp(1640995200, 0).unwrap().naive_utc(), |
| metadata: { |
| let mut map = HashMap::new(); |
| for k in 1..=10 { |
| map.insert(format!("meta_{}", k), generate_random_string(30)); |
| } |
| map |
| }, |
| }; |
| |
| order_lookup.insert(order.id.clone(), order.clone()); |
| orders.push(order); |
| } |
| |
| ECommerceData { |
| orders, |
| customers, |
| products, |
| order_lookup, |
| } |
| } |
| } |
| |
| // Conversion functions for Serde |
| impl From<ForyProduct> for SerdeProduct { |
| fn from(f: ForyProduct) -> Self { |
| SerdeProduct { |
| id: f.id, |
| name: f.name, |
| price: f.price, |
| categories: f.categories, |
| attributes: f.attributes, |
| } |
| } |
| } |
| |
| impl From<ForyOrderItem> for SerdeOrderItem { |
| fn from(f: ForyOrderItem) -> Self { |
| SerdeOrderItem { |
| product: f.product.into(), |
| quantity: f.quantity, |
| unit_price: f.unit_price, |
| customizations: f.customizations, |
| } |
| } |
| } |
| |
| impl From<ForyCustomer> for SerdeCustomer { |
| fn from(f: ForyCustomer) -> Self { |
| SerdeCustomer { |
| id: f.id, |
| name: f.name, |
| email: f.email, |
| phone_numbers: f.phone_numbers, |
| preferences: f.preferences, |
| member_since: f.member_since.and_utc(), |
| } |
| } |
| } |
| |
| impl From<ForyOrder> for SerdeOrder { |
| fn from(f: ForyOrder) -> Self { |
| SerdeOrder { |
| id: f.id, |
| customer: f.customer.into(), |
| items: f.items.into_iter().map(|i| i.into()).collect(), |
| total_amount: f.total_amount, |
| status: f.status, |
| order_date: f.order_date.and_utc(), |
| metadata: f.metadata, |
| } |
| } |
| } |
| |
| impl From<ECommerceData> for SerdeECommerceData { |
| fn from(f: ECommerceData) -> Self { |
| SerdeECommerceData { |
| orders: f.orders.into_iter().map(|o| o.into()).collect(), |
| customers: f.customers.into_iter().map(|c| c.into()).collect(), |
| products: f.products.into_iter().map(|p| p.into()).collect(), |
| order_lookup: f |
| .order_lookup |
| .into_iter() |
| .map(|(k, v)| (k, v.into())) |
| .collect(), |
| } |
| } |
| } |
| |
| // Reverse conversions from Serde to Fory |
| impl From<SerdeProduct> for ForyProduct { |
| fn from(s: SerdeProduct) -> Self { |
| ForyProduct { |
| id: s.id, |
| name: s.name, |
| price: s.price, |
| categories: s.categories, |
| attributes: s.attributes, |
| } |
| } |
| } |
| |
| impl From<SerdeOrderItem> for ForyOrderItem { |
| fn from(s: SerdeOrderItem) -> Self { |
| ForyOrderItem { |
| product: s.product.into(), |
| quantity: s.quantity, |
| unit_price: s.unit_price, |
| customizations: s.customizations, |
| } |
| } |
| } |
| |
| impl From<SerdeCustomer> for ForyCustomer { |
| fn from(s: SerdeCustomer) -> Self { |
| ForyCustomer { |
| id: s.id, |
| name: s.name, |
| email: s.email, |
| phone_numbers: s.phone_numbers, |
| preferences: s.preferences, |
| member_since: s.member_since.naive_utc(), |
| } |
| } |
| } |
| |
| impl From<SerdeOrder> for ForyOrder { |
| fn from(s: SerdeOrder) -> Self { |
| ForyOrder { |
| id: s.id, |
| customer: s.customer.into(), |
| items: s.items.into_iter().map(|i| i.into()).collect(), |
| total_amount: s.total_amount, |
| status: s.status, |
| order_date: s.order_date.naive_utc(), |
| metadata: s.metadata, |
| } |
| } |
| } |
| |
| impl From<SerdeECommerceData> for ECommerceData { |
| fn from(s: SerdeECommerceData) -> Self { |
| ECommerceData { |
| orders: s.orders.into_iter().map(|o| o.into()).collect(), |
| customers: s.customers.into_iter().map(|c| c.into()).collect(), |
| products: s.products.into_iter().map(|p| p.into()).collect(), |
| order_lookup: s |
| .order_lookup |
| .into_iter() |
| .map(|(k, v)| (k, v.into())) |
| .collect(), |
| } |
| } |
| } |