proof_of_sql/sql/postprocessing/
order_by_postprocessing.rs

1use super::{PostprocessingError, PostprocessingResult, PostprocessingStep};
2use crate::base::{
3    database::{
4        order_by_util::{
5            compare_indexes_by_owned_columns_with_direction, OrderIndexDirectionPairs,
6        },
7        OwnedTable,
8    },
9    math::permutation::Permutation,
10    scalar::Scalar,
11};
12use alloc::vec::Vec;
13use serde::{Deserialize, Serialize};
14
15/// A node representing a list of `OrderBy` expressions.
16#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
17pub struct OrderByPostprocessing {
18    index_direction_pairs: OrderIndexDirectionPairs,
19}
20
21impl OrderByPostprocessing {
22    /// Create a new `OrderByPostprocessing` node.
23    #[must_use]
24    pub fn new(index_direction_pairs: OrderIndexDirectionPairs) -> Self {
25        Self {
26            index_direction_pairs,
27        }
28    }
29}
30
31impl<S: Scalar> PostprocessingStep<S> for OrderByPostprocessing {
32    /// Apply the slice transformation to the given `OwnedTable`.
33    fn apply(&self, owned_table: OwnedTable<S>) -> PostprocessingResult<OwnedTable<S>> {
34        let opt_max_index = self
35            .index_direction_pairs
36            .iter()
37            .map(|(index, _)| index)
38            .max();
39        if let Some(max_index) = opt_max_index {
40            if *max_index >= owned_table.num_columns() {
41                return Err(PostprocessingError::IndexOutOfBounds { index: *max_index });
42            }
43        }
44        let column_direction_pairs = self
45            .index_direction_pairs
46            .iter()
47            .map(|(index, direction)| {
48                (
49                    owned_table
50                        .column_by_index(*index)
51                        .expect("The index should be valid here")
52                        .clone(),
53                    *direction,
54                )
55            })
56            .collect::<Vec<_>>();
57        // Define the ordering
58        let permutation = Permutation::unchecked_new_from_cmp(owned_table.num_rows(), |&a, &b| {
59            compare_indexes_by_owned_columns_with_direction(&column_direction_pairs, a, b)
60        });
61        // Apply the ordering
62        Ok(
63            OwnedTable::<S>::try_from_iter(owned_table.into_inner().into_iter().map(
64                |(identifier, column)| {
65                    (
66                        identifier,
67                        column
68                            .try_permute(&permutation)
69                            .expect("There should be no column length mismatch here"),
70                    )
71                },
72            ))
73            .expect("There should be no column length mismatch here"),
74        )
75    }
76}