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.

181 lines
6.1KB

  1. use rayon::prelude::*;
  2. use page::Page;
  3. use front_matter::SortBy;
  4. /// Sort pages by the given criteria
  5. ///
  6. /// Any pages that doesn't have a the required field when the sorting method is other than none
  7. /// will be ignored.
  8. pub fn sort_pages(pages: Vec<Page>, sort_by: SortBy) -> (Vec<Page>, Vec<Page>) {
  9. if sort_by == SortBy::None {
  10. return (pages, vec![]);
  11. }
  12. let (mut can_be_sorted, cannot_be_sorted): (Vec<_>, Vec<_>) = pages
  13. .into_par_iter()
  14. .partition(|ref page| {
  15. match sort_by {
  16. SortBy::Date => page.meta.date.is_some(),
  17. SortBy::Order => page.meta.order.is_some(),
  18. SortBy::Weight => page.meta.weight.is_some(),
  19. _ => unreachable!()
  20. }
  21. });
  22. match sort_by {
  23. SortBy::Date => can_be_sorted.par_sort_unstable_by(|a, b| b.meta.date().unwrap().cmp(&a.meta.date().unwrap())),
  24. SortBy::Order => can_be_sorted.par_sort_unstable_by(|a, b| b.meta.order().cmp(&a.meta.order())),
  25. SortBy::Weight => can_be_sorted.par_sort_unstable_by(|a, b| a.meta.weight().cmp(&b.meta.weight())),
  26. _ => unreachable!()
  27. };
  28. (can_be_sorted, cannot_be_sorted)
  29. }
  30. /// Horribly inefficient way to set previous and next on each pages
  31. /// So many clones
  32. pub fn populate_previous_and_next_pages(input: Vec<Page>) -> Vec<Page> {
  33. let mut res = Vec::with_capacity(input.len());
  34. // The input is already sorted
  35. for (i, _) in input.iter().enumerate() {
  36. let mut new_page = input[i].clone();
  37. if i > 0 {
  38. let mut previous_page = input[i - 1].clone();
  39. // Remove prev/next otherwise we serialise the whole thing...
  40. previous_page.previous = None;
  41. previous_page.next = None;
  42. new_page.previous = Some(Box::new(previous_page));
  43. }
  44. if i < input.len() - 1 {
  45. let mut next_page = input[i + 1].clone();
  46. // Remove prev/next otherwise we serialise the whole thing...
  47. next_page.previous = None;
  48. next_page.next = None;
  49. new_page.next = Some(Box::new(next_page));
  50. }
  51. res.push(new_page);
  52. }
  53. res
  54. }
  55. #[cfg(test)]
  56. mod tests {
  57. use front_matter::{PageFrontMatter, SortBy};
  58. use page::Page;
  59. use super::{sort_pages, populate_previous_and_next_pages};
  60. fn create_page_with_date(date: &str) -> Page {
  61. let mut front_matter = PageFrontMatter::default();
  62. front_matter.date = Some(date.to_string());
  63. Page::new("content/hello.md", front_matter)
  64. }
  65. fn create_page_with_order(order: usize) -> Page {
  66. let mut front_matter = PageFrontMatter::default();
  67. front_matter.order = Some(order);
  68. Page::new("content/hello.md", front_matter)
  69. }
  70. fn create_page_with_weight(weight: usize) -> Page {
  71. let mut front_matter = PageFrontMatter::default();
  72. front_matter.weight = Some(weight);
  73. Page::new("content/hello.md", front_matter)
  74. }
  75. #[test]
  76. fn can_sort_by_dates() {
  77. let input = vec![
  78. create_page_with_date("2018-01-01"),
  79. create_page_with_date("2017-01-01"),
  80. create_page_with_date("2019-01-01"),
  81. ];
  82. let (pages, _) = sort_pages(input, SortBy::Date);
  83. // Should be sorted by date
  84. assert_eq!(pages[0].clone().meta.date.unwrap(), "2019-01-01");
  85. assert_eq!(pages[1].clone().meta.date.unwrap(), "2018-01-01");
  86. assert_eq!(pages[2].clone().meta.date.unwrap(), "2017-01-01");
  87. }
  88. #[test]
  89. fn can_sort_by_order() {
  90. let input = vec![
  91. create_page_with_order(2),
  92. create_page_with_order(3),
  93. create_page_with_order(1),
  94. ];
  95. let (pages, _) = sort_pages(input, SortBy::Order);
  96. // Should be sorted by date
  97. assert_eq!(pages[0].clone().meta.order.unwrap(), 3);
  98. assert_eq!(pages[1].clone().meta.order.unwrap(), 2);
  99. assert_eq!(pages[2].clone().meta.order.unwrap(), 1);
  100. }
  101. #[test]
  102. fn can_sort_by_weight() {
  103. let input = vec![
  104. create_page_with_weight(2),
  105. create_page_with_weight(3),
  106. create_page_with_weight(1),
  107. ];
  108. let (pages, _) = sort_pages(input, SortBy::Weight);
  109. // Should be sorted by date
  110. assert_eq!(pages[0].clone().meta.weight.unwrap(), 1);
  111. assert_eq!(pages[1].clone().meta.weight.unwrap(), 2);
  112. assert_eq!(pages[2].clone().meta.weight.unwrap(), 3);
  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(1),
  142. create_page_with_order(2),
  143. create_page_with_order(3),
  144. ];
  145. let pages = populate_previous_and_next_pages(input);
  146. assert!(pages[0].clone().previous.is_none());
  147. assert!(pages[0].clone().next.is_some());
  148. assert_eq!(pages[0].clone().next.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().previous.unwrap().meta.order.unwrap(), 1);
  152. assert_eq!(pages[1].clone().next.unwrap().meta.order.unwrap(), 3);
  153. assert!(pages[2].clone().next.is_none());
  154. assert!(pages[2].clone().previous.is_some());
  155. assert_eq!(pages[2].clone().previous.unwrap().meta.order.unwrap(), 2);
  156. }
  157. }