1use std::cmp::Ordering;
16use std::fmt;
17use std::sync::Arc;
18
19use parse_display::Display;
20use risingwave_common_estimate_size::EstimateSize;
21use risingwave_pb::common::{PbColumnOrder, PbDirection, PbNullsAre, PbOrderType};
22
23use super::iter_util::ZipEqDebug;
24use crate::array::{Array, DataChunk};
25use crate::catalog::{FieldDisplay, Schema};
26use crate::dispatch_array_variants;
27use crate::row::Row;
28use crate::types::{DefaultOrdered, ToDatumRef};
29
30#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug, Display, Default)]
32pub enum Direction {
33 #[default]
34 #[display("ASC")]
35 Ascending,
36 #[display("DESC")]
37 Descending,
38}
39
40impl Direction {
41 fn from_protobuf(direction: &PbDirection) -> Self {
42 match direction {
43 PbDirection::Ascending => Self::Ascending,
44 PbDirection::Descending => Self::Descending,
45 PbDirection::Unspecified => unreachable!(),
46 }
47 }
48
49 fn to_protobuf(self) -> PbDirection {
50 match self {
51 Self::Ascending => PbDirection::Ascending,
52 Self::Descending => PbDirection::Descending,
53 }
54 }
55}
56
57impl Direction {
58 fn reverse(self) -> Self {
59 match self {
60 Self::Ascending => Self::Descending,
61 Self::Descending => Self::Ascending,
62 }
63 }
64}
65
66#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug, Display, Default)]
68enum NullsAre {
69 #[default]
70 #[display("LARGEST")]
71 Largest,
72 #[display("SMALLEST")]
73 Smallest,
74}
75
76impl NullsAre {
77 fn from_protobuf(nulls_are: &PbNullsAre) -> Self {
78 match nulls_are {
79 PbNullsAre::Largest => Self::Largest,
80 PbNullsAre::Smallest => Self::Smallest,
81 PbNullsAre::Unspecified => unreachable!(),
82 }
83 }
84
85 fn to_protobuf(self) -> PbNullsAre {
86 match self {
87 Self::Largest => PbNullsAre::Largest,
88 Self::Smallest => PbNullsAre::Smallest,
89 }
90 }
91}
92
93#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug, Default)]
95pub struct OrderType {
96 direction: Direction,
97 nulls_are: NullsAre,
98}
99
100impl OrderType {
101 pub fn from_protobuf(order_type: &PbOrderType) -> OrderType {
102 OrderType {
103 direction: Direction::from_protobuf(&order_type.direction()),
104 nulls_are: NullsAre::from_protobuf(&order_type.nulls_are()),
105 }
106 }
107
108 pub fn to_protobuf(self) -> PbOrderType {
109 PbOrderType {
110 direction: self.direction.to_protobuf() as _,
111 nulls_are: self.nulls_are.to_protobuf() as _,
112 }
113 }
114}
115
116impl OrderType {
117 fn new(direction: Direction, nulls_are: NullsAre) -> Self {
118 Self {
119 direction,
120 nulls_are,
121 }
122 }
123
124 fn nulls_first(direction: Direction) -> Self {
125 match direction {
126 Direction::Ascending => Self::new(direction, NullsAre::Smallest),
127 Direction::Descending => Self::new(direction, NullsAre::Largest),
128 }
129 }
130
131 fn nulls_last(direction: Direction) -> Self {
132 match direction {
133 Direction::Ascending => Self::new(direction, NullsAre::Largest),
134 Direction::Descending => Self::new(direction, NullsAre::Smallest),
135 }
136 }
137
138 pub fn from_bools(asc: Option<bool>, nulls_first: Option<bool>) -> Self {
139 let direction = match asc {
140 None => Direction::default(),
141 Some(true) => Direction::Ascending,
142 Some(false) => Direction::Descending,
143 };
144 match nulls_first {
145 None => Self::new(direction, NullsAre::default()),
146 Some(true) => Self::nulls_first(direction),
147 Some(false) => Self::nulls_last(direction),
148 }
149 }
150
151 pub fn ascending() -> Self {
154 Self {
155 direction: Direction::Ascending,
156 nulls_are: NullsAre::default(),
157 }
158 }
159
160 pub fn descending() -> Self {
162 Self {
163 direction: Direction::Descending,
164 nulls_are: NullsAre::default(),
165 }
166 }
167
168 pub fn ascending_nulls_first() -> Self {
170 Self::nulls_first(Direction::Ascending)
171 }
172
173 pub fn ascending_nulls_last() -> Self {
175 Self::nulls_last(Direction::Ascending)
176 }
177
178 pub fn descending_nulls_first() -> Self {
180 Self::nulls_first(Direction::Descending)
181 }
182
183 pub fn descending_nulls_last() -> Self {
185 Self::nulls_last(Direction::Descending)
186 }
187
188 pub fn direction(&self) -> Direction {
189 self.direction
190 }
191
192 pub fn is_ascending(&self) -> bool {
193 self.direction == Direction::Ascending
194 }
195
196 pub fn is_descending(&self) -> bool {
197 self.direction == Direction::Descending
198 }
199
200 pub fn nulls_are_largest(&self) -> bool {
201 self.nulls_are == NullsAre::Largest
202 }
203
204 pub fn nulls_are_smallest(&self) -> bool {
205 self.nulls_are == NullsAre::Smallest
206 }
207
208 pub fn nulls_are_first(&self) -> bool {
209 self.is_ascending() && self.nulls_are_smallest()
210 || self.is_descending() && self.nulls_are_largest()
211 }
212
213 pub fn nulls_are_last(&self) -> bool {
214 !self.nulls_are_first()
215 }
216
217 pub fn reverse(self) -> Self {
218 Self::new(self.direction.reverse(), self.nulls_are)
219 }
220
221 pub fn all() -> Vec<Self> {
222 vec![
223 Self::ascending_nulls_first(),
224 Self::ascending_nulls_last(),
225 Self::descending_nulls_first(),
226 Self::descending_nulls_last(),
227 ]
228 }
229}
230
231impl fmt::Display for OrderType {
232 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233 write!(f, "{}", self.direction)?;
234 if self.nulls_are != NullsAre::default() {
235 write!(
236 f,
237 " NULLS {}",
238 if self.nulls_are_first() {
239 "FIRST"
240 } else {
241 "LAST"
242 }
243 )?;
244 }
245 Ok(())
246 }
247}
248
249#[derive(Clone, PartialEq, Eq, Hash, Copy)]
254pub struct ColumnOrder {
255 pub column_index: usize,
256 pub order_type: OrderType,
257}
258
259impl ColumnOrder {
260 pub fn new(column_index: usize, order_type: OrderType) -> Self {
261 Self {
262 column_index,
263 order_type,
264 }
265 }
266
267 pub fn shift_with_offset(&mut self, offset: isize) {
269 self.column_index = (self.column_index as isize + offset) as usize;
270 }
271}
272
273impl ColumnOrder {
274 pub fn from_protobuf(column_order: &PbColumnOrder) -> Self {
275 ColumnOrder {
276 column_index: column_order.column_index as _,
277 order_type: OrderType::from_protobuf(column_order.get_order_type().unwrap()),
278 }
279 }
280
281 pub fn to_protobuf(self) -> PbColumnOrder {
282 PbColumnOrder {
283 column_index: self.column_index as _,
284 order_type: Some(self.order_type.to_protobuf()),
285 }
286 }
287}
288
289impl fmt::Display for ColumnOrder {
290 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
291 write!(f, "${} {}", self.column_index, self.order_type)
292 }
293}
294
295impl fmt::Debug for ColumnOrder {
296 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
297 write!(f, "{}", self)
298 }
299}
300
301pub fn topn_watermark_forwardable_order_key(order_by: &[ColumnOrder]) -> Option<usize> {
316 let first = order_by.first()?;
317 (first.order_type.is_ascending() && first.order_type.nulls_are_largest())
318 .then_some(first.column_index)
319}
320
321pub struct ColumnOrderDisplay<'a> {
322 pub column_order: &'a ColumnOrder,
323 pub input_schema: &'a Schema,
324}
325
326impl fmt::Display for ColumnOrderDisplay<'_> {
327 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
328 let that = self.column_order;
329 write!(
330 f,
331 "{} {}",
332 FieldDisplay(self.input_schema.fields.get(that.column_index).unwrap()),
333 that.order_type
334 )
335 }
336}
337
338#[derive(Clone, Debug)]
339pub struct HeapElem {
340 column_orders: Arc<Vec<ColumnOrder>>,
341 chunk: DataChunk,
342 chunk_idx: usize,
343 elem_idx: usize,
344 encoded_chunk: Option<Arc<Vec<Vec<u8>>>>,
349 estimated_size: usize,
350}
351
352impl HeapElem {
353 pub fn new(
354 column_orders: Arc<Vec<ColumnOrder>>,
355 chunk: DataChunk,
356 chunk_idx: usize,
357 elem_idx: usize,
358 encoded_chunk: Option<Arc<Vec<Vec<u8>>>>,
359 ) -> Self {
360 let estimated_size = encoded_chunk
361 .as_ref()
362 .map(|inner| inner.iter().map(|i| i.capacity()).sum())
363 .unwrap_or(0);
364
365 Self {
366 column_orders,
367 chunk,
368 chunk_idx,
369 elem_idx,
370 encoded_chunk,
371 estimated_size,
372 }
373 }
374
375 #[inline(always)]
376 pub fn chunk_idx(&self) -> usize {
377 self.chunk_idx
378 }
379
380 #[inline(always)]
381 pub fn elem_idx(&self) -> usize {
382 self.elem_idx
383 }
384
385 pub fn chunk(&self) -> &DataChunk {
386 &self.chunk
387 }
388}
389
390impl Ord for HeapElem {
391 fn cmp(&self, other: &Self) -> Ordering {
392 let ord = if let (Some(lhs_encoded_chunk), Some(rhs_encoded_chunk)) =
393 (self.encoded_chunk.as_ref(), other.encoded_chunk.as_ref())
394 {
395 lhs_encoded_chunk[self.elem_idx]
396 .as_slice()
397 .cmp(rhs_encoded_chunk[other.elem_idx].as_slice())
398 } else {
399 compare_rows_in_chunk(
400 &self.chunk,
401 self.elem_idx,
402 &other.chunk,
403 other.elem_idx,
404 self.column_orders.as_ref(),
405 )
406 };
407 ord.reverse()
408 }
409}
410
411impl EstimateSize for HeapElem {
412 fn estimated_heap_size(&self) -> usize {
413 self.estimated_size
414 }
415}
416
417impl PartialOrd for HeapElem {
418 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
419 Some(self.cmp(other))
420 }
421}
422
423impl PartialEq for HeapElem {
424 fn eq(&self, other: &Self) -> bool {
425 self.cmp(other) == Ordering::Equal
426 }
427}
428
429impl Eq for HeapElem {}
430
431fn generic_partial_cmp<T: PartialOrd>(
432 lhs: Option<&T>,
433 rhs: Option<&T>,
434 order_type: OrderType,
435) -> Option<Ordering> {
436 let ord = match (lhs, rhs, order_type.nulls_are) {
437 (Some(l), Some(r), _) => l.partial_cmp(r),
438 (None, None, _) => Some(Ordering::Equal),
439 (Some(_), None, NullsAre::Largest) => Some(Ordering::Less),
440 (Some(_), None, NullsAre::Smallest) => Some(Ordering::Greater),
441 (None, Some(_), NullsAre::Largest) => Some(Ordering::Greater),
442 (None, Some(_), NullsAre::Smallest) => Some(Ordering::Less),
443 };
444 ord.map(|o| {
445 if order_type.is_descending() {
446 o.reverse()
447 } else {
448 o
449 }
450 })
451}
452
453fn compare_values_in_array<'a, T>(
454 lhs_array: &'a T,
455 lhs_idx: usize,
456 rhs_array: &'a T,
457 rhs_idx: usize,
458 order_type: OrderType,
459) -> Ordering
460where
461 T: Array,
462 <T as Array>::RefItem<'a>: PartialOrd,
463{
464 generic_partial_cmp(
465 lhs_array.value_at(lhs_idx).as_ref(),
466 rhs_array.value_at(rhs_idx).as_ref(),
467 order_type,
468 )
469 .expect("items in the same `Array` type should be able to compare")
470}
471
472fn compare_rows_in_chunk(
473 lhs_data_chunk: &DataChunk,
474 lhs_idx: usize,
475 rhs_data_chunk: &DataChunk,
476 rhs_idx: usize,
477 column_orders: &[ColumnOrder],
478) -> Ordering {
479 for column_order in column_orders {
480 let lhs_array = lhs_data_chunk.column_at(column_order.column_index);
481 let rhs_array = rhs_data_chunk.column_at(column_order.column_index);
482
483 let res = dispatch_array_variants!(&**lhs_array, lhs_inner, {
484 #[expect(
485 clippy::unnecessary_fallible_conversions,
486 reason = "FIXME: Array's `into` is not safe. We should revise it."
487 )]
488 let rhs_inner = (&**rhs_array).try_into().unwrap_or_else(|_| {
489 panic!(
490 "Unmatched array types, lhs array is: {}, rhs array is: {}",
491 lhs_array.get_ident(),
492 rhs_array.get_ident(),
493 )
494 });
495 compare_values_in_array(
496 lhs_inner,
497 lhs_idx,
498 rhs_inner,
499 rhs_idx,
500 column_order.order_type,
501 )
502 });
503
504 if res != Ordering::Equal {
505 return res;
506 }
507 }
508 Ordering::Equal
509}
510
511pub fn partial_cmp_datum(
513 lhs: impl ToDatumRef,
514 rhs: impl ToDatumRef,
515 order_type: OrderType,
516) -> Option<Ordering> {
517 let lhs = lhs.to_datum_ref().map(DefaultOrdered);
518 let rhs = rhs.to_datum_ref().map(DefaultOrdered);
519 generic_partial_cmp(lhs.as_ref(), rhs.as_ref(), order_type)
520}
521
522pub fn cmp_datum(lhs: impl ToDatumRef, rhs: impl ToDatumRef, order_type: OrderType) -> Ordering {
528 let lhs = lhs.to_datum_ref();
529 let rhs = rhs.to_datum_ref();
530 partial_cmp_datum(lhs, rhs, order_type)
531 .unwrap_or_else(|| panic!("cannot compare {lhs:?} with {rhs:?}"))
532}
533
534pub fn partial_cmp_datum_iter(
536 lhs: impl IntoIterator<Item = impl ToDatumRef>,
537 rhs: impl IntoIterator<Item = impl ToDatumRef>,
538 order_types: impl IntoIterator<Item = OrderType>,
539) -> Option<Ordering> {
540 let mut order_types_iter = order_types.into_iter();
541 lhs.into_iter().partial_cmp_by(rhs, |x, y| {
542 let order_type = order_types_iter.next()?;
543 partial_cmp_datum(x, y, order_type)
544 })
545}
546
547pub fn cmp_datum_iter(
554 lhs: impl IntoIterator<Item = impl ToDatumRef>,
555 rhs: impl IntoIterator<Item = impl ToDatumRef>,
556 order_types: impl IntoIterator<Item = OrderType>,
557) -> Ordering {
558 let mut order_types_iter = order_types.into_iter();
559 lhs.into_iter().cmp_by(rhs, |x, y| {
560 let order_type = order_types_iter
561 .next()
562 .expect("number of `OrderType`s is not enough");
563 cmp_datum(x, y, order_type)
564 })
565}
566
567pub fn partial_cmp_rows(
571 lhs: impl Row,
572 rhs: impl Row,
573 order_types: &[OrderType],
574) -> Option<Ordering> {
575 if lhs.len() != rhs.len() {
576 return None;
577 }
578 lhs.iter()
579 .zip_eq_debug(rhs.iter())
580 .zip_eq_debug(order_types)
581 .try_fold(Ordering::Equal, |acc, ((l, r), order_type)| match acc {
582 Ordering::Equal => partial_cmp_datum(l, r, *order_type),
583 acc => Some(acc),
584 })
585}
586
587pub fn cmp_rows(lhs: impl Row, rhs: impl Row, order_types: &[OrderType]) -> Ordering {
594 assert_eq!(lhs.len(), rhs.len());
595 lhs.iter()
596 .zip_eq_debug(rhs.iter())
597 .zip_eq_debug(order_types)
598 .fold(Ordering::Equal, |acc, ((l, r), order_type)| match acc {
599 Ordering::Equal => cmp_datum(l, r, *order_type),
600 acc => acc,
601 })
602}
603
604pub fn cmp_rows_ascending(lhs: impl Row, rhs: impl Row) -> Ordering {
611 assert_eq!(lhs.len(), rhs.len());
612 let order_type = OrderType::ascending();
613 lhs.iter()
614 .zip_eq_debug(rhs.iter())
615 .fold(Ordering::Equal, |acc, (l, r)| match acc {
616 Ordering::Equal => cmp_datum(l, r, order_type),
617 acc => acc,
618 })
619}
620
621#[cfg(test)]
622mod tests {
623 use itertools::Itertools;
624
625 use super::*;
626 use crate::array::{ListValue, StructValue};
627 use crate::row::OwnedRow;
628 use crate::types::{DataType, Datum, ScalarImpl, StructType};
629
630 #[test]
631 fn test_order_type() {
632 assert_eq!(OrderType::default(), OrderType::ascending());
633 assert_eq!(
634 OrderType::default(),
635 OrderType::new(Direction::Ascending, NullsAre::Largest)
636 );
637 assert_eq!(
638 OrderType::default(),
639 OrderType::from_bools(Some(true), Some(false))
640 );
641 assert_eq!(OrderType::default(), OrderType::from_bools(None, None));
642
643 assert!(OrderType::ascending().is_ascending());
644 assert!(OrderType::ascending().nulls_are_largest());
645 assert!(OrderType::ascending().nulls_are_last());
646
647 assert!(OrderType::descending().is_descending());
648 assert!(OrderType::descending().nulls_are_largest());
649 assert!(OrderType::descending().nulls_are_first());
650
651 assert!(OrderType::ascending_nulls_first().is_ascending());
652 assert!(OrderType::ascending_nulls_first().nulls_are_smallest());
653 assert!(OrderType::ascending_nulls_first().nulls_are_first());
654
655 assert!(OrderType::ascending_nulls_last().is_ascending());
656 assert!(OrderType::ascending_nulls_last().nulls_are_largest());
657 assert!(OrderType::ascending_nulls_last().nulls_are_last());
658
659 assert!(OrderType::descending_nulls_first().is_descending());
660 assert!(OrderType::descending_nulls_first().nulls_are_largest());
661 assert!(OrderType::descending_nulls_first().nulls_are_first());
662
663 assert!(OrderType::descending_nulls_last().is_descending());
664 assert!(OrderType::descending_nulls_last().nulls_are_smallest());
665 assert!(OrderType::descending_nulls_last().nulls_are_last());
666
667 assert_eq!(OrderType::ascending().reverse(), OrderType::descending());
668 assert_eq!(OrderType::descending().reverse(), OrderType::ascending());
669 assert_eq!(
670 OrderType::ascending_nulls_first().reverse(),
671 OrderType::descending_nulls_last()
672 );
673 assert_eq!(
674 OrderType::ascending_nulls_last().reverse(),
675 OrderType::descending_nulls_first()
676 );
677 }
678
679 #[test]
680 fn test_compare_rows_in_chunk() {
681 let v10 = Some(ScalarImpl::Int32(42));
682 let v11 = Some(ScalarImpl::Utf8("hello".into()));
683 let v12 = Some(ScalarImpl::Float32(4.0.into()));
684 let v20 = Some(ScalarImpl::Int32(42));
685 let v21 = Some(ScalarImpl::Utf8("hell".into()));
686 let v22 = Some(ScalarImpl::Float32(3.0.into()));
687
688 let row1 = OwnedRow::new(vec![v10, v11, v12]);
689 let row2 = OwnedRow::new(vec![v20, v21, v22]);
690 let chunk = DataChunk::from_rows(
691 &[row1, row2],
692 &[DataType::Int32, DataType::Varchar, DataType::Float32],
693 );
694 let column_orders = vec![
695 ColumnOrder::new(0, OrderType::ascending()),
696 ColumnOrder::new(1, OrderType::descending()),
697 ];
698
699 assert_eq!(
700 Ordering::Equal,
701 compare_rows_in_chunk(&chunk, 0, &chunk, 0, &column_orders)
702 );
703 assert_eq!(
704 Ordering::Less,
705 compare_rows_in_chunk(&chunk, 0, &chunk, 1, &column_orders)
706 );
707 }
708
709 #[test]
710 fn test_compare_all_types() {
711 let row1 = OwnedRow::new(vec![
712 Some(ScalarImpl::Int16(16)),
713 Some(ScalarImpl::Int32(32)),
714 Some(ScalarImpl::Int64(64)),
715 Some(ScalarImpl::Float32(3.2.into())),
716 Some(ScalarImpl::Float64(6.4.into())),
717 Some(ScalarImpl::Utf8("hello".into())),
718 Some(ScalarImpl::Bool(true)),
719 Some(ScalarImpl::Decimal(10.into())),
720 Some(ScalarImpl::Interval(Default::default())),
721 Some(ScalarImpl::Date(Default::default())),
722 Some(ScalarImpl::Timestamp(Default::default())),
723 Some(ScalarImpl::Time(Default::default())),
724 Some(ScalarImpl::Struct(StructValue::new(vec![
725 Some(ScalarImpl::Int32(1)),
726 Some(ScalarImpl::Float32(3.0.into())),
727 ]))),
728 Some(ScalarImpl::List(ListValue::from_iter([1, 2]))),
729 ]);
730 let row2 = OwnedRow::new(vec![
731 Some(ScalarImpl::Int16(16)),
732 Some(ScalarImpl::Int32(32)),
733 Some(ScalarImpl::Int64(64)),
734 Some(ScalarImpl::Float32(3.2.into())),
735 Some(ScalarImpl::Float64(6.4.into())),
736 Some(ScalarImpl::Utf8("hello".into())),
737 Some(ScalarImpl::Bool(true)),
738 Some(ScalarImpl::Decimal(10.into())),
739 Some(ScalarImpl::Interval(Default::default())),
740 Some(ScalarImpl::Date(Default::default())),
741 Some(ScalarImpl::Timestamp(Default::default())),
742 Some(ScalarImpl::Time(Default::default())),
743 Some(ScalarImpl::Struct(StructValue::new(vec![
744 Some(ScalarImpl::Int32(1)),
745 Some(ScalarImpl::Float32(33333.0.into())), ]))),
747 Some(ScalarImpl::List(ListValue::from_iter([1, 2]))),
748 ]);
749
750 let column_orders = (0..row1.len())
751 .map(|i| ColumnOrder::new(i, OrderType::ascending()))
752 .collect_vec();
753
754 let chunk = DataChunk::from_rows(
755 &[row1, row2],
756 &[
757 DataType::Int16,
758 DataType::Int32,
759 DataType::Int64,
760 DataType::Float32,
761 DataType::Float64,
762 DataType::Varchar,
763 DataType::Boolean,
764 DataType::Decimal,
765 DataType::Interval,
766 DataType::Date,
767 DataType::Timestamp,
768 DataType::Time,
769 StructType::unnamed(vec![DataType::Int32, DataType::Float32]).into(),
770 DataType::Int32.list(),
771 ],
772 );
773 assert_eq!(
774 Ordering::Equal,
775 compare_rows_in_chunk(&chunk, 0, &chunk, 0, &column_orders)
776 );
777 assert_eq!(
778 Ordering::Less,
779 compare_rows_in_chunk(&chunk, 0, &chunk, 1, &column_orders)
780 );
781 }
782
783 fn common_compare_datum<CmpFn>(compare: CmpFn)
784 where
785 CmpFn: Fn(Datum, Datum, OrderType) -> Ordering,
786 {
787 assert_eq!(
788 Ordering::Equal,
789 compare(Some(42.into()), Some(42.into()), OrderType::default(),)
790 );
791 assert_eq!(Ordering::Equal, compare(None, None, OrderType::default(),));
792 assert_eq!(
793 Ordering::Less,
794 compare(Some(42.into()), Some(100.into()), OrderType::ascending(),)
795 );
796 assert_eq!(
797 Ordering::Greater,
798 compare(Some(42.into()), None, OrderType::ascending_nulls_first(),)
799 );
800 assert_eq!(
801 Ordering::Less,
802 compare(Some(42.into()), None, OrderType::ascending_nulls_last(),)
803 );
804 assert_eq!(
805 Ordering::Greater,
806 compare(Some(42.into()), None, OrderType::descending_nulls_first(),)
807 );
808 assert_eq!(
809 Ordering::Less,
810 compare(Some(42.into()), None, OrderType::descending_nulls_last(),)
811 );
812 }
813
814 fn common_compare_rows<CmpFn>(compare: CmpFn)
815 where
816 CmpFn: Fn(OwnedRow, OwnedRow, &[OrderType]) -> Ordering,
817 {
818 assert_eq!(
819 Ordering::Equal,
820 compare(
821 OwnedRow::new(vec![Some(42.into()), Some(42.into())]),
822 OwnedRow::new(vec![Some(42.into()), Some(42.into())]),
823 &[OrderType::ascending(), OrderType::ascending()],
824 )
825 );
826
827 assert_eq!(
828 Ordering::Greater,
829 compare(
830 OwnedRow::new(vec![Some(42.into()), Some(42.into())]),
831 OwnedRow::new(vec![Some(42.into()), Some(100.into())]),
832 &[OrderType::ascending(), OrderType::descending()],
833 )
834 );
835
836 assert_eq!(
837 Ordering::Less,
838 compare(
839 OwnedRow::new(vec![Some(42.into()), Some(42.into())]),
840 OwnedRow::new(vec![Some(42.into()), Some(100.into())]),
841 &[OrderType::ascending(), OrderType::ascending()],
842 )
843 );
844 }
845
846 #[test]
847 fn test_compare_datum() {
848 common_compare_datum(cmp_datum);
849 }
850
851 #[test]
852 fn test_compare_rows() {
853 common_compare_rows(cmp_rows);
854 }
855
856 #[test]
857 fn test_partial_compare_datum() {
858 common_compare_datum(|lhs, rhs, order| partial_cmp_datum(lhs, rhs, order).unwrap());
859
860 assert_eq!(
861 None,
862 partial_cmp_datum(
863 Some(ScalarImpl::from(42)),
864 Some(ScalarImpl::from("abc")),
865 OrderType::default()
866 )
867 )
868 }
869
870 #[test]
871 fn test_partial_compare_rows() {
872 common_compare_rows(|lhs, rhs, orders| partial_cmp_rows(lhs, rhs, orders).unwrap());
873
874 assert_eq!(
875 None,
876 partial_cmp_rows(
877 OwnedRow::new(vec![Some(42.into())]),
878 OwnedRow::new(vec![Some("abc".into())]),
879 &[OrderType::default()]
880 )
881 )
882 }
883}