You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

178 lines
5.9KB

  1. use content::Page;
  2. #[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
  3. #[serde(rename_all = "lowercase")]
  4. pub enum SortBy {
  5. Date,
  6. Order,
  7. None,
  8. }
  9. /// Sort pages using the method for the given section
  10. ///
  11. /// Any pages that doesn't have a date when the sorting method is date or order
  12. /// when the sorting method is order will be ignored.
  13. pub fn sort_pages(pages: Vec<Page>, sort_by: SortBy) -> (Vec<Page>, Vec<Page>) {
  14. match sort_by {
  15. SortBy::Date => {
  16. let mut can_be_sorted = vec![];
  17. let mut cannot_be_sorted = vec![];
  18. for page in pages {
  19. if page.meta.date.is_some() {
  20. can_be_sorted.push(page);
  21. } else {
  22. cannot_be_sorted.push(page);
  23. }
  24. }
  25. can_be_sorted.sort_by(|a, b| b.meta.date().unwrap().cmp(&a.meta.date().unwrap()));
  26. (can_be_sorted, cannot_be_sorted)
  27. },
  28. SortBy::Order => {
  29. let mut can_be_sorted = vec![];
  30. let mut cannot_be_sorted = vec![];
  31. for page in pages {
  32. if page.meta.order.is_some() {
  33. can_be_sorted.push(page);
  34. } else {
  35. cannot_be_sorted.push(page);
  36. }
  37. }
  38. can_be_sorted.sort_by(|a, b| b.meta.order().cmp(&a.meta.order()));
  39. (can_be_sorted, cannot_be_sorted)
  40. },
  41. SortBy::None => (pages, vec![])
  42. }
  43. }
  44. /// Horribly inefficient way to set previous and next on each pages
  45. /// So many clones
  46. pub fn populate_previous_and_next_pages(input: &[Page]) -> Vec<Page> {
  47. let pages = input.to_vec();
  48. let mut res = Vec::new();
  49. // the input is already sorted
  50. // We might put prev/next randomly if a page is missing date/order, probably fine
  51. for (i, page) in input.iter().enumerate() {
  52. let mut new_page = page.clone();
  53. if i > 0 {
  54. let next = &pages[i - 1];
  55. let mut next_page = next.clone();
  56. // Remove prev/next otherwise we serialise the whole thing...
  57. next_page.previous = None;
  58. next_page.next = None;
  59. new_page.next = Some(Box::new(next_page));
  60. }
  61. if i < input.len() - 1 {
  62. let previous = &pages[i + 1];
  63. // Remove prev/next otherwise we serialise the whole thing...
  64. let mut previous_page = previous.clone();
  65. previous_page.previous = None;
  66. previous_page.next = None;
  67. new_page.previous = Some(Box::new(previous_page));
  68. }
  69. res.push(new_page);
  70. }
  71. res
  72. }
  73. #[cfg(test)]
  74. mod tests {
  75. use front_matter::{PageFrontMatter};
  76. use content::Page;
  77. use super::{SortBy, sort_pages, populate_previous_and_next_pages};
  78. fn create_page_with_date(date: &str) -> Page {
  79. let mut front_matter = PageFrontMatter::default();
  80. front_matter.date = Some(date.to_string());
  81. Page::new("content/hello.md", front_matter)
  82. }
  83. fn create_page_with_order(order: usize) -> Page {
  84. let mut front_matter = PageFrontMatter::default();
  85. front_matter.order = Some(order);
  86. Page::new("content/hello.md", front_matter)
  87. }
  88. #[test]
  89. fn can_sort_by_dates() {
  90. let input = vec![
  91. create_page_with_date("2018-01-01"),
  92. create_page_with_date("2017-01-01"),
  93. create_page_with_date("2019-01-01"),
  94. ];
  95. let (pages, _) = sort_pages(input, SortBy::Date);
  96. // Should be sorted by date
  97. assert_eq!(pages[0].clone().meta.date.unwrap(), "2019-01-01");
  98. assert_eq!(pages[1].clone().meta.date.unwrap(), "2018-01-01");
  99. assert_eq!(pages[2].clone().meta.date.unwrap(), "2017-01-01");
  100. }
  101. #[test]
  102. fn can_sort_by_order() {
  103. let input = vec![
  104. create_page_with_order(2),
  105. create_page_with_order(3),
  106. create_page_with_order(1),
  107. ];
  108. let (pages, _) = sort_pages(input, SortBy::Order);
  109. // Should be sorted by date
  110. assert_eq!(pages[0].clone().meta.order.unwrap(), 3);
  111. assert_eq!(pages[1].clone().meta.order.unwrap(), 2);
  112. assert_eq!(pages[2].clone().meta.order.unwrap(), 1);
  113. }
  114. #[test]
  115. fn can_sort_by_none() {
  116. let input = vec![
  117. create_page_with_order(2),
  118. create_page_with_order(3),
  119. create_page_with_order(1),
  120. ];
  121. let (pages, _) = sort_pages(input, SortBy::None);
  122. // Should be sorted by date
  123. assert_eq!(pages[0].clone().meta.order.unwrap(), 2);
  124. assert_eq!(pages[1].clone().meta.order.unwrap(), 3);
  125. assert_eq!(pages[2].clone().meta.order.unwrap(), 1);
  126. }
  127. #[test]
  128. fn ignore_page_with_missing_field() {
  129. let input = vec![
  130. create_page_with_order(2),
  131. create_page_with_order(3),
  132. create_page_with_date("2019-01-01"),
  133. ];
  134. let (pages, unsorted) = sort_pages(input, SortBy::Order);
  135. assert_eq!(pages.len(), 2);
  136. assert_eq!(unsorted.len(), 1);
  137. }
  138. #[test]
  139. fn can_populate_previous_and_next_pages() {
  140. let input = vec![
  141. create_page_with_order(3),
  142. create_page_with_order(2),
  143. create_page_with_order(1),
  144. ];
  145. let pages = populate_previous_and_next_pages(input.as_slice());
  146. assert!(pages[0].clone().next.is_none());
  147. assert!(pages[0].clone().previous.is_some());
  148. assert_eq!(pages[0].clone().previous.unwrap().meta.order.unwrap(), 2);
  149. assert!(pages[1].clone().next.is_some());
  150. assert!(pages[1].clone().previous.is_some());
  151. assert_eq!(pages[1].clone().next.unwrap().meta.order.unwrap(), 3);
  152. assert_eq!(pages[1].clone().previous.unwrap().meta.order.unwrap(), 1);
  153. assert!(pages[2].clone().next.is_some());
  154. assert!(pages[2].clone().previous.is_none());
  155. assert_eq!(pages[2].clone().next.unwrap().meta.order.unwrap(), 2);
  156. }
  157. }