demit 1.0.0

A flexible data generator for various domains
Documentation
use crate::common::{self, DateTime};
use crate::domain::Record;
use rand::Rng;
use rayon::prelude::*;
use serde::{Deserialize, Serialize};
use uuid::Uuid;

const BIG_ORDER_MAX_SALE_AMOUNT: i64 = 1000;
const BIG_ORDER_MIN_SALE_AMOUNT: i64 = 151;
const SMALL_ORDER_MAX_SALE_AMOUNT: i64 = 150;
const SMALL_ORDER_MIN_SALE_AMOUNT: i64 = 1;

/// A point-of-sale transaction record
#[derive(Debug, Deserialize, Serialize)]
pub struct PosRecord {
    /// Unique identifier for the transaction
    id: String,
    /// Sale amount in cents
    amount: i64,
    /// Username of the salesperson
    username: String,
    /// Date and time of the sale
    sales_date: String,
}

impl Record for PosRecord {
    fn generate(count: usize) -> Vec<Self> {
        (0..count).into_par_iter().map(|_| Self::random()).collect()
    }
}

impl PosRecord {
    fn random() -> Self {
        Self {
            id: Self::generate_id(),
            amount: Self::generate_sale_amount(),
            username: common::user::gen_username(true),
            sales_date: DateTime::gen_rfc3339(2),
        }
    }

    /// Returns a random sale amount between configured min and max values
    fn generate_sale_amount() -> i64 {
        let mut rng = rand::rng();
        if rng.random_range(0..=1) == 0 {
            rng.random_range(
                SMALL_ORDER_MIN_SALE_AMOUNT..=SMALL_ORDER_MAX_SALE_AMOUNT,
            )
        } else {
            rng.random_range(
                BIG_ORDER_MIN_SALE_AMOUNT..=BIG_ORDER_MAX_SALE_AMOUNT,
            )
        }
    }

    /// Returns a random UUID v4 as a string
    fn generate_id() -> String {
        Uuid::new_v4().to_string()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_generate_sale_amount() {
        let amount = PosRecord::generate_sale_amount();
        assert!(amount >= SMALL_ORDER_MIN_SALE_AMOUNT);
        assert!(amount <= BIG_ORDER_MAX_SALE_AMOUNT);
    }
}