}
impl PivotTable {
+ fn builder(title: impl Into<Value>, dimensions: &[DimensionBuilder]) -> PivotTableBuilder {
+ PivotTableBuilder::new(title, dimensions)
+ }
fn axis_values(&self, axis: Axis3) -> AxisIterator {
AxisIterator {
indexes: repeat_n(0, self.axes[axis].dimensions.len()).collect(),
pub fn len(&self) -> usize {
self.data_leaves.len()
}
+
+ pub fn builder(axis: Axis3, root: GroupBuilder) -> DimensionBuilder {
+ DimensionBuilder::new(axis, root)
+ }
}
#[derive(Clone, Debug)]
}
impl Group {
+ pub fn builder(name: impl Into<Value>) -> GroupBuilder {
+ GroupBuilder::new(name)
+ }
+
pub fn parent(&self) -> Option<Arc<Group>> {
self.parent.as_ref().map(|parent| parent.upgrade().unwrap())
}
}
impl GroupBuilder {
- pub fn new(name: Value) -> Self {
+ pub fn new(name: impl Into<Value>) -> Self {
Self {
- name: Box::new(name),
+ name: Box::new(name.into()),
children: Vec::new(),
show_label: None,
}
}
}
+impl From<&str> for CategoryBuilder {
+ fn from(name: &str) -> Self {
+ Self::Leaf {
+ name: Box::new(Value::new_text(name)),
+ class: None,
+ }
+ }
+}
pub struct PivotTableBuilder {
look: Arc<Look>,
title: Box<Value>,
}
impl PivotTableBuilder {
- pub fn new(title: Value, dimensions: &[DimensionBuilder]) -> Self {
+ pub fn new(title: impl Into<Value>, dimensions: &[DimensionBuilder]) -> Self {
Self {
look: Settings::global().look.clone(),
- title: Box::new(title),
+ title: Box::new(title.into()),
dimensions: dimensions.to_vec(),
cells: HashMap::new(),
}
self.row_label_position = row_label_position;
self
}
+ pub fn with_borders(mut self, borders: EnumMap<Border, BorderStyle>) -> Self {
+ self.borders = borders;
+ self
+ }
}
impl Default for Look {
}
}
+impl From<&str> for Value {
+ fn from(value: &str) -> Self {
+ Self::new_text(value)
+ }
+}
+
pub struct DisplayValue<'a> {
inner: &'a ValueInner,
markup: bool,
use std::sync::Arc;
-use crate::output::pivot::{Area, Color, LabelPosition, Look, PivotTable};
+use enum_map::EnumMap;
+
+use crate::output::pivot::{
+ Area, Axis2, Border, BorderStyle, Color, Dimension, Group, HeadingRegion, LabelPosition, Look,
+ PivotTable, RowColBorder, Stroke,
+};
use super::{Axis3, DimensionBuilder, GroupBuilder, PivotTableBuilder, Value};
.with(Value::new_text("c1"))
.with(Value::new_text("c2")),
);
- let pivot_table =
- PivotTableBuilder::new(Value::new_text("Three Dimensions, Two Empty"), &[d1, d2, d3])
- .with_look(look.clone())
- .build();
+ let pivot_table = PivotTableBuilder::new(
+ Value::new_text("Three Dimensions, Two Empty"),
+ &[d1, d2, d3],
+ )
+ .with_look(look.clone())
+ .build();
assert_rendering(&pivot_table, "Three Dimensions, Two Empty\n");
}
+
+#[test]
+fn empty_groups() {
+ let mut a = GroupBuilder::new(Value::new_text("a"))
+ .with(Value::new_text("a1"))
+ .with(GroupBuilder::new(Value::new_text("a2")))
+ .with(Value::new_text("a3"));
+ let d1 = DimensionBuilder::new(Axis3::X, a);
+
+ let mut b = GroupBuilder::new(Value::new_text("b"))
+ .with(GroupBuilder::new(Value::new_text("b1")))
+ .with(Value::new_text("b2"))
+ .with(Value::new_text("b3"));
+ let d2 = DimensionBuilder::new(Axis3::Y, b);
+
+ let mut pt = PivotTableBuilder::new(Value::new_text("Empty Groups"), &[d1, d2]);
+ let mut i = 0;
+ for b in 0..2 {
+ for a in 0..2 {
+ pt.insert(&[a, b], Value::new_integer(Some(i as f64)));
+ i += 1;
+ }
+ }
+ let pivot_table = pt
+ .with_look(Arc::new(test_look().with_omit_empty(false)))
+ .build();
+ assert_rendering(
+ &pivot_table,
+ "\
+Empty Groups
+╭──┬──┬──╮
+│ │a1│a3│
+├──┼──┼──┤
+│b2│ 0│ 1│
+│b3│ 2│ 3│
+╰──┴──┴──╯
+",
+ );
+}
+
+#[test]
+fn borders() {
+ let a = Dimension::builder(
+ Axis3::X,
+ Group::builder("a")
+ .with_label_shown()
+ .with("a1")
+ .with(Group::builder("ag1").with("a2").with("a3")),
+ );
+ let b = Dimension::builder(
+ Axis3::X,
+ Group::builder("b")
+ .with_label_shown()
+ .with(Group::builder("bg1").with("b1").with("b2"))
+ .with("b3"),
+ );
+ let c = Dimension::builder(
+ Axis3::Y,
+ Group::builder("c")
+ .with_label_shown()
+ .with("c1")
+ .with(Group::builder("cg1").with("c2").with("c3")),
+ );
+ let d = Dimension::builder(
+ Axis3::Y,
+ Group::builder("d")
+ .with_label_shown()
+ .with(Group::builder("dg1").with("d1").with("d2"))
+ .with("d3"),
+ );
+ let borders = EnumMap::from_fn(|border| match border {
+ Border::Dimension(RowColBorder(HeadingRegion::Rows, Axis2::X))
+ | Border::Dimension(RowColBorder(HeadingRegion::Columns, Axis2::Y)) => BorderStyle {
+ stroke: Stroke::Solid,
+ color: Color {
+ alpha: 255,
+ r: 0,
+ g: 0,
+ b: 255,
+ },
+ },
+ _ => BorderStyle::none(),
+ });
+ let mut pivot_table = PivotTable::builder("Dimension Borders 1", &[a, b, c, d])
+ .with_look(Arc::new(test_look().with_borders(borders)));
+ let mut i = 0;
+ for d in 0..3 {
+ for c in 0..3 {
+ for b in 0..3 {
+ for a in 0..3 {
+ pivot_table.insert(&[a, b, c, d], Value::new_integer(Some(i as f64)));
+ i += 1;
+ }
+ }
+ }
+ }
+ let pivot_table = pivot_table.build();
+ assert_rendering(
+ &pivot_table,
+ "\
+Dimension Borders 1
+ b
+ bg1 │
+ b1 │ b2 │ b3
+ a │ a │ a
+ │ ag1 │ │ ag1 │ │ ag1
+d c a1│a2 a3│a1│a2 a3│a1│a2 a3
+dg1 d1 c1 0│ 1 2│ 3│ 4 5│ 6│ 7 8
+ ╶─────────┼─────┼──┼─────┼──┼─────
+ cg1 c2 9│10 11│12│13 14│15│16 17
+ c3 18│19 20│21│22 23│24│25 26
+ ╶────────────┼─────┼──┼─────┼──┼─────
+ d2 c1 27│28 29│30│31 32│33│34 35
+ ╶─────────┼─────┼──┼─────┼──┼─────
+ cg1 c2 36│37 38│39│40 41│42│43 44
+ c3 45│46 47│48│49 50│51│52 53
+────────────────┼─────┼──┼─────┼──┼─────
+d3 c1 54│55 56│57│58 59│60│61 62
+ ╶─────────┼─────┼──┼─────┼──┼─────
+ cg1 c2 63│64 65│66│67 68│69│70 71
+ c3 72│73 74│75│76 77│78│79 80
+",
+ );
+}