1use crate::error::{Error, Result};
14use crate::schema::{ClusteringOrder, TableSchema};
15use crate::types::{ComparatorType, Value};
16use std::cmp::Ordering;
17
18#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
20pub struct TableId {
21 pub keyspace: String,
23 pub table: String,
25}
26
27impl TableId {
28 pub fn new(keyspace: impl Into<String>, table: impl Into<String>) -> Self {
30 Self {
31 keyspace: keyspace.into(),
32 table: table.into(),
33 }
34 }
35
36 pub fn qualified_name(&self) -> String {
38 format!("{}.{}", self.keyspace, self.table)
39 }
40}
41
42impl std::fmt::Display for TableId {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 write!(f, "{}.{}", self.keyspace, self.table)
45 }
46}
47
48#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
63pub struct Mutation {
64 pub table: TableId,
66 pub partition_key: PartitionKey,
68 pub clustering_key: Option<ClusteringKey>,
70 pub operations: Vec<CellOperation>,
72 pub timestamp_micros: i64,
74 pub ttl_seconds: Option<u32>,
80 pub partition_tombstone: Option<PartitionTombstone>,
82 pub range_tombstones: Vec<RangeTombstone>,
84 #[serde(default)]
97 pub local_deletion_time: Option<i32>,
98 #[serde(default)]
114 pub row_tombstone: Option<(i64, i32)>,
115 #[serde(default)]
134 pub cell_write_timestamps: Option<std::collections::HashMap<String, i64>>,
135}
136
137impl Mutation {
138 pub fn new(
140 table: TableId,
141 partition_key: PartitionKey,
142 clustering_key: Option<ClusteringKey>,
143 operations: Vec<CellOperation>,
144 timestamp_micros: i64,
145 ttl_seconds: Option<u32>,
146 ) -> Self {
147 Self {
148 table,
149 partition_key,
150 clustering_key,
151 operations,
152 timestamp_micros,
153 ttl_seconds,
154 partition_tombstone: None,
155 range_tombstones: Vec::new(),
156 local_deletion_time: None,
157 row_tombstone: None,
158 cell_write_timestamps: None,
159 }
160 }
161
162 pub fn cell_write_timestamp(&self, column: &str) -> i64 {
167 self.cell_write_timestamps
168 .as_ref()
169 .and_then(|m| m.get(column).copied())
170 .unwrap_or(self.timestamp_micros)
171 }
172
173 #[must_use]
181 pub fn with_row_tombstone(mut self, deletion_time: i64, ldt: i32) -> Self {
182 self.row_tombstone = Some((deletion_time, ldt));
183 self
184 }
185
186 pub fn with_local_deletion_time(mut self, local_deletion_time: i32) -> Self {
192 self.local_deletion_time = Some(local_deletion_time);
193 self
194 }
195
196 pub fn effective_local_deletion_time(&self) -> i32 {
200 self.local_deletion_time
201 .unwrap_or((self.timestamp_micros / 1_000_000) as i32)
202 }
203
204 pub fn decorated_key(&self, schema: &TableSchema) -> Result<DecoratedKey> {
206 self.partition_key.to_decorated_key(schema)
207 }
208}
209
210#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
215pub struct PartitionTombstone {
216 pub deletion_time: i64,
218 pub local_deletion_time: i32,
220}
221
222#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
227pub struct RangeTombstone {
228 pub start: ClusteringBound,
230 pub end: ClusteringBound,
232 pub deletion_time: i64,
234 pub local_deletion_time: i32,
236}
237
238#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
243pub enum ClusteringBound {
244 Inclusive(ClusteringKey),
246 Exclusive(ClusteringKey),
248 Bottom,
250 Top,
252}
253
254#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
268pub enum CellOperation {
269 Write {
271 column: String,
273 value: Value,
275 },
276 WriteWithTtl {
282 column: String,
284 value: Value,
286 ttl_seconds: u32,
288 },
289 Delete {
291 column: String,
293 #[serde(default)]
313 local_deletion_time: Option<i32>,
314 },
315 DeleteRow,
317 WriteComplexElement {
334 column: String,
336 cell_path: Vec<u8>,
341 value: Option<Value>,
346 timestamp_micros: i64,
350 ttl_seconds: Option<u32>,
352 local_deletion_time: Option<i32>,
356 is_deleted: bool,
368 },
369 ComplexDeletion {
381 column: String,
383 marked_for_delete_at: i64,
385 local_deletion_time: i32,
387 },
388}
389
390#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
395pub struct PartitionKey {
396 pub columns: Vec<(String, Value)>,
398}
399
400impl PartitionKey {
401 pub fn new(columns: Vec<(String, Value)>) -> Self {
403 Self { columns }
404 }
405
406 pub fn single(column: impl Into<String>, value: Value) -> Self {
408 Self {
409 columns: vec![(column.into(), value)],
410 }
411 }
412
413 pub fn to_bytes(&self, schema: &TableSchema) -> Result<Vec<u8>> {
419 if self.columns.is_empty() {
420 return Err(Error::InvalidInput("Empty partition key".to_string()));
421 }
422
423 if self.columns.len() != schema.partition_keys.len() {
425 return Err(Error::InvalidInput(format!(
426 "Partition key column count mismatch: expected {}, got {}",
427 schema.partition_keys.len(),
428 self.columns.len()
429 )));
430 }
431
432 if self.columns.len() == 1 {
435 return self.serialize_value(&self.columns[0].1, &schema.partition_keys[0]);
436 }
437
438 let mut result = Vec::new();
439
440 for (i, (_, value)) in self.columns.iter().enumerate() {
443 let value_bytes = self.serialize_value(value, &schema.partition_keys[i])?;
444 let len = value_bytes.len();
445 if len > u16::MAX as usize {
446 return Err(Error::InvalidInput(format!(
447 "Partition key component too large: {} bytes",
448 len
449 )));
450 }
451 result.extend_from_slice(&(len as u16).to_be_bytes());
453 result.extend_from_slice(&value_bytes);
454 result.push(0x00);
455 }
456
457 Ok(result)
458 }
459
460 pub fn to_decorated_key(&self, schema: &TableSchema) -> Result<DecoratedKey> {
462 let key_bytes = self.to_bytes(schema)?;
463 let token = calculate_murmur3_token(&key_bytes)?;
464 Ok(DecoratedKey::new(token, key_bytes))
465 }
466
467 pub fn from_bytes(data: &[u8], schema: &TableSchema) -> Result<Self> {
472 if schema.partition_keys.is_empty() {
473 return Err(Error::InvalidInput(
474 "Schema has no partition keys".to_string(),
475 ));
476 }
477
478 if data.is_empty() {
479 return Err(Error::InvalidInput("Empty partition key bytes".to_string()));
480 }
481
482 let columns =
485 crate::storage::partition_key_codec::decode_partition_key_columns(data, schema)?;
486
487 Ok(PartitionKey { columns })
488 }
489
490 fn serialize_value(
492 &self,
493 value: &Value,
494 key_column: &crate::schema::KeyColumn,
495 ) -> Result<Vec<u8>> {
496 let comparator = ComparatorType::from_data_type(&key_column.data_type)?;
498
499 serialize_value_bytes(value, &comparator)
500 }
501}
502
503#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
508pub struct ClusteringKey {
509 pub columns: Vec<(String, Value)>,
511}
512
513impl ClusteringKey {
514 pub fn new(columns: Vec<(String, Value)>) -> Self {
516 Self { columns }
517 }
518
519 pub fn single(column: impl Into<String>, value: Value) -> Self {
521 Self {
522 columns: vec![(column.into(), value)],
523 }
524 }
525
526 pub fn compare(&self, other: &Self, schema: &TableSchema) -> Result<Ordering> {
531 if self.columns.len() > schema.clustering_keys.len()
539 || other.columns.len() > schema.clustering_keys.len()
540 {
541 return Err(Error::Schema(format!(
542 "Clustering key has more columns than schema: {} / {} > {}",
543 self.columns.len(),
544 other.columns.len(),
545 schema.clustering_keys.len()
546 )));
547 }
548
549 for (i, cluster_col) in schema.clustering_keys.iter().enumerate() {
550 let a_val = self.columns.get(i).map(|(_, v)| v).unwrap_or(&Value::Null);
552 let b_val = other.columns.get(i).map(|(_, v)| v).unwrap_or(&Value::Null);
553
554 let final_ordering = match (a_val, b_val) {
562 (Value::Null, Value::Null) => Ordering::Equal,
564 (Value::Null, _) => Ordering::Less,
567 (_, Value::Null) => Ordering::Greater,
568 (_, _) => {
571 let ordering = compare_values(a_val, b_val)?;
572 if cluster_col.order == ClusteringOrder::Desc {
573 ordering.reverse()
574 } else {
575 ordering
576 }
577 }
578 };
579
580 if final_ordering != Ordering::Equal {
581 return Ok(final_ordering);
582 }
583 }
584
585 Ok(Ordering::Equal)
586 }
587}
588
589impl Ord for ClusteringKey {
590 fn cmp(&self, other: &Self) -> Ordering {
591 for ((_, a_val), (_, b_val)) in self.columns.iter().zip(other.columns.iter()) {
595 let ordering = compare_values(a_val, b_val).unwrap_or_else(|_| {
596 format!("{a_val:?}").cmp(&format!("{b_val:?}"))
600 });
601 if ordering != Ordering::Equal {
602 return ordering;
603 }
604 }
605 self.columns.len().cmp(&other.columns.len())
606 }
607}
608
609impl PartialOrd for ClusteringKey {
610 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
611 Some(self.cmp(other))
612 }
613}
614
615impl Eq for ClusteringKey {}
616
617#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
632pub struct DecoratedKey {
633 pub token: i64,
635 pub key: Vec<u8>,
637}
638
639impl DecoratedKey {
640 pub fn new(token: i64, key: Vec<u8>) -> Self {
642 Self { token, key }
643 }
644
645 pub fn from_key_bytes(key_bytes: Vec<u8>) -> Result<Self> {
647 let token = calculate_murmur3_token(&key_bytes)?;
648 Ok(Self::new(token, key_bytes))
649 }
650}
651
652impl Ord for DecoratedKey {
653 fn cmp(&self, other: &Self) -> Ordering {
654 match self.token.cmp(&other.token) {
656 Ordering::Equal => {
657 self.key.cmp(&other.key)
659 }
660 other => other,
661 }
662 }
663}
664
665impl PartialOrd for DecoratedKey {
666 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
667 Some(self.cmp(other))
668 }
669}
670
671fn calculate_murmur3_token(key_bytes: &[u8]) -> Result<i64> {
678 if key_bytes.is_empty() {
679 return Ok(i64::MIN);
680 }
681
682 Ok(crate::util::cassandra_murmur3::cassandra_murmur3_token(
683 key_bytes,
684 ))
685}
686
687fn serialize_value_bytes(value: &Value, comparator: &ComparatorType) -> Result<Vec<u8>> {
692 match (value, comparator) {
693 (Value::Null, _) => Ok(Vec::new()),
694
695 (Value::Boolean(b), ComparatorType::Boolean) => Ok(vec![if *b { 1 } else { 0 }]),
696
697 (Value::TinyInt(n), ComparatorType::TinyInt) => Ok(vec![*n as u8]),
698
699 (Value::SmallInt(n), ComparatorType::SmallInt) => Ok(n.to_be_bytes().to_vec()),
700
701 (Value::Integer(n), ComparatorType::Int) => Ok(n.to_be_bytes().to_vec()),
702
703 (Value::BigInt(n), ComparatorType::BigInt) => Ok(n.to_be_bytes().to_vec()),
704
705 (Value::Counter(n), ComparatorType::Counter) => Ok(n.to_be_bytes().to_vec()),
706
707 (Value::Float32(f), ComparatorType::Float32) => Ok(f.to_bits().to_be_bytes().to_vec()),
708
709 (Value::Float(f), ComparatorType::Float) => Ok(f.to_bits().to_be_bytes().to_vec()),
710
711 (Value::Text(s), ComparatorType::Text) => Ok(s.as_bytes().to_vec()),
712
713 (Value::Blob(bytes), ComparatorType::Blob) => Ok(bytes.clone()),
714
715 (Value::Timestamp(millis), ComparatorType::Timestamp) => Ok(millis.to_be_bytes().to_vec()),
716
717 (Value::Date(days), ComparatorType::Date) => {
718 let stored = days.wrapping_sub(i32::MIN) as u32;
720 Ok(stored.to_be_bytes().to_vec())
721 }
722
723 (Value::Uuid(bytes), ComparatorType::Uuid) => Ok(bytes.to_vec()),
724
725 (Value::Time(nanos), ComparatorType::Custom(name)) if name == "time" => {
727 Ok(nanos.to_be_bytes().to_vec())
728 }
729
730 (Value::Inet(bytes), ComparatorType::Custom(name)) if name == "inet" => Ok(bytes.clone()),
731
732 (Value::Varint(bytes), ComparatorType::Varint) => Ok(bytes.clone()),
733
734 (Value::Decimal { scale, unscaled }, ComparatorType::Decimal) => {
735 let mut result = Vec::new();
737 result.extend_from_slice(&scale.to_be_bytes());
738 result.extend_from_slice(unscaled);
739 Ok(result)
740 }
741
742 (
743 Value::Duration {
744 months,
745 days,
746 nanos,
747 },
748 ComparatorType::Duration,
749 ) => {
750 let mut result = Vec::new();
752 result.extend_from_slice(&months.to_be_bytes());
753 result.extend_from_slice(&days.to_be_bytes());
754 result.extend_from_slice(&nanos.to_be_bytes());
755 Ok(result)
756 }
757
758 _ => Err(Error::InvalidInput(format!(
759 "Type mismatch: value {:?} does not match comparator {:?}",
760 value, comparator
761 ))),
762 }
763}
764
765fn compare_values(a: &Value, b: &Value) -> Result<Ordering> {
767 use Value::*;
768
769 match (a, b) {
770 (Null, Null) => Ok(Ordering::Equal),
771 (Null, _) => Ok(Ordering::Less),
772 (_, Null) => Ok(Ordering::Greater),
773
774 (Boolean(a), Boolean(b)) => Ok(a.cmp(b)),
775 (TinyInt(a), TinyInt(b)) => Ok(a.cmp(b)),
776 (SmallInt(a), SmallInt(b)) => Ok(a.cmp(b)),
777 (Integer(a), Integer(b)) => Ok(a.cmp(b)),
778 (BigInt(a), BigInt(b)) => Ok(a.cmp(b)),
779 (Counter(a), Counter(b)) => Ok(a.cmp(b)),
780 (Float32(a), Float32(b)) => Ok(a.partial_cmp(b).unwrap_or(Ordering::Equal)),
781 (Float(a), Float(b)) => Ok(a.partial_cmp(b).unwrap_or(Ordering::Equal)),
782 (Text(a), Text(b)) => Ok(a.cmp(b)),
783 (Blob(a), Blob(b)) => Ok(a.cmp(b)),
784 (Timestamp(a), Timestamp(b)) => Ok(a.cmp(b)),
785 (Date(a), Date(b)) => Ok(a.cmp(b)),
786 (Time(a), Time(b)) => Ok(a.cmp(b)),
787 (Uuid(a), Uuid(b)) => Ok(a.cmp(b)),
788 (Inet(a), Inet(b)) => Ok(a.cmp(b)),
789
790 (List(a), List(b)) | (Set(a), Set(b)) => {
792 for (elem_a, elem_b) in a.iter().zip(b.iter()) {
793 let ord = compare_values(elem_a, elem_b)?;
794 if ord != Ordering::Equal {
795 return Ok(ord);
796 }
797 }
798 Ok(a.len().cmp(&b.len()))
799 }
800 (Map(a), Map(b)) => {
801 for ((ka, va), (kb, vb)) in a.iter().zip(b.iter()) {
802 let key_ord = compare_values(ka, kb)?;
803 if key_ord != Ordering::Equal {
804 return Ok(key_ord);
805 }
806 let val_ord = compare_values(va, vb)?;
807 if val_ord != Ordering::Equal {
808 return Ok(val_ord);
809 }
810 }
811 Ok(a.len().cmp(&b.len()))
812 }
813 (Tuple(a), Tuple(b)) => {
814 for (fa, fb) in a.iter().zip(b.iter()) {
815 let ord = compare_values(fa, fb)?;
816 if ord != Ordering::Equal {
817 return Ok(ord);
818 }
819 }
820 Ok(a.len().cmp(&b.len()))
821 }
822
823 (Frozen(a), Frozen(b)) => compare_values(a, b),
825
826 _ => Err(Error::InvalidInput(format!(
827 "Cannot compare values of different types: {:?} vs {:?}",
828 a, b
829 ))),
830 }
831}
832
833#[cfg(test)]
834mod tests {
835 use super::*;
836 use crate::schema::{ClusteringColumn, ClusteringOrder, KeyColumn};
837 use std::collections::HashMap;
838
839 fn create_test_schema(
840 partition_cols: Vec<(&str, &str)>,
841 clustering_cols: Vec<(&str, &str, ClusteringOrder)>,
842 ) -> TableSchema {
843 TableSchema {
844 keyspace: "test_ks".to_string(),
845 table: "test_table".to_string(),
846 partition_keys: partition_cols
847 .into_iter()
848 .enumerate()
849 .map(|(i, (name, data_type))| KeyColumn {
850 name: name.to_string(),
851 data_type: data_type.to_string(),
852 position: i,
853 })
854 .collect(),
855 clustering_keys: clustering_cols
856 .into_iter()
857 .enumerate()
858 .map(|(i, (name, data_type, order))| ClusteringColumn {
859 name: name.to_string(),
860 data_type: data_type.to_string(),
861 position: i,
862 order,
863 })
864 .collect(),
865 columns: vec![],
866 comments: HashMap::new(),
867 dropped_columns: HashMap::new(),
868 }
869 }
870
871 #[test]
872 fn test_table_id() {
873 let table_id = TableId::new("my_keyspace", "my_table");
874 assert_eq!(table_id.keyspace, "my_keyspace");
875 assert_eq!(table_id.table, "my_table");
876 assert_eq!(table_id.qualified_name(), "my_keyspace.my_table");
877 assert_eq!(table_id.to_string(), "my_keyspace.my_table");
878 }
879
880 #[test]
881 fn test_partition_key_single_int() {
882 let schema = create_test_schema(vec![("id", "int")], vec![]);
883 let pk = PartitionKey::single("id", Value::Integer(42));
884
885 let bytes = pk.to_bytes(&schema).unwrap();
886 assert_eq!(bytes, vec![0x00, 0x00, 0x00, 0x2A]);
888 }
889
890 #[test]
891 fn test_partition_key_multi_component() {
892 let schema = create_test_schema(vec![("id", "int"), ("name", "text")], vec![]);
893 let pk = PartitionKey::new(vec![
894 ("id".to_string(), Value::Integer(42)),
895 ("name".to_string(), Value::Text("hello".to_string())),
896 ]);
897
898 let bytes = pk.to_bytes(&schema).unwrap();
899 let expected = vec![
902 0x00, 0x04, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x05, b'h', b'e', b'l', b'l', b'o', 0x00, ];
909 assert_eq!(bytes, expected);
910 }
911
912 #[test]
913 fn test_partition_key_three_components() {
914 let schema = create_test_schema(
916 vec![("symbol", "text"), ("exchange", "text"), ("bucket", "int")],
917 vec![],
918 );
919 let pk = PartitionKey::new(vec![
920 ("symbol".to_string(), Value::Text("AAPL".to_string())),
921 ("exchange".to_string(), Value::Text("NYSE".to_string())),
922 ("bucket".to_string(), Value::Integer(100)),
923 ]);
924
925 let bytes = pk.to_bytes(&schema).unwrap();
926 let expected = vec![
928 0x00, 0x04, b'A', b'A', b'P', b'L', 0x00, 0x00, 0x04, b'N', b'Y', b'S', b'E', 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x64, 0x00, ];
938 assert_eq!(bytes, expected);
939 }
940
941 #[test]
942 fn test_decorated_key_ordering() {
943 let dk1 = DecoratedKey::new(100, vec![1, 2, 3]);
944 let dk2 = DecoratedKey::new(200, vec![1, 2, 3]);
945 let dk3 = DecoratedKey::new(100, vec![1, 2, 4]);
946
947 assert!(dk1 < dk2);
949 assert!(dk2 > dk1);
950
951 assert!(dk1 < dk3);
953 assert!(dk3 > dk1);
954
955 let dk4 = DecoratedKey::new(100, vec![1, 2, 3]);
957 assert_eq!(dk1, dk4);
958 }
959
960 #[test]
961 fn test_murmur3_token_empty_key() {
962 let token = calculate_murmur3_token(&[]).unwrap();
963 assert_eq!(token, i64::MIN);
964 }
965
966 #[test]
967 fn test_murmur3_token_deterministic() {
968 let key_bytes = b"test_key";
969 let token1 = calculate_murmur3_token(key_bytes).unwrap();
970 let token2 = calculate_murmur3_token(key_bytes).unwrap();
971 assert_eq!(token1, token2, "Token calculation should be deterministic");
972 }
973
974 #[test]
975 fn test_murmur3_token_different_keys() {
976 let token1 = calculate_murmur3_token(b"key1").unwrap();
977 let token2 = calculate_murmur3_token(b"key2").unwrap();
978 assert_ne!(
979 token1, token2,
980 "Different keys should produce different tokens"
981 );
982 }
983
984 #[test]
985 fn test_murmur3_token_matches_cassandra_for_composite_uuid_key() {
986 let key_bytes = vec![
989 0x00, 0x10, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x40, 0x00, 0x80, 0x00, 0x00, 0x00,
990 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x40,
991 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x00,
992 ];
993
994 let token = calculate_murmur3_token(&key_bytes).unwrap();
995 assert_eq!(token, -5_116_541_970_184_546_410);
996 }
997
998 #[test]
999 fn test_decorated_key_from_bytes() {
1000 let key_bytes = vec![0x00, 0x00, 0x00, 0x2A]; let dk = DecoratedKey::from_key_bytes(key_bytes.clone()).unwrap();
1002
1003 assert_eq!(dk.key, key_bytes);
1004 let expected_token = calculate_murmur3_token(&key_bytes).unwrap();
1006 assert_eq!(dk.token, expected_token);
1007 }
1008
1009 #[test]
1010 fn test_clustering_key_ordering() {
1011 let schema = create_test_schema(
1012 vec![("id", "int")],
1013 vec![("ts", "timestamp", ClusteringOrder::Asc)],
1014 );
1015
1016 let ck1 = ClusteringKey::single("ts", Value::Timestamp(1000));
1017 let ck2 = ClusteringKey::single("ts", Value::Timestamp(2000));
1018
1019 let ordering = ck1.compare(&ck2, &schema).unwrap();
1020 assert_eq!(ordering, Ordering::Less);
1021 }
1022
1023 #[test]
1024 fn test_clustering_key_desc_ordering() {
1025 let schema = create_test_schema(
1026 vec![("id", "int")],
1027 vec![("ts", "timestamp", ClusteringOrder::Desc)],
1028 );
1029
1030 let ck1 = ClusteringKey::single("ts", Value::Timestamp(1000));
1031 let ck2 = ClusteringKey::single("ts", Value::Timestamp(2000));
1032
1033 let ordering = ck1.compare(&ck2, &schema).unwrap();
1034 assert_eq!(ordering, Ordering::Greater);
1036 }
1037
1038 #[test]
1041 fn test_clustering_null_sorts_first_asc() {
1042 let schema = create_test_schema(
1045 vec![("id", "int")],
1046 vec![("ts", "timestamp", ClusteringOrder::Asc)],
1047 );
1048
1049 let null_ck = ClusteringKey::single("ts", Value::Null);
1050 let valued_ck = ClusteringKey::single("ts", Value::Timestamp(1000));
1051
1052 assert_eq!(
1053 null_ck.compare(&valued_ck, &schema).unwrap(),
1054 Ordering::Less,
1055 "NULL must sort before a value on ASC"
1056 );
1057 assert_eq!(
1058 valued_ck.compare(&null_ck, &schema).unwrap(),
1059 Ordering::Greater,
1060 "value must sort after NULL on ASC"
1061 );
1062 }
1063
1064 #[test]
1065 fn test_clustering_null_sorts_first_desc() {
1066 let schema = create_test_schema(
1070 vec![("id", "int")],
1071 vec![("ts", "timestamp", ClusteringOrder::Desc)],
1072 );
1073
1074 let null_ck = ClusteringKey::single("ts", Value::Null);
1075 let valued_ck = ClusteringKey::single("ts", Value::Timestamp(1000));
1076
1077 assert_eq!(
1078 null_ck.compare(&valued_ck, &schema).unwrap(),
1079 Ordering::Less,
1080 "NULL must sort before a value even on DESC"
1081 );
1082 assert_eq!(
1083 valued_ck.compare(&null_ck, &schema).unwrap(),
1084 Ordering::Greater,
1085 "value must sort after NULL even on DESC"
1086 );
1087
1088 let null_ck2 = ClusteringKey::single("ts", Value::Null);
1090 assert_eq!(
1091 null_ck.compare(&null_ck2, &schema).unwrap(),
1092 Ordering::Equal
1093 );
1094 }
1095
1096 #[test]
1097 fn test_clustering_empty_vs_valued_asc() {
1098 let schema = create_test_schema(
1101 vec![("id", "int")],
1102 vec![("c", "text", ClusteringOrder::Asc)],
1103 );
1104
1105 let empty_ck = ClusteringKey::single("c", Value::Text(String::new()));
1106 let valued_ck = ClusteringKey::single("c", Value::Text("a".to_string()));
1107
1108 assert_eq!(
1109 empty_ck.compare(&valued_ck, &schema).unwrap(),
1110 Ordering::Less,
1111 "empty text must sort before non-empty on ASC"
1112 );
1113 }
1114
1115 #[test]
1116 fn test_clustering_empty_vs_valued_desc() {
1117 let schema = create_test_schema(
1120 vec![("id", "int")],
1121 vec![("c", "text", ClusteringOrder::Desc)],
1122 );
1123
1124 let empty_ck = ClusteringKey::single("c", Value::Text(String::new()));
1125 let valued_ck = ClusteringKey::single("c", Value::Text("a".to_string()));
1126
1127 assert_eq!(
1128 empty_ck.compare(&valued_ck, &schema).unwrap(),
1129 Ordering::Greater,
1130 "empty text must sort after non-empty on DESC (type-routed reversal)"
1131 );
1132 assert_eq!(
1133 valued_ck.compare(&empty_ck, &schema).unwrap(),
1134 Ordering::Less
1135 );
1136 }
1137
1138 #[test]
1139 fn test_clustering_null_first_on_second_desc_component() {
1140 let schema = create_test_schema(
1143 vec![("id", "int")],
1144 vec![
1145 ("a", "int", ClusteringOrder::Asc),
1146 ("b", "timestamp", ClusteringOrder::Desc),
1147 ],
1148 );
1149
1150 let null_b = ClusteringKey::new(vec![
1151 ("a".to_string(), Value::Integer(1)),
1152 ("b".to_string(), Value::Null),
1153 ]);
1154 let valued_b = ClusteringKey::new(vec![
1155 ("a".to_string(), Value::Integer(1)),
1156 ("b".to_string(), Value::Timestamp(5000)),
1157 ]);
1158
1159 assert_eq!(
1160 null_b.compare(&valued_b, &schema).unwrap(),
1161 Ordering::Less,
1162 "NULL on a DESC sub-component still sorts first"
1163 );
1164 }
1165
1166 #[test]
1167 fn test_clustering_absent_trailing_desc_component_sorts_first() {
1168 let schema = create_test_schema(
1174 vec![("id", "int")],
1175 vec![
1176 ("a", "int", ClusteringOrder::Asc),
1177 ("b", "timestamp", ClusteringOrder::Desc),
1178 ],
1179 );
1180
1181 let absent_b = ClusteringKey::new(vec![("a".to_string(), Value::Integer(1))]);
1183 let valued_b = ClusteringKey::new(vec![
1184 ("a".to_string(), Value::Integer(1)),
1185 ("b".to_string(), Value::Timestamp(5000)),
1186 ]);
1187
1188 assert_eq!(
1189 absent_b.compare(&valued_b, &schema).unwrap(),
1190 Ordering::Less,
1191 "absent trailing DESC component must sort first (null-first), not Equal"
1192 );
1193 assert_eq!(
1194 valued_b.compare(&absent_b, &schema).unwrap(),
1195 Ordering::Greater,
1196 "present value must sort after an absent trailing component"
1197 );
1198
1199 let explicit_null_b = ClusteringKey::new(vec![
1202 ("a".to_string(), Value::Integer(1)),
1203 ("b".to_string(), Value::Null),
1204 ]);
1205 assert_eq!(
1206 absent_b.compare(&explicit_null_b, &schema).unwrap(),
1207 Ordering::Equal,
1208 "absent trailing component == explicit NULL at the same position"
1209 );
1210 assert_eq!(
1211 explicit_null_b.compare(&absent_b, &schema).unwrap(),
1212 Ordering::Equal,
1213 );
1214 }
1215
1216 #[test]
1217 fn test_clustering_absent_trailing_asc_component_sorts_first() {
1218 let schema = create_test_schema(
1221 vec![("id", "int")],
1222 vec![
1223 ("a", "int", ClusteringOrder::Asc),
1224 ("b", "int", ClusteringOrder::Asc),
1225 ],
1226 );
1227
1228 let absent_b = ClusteringKey::new(vec![("a".to_string(), Value::Integer(7))]);
1229 let valued_b = ClusteringKey::new(vec![
1230 ("a".to_string(), Value::Integer(7)),
1231 ("b".to_string(), Value::Integer(0)),
1232 ]);
1233
1234 assert_eq!(
1235 absent_b.compare(&valued_b, &schema).unwrap(),
1236 Ordering::Less,
1237 "absent trailing ASC component must sort first"
1238 );
1239 assert_eq!(
1240 valued_b.compare(&absent_b, &schema).unwrap(),
1241 Ordering::Greater,
1242 );
1243 }
1244
1245 #[test]
1246 fn test_clustering_both_absent_trailing_component_equal() {
1247 let schema = create_test_schema(
1249 vec![("id", "int")],
1250 vec![
1251 ("a", "int", ClusteringOrder::Asc),
1252 ("b", "timestamp", ClusteringOrder::Desc),
1253 ],
1254 );
1255
1256 let a1 = ClusteringKey::new(vec![("a".to_string(), Value::Integer(3))]);
1257 let a2 = ClusteringKey::new(vec![("a".to_string(), Value::Integer(3))]);
1258 assert_eq!(a1.compare(&a2, &schema).unwrap(), Ordering::Equal);
1259 }
1260
1261 #[test]
1262 fn test_mutation_creation() {
1263 let table_id = TableId::new("ks", "table");
1264 let pk = PartitionKey::single("id", Value::Integer(1));
1265 let ops = vec![CellOperation::Write {
1266 column: "name".to_string(),
1267 value: Value::Text("Alice".to_string()),
1268 }];
1269
1270 let mutation = Mutation::new(table_id.clone(), pk, None, ops, 1234567890, None);
1271
1272 assert_eq!(mutation.table.keyspace, "ks");
1273 assert_eq!(mutation.table.table, "table");
1274 assert_eq!(mutation.timestamp_micros, 1234567890);
1275 assert_eq!(mutation.ttl_seconds, None);
1276 assert_eq!(mutation.operations.len(), 1);
1277 }
1278
1279 #[test]
1280 fn test_cell_operation_write() {
1281 let op = CellOperation::Write {
1282 column: "age".to_string(),
1283 value: Value::Integer(30),
1284 };
1285
1286 match op {
1287 CellOperation::Write { column, value } => {
1288 assert_eq!(column, "age");
1289 assert_eq!(value, Value::Integer(30));
1290 }
1291 _ => panic!("Expected Write operation"),
1292 }
1293 }
1294
1295 #[test]
1296 fn test_cell_operation_delete() {
1297 let op = CellOperation::Delete {
1298 column: "name".to_string(),
1299 local_deletion_time: None,
1300 };
1301
1302 match op {
1303 CellOperation::Delete { column, .. } => {
1304 assert_eq!(column, "name");
1305 }
1306 _ => panic!("Expected Delete operation"),
1307 }
1308 }
1309
1310 #[test]
1311 fn test_cell_operation_delete_row() {
1312 let op = CellOperation::DeleteRow;
1313 assert!(matches!(op, CellOperation::DeleteRow));
1314 }
1315
1316 #[test]
1317 fn test_serialize_value_types() {
1318 let bytes = serialize_value_bytes(&Value::Boolean(true), &ComparatorType::Boolean).unwrap();
1320 assert_eq!(bytes, vec![1]);
1321
1322 let bytes = serialize_value_bytes(&Value::Integer(42), &ComparatorType::Int).unwrap();
1324 assert_eq!(bytes, vec![0x00, 0x00, 0x00, 0x2A]);
1325
1326 let bytes = serialize_value_bytes(&Value::Text("hello".to_string()), &ComparatorType::Text)
1328 .unwrap();
1329 assert_eq!(bytes, b"hello");
1330
1331 let uuid_bytes = [
1333 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB,
1334 0xCD, 0xEF,
1335 ];
1336 let bytes = serialize_value_bytes(&Value::Uuid(uuid_bytes), &ComparatorType::Uuid).unwrap();
1337 assert_eq!(bytes, uuid_bytes);
1338 }
1339
1340 #[test]
1341 fn test_compare_values() {
1342 assert_eq!(
1343 compare_values(&Value::Integer(1), &Value::Integer(2)).unwrap(),
1344 Ordering::Less
1345 );
1346 assert_eq!(
1347 compare_values(&Value::Integer(2), &Value::Integer(1)).unwrap(),
1348 Ordering::Greater
1349 );
1350 assert_eq!(
1351 compare_values(&Value::Integer(1), &Value::Integer(1)).unwrap(),
1352 Ordering::Equal
1353 );
1354
1355 assert_eq!(
1357 compare_values(&Value::Null, &Value::Integer(1)).unwrap(),
1358 Ordering::Less
1359 );
1360 assert_eq!(
1361 compare_values(&Value::Integer(1), &Value::Null).unwrap(),
1362 Ordering::Greater
1363 );
1364 }
1365
1366 #[test]
1367 fn test_partition_key_to_decorated_key() {
1368 let schema = create_test_schema(vec![("id", "int")], vec![]);
1369 let pk = PartitionKey::single("id", Value::Integer(42));
1370
1371 let dk = pk.to_decorated_key(&schema).unwrap();
1372 assert_eq!(dk.key, vec![0x00, 0x00, 0x00, 0x2A]);
1373
1374 let expected_token = calculate_murmur3_token(&dk.key).unwrap();
1376 assert_eq!(dk.token, expected_token);
1377 }
1378
1379 #[test]
1380 fn test_murmur3_token_cassandra_compatibility() {
1381 let key1 = vec![0x00, 0x00, 0x00, 0x01];
1386 let token1 = calculate_murmur3_token(&key1).unwrap();
1387 assert_ne!(token1, 0, "Token should not be zero for non-zero input");
1390
1391 let key2 = vec![0x00, 0x00, 0x00, 0x64];
1393 let token2 = calculate_murmur3_token(&key2).unwrap();
1394 assert_ne!(
1395 token2, token1,
1396 "Different keys should produce different tokens"
1397 );
1398
1399 let key3 = b"test";
1401 let token3 = calculate_murmur3_token(key3).unwrap();
1402 assert_ne!(token3, token1);
1403 assert_ne!(token3, token2);
1404
1405 let token1_repeat = calculate_murmur3_token(&key1).unwrap();
1407 assert_eq!(token1, token1_repeat, "Tokens must be deterministic");
1408 }
1409
1410 #[test]
1411 fn test_decorated_key_btree_ordering() {
1412 use std::collections::BTreeMap;
1414
1415 let mut map = BTreeMap::new();
1416
1417 let dk3 = DecoratedKey::new(300, vec![3]);
1419 let dk1 = DecoratedKey::new(100, vec![1]);
1420 let dk2 = DecoratedKey::new(200, vec![2]);
1421
1422 map.insert(dk3.clone(), "value3");
1423 map.insert(dk1.clone(), "value1");
1424 map.insert(dk2.clone(), "value2");
1425
1426 let keys: Vec<_> = map.keys().collect();
1428 assert_eq!(keys[0].token, 100);
1429 assert_eq!(keys[1].token, 200);
1430 assert_eq!(keys[2].token, 300);
1431 }
1432
1433 #[test]
1434 fn test_decorated_key_hash_collision_handling() {
1435 let token = 12345_i64; let dk1 = DecoratedKey::new(token, vec![0x00, 0x01, 0x02]); let dk2 = DecoratedKey::new(token, vec![0x00, 0x01, 0x03]); let dk3 = DecoratedKey::new(token, vec![0x00, 0x01, 0x02]); assert!(dk1 < dk2, "Keys with same token should order by bytes");
1447 assert!(dk2 > dk1, "Key comparison should be consistent");
1448 assert_eq!(
1449 dk1.cmp(&dk3),
1450 Ordering::Equal,
1451 "Identical keys should be equal"
1452 );
1453
1454 use std::collections::BTreeMap;
1456 let mut map = BTreeMap::new();
1457
1458 map.insert(dk2.clone(), "value2");
1459 map.insert(dk1.clone(), "value1");
1460 map.insert(dk3.clone(), "value3"); assert_eq!(map.len(), 2);
1464
1465 let keys: Vec<_> = map.keys().collect();
1467 assert_eq!(keys[0].key, vec![0x00, 0x01, 0x02]); assert_eq!(keys[1].key, vec![0x00, 0x01, 0x03]); }
1470
1471 #[test]
1472 fn test_clustering_key_ord_valid_comparison() {
1473 let ck1 = ClusteringKey::single("ts", Value::Timestamp(1000));
1475 let ck2 = ClusteringKey::single("ts", Value::Timestamp(2000));
1476 let ck3 = ClusteringKey::single("ts", Value::Timestamp(1000));
1477
1478 assert_eq!(ck1.cmp(&ck2), Ordering::Less);
1480 assert_eq!(ck2.cmp(&ck1), Ordering::Greater);
1481 assert_eq!(ck1.cmp(&ck3), Ordering::Equal);
1482
1483 let ck_multi1 = ClusteringKey::new(vec![
1485 ("year".to_string(), Value::Integer(2024)),
1486 ("month".to_string(), Value::SmallInt(1)),
1487 ]);
1488 let ck_multi2 = ClusteringKey::new(vec![
1489 ("year".to_string(), Value::Integer(2024)),
1490 ("month".to_string(), Value::SmallInt(2)),
1491 ]);
1492
1493 assert_eq!(ck_multi1.cmp(&ck_multi2), Ordering::Less);
1494 }
1495
1496 #[test]
1497 fn test_clustering_key_ord_type_mismatch_is_total_and_does_not_panic() {
1498 let ck1 = ClusteringKey::single("ts", Value::Timestamp(1000));
1504 let ck2 = ClusteringKey::single("ts", Value::Integer(2000)); let ord_12 = ck1.cmp(&ck2);
1508 let ord_21 = ck2.cmp(&ck1);
1509
1510 assert_eq!(ord_12, ck1.cmp(&ck2), "comparison must be deterministic");
1512
1513 assert_ne!(
1516 ord_12,
1517 Ordering::Equal,
1518 "mismatched types must not compare Equal"
1519 );
1520 assert_eq!(
1521 ord_12.reverse(),
1522 ord_21,
1523 "ordering must be antisymmetric (a.cmp(b) == b.cmp(a).reverse())"
1524 );
1525
1526 assert_eq!(ck1.cmp(&ck1), Ordering::Equal);
1528
1529 use std::collections::BTreeMap;
1531 let mut map = BTreeMap::new();
1532 map.insert(ck1.clone(), "a");
1533 map.insert(ck2.clone(), "b");
1534 assert_eq!(map.len(), 2, "both distinct keys should be retained");
1535 }
1536
1537 #[test]
1538 fn test_clustering_key_ord_btree_ordering() {
1539 use std::collections::BTreeMap;
1541
1542 let mut map = BTreeMap::new();
1543
1544 let ck3 = ClusteringKey::single("ts", Value::Timestamp(3000));
1545 let ck1 = ClusteringKey::single("ts", Value::Timestamp(1000));
1546 let ck2 = ClusteringKey::single("ts", Value::Timestamp(2000));
1547
1548 map.insert(ck3.clone(), "value3");
1550 map.insert(ck1.clone(), "value1");
1551 map.insert(ck2.clone(), "value2");
1552
1553 let values: Vec<_> = map.values().copied().collect();
1555 assert_eq!(values, vec!["value1", "value2", "value3"]);
1556 }
1557
1558 #[test]
1559 fn test_compare_frozen_list_values() {
1560 let list_a = Value::Frozen(Box::new(Value::List(vec![
1562 Value::Text("a".to_string()),
1563 Value::Text("b".to_string()),
1564 ])));
1565 let list_b = Value::Frozen(Box::new(Value::List(vec![
1566 Value::Text("a".to_string()),
1567 Value::Text("c".to_string()),
1568 ])));
1569 let list_c = Value::Frozen(Box::new(Value::List(vec![
1570 Value::Text("a".to_string()),
1571 Value::Text("b".to_string()),
1572 Value::Text("c".to_string()),
1573 ])));
1574
1575 assert_eq!(compare_values(&list_a, &list_a).unwrap(), Ordering::Equal);
1577 assert_eq!(compare_values(&list_a, &list_b).unwrap(), Ordering::Less);
1579 assert_eq!(compare_values(&list_b, &list_a).unwrap(), Ordering::Greater);
1580 assert_eq!(compare_values(&list_a, &list_c).unwrap(), Ordering::Less);
1582 assert_eq!(compare_values(&list_c, &list_a).unwrap(), Ordering::Greater);
1583 }
1584
1585 #[test]
1586 fn test_frozen_list_clustering_key_btree_ordering() {
1587 use std::collections::BTreeMap;
1589
1590 let mut map = BTreeMap::new();
1591
1592 let ck_2elem = ClusteringKey::single(
1594 "tags",
1595 Value::Frozen(Box::new(Value::List(vec![
1596 Value::Text("ck_0_0".to_string()),
1597 Value::Text("ck_0_1".to_string()),
1598 ]))),
1599 );
1600 let ck_3elem = ClusteringKey::single(
1601 "tags",
1602 Value::Frozen(Box::new(Value::List(vec![
1603 Value::Text("ck_1_0".to_string()),
1604 Value::Text("ck_1_1".to_string()),
1605 Value::Text("ck_1_2".to_string()),
1606 ]))),
1607 );
1608 let ck_4elem = ClusteringKey::single(
1609 "tags",
1610 Value::Frozen(Box::new(Value::List(vec![
1611 Value::Text("ck_2_0".to_string()),
1612 Value::Text("ck_2_1".to_string()),
1613 Value::Text("ck_2_2".to_string()),
1614 Value::Text("ck_2_3".to_string()),
1615 ]))),
1616 );
1617
1618 map.insert(ck_4elem.clone(), "4elem");
1620 map.insert(ck_2elem.clone(), "2elem");
1621 map.insert(ck_3elem.clone(), "3elem");
1622
1623 assert_eq!(map.len(), 3, "All frozen list CKs should be distinct");
1625
1626 let values: Vec<_> = map.values().copied().collect();
1628 assert_eq!(values, vec!["2elem", "3elem", "4elem"]);
1629 }
1630
1631 #[test]
1632 fn test_partition_key_from_bytes_single_int() {
1633 let schema = TableSchema {
1634 keyspace: "ks".to_string(),
1635 table: "tbl".to_string(),
1636 partition_keys: vec![KeyColumn {
1637 name: "id".to_string(),
1638 data_type: "int".to_string(),
1639 position: 0,
1640 }],
1641 clustering_keys: vec![],
1642 columns: vec![],
1643 comments: HashMap::new(),
1644 dropped_columns: HashMap::new(),
1645 };
1646
1647 let original = PartitionKey::single("id", Value::Integer(42));
1648 let bytes = original.to_bytes(&schema).unwrap();
1649 let decoded = PartitionKey::from_bytes(&bytes, &schema).unwrap();
1650 assert_eq!(original, decoded);
1651 }
1652
1653 #[test]
1654 fn test_partition_key_from_bytes_single_uuid() {
1655 let schema = TableSchema {
1656 keyspace: "ks".to_string(),
1657 table: "tbl".to_string(),
1658 partition_keys: vec![KeyColumn {
1659 name: "id".to_string(),
1660 data_type: "uuid".to_string(),
1661 position: 0,
1662 }],
1663 clustering_keys: vec![],
1664 columns: vec![],
1665 comments: HashMap::new(),
1666 dropped_columns: HashMap::new(),
1667 };
1668
1669 let uuid_bytes = [1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
1670 let original = PartitionKey::single("id", Value::Uuid(uuid_bytes));
1671 let bytes = original.to_bytes(&schema).unwrap();
1672 let decoded = PartitionKey::from_bytes(&bytes, &schema).unwrap();
1673 assert_eq!(original, decoded);
1674 }
1675
1676 #[test]
1677 fn test_partition_key_from_bytes_single_text() {
1678 let schema = TableSchema {
1679 keyspace: "ks".to_string(),
1680 table: "tbl".to_string(),
1681 partition_keys: vec![KeyColumn {
1682 name: "name".to_string(),
1683 data_type: "text".to_string(),
1684 position: 0,
1685 }],
1686 clustering_keys: vec![],
1687 columns: vec![],
1688 comments: HashMap::new(),
1689 dropped_columns: HashMap::new(),
1690 };
1691
1692 let original = PartitionKey::single("name", Value::Text("hello".to_string()));
1693 let bytes = original.to_bytes(&schema).unwrap();
1694 let decoded = PartitionKey::from_bytes(&bytes, &schema).unwrap();
1695 assert_eq!(original, decoded);
1696 }
1697
1698 #[test]
1699 fn test_partition_key_from_bytes_multi_component() {
1700 let schema = TableSchema {
1701 keyspace: "ks".to_string(),
1702 table: "tbl".to_string(),
1703 partition_keys: vec![
1704 KeyColumn {
1705 name: "tenant".to_string(),
1706 data_type: "text".to_string(),
1707 position: 0,
1708 },
1709 KeyColumn {
1710 name: "id".to_string(),
1711 data_type: "int".to_string(),
1712 position: 1,
1713 },
1714 ],
1715 clustering_keys: vec![],
1716 columns: vec![],
1717 comments: HashMap::new(),
1718 dropped_columns: HashMap::new(),
1719 };
1720
1721 let original = PartitionKey::new(vec![
1722 ("tenant".to_string(), Value::Text("acme".to_string())),
1723 ("id".to_string(), Value::Integer(99)),
1724 ]);
1725 let bytes = original.to_bytes(&schema).unwrap();
1726 let decoded = PartitionKey::from_bytes(&bytes, &schema).unwrap();
1727 assert_eq!(original, decoded);
1728 }
1729
1730 #[test]
1731 fn test_partition_key_from_bytes_empty_errors() {
1732 let schema = TableSchema {
1733 keyspace: "ks".to_string(),
1734 table: "tbl".to_string(),
1735 partition_keys: vec![KeyColumn {
1736 name: "id".to_string(),
1737 data_type: "int".to_string(),
1738 position: 0,
1739 }],
1740 clustering_keys: vec![],
1741 columns: vec![],
1742 comments: HashMap::new(),
1743 dropped_columns: HashMap::new(),
1744 };
1745
1746 assert!(PartitionKey::from_bytes(&[], &schema).is_err());
1747 }
1748
1749 #[test]
1750 fn test_clustering_key_cmp_type_mismatch_does_not_panic() {
1751 let key_a = ClusteringKey {
1755 columns: vec![("col".to_string(), Value::Integer(1))],
1756 };
1757 let key_b = ClusteringKey {
1758 columns: vec![("col".to_string(), Value::Text("1".to_string()))],
1759 };
1760
1761 let first = key_a.cmp(&key_b);
1763 let second = key_a.cmp(&key_b);
1765 assert_eq!(first, second);
1766
1767 assert_eq!(key_a.cmp(&key_a), Ordering::Equal);
1769 }
1770}