credence_lib/render/catalog/
annotation.rs

1use super::{super::super::util::*, columns::*};
2
3use {
4    compris::{normal::*, *},
5    std::cmp::*,
6};
7
8//
9// CatalogAnnotation
10//
11
12/// Catalog annotation.
13pub struct CatalogAnnotation<'own> {
14    /// Sort column.
15    pub sort_column: Option<RefValuePath<'own>>,
16
17    /// Sort ascending.
18    pub sort_ascending: bool,
19
20    /// Extra columns.
21    pub extra_columns: ExtraColumns<'own>,
22}
23
24impl<'own> CatalogAnnotation<'own> {
25    /// Constructor.
26    pub fn new(
27        sort_column: Option<RefValuePath<'own>>,
28        sort_ascending: bool,
29        extra_columns: ExtraColumns<'own>,
30    ) -> Self {
31        Self { sort_column, sort_ascending, extra_columns }
32    }
33
34    /// Resolve.
35    pub fn resolve(value: &'own Value) -> Self {
36        let extra_columns = flatten_columns(
37            traverse!(value, "columns").and_then(
38                |columns| {
39                    if let Value::Map(map) = columns { Some(map) } else { None }
40                },
41            ),
42        );
43
44        let (sort_column, sort_ascending) = traverse!(value, "sort")
45            .and_then(|sort| match sort {
46                Value::Map(map) => Some((
47                    map.value.get(&"column".into()).and_then(to_ref_value_path),
48                    map.value
49                        .get(&"ascending".into())
50                        .map(|ascending| match ascending {
51                            Value::Boolean(ascending) => ascending.value,
52                            _ => true,
53                        })
54                        .unwrap_or(true),
55                )),
56
57                Value::List(_) | Value::Text(_) => Some((to_ref_value_path(sort), true)),
58
59                _ => None,
60            })
61            .unwrap_or((None, true));
62
63        Self::new(sort_column, sort_ascending, extra_columns)
64    }
65
66    /// Sort rows by column.
67    pub fn sort(self, rows: &mut Vec<Value>) {
68        let ascending = self.sort_ascending;
69        let sort_column = self.into_sort_column();
70        rows.sort_by(|row1, row2| cmp_rows_by_column(row1, row2, &sort_column, ascending));
71    }
72
73    /// Into sort column (defaults to "title").
74    fn into_sort_column(self) -> ValuePath {
75        self.sort_column.map(to_value_path).unwrap_or_else(|| vec!["title".into()])
76    }
77}
78
79fn cmp_rows_by_column(row1: &Value, row2: &Value, column_path: &ValuePath, ascending: bool) -> Ordering {
80    if let Some(a) = row1.traverse(column_path.iter()) {
81        if let Some(b) = row2.traverse(column_path.iter()) {
82            let ordering = cmp_lowercase(a, b);
83            return if ascending { ordering } else { ordering.reverse() };
84        }
85    }
86
87    Ordering::Less
88}