Skip to main content

datafusion_physical_expr_common/
sort_expr.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! Sort expressions
19
20use std::cmp::Ordering;
21use std::fmt::{self, Display, Formatter};
22use std::hash::{Hash, Hasher};
23use std::ops::{Deref, DerefMut};
24use std::sync::Arc;
25use std::vec::IntoIter;
26
27use crate::physical_expr::{PhysicalExpr, fmt_sql};
28
29use arrow::compute::kernels::sort::{SortColumn, SortOptions};
30use arrow::datatypes::Schema;
31use arrow::record_batch::RecordBatch;
32use datafusion_common::{HashSet, Result};
33use datafusion_expr_common::columnar_value::ColumnarValue;
34use indexmap::IndexSet;
35/// Represents Sort operation for a column in a RecordBatch
36///
37/// Example:
38/// ```
39/// # use std::any::Any;
40/// # use std::collections::HashMap;
41/// # use std::fmt::{Display, Formatter};
42/// # use std::hash::Hasher;
43/// # use std::sync::Arc;
44/// # use arrow::array::RecordBatch;
45/// # use datafusion_common::Result;
46/// # use arrow::compute::SortOptions;
47/// # use arrow::datatypes::{DataType, Field, FieldRef, Schema};
48/// # use datafusion_expr_common::columnar_value::ColumnarValue;
49/// # use datafusion_physical_expr_common::physical_expr::PhysicalExpr;
50/// # use datafusion_physical_expr_common::sort_expr::PhysicalSortExpr;
51/// # // this crate doesn't have a physical expression implementation
52/// # // so make a really simple one
53/// # #[derive(Clone, Debug, PartialEq, Eq, Hash)]
54/// # struct MyPhysicalExpr;
55/// # impl PhysicalExpr for MyPhysicalExpr {
56/// #  fn data_type(&self, input_schema: &Schema) -> Result<DataType> {todo!()}
57/// #  fn nullable(&self, input_schema: &Schema) -> Result<bool> {todo!() }
58/// #  fn evaluate(&self, batch: &RecordBatch) -> Result<ColumnarValue> {todo!() }
59/// #  fn return_field(&self, input_schema: &Schema) -> Result<FieldRef> { unimplemented!() }
60/// #  fn children(&self) -> Vec<&Arc<dyn PhysicalExpr>> {todo!()}
61/// #  fn with_new_children(self: Arc<Self>, children: Vec<Arc<dyn PhysicalExpr>>) -> Result<Arc<dyn PhysicalExpr>> {todo!()}
62/// # fn fmt_sql(&self, f: &mut Formatter<'_>) -> std::fmt::Result { todo!() }
63/// # }
64/// # impl Display for MyPhysicalExpr {
65/// #    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "a") }
66/// # }
67/// # fn col(name: &str) -> Arc<dyn PhysicalExpr> { Arc::new(MyPhysicalExpr) }
68/// // Sort by a ASC
69/// let options = SortOptions::default();
70/// let sort_expr = PhysicalSortExpr::new(col("a"), options);
71/// assert_eq!(sort_expr.to_string(), "a ASC");
72///
73/// // Sort by a DESC NULLS LAST
74/// let sort_expr = PhysicalSortExpr::new_default(col("a"))
75///   .desc()
76///   .nulls_last();
77/// assert_eq!(sort_expr.to_string(), "a DESC NULLS LAST");
78/// ```
79#[derive(Clone, Debug, Eq)]
80pub struct PhysicalSortExpr {
81    /// Physical expression representing the column to sort
82    pub expr: Arc<dyn PhysicalExpr>,
83    /// Option to specify how the given column should be sorted
84    pub options: SortOptions,
85}
86
87impl PhysicalSortExpr {
88    /// Create a new PhysicalSortExpr
89    pub fn new(expr: Arc<dyn PhysicalExpr>, options: SortOptions) -> Self {
90        Self { expr, options }
91    }
92
93    /// Create a new PhysicalSortExpr with default [`SortOptions`]
94    pub fn new_default(expr: Arc<dyn PhysicalExpr>) -> Self {
95        Self::new(expr, SortOptions::default())
96    }
97
98    /// Reverses the sort expression. For instance, `[a ASC NULLS LAST]` turns
99    /// into `[a DESC NULLS FIRST]`. Such reversals are useful in planning, e.g.
100    /// when constructing equivalent window expressions.
101    pub fn reverse(&self) -> Self {
102        let mut result = self.clone();
103        result.options = !result.options;
104        result
105    }
106
107    /// Set the sort sort options to ASC
108    pub fn asc(mut self) -> Self {
109        self.options.descending = false;
110        self
111    }
112
113    /// Set the sort sort options to DESC
114    pub fn desc(mut self) -> Self {
115        self.options.descending = true;
116        self
117    }
118
119    /// Set the sort sort options to NULLS FIRST
120    pub fn nulls_first(mut self) -> Self {
121        self.options.nulls_first = true;
122        self
123    }
124
125    /// Set the sort sort options to NULLS LAST
126    pub fn nulls_last(mut self) -> Self {
127        self.options.nulls_first = false;
128        self
129    }
130
131    /// Like [`PhysicalExpr::fmt_sql`] prints a [`PhysicalSortExpr`] in a SQL-like format.
132    pub fn fmt_sql(&self, f: &mut Formatter) -> fmt::Result {
133        write!(
134            f,
135            "{} {}",
136            fmt_sql(self.expr.as_ref()),
137            to_str(&self.options)
138        )
139    }
140
141    /// Evaluates the sort expression into a `SortColumn` that can be passed
142    /// into the arrow sort kernel.
143    pub fn evaluate_to_sort_column(&self, batch: &RecordBatch) -> Result<SortColumn> {
144        let array_to_sort = match self.expr.evaluate(batch)? {
145            ColumnarValue::Array(array) => array,
146            ColumnarValue::Scalar(scalar) => scalar.to_array_of_size(batch.num_rows())?,
147        };
148        Ok(SortColumn {
149            values: array_to_sort,
150            options: Some(self.options),
151        })
152    }
153
154    /// Checks whether this sort expression satisfies the given `requirement`.
155    /// If sort options are unspecified in `requirement`, only expressions are
156    /// compared for inequality. See [`options_compatible`] for details on
157    /// how sort options compare with one another.
158    pub fn satisfy(
159        &self,
160        requirement: &PhysicalSortRequirement,
161        schema: &Schema,
162    ) -> bool {
163        self.expr.eq(&requirement.expr)
164            && requirement.options.is_none_or(|opts| {
165                options_compatible(
166                    &self.options,
167                    &opts,
168                    self.expr.nullable(schema).unwrap_or(true),
169                )
170            })
171    }
172
173    /// Checks whether this sort expression satisfies the given `sort_expr`.
174    /// See [`options_compatible`] for details on how sort options compare with
175    /// one another.
176    pub fn satisfy_expr(&self, sort_expr: &Self, schema: &Schema) -> bool {
177        self.expr.eq(&sort_expr.expr)
178            && options_compatible(
179                &self.options,
180                &sort_expr.options,
181                self.expr.nullable(schema).unwrap_or(true),
182            )
183    }
184}
185
186impl PartialEq for PhysicalSortExpr {
187    fn eq(&self, other: &Self) -> bool {
188        self.options == other.options && self.expr.eq(&other.expr)
189    }
190}
191
192impl Hash for PhysicalSortExpr {
193    fn hash<H: Hasher>(&self, state: &mut H) {
194        self.expr.hash(state);
195        self.options.hash(state);
196    }
197}
198
199impl Display for PhysicalSortExpr {
200    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
201        write!(f, "{} {}", self.expr, to_str(&self.options))
202    }
203}
204
205/// Returns whether the given two [`SortOptions`] are compatible. Here,
206/// compatibility means that they are either exactly equal, or they differ only
207/// in whether NULL values come in first/last, which is immaterial because the
208/// column in question is not nullable (specified by the `nullable` parameter).
209pub fn options_compatible(
210    options_lhs: &SortOptions,
211    options_rhs: &SortOptions,
212    nullable: bool,
213) -> bool {
214    if nullable {
215        options_lhs == options_rhs
216    } else {
217        // If the column is not nullable, NULLS FIRST/LAST is not important.
218        options_lhs.descending == options_rhs.descending
219    }
220}
221
222/// Represents sort requirement associated with a plan
223///
224/// If the requirement includes [`SortOptions`] then both the
225/// expression *and* the sort options must match.
226///
227/// If the requirement does not include [`SortOptions`]) then only the
228/// expressions must match.
229///
230/// # Examples
231///
232/// With sort options (`A`, `DESC NULLS FIRST`):
233/// * `ORDER BY A DESC NULLS FIRST` matches
234/// * `ORDER BY A ASC  NULLS FIRST` does not match (`ASC` vs `DESC`)
235/// * `ORDER BY B DESC NULLS FIRST` does not match (different expr)
236///
237/// Without sort options (`A`, None):
238/// * `ORDER BY A DESC NULLS FIRST` matches
239/// * `ORDER BY A ASC  NULLS FIRST` matches (`ASC` and `NULL` options ignored)
240/// * `ORDER BY B DESC NULLS FIRST` does not match  (different expr)
241#[derive(Clone, Debug)]
242pub struct PhysicalSortRequirement {
243    /// Physical expression representing the column to sort
244    pub expr: Arc<dyn PhysicalExpr>,
245    /// Option to specify how the given column should be sorted.
246    /// If unspecified, there are no constraints on sort options.
247    pub options: Option<SortOptions>,
248}
249
250impl PartialEq for PhysicalSortRequirement {
251    fn eq(&self, other: &Self) -> bool {
252        self.options == other.options && self.expr.eq(&other.expr)
253    }
254}
255
256impl Display for PhysicalSortRequirement {
257    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
258        let opts_string = self.options.as_ref().map_or("NA", to_str);
259        write!(f, "{} {}", self.expr, opts_string)
260    }
261}
262
263/// Writes a list of [`PhysicalSortRequirement`]s to a `std::fmt::Formatter`.
264///
265/// Example output: `[a + 1, b]`
266pub fn format_physical_sort_requirement_list(
267    exprs: &[PhysicalSortRequirement],
268) -> impl Display + '_ {
269    struct DisplayWrapper<'a>(&'a [PhysicalSortRequirement]);
270    impl Display for DisplayWrapper<'_> {
271        fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
272            let mut iter = self.0.iter();
273            write!(f, "[")?;
274            if let Some(expr) = iter.next() {
275                write!(f, "{expr}")?;
276            }
277            for expr in iter {
278                write!(f, ", {expr}")?;
279            }
280            write!(f, "]")?;
281            Ok(())
282        }
283    }
284    DisplayWrapper(exprs)
285}
286
287impl PhysicalSortRequirement {
288    /// Creates a new requirement.
289    ///
290    /// If `options` is `Some(..)`, creates an `exact` requirement,
291    /// which must match both `options` and `expr`.
292    ///
293    /// If `options` is `None`, Creates a new `expr_only` requirement,
294    /// which must match only `expr`.
295    ///
296    /// See [`PhysicalSortRequirement`] for examples.
297    pub fn new(expr: Arc<dyn PhysicalExpr>, options: Option<SortOptions>) -> Self {
298        Self { expr, options }
299    }
300
301    /// Returns whether this requirement is equal or more specific than `other`.
302    pub fn compatible(&self, other: &Self) -> bool {
303        self.expr.eq(&other.expr)
304            && other
305                .options
306                .is_none_or(|other_opts| self.options == Some(other_opts))
307    }
308}
309
310/// Returns the SQL string representation of the given [`SortOptions`] object.
311#[inline]
312fn to_str(options: &SortOptions) -> &str {
313    match (options.descending, options.nulls_first) {
314        (true, true) => "DESC",
315        (true, false) => "DESC NULLS LAST",
316        (false, true) => "ASC",
317        (false, false) => "ASC NULLS LAST",
318    }
319}
320
321// Cross-conversion utilities between `PhysicalSortExpr` and `PhysicalSortRequirement`
322impl From<PhysicalSortExpr> for PhysicalSortRequirement {
323    fn from(value: PhysicalSortExpr) -> Self {
324        Self::new(value.expr, Some(value.options))
325    }
326}
327
328impl From<PhysicalSortRequirement> for PhysicalSortExpr {
329    /// The default sort options `ASC, NULLS LAST` when the requirement does
330    /// not specify sort options. This default is consistent with PostgreSQL.
331    ///
332    /// Reference: <https://www.postgresql.org/docs/current/queries-order.html>
333    fn from(value: PhysicalSortRequirement) -> Self {
334        let options = value
335            .options
336            .unwrap_or_else(|| SortOptions::new(false, false));
337        Self::new(value.expr, options)
338    }
339}
340
341/// This object represents a lexicographical ordering and contains a vector
342/// of `PhysicalSortExpr` objects.
343///
344/// For example, a `vec![a ASC, b DESC]` represents a lexicographical ordering
345/// that first sorts by column `a` in ascending order, then by column `b` in
346/// descending order.
347///
348/// # Invariants
349///
350/// The following always hold true for a `LexOrdering`:
351///
352/// 1. It is non-degenerate, meaning it contains at least one element.
353/// 2. It is duplicate-free, meaning it does not contain multiple entries for
354///    the same column.
355#[derive(Clone, Debug)]
356pub struct LexOrdering {
357    /// Vector of sort expressions representing the lexicographical ordering.
358    exprs: Vec<PhysicalSortExpr>,
359    /// Set of expressions in the lexicographical ordering, used to ensure
360    /// that the ordering is duplicate-free. Note that the elements in this
361    /// set are the same underlying physical expressions as in `exprs`.
362    set: IndexSet<Arc<dyn PhysicalExpr>>,
363}
364
365impl LexOrdering {
366    /// Creates a new [`LexOrdering`] from the given vector of sort expressions.
367    /// If the vector is empty, returns `None`.
368    pub fn new(exprs: impl IntoIterator<Item = PhysicalSortExpr>) -> Option<Self> {
369        let exprs = exprs.into_iter();
370        let mut candidate = Self {
371            // not valid yet; valid publicly-returned instance must be non-empty
372            exprs: Vec::new(),
373            set: IndexSet::new(),
374        };
375        for expr in exprs {
376            candidate.push(expr);
377        }
378        if candidate.exprs.is_empty() {
379            None
380        } else {
381            Some(candidate)
382        }
383    }
384
385    /// Appends an element to the back of the `LexOrdering`.
386    pub fn push(&mut self, sort_expr: PhysicalSortExpr) {
387        if self.set.insert(Arc::clone(&sort_expr.expr)) {
388            self.exprs.push(sort_expr);
389        }
390    }
391
392    /// Add all elements from `iter` to the `LexOrdering`.
393    pub fn extend(&mut self, sort_exprs: impl IntoIterator<Item = PhysicalSortExpr>) {
394        for sort_expr in sort_exprs {
395            self.push(sort_expr);
396        }
397    }
398
399    /// Returns the leading `PhysicalSortExpr` of the `LexOrdering`. Note that
400    /// this function does not return an `Option`, as a `LexOrdering` is always
401    /// non-degenerate (i.e. it contains at least one element).
402    pub fn first(&self) -> &PhysicalSortExpr {
403        // Can safely `unwrap` because `LexOrdering` is non-degenerate:
404        self.exprs.first().unwrap()
405    }
406
407    /// Returns the number of elements that can be stored in the `LexOrdering`
408    /// without reallocating.
409    pub fn capacity(&self) -> usize {
410        self.exprs.capacity()
411    }
412
413    /// Truncates the `LexOrdering`, keeping only the first `len` elements.
414    /// Returns `true` if truncation made a change, `false` otherwise. Negative
415    /// cases happen in two scenarios: (1) When `len` is greater than or equal
416    /// to the number of expressions inside this `LexOrdering`, making truncation
417    /// a no-op, or (2) when `len` is `0`, making truncation impossible.
418    pub fn truncate(&mut self, len: usize) -> bool {
419        if len == 0 || len >= self.exprs.len() {
420            return false;
421        }
422        for PhysicalSortExpr { expr, .. } in self.exprs[len..].iter() {
423            self.set.swap_remove(expr);
424        }
425        self.exprs.truncate(len);
426        true
427    }
428
429    /// Check if reversing this ordering would satisfy another ordering requirement.
430    ///
431    /// This supports **prefix matching**: if this ordering is `[A DESC, B ASC]`
432    /// and `other` is `[A ASC]`, reversing this gives `[A ASC, B DESC]`, which
433    /// satisfies `other` since `[A ASC]` is a prefix.
434    ///
435    /// # Arguments
436    /// * `other` - The ordering requirement to check against
437    ///
438    /// # Returns
439    /// `true` if reversing this ordering would satisfy `other`
440    ///
441    /// # Example
442    /// ```text
443    /// self:  [number DESC, letter ASC]
444    /// other: [number ASC]
445    /// After reversing self: [number ASC, letter DESC]  ✓ Prefix match!
446    /// ```
447    pub fn is_reverse(&self, other: &LexOrdering) -> bool {
448        let self_exprs = self.as_ref();
449        let other_exprs = other.as_ref();
450
451        if other_exprs.len() > self_exprs.len() {
452            return false;
453        }
454
455        other_exprs.iter().zip(self_exprs.iter()).all(|(req, cur)| {
456            req.expr.eq(&cur.expr) && is_reversed_sort_options(&req.options, &cur.options)
457        })
458    }
459
460    /// Returns the sort options for the given expression if one is defined in this `LexOrdering`.
461    pub fn get_sort_options(&self, expr: &dyn PhysicalExpr) -> Option<SortOptions> {
462        for e in self {
463            if e.expr.as_ref().dyn_eq(expr) {
464                return Some(e.options);
465            }
466        }
467
468        None
469    }
470}
471
472/// Check if two SortOptions represent reversed orderings.
473///
474/// Returns `true` if both `descending` and `nulls_first` are opposite.
475///
476/// # Example
477/// ```
478/// use arrow::compute::SortOptions;
479/// # use datafusion_physical_expr_common::sort_expr::is_reversed_sort_options;
480///
481/// let asc_nulls_last = SortOptions {
482///     descending: false,
483///     nulls_first: false,
484/// };
485/// let desc_nulls_first = SortOptions {
486///     descending: true,
487///     nulls_first: true,
488/// };
489///
490/// assert!(is_reversed_sort_options(&asc_nulls_last, &desc_nulls_first));
491/// assert!(is_reversed_sort_options(&desc_nulls_first, &asc_nulls_last));
492/// ```
493pub fn is_reversed_sort_options(lhs: &SortOptions, rhs: &SortOptions) -> bool {
494    lhs.descending != rhs.descending && lhs.nulls_first != rhs.nulls_first
495}
496
497impl PartialEq for LexOrdering {
498    fn eq(&self, other: &Self) -> bool {
499        let Self {
500            exprs,
501            set: _, // derived from `exprs`
502        } = self;
503        // PartialEq must be consistent with PartialOrd
504        exprs == &other.exprs
505    }
506}
507impl Eq for LexOrdering {}
508impl PartialOrd for LexOrdering {
509    /// There is a partial ordering among `LexOrdering` objects. For example, the
510    /// ordering `[a ASC]` is coarser (less) than ordering `[a ASC, b ASC]`.
511    /// If two orderings do not share a prefix, they are incomparable.
512    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
513        // PartialEq must be consistent with PartialOrd
514        self.exprs
515            .iter()
516            .zip(other.exprs.iter())
517            .all(|(lhs, rhs)| lhs == rhs)
518            .then(|| self.len().cmp(&other.len()))
519    }
520}
521
522impl<const N: usize> From<[PhysicalSortExpr; N]> for LexOrdering {
523    fn from(value: [PhysicalSortExpr; N]) -> Self {
524        // TODO: Replace this assertion with a condition on the generic parameter
525        //       when Rust supports it.
526        assert!(N > 0);
527        Self::new(value)
528            .expect("A LexOrdering from non-empty array must be non-degenerate")
529    }
530}
531
532impl Deref for LexOrdering {
533    type Target = [PhysicalSortExpr];
534
535    fn deref(&self) -> &Self::Target {
536        self.exprs.as_slice()
537    }
538}
539
540impl Display for LexOrdering {
541    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
542        let mut first = true;
543        for sort_expr in &self.exprs {
544            if first {
545                first = false;
546            } else {
547                write!(f, ", ")?;
548            }
549            write!(f, "{sort_expr}")?;
550        }
551        Ok(())
552    }
553}
554
555impl IntoIterator for LexOrdering {
556    type Item = PhysicalSortExpr;
557    type IntoIter = IntoIter<Self::Item>;
558
559    fn into_iter(self) -> Self::IntoIter {
560        self.exprs.into_iter()
561    }
562}
563
564impl<'a> IntoIterator for &'a LexOrdering {
565    type Item = &'a PhysicalSortExpr;
566    type IntoIter = std::slice::Iter<'a, PhysicalSortExpr>;
567
568    fn into_iter(self) -> Self::IntoIter {
569        self.exprs.iter()
570    }
571}
572
573impl From<LexOrdering> for Vec<PhysicalSortExpr> {
574    fn from(ordering: LexOrdering) -> Self {
575        ordering.exprs
576    }
577}
578
579/// This object represents a lexicographical ordering requirement and contains
580/// a vector of `PhysicalSortRequirement` objects.
581///
582/// For example, a `vec![a Some(ASC), b None]` represents a lexicographical
583/// requirement that firsts imposes an ordering by column `a` in ascending
584/// order, then by column `b` in *any* (ascending or descending) order. The
585/// ordering is non-degenerate, meaning it contains at least one element, and
586/// it is duplicate-free, meaning it does not contain multiple entries for the
587/// same column.
588///
589/// Note that a `LexRequirement` need not enforce the uniqueness of its sort
590/// expressions after construction like a `LexOrdering` does, because it provides
591/// no mutation methods. If such methods become necessary, we will need to
592/// enforce uniqueness like the latter object.
593#[derive(Debug, Clone, PartialEq)]
594pub struct LexRequirement {
595    reqs: Vec<PhysicalSortRequirement>,
596}
597
598impl LexRequirement {
599    /// Creates a new [`LexRequirement`] from the given vector of sort expressions.
600    /// If the vector is empty, returns `None`.
601    pub fn new(reqs: impl IntoIterator<Item = PhysicalSortRequirement>) -> Option<Self> {
602        let (non_empty, requirements) = Self::construct(reqs);
603        non_empty.then_some(requirements)
604    }
605
606    /// Returns the leading `PhysicalSortRequirement` of the `LexRequirement`.
607    /// Note that this function does not return an `Option`, as a `LexRequirement`
608    /// is always non-degenerate (i.e. it contains at least one element).
609    pub fn first(&self) -> &PhysicalSortRequirement {
610        // Can safely `unwrap` because `LexRequirement` is non-degenerate:
611        self.reqs.first().unwrap()
612    }
613
614    /// Constructs a new `LexRequirement` from the given sort requirements w/o
615    /// enforcing non-degeneracy. This function is used internally and is not
616    /// meant (or safe) for external use.
617    fn construct(
618        reqs: impl IntoIterator<Item = PhysicalSortRequirement>,
619    ) -> (bool, Self) {
620        let mut set = HashSet::new();
621        let reqs = reqs
622            .into_iter()
623            .filter_map(|r| set.insert(Arc::clone(&r.expr)).then_some(r))
624            .collect();
625        (!set.is_empty(), Self { reqs })
626    }
627}
628
629impl<const N: usize> From<[PhysicalSortRequirement; N]> for LexRequirement {
630    fn from(value: [PhysicalSortRequirement; N]) -> Self {
631        // TODO: Replace this assertion with a condition on the generic parameter
632        //       when Rust supports it.
633        assert!(N > 0);
634        let (non_empty, requirement) = Self::construct(value);
635        debug_assert!(non_empty);
636        requirement
637    }
638}
639
640impl Deref for LexRequirement {
641    type Target = [PhysicalSortRequirement];
642
643    fn deref(&self) -> &Self::Target {
644        self.reqs.as_slice()
645    }
646}
647
648impl IntoIterator for LexRequirement {
649    type Item = PhysicalSortRequirement;
650    type IntoIter = IntoIter<Self::Item>;
651
652    fn into_iter(self) -> Self::IntoIter {
653        self.reqs.into_iter()
654    }
655}
656
657impl<'a> IntoIterator for &'a LexRequirement {
658    type Item = &'a PhysicalSortRequirement;
659    type IntoIter = std::slice::Iter<'a, PhysicalSortRequirement>;
660
661    fn into_iter(self) -> Self::IntoIter {
662        self.reqs.iter()
663    }
664}
665
666impl From<LexRequirement> for Vec<PhysicalSortRequirement> {
667    fn from(requirement: LexRequirement) -> Self {
668        requirement.reqs
669    }
670}
671
672// Cross-conversion utilities between `LexOrdering` and `LexRequirement`
673impl From<LexOrdering> for LexRequirement {
674    fn from(value: LexOrdering) -> Self {
675        // Can construct directly as `value` is non-degenerate:
676        let (non_empty, requirements) =
677            Self::construct(value.into_iter().map(Into::into));
678        debug_assert!(non_empty);
679        requirements
680    }
681}
682
683impl From<LexRequirement> for LexOrdering {
684    fn from(value: LexRequirement) -> Self {
685        // Can construct directly as `value` is non-degenerate
686        Self::new(value.into_iter().map(Into::into))
687            .expect("A LexOrdering from LexRequirement must be non-degenerate")
688    }
689}
690
691/// Represents a plan's input ordering requirements. Vector elements represent
692/// alternative ordering requirements in the order of preference. The list of
693/// alternatives can be either hard or soft, depending on whether the operator
694/// can work without an input ordering.
695///
696/// # Invariants
697///
698/// The following always hold true for a `OrderingRequirements`:
699///
700/// 1. It is non-degenerate, meaning it contains at least one ordering. The
701///    absence of an input ordering requirement is represented by a `None` value
702///    in `ExecutionPlan` APIs, which return an `Option<OrderingRequirements>`.
703#[derive(Debug, Clone, PartialEq)]
704pub enum OrderingRequirements {
705    /// The operator is not able to work without one of these requirements.
706    Hard(Vec<LexRequirement>),
707    /// The operator can benefit from these input orderings when available,
708    /// but can still work in the absence of any input ordering.
709    Soft(Vec<LexRequirement>),
710}
711
712impl OrderingRequirements {
713    /// Creates a new instance from the given alternatives. If an empty list of
714    /// alternatives are given, returns `None`.
715    pub fn new_alternatives(
716        alternatives: impl IntoIterator<Item = LexRequirement>,
717        soft: bool,
718    ) -> Option<Self> {
719        let alternatives = alternatives.into_iter().collect::<Vec<_>>();
720        (!alternatives.is_empty()).then(|| {
721            if soft {
722                Self::Soft(alternatives)
723            } else {
724                Self::Hard(alternatives)
725            }
726        })
727    }
728
729    /// Creates a new instance with a single hard requirement.
730    pub fn new(requirement: LexRequirement) -> Self {
731        Self::Hard(vec![requirement])
732    }
733
734    /// Creates a new instance with a single soft requirement.
735    pub fn new_soft(requirement: LexRequirement) -> Self {
736        Self::Soft(vec![requirement])
737    }
738
739    /// Adds an alternative requirement to the list of alternatives.
740    pub fn add_alternative(&mut self, requirement: LexRequirement) {
741        match self {
742            Self::Hard(alts) | Self::Soft(alts) => alts.push(requirement),
743        }
744    }
745
746    /// Returns the first (i.e. most preferred) `LexRequirement` among
747    /// alternative requirements.
748    pub fn into_single(self) -> LexRequirement {
749        match self {
750            Self::Hard(mut alts) | Self::Soft(mut alts) => alts.swap_remove(0),
751        }
752    }
753
754    /// Returns a reference to the first (i.e. most preferred) `LexRequirement`
755    /// among alternative requirements.
756    pub fn first(&self) -> &LexRequirement {
757        match self {
758            Self::Hard(alts) | Self::Soft(alts) => &alts[0],
759        }
760    }
761
762    /// Returns all alternatives as a vector of `LexRequirement` objects and a
763    /// boolean value indicating softness/hardness of the requirements.
764    pub fn into_alternatives(self) -> (Vec<LexRequirement>, bool) {
765        match self {
766            Self::Hard(alts) => (alts, false),
767            Self::Soft(alts) => (alts, true),
768        }
769    }
770}
771
772impl From<LexRequirement> for OrderingRequirements {
773    fn from(requirement: LexRequirement) -> Self {
774        Self::new(requirement)
775    }
776}
777
778impl From<LexOrdering> for OrderingRequirements {
779    fn from(ordering: LexOrdering) -> Self {
780        Self::new(ordering.into())
781    }
782}
783
784impl Deref for OrderingRequirements {
785    type Target = [LexRequirement];
786
787    fn deref(&self) -> &Self::Target {
788        match &self {
789            Self::Hard(alts) | Self::Soft(alts) => alts.as_slice(),
790        }
791    }
792}
793
794impl DerefMut for OrderingRequirements {
795    fn deref_mut(&mut self) -> &mut Self::Target {
796        match self {
797            Self::Hard(alts) | Self::Soft(alts) => alts.as_mut_slice(),
798        }
799    }
800}
801
802#[cfg(test)]
803mod tests {
804    use super::*;
805
806    #[test]
807    fn test_is_reversed_sort_options() {
808        // Test basic reversal: ASC NULLS LAST ↔ DESC NULLS FIRST
809        let asc_nulls_last = SortOptions {
810            descending: false,
811            nulls_first: false,
812        };
813        let desc_nulls_first = SortOptions {
814            descending: true,
815            nulls_first: true,
816        };
817        assert!(is_reversed_sort_options(&asc_nulls_last, &desc_nulls_first));
818        assert!(is_reversed_sort_options(&desc_nulls_first, &asc_nulls_last));
819
820        // Test another reversal: ASC NULLS FIRST ↔ DESC NULLS LAST
821        let asc_nulls_first = SortOptions {
822            descending: false,
823            nulls_first: true,
824        };
825        let desc_nulls_last = SortOptions {
826            descending: true,
827            nulls_first: false,
828        };
829        assert!(is_reversed_sort_options(&asc_nulls_first, &desc_nulls_last));
830        assert!(is_reversed_sort_options(&desc_nulls_last, &asc_nulls_first));
831
832        // Test non-reversal: same options
833        assert!(!is_reversed_sort_options(&asc_nulls_last, &asc_nulls_last));
834        assert!(!is_reversed_sort_options(
835            &desc_nulls_first,
836            &desc_nulls_first
837        ));
838
839        // Test non-reversal: only descending differs
840        assert!(!is_reversed_sort_options(&asc_nulls_last, &desc_nulls_last));
841        assert!(!is_reversed_sort_options(&desc_nulls_last, &asc_nulls_last));
842
843        // Test non-reversal: only nulls_first differs
844        assert!(!is_reversed_sort_options(&asc_nulls_last, &asc_nulls_first));
845        assert!(!is_reversed_sort_options(&asc_nulls_first, &asc_nulls_last));
846    }
847}