samling 0.13.1

App for managing apparel collections
Documentation
use indexmap::IndexSet;
use itertools::Itertools;

use super::aggregator::GroupBy;
use crate::{
    AnyId, CategorySummary, ImageSummary, NestedColor, NestedPrice, NestedSize, NestedStyle,
};

#[derive(Debug, Clone)]
pub(super) struct ExpandedRow<'a> {
    pub(super) style: &'a NestedStyle,
    pub(super) color: Option<&'a NestedColor>,
    pub(super) size: Option<&'a NestedSize>,
    pub(super) category: Option<&'a CategorySummary>,
    pub(super) image: Option<&'a ImageSummary>,
    pub(super) price: Option<&'a NestedPrice>,
}

impl<'a> ExpandedRow<'a> {
    pub(crate) fn group_by_ids(&self, group_by: &IndexSet<GroupBy>) -> Vec<AnyId> {
        group_by
            .iter()
            .filter_map(|&g| match g {
                GroupBy::Style => Some(self.style.id.into()),
                GroupBy::Color => self.color.map(|c| c.id.into()),
                GroupBy::Size => self.size.map(|s| s.id.into()),
                GroupBy::Category => self.category.map(|c| c.id.into()),
                GroupBy::Image => self.image.map(|i| i.id.into()),
                GroupBy::PriceList => self.price.map(|r| r.list.id.into()),
            })
            .collect_vec()
    }

    fn new(style: &'a NestedStyle) -> Self {
        Self {
            style,
            color: None,
            size: None,
            category: None,
            image: None,
            price: None,
        }
    }

    fn with_color(self, color: &'a NestedColor) -> Self {
        Self {
            color: Some(color),
            ..self
        }
    }

    fn with_size(self, size: &'a NestedSize) -> Self {
        Self {
            size: Some(size),
            ..self
        }
    }

    fn clear_size(self) -> Self {
        Self { size: None, ..self }
    }

    fn with_category(self, category: &'a CategorySummary) -> Self {
        Self {
            category: Some(category),
            ..self
        }
    }

    fn with_image(self, image: &'a ImageSummary) -> Self {
        Self {
            image: Some(image),
            ..self
        }
    }

    fn with_price(self, price: &'a NestedPrice) -> Self {
        Self {
            price: Some(price),
            ..self
        }
    }
}

pub(super) fn expand(style: &NestedStyle) -> Vec<ExpandedRow> {
    let base = ExpandedRow::new(style);
    let expanded = expand_colors(base, &style.colors);

    let expanded = expand_categories(expanded, &style.categories);
    expand_prices(expanded, &style.prices)
}

fn expand_colors<'a>(mut base: ExpandedRow<'a>, colors: &'a [NestedColor]) -> Vec<ExpandedRow<'a>> {
    let mut sources = Vec::new();
    if colors.is_empty() {
        sources.push(base);
    } else {
        let mut sub_bases = Vec::new();
        for color in colors {
            base = base.with_color(color).clear_size();
            if color.sizes.is_empty() {
                sub_bases.push(base.clone());
            } else {
                for size in &color.sizes {
                    base = base.with_size(size);
                    sub_bases.push(base.clone());
                }
            }

            sub_bases = expand_images(sub_bases, &color.images);
            sources.append(&mut sub_bases);
        }
    }
    sources
}

fn expand_images<'a>(
    mut sources: Vec<ExpandedRow<'a>>,
    images: &'a [ImageSummary],
) -> Vec<ExpandedRow<'a>> {
    if images.is_empty() {
        sources
    } else {
        let temp_rows = sources.drain(..).collect_vec();
        for image in images {
            for temp_row in temp_rows.clone() {
                sources.push(temp_row.with_image(image));
            }
        }
        sources
    }
}

fn expand_prices<'a>(
    mut sources: Vec<ExpandedRow<'a>>,
    prices: &'a [NestedPrice],
) -> Vec<ExpandedRow<'a>> {
    if prices.is_empty() {
        sources
    } else {
        let temp_rows = sources.drain(..).collect_vec();
        for price in prices {
            for temp_row in temp_rows.clone() {
                sources.push(temp_row.with_price(price));
            }
        }
        sources
    }
}

fn expand_categories<'a>(
    mut sources: Vec<ExpandedRow<'a>>,
    categories: &'a [CategorySummary],
) -> Vec<ExpandedRow<'a>> {
    if categories.is_empty() {
        sources
    } else {
        let temp_rows = sources.drain(..).collect_vec();
        for category in categories {
            for temp_row in temp_rows.clone() {
                sources.push(temp_row.with_category(category));
            }
        }
        sources
    }
}