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 #[serde(default)]
319 local_deletion_time: Option<i32>,
320 },
321 Delete {
323 column: String,
325 #[serde(default)]
345 local_deletion_time: Option<i32>,
346 },
347 DeleteRow,
349 WriteComplexElement {
366 column: String,
368 cell_path: Vec<u8>,
373 value: Option<Value>,
378 timestamp_micros: i64,
382 ttl_seconds: Option<u32>,
384 local_deletion_time: Option<i32>,
388 is_deleted: bool,
400 },
401 ComplexDeletion {
413 column: String,
415 marked_for_delete_at: i64,
417 local_deletion_time: i32,
419 },
420}
421
422#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
427pub struct PartitionKey {
428 pub columns: Vec<(String, Value)>,
430}
431
432impl PartitionKey {
433 pub fn new(columns: Vec<(String, Value)>) -> Self {
435 Self { columns }
436 }
437
438 pub fn single(column: impl Into<String>, value: Value) -> Self {
440 Self {
441 columns: vec![(column.into(), value)],
442 }
443 }
444
445 pub fn to_bytes(&self, schema: &TableSchema) -> Result<Vec<u8>> {
451 if self.columns.is_empty() {
452 return Err(Error::InvalidInput("Empty partition key".to_string()));
453 }
454
455 if self.columns.len() != schema.partition_keys.len() {
457 return Err(Error::InvalidInput(format!(
458 "Partition key column count mismatch: expected {}, got {}",
459 schema.partition_keys.len(),
460 self.columns.len()
461 )));
462 }
463
464 if self.columns.len() == 1 {
467 return self.serialize_value(&self.columns[0].1, &schema.partition_keys[0]);
468 }
469
470 let mut result = Vec::new();
471
472 for (i, (_, value)) in self.columns.iter().enumerate() {
475 let value_bytes = self.serialize_value(value, &schema.partition_keys[i])?;
476 let len = value_bytes.len();
477 if len > u16::MAX as usize {
478 return Err(Error::InvalidInput(format!(
479 "Partition key component too large: {} bytes",
480 len
481 )));
482 }
483 result.extend_from_slice(&(len as u16).to_be_bytes());
485 result.extend_from_slice(&value_bytes);
486 result.push(0x00);
487 }
488
489 Ok(result)
490 }
491
492 pub fn to_decorated_key(&self, schema: &TableSchema) -> Result<DecoratedKey> {
494 let key_bytes = self.to_bytes(schema)?;
495 let token = calculate_murmur3_token(&key_bytes)?;
496 Ok(DecoratedKey::new(token, key_bytes))
497 }
498
499 pub fn from_bytes(data: &[u8], schema: &TableSchema) -> Result<Self> {
504 if schema.partition_keys.is_empty() {
505 return Err(Error::InvalidInput(
506 "Schema has no partition keys".to_string(),
507 ));
508 }
509
510 if data.is_empty() {
511 return Err(Error::InvalidInput("Empty partition key bytes".to_string()));
512 }
513
514 let columns =
517 crate::storage::partition_key_codec::decode_partition_key_columns(data, schema)?;
518
519 Ok(PartitionKey { columns })
520 }
521
522 fn serialize_value(
524 &self,
525 value: &Value,
526 key_column: &crate::schema::KeyColumn,
527 ) -> Result<Vec<u8>> {
528 let comparator = ComparatorType::from_data_type(&key_column.data_type)?;
530
531 serialize_value_bytes(value, &comparator)
532 }
533}
534
535#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
540pub struct ClusteringKey {
541 pub columns: Vec<(String, Value)>,
543}
544
545impl ClusteringKey {
546 pub fn new(columns: Vec<(String, Value)>) -> Self {
548 Self { columns }
549 }
550
551 pub fn single(column: impl Into<String>, value: Value) -> Self {
553 Self {
554 columns: vec![(column.into(), value)],
555 }
556 }
557
558 pub fn compare(&self, other: &Self, schema: &TableSchema) -> Result<Ordering> {
563 if self.columns.len() > schema.clustering_keys.len()
571 || other.columns.len() > schema.clustering_keys.len()
572 {
573 return Err(Error::Schema(format!(
574 "Clustering key has more columns than schema: {} / {} > {}",
575 self.columns.len(),
576 other.columns.len(),
577 schema.clustering_keys.len()
578 )));
579 }
580
581 for (i, cluster_col) in schema.clustering_keys.iter().enumerate() {
582 let a_val = self.columns.get(i).map(|(_, v)| v).unwrap_or(&Value::Null);
584 let b_val = other.columns.get(i).map(|(_, v)| v).unwrap_or(&Value::Null);
585
586 let final_ordering = match (a_val, b_val) {
594 (Value::Null, Value::Null) => Ordering::Equal,
596 (Value::Null, _) => Ordering::Less,
599 (_, Value::Null) => Ordering::Greater,
600 (_, _) => {
603 let ordering = compare_values(a_val, b_val)?;
604 if cluster_col.order == ClusteringOrder::Desc {
605 ordering.reverse()
606 } else {
607 ordering
608 }
609 }
610 };
611
612 if final_ordering != Ordering::Equal {
613 return Ok(final_ordering);
614 }
615 }
616
617 Ok(Ordering::Equal)
618 }
619}
620
621impl Ord for ClusteringKey {
622 fn cmp(&self, other: &Self) -> Ordering {
623 for ((_, a_val), (_, b_val)) in self.columns.iter().zip(other.columns.iter()) {
627 let ordering = compare_values(a_val, b_val).unwrap_or_else(|_| {
628 format!("{a_val:?}").cmp(&format!("{b_val:?}"))
632 });
633 if ordering != Ordering::Equal {
634 return ordering;
635 }
636 }
637 self.columns.len().cmp(&other.columns.len())
638 }
639}
640
641impl PartialOrd for ClusteringKey {
642 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
643 Some(self.cmp(other))
644 }
645}
646
647impl PartialEq for ClusteringKey {
656 fn eq(&self, other: &Self) -> bool {
657 self.cmp(other) == Ordering::Equal
658 }
659}
660
661impl Eq for ClusteringKey {}
662
663#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
678pub struct DecoratedKey {
679 pub token: i64,
681 pub key: Vec<u8>,
683}
684
685impl DecoratedKey {
686 pub fn new(token: i64, key: Vec<u8>) -> Self {
688 Self { token, key }
689 }
690
691 pub fn from_key_bytes(key_bytes: Vec<u8>) -> Result<Self> {
693 let token = calculate_murmur3_token(&key_bytes)?;
694 Ok(Self::new(token, key_bytes))
695 }
696}
697
698impl Ord for DecoratedKey {
699 fn cmp(&self, other: &Self) -> Ordering {
700 match self.token.cmp(&other.token) {
702 Ordering::Equal => {
703 self.key.cmp(&other.key)
705 }
706 other => other,
707 }
708 }
709}
710
711impl PartialOrd for DecoratedKey {
712 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
713 Some(self.cmp(other))
714 }
715}
716
717fn calculate_murmur3_token(key_bytes: &[u8]) -> Result<i64> {
724 if key_bytes.is_empty() {
725 return Ok(i64::MIN);
726 }
727
728 Ok(crate::util::cassandra_murmur3::cassandra_murmur3_token(
729 key_bytes,
730 ))
731}
732
733fn serialize_value_bytes(value: &Value, comparator: &ComparatorType) -> Result<Vec<u8>> {
738 match (value, comparator) {
739 (Value::Null, _) => Ok(Vec::new()),
740
741 (Value::Boolean(b), ComparatorType::Boolean) => Ok(vec![if *b { 1 } else { 0 }]),
742
743 (Value::TinyInt(n), ComparatorType::TinyInt) => Ok(vec![*n as u8]),
744
745 (Value::SmallInt(n), ComparatorType::SmallInt) => Ok(n.to_be_bytes().to_vec()),
746
747 (Value::Integer(n), ComparatorType::Int) => Ok(n.to_be_bytes().to_vec()),
748
749 (Value::BigInt(n), ComparatorType::BigInt) => Ok(n.to_be_bytes().to_vec()),
750
751 (Value::Counter(n), ComparatorType::Counter) => Ok(n.to_be_bytes().to_vec()),
752
753 (Value::Float32(f), ComparatorType::Float32) => Ok(f.to_bits().to_be_bytes().to_vec()),
754
755 (Value::Float(f), ComparatorType::Float) => Ok(f.to_bits().to_be_bytes().to_vec()),
756
757 (Value::Text(s), ComparatorType::Text) => Ok(s.to_vec()),
758
759 (Value::Blob(bytes), ComparatorType::Blob) => Ok(bytes.to_vec()),
760
761 (Value::Timestamp(millis), ComparatorType::Timestamp) => Ok(millis.to_be_bytes().to_vec()),
762
763 (Value::Date(days), ComparatorType::Date) => {
764 let stored = days.wrapping_sub(i32::MIN) as u32;
766 Ok(stored.to_be_bytes().to_vec())
767 }
768
769 (Value::Uuid(bytes), ComparatorType::Uuid) => Ok(bytes.to_vec()),
770
771 (Value::Time(nanos), ComparatorType::Custom(name)) if name == "time" => {
773 Ok(nanos.to_be_bytes().to_vec())
774 }
775
776 (Value::Inet(bytes), ComparatorType::Custom(name)) if name == "inet" => Ok(bytes.to_vec()),
777
778 (Value::Varint(bytes), ComparatorType::Varint) => Ok(bytes.to_vec()),
779
780 (Value::Decimal { scale, unscaled }, ComparatorType::Decimal) => {
781 let mut result = Vec::new();
783 result.extend_from_slice(&scale.to_be_bytes());
784 result.extend_from_slice(unscaled);
785 Ok(result)
786 }
787
788 (
789 Value::Duration {
790 months,
791 days,
792 nanos,
793 },
794 ComparatorType::Duration,
795 ) => {
796 let mut result = Vec::new();
798 result.extend_from_slice(&months.to_be_bytes());
799 result.extend_from_slice(&days.to_be_bytes());
800 result.extend_from_slice(&nanos.to_be_bytes());
801 Ok(result)
802 }
803
804 _ => Err(Error::InvalidInput(format!(
805 "Type mismatch: value {:?} does not match comparator {:?}",
806 value, comparator
807 ))),
808 }
809}
810
811fn compare_values(a: &Value, b: &Value) -> Result<Ordering> {
813 use Value::*;
814
815 match (a, b) {
816 (Null, Null) => Ok(Ordering::Equal),
817 (Null, _) => Ok(Ordering::Less),
818 (_, Null) => Ok(Ordering::Greater),
819
820 (Boolean(a), Boolean(b)) => Ok(a.cmp(b)),
821 (TinyInt(a), TinyInt(b)) => Ok(a.cmp(b)),
822 (SmallInt(a), SmallInt(b)) => Ok(a.cmp(b)),
823 (Integer(a), Integer(b)) => Ok(a.cmp(b)),
824 (BigInt(a), BigInt(b)) => Ok(a.cmp(b)),
825 (Counter(a), Counter(b)) => Ok(a.cmp(b)),
826 (Float32(a), Float32(b)) => Ok(crate::float_cmp::cassandra_float_cmp(*a, *b)),
833 (Float(a), Float(b)) => Ok(crate::float_cmp::cassandra_double_cmp(*a, *b)),
834 (Text(a), Text(b)) => Ok(a.cmp(b)),
835 (Blob(a), Blob(b)) => Ok(a.cmp(b)),
836 (Timestamp(a), Timestamp(b)) => Ok(a.cmp(b)),
837 (Date(a), Date(b)) => Ok(a.cmp(b)),
838 (Time(a), Time(b)) => Ok(a.cmp(b)),
839 (Uuid(a), Uuid(b)) => Ok(a.cmp(b)),
840 (Inet(a), Inet(b)) => Ok(a.cmp(b)),
841
842 (List(a), List(b)) | (Set(a), Set(b)) => {
844 for (elem_a, elem_b) in a.iter().zip(b.iter()) {
845 let ord = compare_values(elem_a, elem_b)?;
846 if ord != Ordering::Equal {
847 return Ok(ord);
848 }
849 }
850 Ok(a.len().cmp(&b.len()))
851 }
852 (Map(a), Map(b)) => {
853 for ((ka, va), (kb, vb)) in a.iter().zip(b.iter()) {
854 let key_ord = compare_values(ka, kb)?;
855 if key_ord != Ordering::Equal {
856 return Ok(key_ord);
857 }
858 let val_ord = compare_values(va, vb)?;
859 if val_ord != Ordering::Equal {
860 return Ok(val_ord);
861 }
862 }
863 Ok(a.len().cmp(&b.len()))
864 }
865 (Tuple(a), Tuple(b)) => {
866 for (fa, fb) in a.iter().zip(b.iter()) {
867 let ord = compare_values(fa, fb)?;
868 if ord != Ordering::Equal {
869 return Ok(ord);
870 }
871 }
872 Ok(a.len().cmp(&b.len()))
873 }
874
875 (Frozen(a), Frozen(b)) => compare_values(a, b),
877
878 _ => Err(Error::InvalidInput(format!(
879 "Cannot compare values of different types: {:?} vs {:?}",
880 a, b
881 ))),
882 }
883}
884
885#[cfg(test)]
886mod tests {
887 use super::*;
888 use crate::schema::{ClusteringColumn, ClusteringOrder, KeyColumn};
889 use std::collections::HashMap;
890
891 fn create_test_schema(
892 partition_cols: Vec<(&str, &str)>,
893 clustering_cols: Vec<(&str, &str, ClusteringOrder)>,
894 ) -> TableSchema {
895 TableSchema {
896 keyspace: "test_ks".to_string(),
897 table: "test_table".to_string(),
898 partition_keys: partition_cols
899 .into_iter()
900 .enumerate()
901 .map(|(i, (name, data_type))| KeyColumn {
902 name: name.to_string(),
903 data_type: data_type.to_string(),
904 position: i,
905 })
906 .collect(),
907 clustering_keys: clustering_cols
908 .into_iter()
909 .enumerate()
910 .map(|(i, (name, data_type, order))| ClusteringColumn {
911 name: name.to_string(),
912 data_type: data_type.to_string(),
913 position: i,
914 order,
915 })
916 .collect(),
917 columns: vec![],
918 comments: HashMap::new(),
919 dropped_columns: HashMap::new(),
920 }
921 }
922
923 #[test]
924 fn test_table_id() {
925 let table_id = TableId::new("my_keyspace", "my_table");
926 assert_eq!(table_id.keyspace, "my_keyspace");
927 assert_eq!(table_id.table, "my_table");
928 assert_eq!(table_id.qualified_name(), "my_keyspace.my_table");
929 assert_eq!(table_id.to_string(), "my_keyspace.my_table");
930 }
931
932 #[test]
933 fn test_partition_key_single_int() {
934 let schema = create_test_schema(vec![("id", "int")], vec![]);
935 let pk = PartitionKey::single("id", Value::Integer(42));
936
937 let bytes = pk.to_bytes(&schema).unwrap();
938 assert_eq!(bytes, vec![0x00, 0x00, 0x00, 0x2A]);
940 }
941
942 #[test]
943 fn test_partition_key_multi_component() {
944 let schema = create_test_schema(vec![("id", "int"), ("name", "text")], vec![]);
945 let pk = PartitionKey::new(vec![
946 ("id".to_string(), Value::Integer(42)),
947 ("name".to_string(), Value::text("hello".to_string())),
948 ]);
949
950 let bytes = pk.to_bytes(&schema).unwrap();
951 let expected = vec![
954 0x00, 0x04, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x05, b'h', b'e', b'l', b'l', b'o', 0x00, ];
961 assert_eq!(bytes, expected);
962 }
963
964 #[test]
965 fn test_partition_key_three_components() {
966 let schema = create_test_schema(
968 vec![("symbol", "text"), ("exchange", "text"), ("bucket", "int")],
969 vec![],
970 );
971 let pk = PartitionKey::new(vec![
972 ("symbol".to_string(), Value::text("AAPL".to_string())),
973 ("exchange".to_string(), Value::text("NYSE".to_string())),
974 ("bucket".to_string(), Value::Integer(100)),
975 ]);
976
977 let bytes = pk.to_bytes(&schema).unwrap();
978 let expected = vec![
980 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, ];
990 assert_eq!(bytes, expected);
991 }
992
993 #[test]
994 fn test_decorated_key_ordering() {
995 let dk1 = DecoratedKey::new(100, vec![1, 2, 3]);
996 let dk2 = DecoratedKey::new(200, vec![1, 2, 3]);
997 let dk3 = DecoratedKey::new(100, vec![1, 2, 4]);
998
999 assert!(dk1 < dk2);
1001 assert!(dk2 > dk1);
1002
1003 assert!(dk1 < dk3);
1005 assert!(dk3 > dk1);
1006
1007 let dk4 = DecoratedKey::new(100, vec![1, 2, 3]);
1009 assert_eq!(dk1, dk4);
1010 }
1011
1012 #[test]
1013 fn test_murmur3_token_empty_key() {
1014 let token = calculate_murmur3_token(&[]).unwrap();
1015 assert_eq!(token, i64::MIN);
1016 }
1017
1018 #[test]
1019 fn test_murmur3_token_deterministic() {
1020 let key_bytes = b"test_key";
1021 let token1 = calculate_murmur3_token(key_bytes).unwrap();
1022 let token2 = calculate_murmur3_token(key_bytes).unwrap();
1023 assert_eq!(token1, token2, "Token calculation should be deterministic");
1024 }
1025
1026 #[test]
1027 fn test_murmur3_token_different_keys() {
1028 let token1 = calculate_murmur3_token(b"key1").unwrap();
1029 let token2 = calculate_murmur3_token(b"key2").unwrap();
1030 assert_ne!(
1031 token1, token2,
1032 "Different keys should produce different tokens"
1033 );
1034 }
1035
1036 #[test]
1037 fn test_murmur3_token_matches_cassandra_for_composite_uuid_key() {
1038 let key_bytes = vec![
1041 0x00, 0x10, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x40, 0x00, 0x80, 0x00, 0x00, 0x00,
1042 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x40,
1043 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x00,
1044 ];
1045
1046 let token = calculate_murmur3_token(&key_bytes).unwrap();
1047 assert_eq!(token, -5_116_541_970_184_546_410);
1048 }
1049
1050 #[test]
1051 fn test_decorated_key_from_bytes() {
1052 let key_bytes = vec![0x00, 0x00, 0x00, 0x2A]; let dk = DecoratedKey::from_key_bytes(key_bytes.clone()).unwrap();
1054
1055 assert_eq!(dk.key, key_bytes);
1056 let expected_token = calculate_murmur3_token(&key_bytes).unwrap();
1058 assert_eq!(dk.token, expected_token);
1059 }
1060
1061 #[test]
1062 fn test_clustering_key_ordering() {
1063 let schema = create_test_schema(
1064 vec![("id", "int")],
1065 vec![("ts", "timestamp", ClusteringOrder::Asc)],
1066 );
1067
1068 let ck1 = ClusteringKey::single("ts", Value::Timestamp(1000));
1069 let ck2 = ClusteringKey::single("ts", Value::Timestamp(2000));
1070
1071 let ordering = ck1.compare(&ck2, &schema).unwrap();
1072 assert_eq!(ordering, Ordering::Less);
1073 }
1074
1075 #[test]
1076 fn test_clustering_key_desc_ordering() {
1077 let schema = create_test_schema(
1078 vec![("id", "int")],
1079 vec![("ts", "timestamp", ClusteringOrder::Desc)],
1080 );
1081
1082 let ck1 = ClusteringKey::single("ts", Value::Timestamp(1000));
1083 let ck2 = ClusteringKey::single("ts", Value::Timestamp(2000));
1084
1085 let ordering = ck1.compare(&ck2, &schema).unwrap();
1086 assert_eq!(ordering, Ordering::Greater);
1088 }
1089
1090 #[test]
1094 fn test_clustering_key_partial_eq_consistent_with_ord() {
1095 let neg_zero = ClusteringKey::single("f", Value::Float(-0.0));
1098 let pos_zero = ClusteringKey::single("f", Value::Float(0.0));
1099 assert_eq!(neg_zero.cmp(&pos_zero), Ordering::Less);
1100 assert_ne!(neg_zero, pos_zero);
1101 assert_eq!(
1102 neg_zero == pos_zero,
1103 neg_zero.cmp(&pos_zero) == Ordering::Equal
1104 );
1105
1106 let nan_a = ClusteringKey::single("f", Value::Float(f64::NAN));
1109 let nan_b = ClusteringKey::single("f", Value::Float(f64::NAN));
1110 assert_eq!(nan_a.cmp(&nan_b), Ordering::Equal);
1111 assert_eq!(nan_a, nan_b);
1112
1113 let f32_neg_zero = ClusteringKey::single("f", Value::Float32(-0.0));
1115 let f32_pos_zero = ClusteringKey::single("f", Value::Float32(0.0));
1116 assert_ne!(f32_neg_zero, f32_pos_zero);
1117 let f32_nan_a = ClusteringKey::single("f", Value::Float32(f32::NAN));
1118 let f32_nan_b = ClusteringKey::single("f", Value::Float32(f32::NAN));
1119 assert_eq!(f32_nan_a, f32_nan_b);
1120 }
1121
1122 #[test]
1125 fn test_clustering_null_sorts_first_asc() {
1126 let schema = create_test_schema(
1129 vec![("id", "int")],
1130 vec![("ts", "timestamp", ClusteringOrder::Asc)],
1131 );
1132
1133 let null_ck = ClusteringKey::single("ts", Value::Null);
1134 let valued_ck = ClusteringKey::single("ts", Value::Timestamp(1000));
1135
1136 assert_eq!(
1137 null_ck.compare(&valued_ck, &schema).unwrap(),
1138 Ordering::Less,
1139 "NULL must sort before a value on ASC"
1140 );
1141 assert_eq!(
1142 valued_ck.compare(&null_ck, &schema).unwrap(),
1143 Ordering::Greater,
1144 "value must sort after NULL on ASC"
1145 );
1146 }
1147
1148 #[test]
1149 fn test_clustering_null_sorts_first_desc() {
1150 let schema = create_test_schema(
1154 vec![("id", "int")],
1155 vec![("ts", "timestamp", ClusteringOrder::Desc)],
1156 );
1157
1158 let null_ck = ClusteringKey::single("ts", Value::Null);
1159 let valued_ck = ClusteringKey::single("ts", Value::Timestamp(1000));
1160
1161 assert_eq!(
1162 null_ck.compare(&valued_ck, &schema).unwrap(),
1163 Ordering::Less,
1164 "NULL must sort before a value even on DESC"
1165 );
1166 assert_eq!(
1167 valued_ck.compare(&null_ck, &schema).unwrap(),
1168 Ordering::Greater,
1169 "value must sort after NULL even on DESC"
1170 );
1171
1172 let null_ck2 = ClusteringKey::single("ts", Value::Null);
1174 assert_eq!(
1175 null_ck.compare(&null_ck2, &schema).unwrap(),
1176 Ordering::Equal
1177 );
1178 }
1179
1180 #[test]
1181 fn test_clustering_empty_vs_valued_asc() {
1182 let schema = create_test_schema(
1185 vec![("id", "int")],
1186 vec![("c", "text", ClusteringOrder::Asc)],
1187 );
1188
1189 let empty_ck = ClusteringKey::single("c", Value::text(String::new()));
1190 let valued_ck = ClusteringKey::single("c", Value::text("a".to_string()));
1191
1192 assert_eq!(
1193 empty_ck.compare(&valued_ck, &schema).unwrap(),
1194 Ordering::Less,
1195 "empty text must sort before non-empty on ASC"
1196 );
1197 }
1198
1199 #[test]
1200 fn test_clustering_empty_vs_valued_desc() {
1201 let schema = create_test_schema(
1204 vec![("id", "int")],
1205 vec![("c", "text", ClusteringOrder::Desc)],
1206 );
1207
1208 let empty_ck = ClusteringKey::single("c", Value::text(String::new()));
1209 let valued_ck = ClusteringKey::single("c", Value::text("a".to_string()));
1210
1211 assert_eq!(
1212 empty_ck.compare(&valued_ck, &schema).unwrap(),
1213 Ordering::Greater,
1214 "empty text must sort after non-empty on DESC (type-routed reversal)"
1215 );
1216 assert_eq!(
1217 valued_ck.compare(&empty_ck, &schema).unwrap(),
1218 Ordering::Less
1219 );
1220 }
1221
1222 #[test]
1223 fn test_clustering_null_first_on_second_desc_component() {
1224 let schema = create_test_schema(
1227 vec![("id", "int")],
1228 vec![
1229 ("a", "int", ClusteringOrder::Asc),
1230 ("b", "timestamp", ClusteringOrder::Desc),
1231 ],
1232 );
1233
1234 let null_b = ClusteringKey::new(vec![
1235 ("a".to_string(), Value::Integer(1)),
1236 ("b".to_string(), Value::Null),
1237 ]);
1238 let valued_b = ClusteringKey::new(vec![
1239 ("a".to_string(), Value::Integer(1)),
1240 ("b".to_string(), Value::Timestamp(5000)),
1241 ]);
1242
1243 assert_eq!(
1244 null_b.compare(&valued_b, &schema).unwrap(),
1245 Ordering::Less,
1246 "NULL on a DESC sub-component still sorts first"
1247 );
1248 }
1249
1250 #[test]
1251 fn test_clustering_absent_trailing_desc_component_sorts_first() {
1252 let schema = create_test_schema(
1258 vec![("id", "int")],
1259 vec![
1260 ("a", "int", ClusteringOrder::Asc),
1261 ("b", "timestamp", ClusteringOrder::Desc),
1262 ],
1263 );
1264
1265 let absent_b = ClusteringKey::new(vec![("a".to_string(), Value::Integer(1))]);
1267 let valued_b = ClusteringKey::new(vec![
1268 ("a".to_string(), Value::Integer(1)),
1269 ("b".to_string(), Value::Timestamp(5000)),
1270 ]);
1271
1272 assert_eq!(
1273 absent_b.compare(&valued_b, &schema).unwrap(),
1274 Ordering::Less,
1275 "absent trailing DESC component must sort first (null-first), not Equal"
1276 );
1277 assert_eq!(
1278 valued_b.compare(&absent_b, &schema).unwrap(),
1279 Ordering::Greater,
1280 "present value must sort after an absent trailing component"
1281 );
1282
1283 let explicit_null_b = ClusteringKey::new(vec![
1286 ("a".to_string(), Value::Integer(1)),
1287 ("b".to_string(), Value::Null),
1288 ]);
1289 assert_eq!(
1290 absent_b.compare(&explicit_null_b, &schema).unwrap(),
1291 Ordering::Equal,
1292 "absent trailing component == explicit NULL at the same position"
1293 );
1294 assert_eq!(
1295 explicit_null_b.compare(&absent_b, &schema).unwrap(),
1296 Ordering::Equal,
1297 );
1298 }
1299
1300 #[test]
1301 fn test_clustering_absent_trailing_asc_component_sorts_first() {
1302 let schema = create_test_schema(
1305 vec![("id", "int")],
1306 vec![
1307 ("a", "int", ClusteringOrder::Asc),
1308 ("b", "int", ClusteringOrder::Asc),
1309 ],
1310 );
1311
1312 let absent_b = ClusteringKey::new(vec![("a".to_string(), Value::Integer(7))]);
1313 let valued_b = ClusteringKey::new(vec![
1314 ("a".to_string(), Value::Integer(7)),
1315 ("b".to_string(), Value::Integer(0)),
1316 ]);
1317
1318 assert_eq!(
1319 absent_b.compare(&valued_b, &schema).unwrap(),
1320 Ordering::Less,
1321 "absent trailing ASC component must sort first"
1322 );
1323 assert_eq!(
1324 valued_b.compare(&absent_b, &schema).unwrap(),
1325 Ordering::Greater,
1326 );
1327 }
1328
1329 #[test]
1330 fn test_clustering_both_absent_trailing_component_equal() {
1331 let schema = create_test_schema(
1333 vec![("id", "int")],
1334 vec![
1335 ("a", "int", ClusteringOrder::Asc),
1336 ("b", "timestamp", ClusteringOrder::Desc),
1337 ],
1338 );
1339
1340 let a1 = ClusteringKey::new(vec![("a".to_string(), Value::Integer(3))]);
1341 let a2 = ClusteringKey::new(vec![("a".to_string(), Value::Integer(3))]);
1342 assert_eq!(a1.compare(&a2, &schema).unwrap(), Ordering::Equal);
1343 }
1344
1345 #[test]
1346 fn test_mutation_creation() {
1347 let table_id = TableId::new("ks", "table");
1348 let pk = PartitionKey::single("id", Value::Integer(1));
1349 let ops = vec![CellOperation::Write {
1350 column: "name".to_string(),
1351 value: Value::text("Alice".to_string()),
1352 }];
1353
1354 let mutation = Mutation::new(table_id.clone(), pk, None, ops, 1234567890, None);
1355
1356 assert_eq!(mutation.table.keyspace, "ks");
1357 assert_eq!(mutation.table.table, "table");
1358 assert_eq!(mutation.timestamp_micros, 1234567890);
1359 assert_eq!(mutation.ttl_seconds, None);
1360 assert_eq!(mutation.operations.len(), 1);
1361 }
1362
1363 #[test]
1364 fn test_cell_operation_write() {
1365 let op = CellOperation::Write {
1366 column: "age".to_string(),
1367 value: Value::Integer(30),
1368 };
1369
1370 match op {
1371 CellOperation::Write { column, value } => {
1372 assert_eq!(column, "age");
1373 assert_eq!(value, Value::Integer(30));
1374 }
1375 _ => panic!("Expected Write operation"),
1376 }
1377 }
1378
1379 #[test]
1380 fn test_cell_operation_delete() {
1381 let op = CellOperation::Delete {
1382 column: "name".to_string(),
1383 local_deletion_time: None,
1384 };
1385
1386 match op {
1387 CellOperation::Delete { column, .. } => {
1388 assert_eq!(column, "name");
1389 }
1390 _ => panic!("Expected Delete operation"),
1391 }
1392 }
1393
1394 #[test]
1395 fn test_cell_operation_delete_row() {
1396 let op = CellOperation::DeleteRow;
1397 assert!(matches!(op, CellOperation::DeleteRow));
1398 }
1399
1400 #[test]
1401 fn test_serialize_value_types() {
1402 let bytes = serialize_value_bytes(&Value::Boolean(true), &ComparatorType::Boolean).unwrap();
1404 assert_eq!(bytes, vec![1]);
1405
1406 let bytes = serialize_value_bytes(&Value::Integer(42), &ComparatorType::Int).unwrap();
1408 assert_eq!(bytes, vec![0x00, 0x00, 0x00, 0x2A]);
1409
1410 let bytes = serialize_value_bytes(&Value::text("hello".to_string()), &ComparatorType::Text)
1412 .unwrap();
1413 assert_eq!(bytes, b"hello");
1414
1415 let uuid_bytes = [
1417 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB,
1418 0xCD, 0xEF,
1419 ];
1420 let bytes = serialize_value_bytes(&Value::Uuid(uuid_bytes), &ComparatorType::Uuid).unwrap();
1421 assert_eq!(bytes, uuid_bytes);
1422 }
1423
1424 #[test]
1425 fn test_compare_values() {
1426 assert_eq!(
1427 compare_values(&Value::Integer(1), &Value::Integer(2)).unwrap(),
1428 Ordering::Less
1429 );
1430 assert_eq!(
1431 compare_values(&Value::Integer(2), &Value::Integer(1)).unwrap(),
1432 Ordering::Greater
1433 );
1434 assert_eq!(
1435 compare_values(&Value::Integer(1), &Value::Integer(1)).unwrap(),
1436 Ordering::Equal
1437 );
1438
1439 assert_eq!(
1441 compare_values(&Value::Null, &Value::Integer(1)).unwrap(),
1442 Ordering::Less
1443 );
1444 assert_eq!(
1445 compare_values(&Value::Integer(1), &Value::Null).unwrap(),
1446 Ordering::Greater
1447 );
1448 }
1449
1450 #[test]
1451 fn test_partition_key_to_decorated_key() {
1452 let schema = create_test_schema(vec![("id", "int")], vec![]);
1453 let pk = PartitionKey::single("id", Value::Integer(42));
1454
1455 let dk = pk.to_decorated_key(&schema).unwrap();
1456 assert_eq!(dk.key, vec![0x00, 0x00, 0x00, 0x2A]);
1457
1458 let expected_token = calculate_murmur3_token(&dk.key).unwrap();
1460 assert_eq!(dk.token, expected_token);
1461 }
1462
1463 #[test]
1464 fn test_murmur3_token_cassandra_compatibility() {
1465 let key1 = vec![0x00, 0x00, 0x00, 0x01];
1470 let token1 = calculate_murmur3_token(&key1).unwrap();
1471 assert_ne!(token1, 0, "Token should not be zero for non-zero input");
1474
1475 let key2 = vec![0x00, 0x00, 0x00, 0x64];
1477 let token2 = calculate_murmur3_token(&key2).unwrap();
1478 assert_ne!(
1479 token2, token1,
1480 "Different keys should produce different tokens"
1481 );
1482
1483 let key3 = b"test";
1485 let token3 = calculate_murmur3_token(key3).unwrap();
1486 assert_ne!(token3, token1);
1487 assert_ne!(token3, token2);
1488
1489 let token1_repeat = calculate_murmur3_token(&key1).unwrap();
1491 assert_eq!(token1, token1_repeat, "Tokens must be deterministic");
1492 }
1493
1494 #[test]
1495 fn test_decorated_key_btree_ordering() {
1496 use std::collections::BTreeMap;
1498
1499 let mut map = BTreeMap::new();
1500
1501 let dk3 = DecoratedKey::new(300, vec![3]);
1503 let dk1 = DecoratedKey::new(100, vec![1]);
1504 let dk2 = DecoratedKey::new(200, vec![2]);
1505
1506 map.insert(dk3.clone(), "value3");
1507 map.insert(dk1.clone(), "value1");
1508 map.insert(dk2.clone(), "value2");
1509
1510 let keys: Vec<_> = map.keys().collect();
1512 assert_eq!(keys[0].token, 100);
1513 assert_eq!(keys[1].token, 200);
1514 assert_eq!(keys[2].token, 300);
1515 }
1516
1517 #[test]
1518 fn test_decorated_key_hash_collision_handling() {
1519 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");
1531 assert!(dk2 > dk1, "Key comparison should be consistent");
1532 assert_eq!(
1533 dk1.cmp(&dk3),
1534 Ordering::Equal,
1535 "Identical keys should be equal"
1536 );
1537
1538 use std::collections::BTreeMap;
1540 let mut map = BTreeMap::new();
1541
1542 map.insert(dk2.clone(), "value2");
1543 map.insert(dk1.clone(), "value1");
1544 map.insert(dk3.clone(), "value3"); assert_eq!(map.len(), 2);
1548
1549 let keys: Vec<_> = map.keys().collect();
1551 assert_eq!(keys[0].key, vec![0x00, 0x01, 0x02]); assert_eq!(keys[1].key, vec![0x00, 0x01, 0x03]); }
1554
1555 #[test]
1556 fn test_clustering_key_ord_valid_comparison() {
1557 let ck1 = ClusteringKey::single("ts", Value::Timestamp(1000));
1559 let ck2 = ClusteringKey::single("ts", Value::Timestamp(2000));
1560 let ck3 = ClusteringKey::single("ts", Value::Timestamp(1000));
1561
1562 assert_eq!(ck1.cmp(&ck2), Ordering::Less);
1564 assert_eq!(ck2.cmp(&ck1), Ordering::Greater);
1565 assert_eq!(ck1.cmp(&ck3), Ordering::Equal);
1566
1567 let ck_multi1 = ClusteringKey::new(vec![
1569 ("year".to_string(), Value::Integer(2024)),
1570 ("month".to_string(), Value::SmallInt(1)),
1571 ]);
1572 let ck_multi2 = ClusteringKey::new(vec![
1573 ("year".to_string(), Value::Integer(2024)),
1574 ("month".to_string(), Value::SmallInt(2)),
1575 ]);
1576
1577 assert_eq!(ck_multi1.cmp(&ck_multi2), Ordering::Less);
1578 }
1579
1580 #[test]
1581 fn test_clustering_key_ord_type_mismatch_is_total_and_does_not_panic() {
1582 let ck1 = ClusteringKey::single("ts", Value::Timestamp(1000));
1588 let ck2 = ClusteringKey::single("ts", Value::Integer(2000)); let ord_12 = ck1.cmp(&ck2);
1592 let ord_21 = ck2.cmp(&ck1);
1593
1594 assert_eq!(ord_12, ck1.cmp(&ck2), "comparison must be deterministic");
1596
1597 assert_ne!(
1600 ord_12,
1601 Ordering::Equal,
1602 "mismatched types must not compare Equal"
1603 );
1604 assert_eq!(
1605 ord_12.reverse(),
1606 ord_21,
1607 "ordering must be antisymmetric (a.cmp(b) == b.cmp(a).reverse())"
1608 );
1609
1610 assert_eq!(ck1.cmp(&ck1), Ordering::Equal);
1612
1613 use std::collections::BTreeMap;
1615 let mut map = BTreeMap::new();
1616 map.insert(ck1.clone(), "a");
1617 map.insert(ck2.clone(), "b");
1618 assert_eq!(map.len(), 2, "both distinct keys should be retained");
1619 }
1620
1621 #[test]
1622 fn test_clustering_key_ord_btree_ordering() {
1623 use std::collections::BTreeMap;
1625
1626 let mut map = BTreeMap::new();
1627
1628 let ck3 = ClusteringKey::single("ts", Value::Timestamp(3000));
1629 let ck1 = ClusteringKey::single("ts", Value::Timestamp(1000));
1630 let ck2 = ClusteringKey::single("ts", Value::Timestamp(2000));
1631
1632 map.insert(ck3.clone(), "value3");
1634 map.insert(ck1.clone(), "value1");
1635 map.insert(ck2.clone(), "value2");
1636
1637 let values: Vec<_> = map.values().copied().collect();
1639 assert_eq!(values, vec!["value1", "value2", "value3"]);
1640 }
1641
1642 #[test]
1643 fn test_compare_frozen_list_values() {
1644 let list_a = Value::Frozen(Box::new(Value::List(vec![
1646 Value::text("a".to_string()),
1647 Value::text("b".to_string()),
1648 ])));
1649 let list_b = Value::Frozen(Box::new(Value::List(vec![
1650 Value::text("a".to_string()),
1651 Value::text("c".to_string()),
1652 ])));
1653 let list_c = Value::Frozen(Box::new(Value::List(vec![
1654 Value::text("a".to_string()),
1655 Value::text("b".to_string()),
1656 Value::text("c".to_string()),
1657 ])));
1658
1659 assert_eq!(compare_values(&list_a, &list_a).unwrap(), Ordering::Equal);
1661 assert_eq!(compare_values(&list_a, &list_b).unwrap(), Ordering::Less);
1663 assert_eq!(compare_values(&list_b, &list_a).unwrap(), Ordering::Greater);
1664 assert_eq!(compare_values(&list_a, &list_c).unwrap(), Ordering::Less);
1666 assert_eq!(compare_values(&list_c, &list_a).unwrap(), Ordering::Greater);
1667 }
1668
1669 #[test]
1670 fn test_frozen_list_clustering_key_btree_ordering() {
1671 use std::collections::BTreeMap;
1673
1674 let mut map = BTreeMap::new();
1675
1676 let ck_2elem = ClusteringKey::single(
1678 "tags",
1679 Value::Frozen(Box::new(Value::List(vec![
1680 Value::text("ck_0_0".to_string()),
1681 Value::text("ck_0_1".to_string()),
1682 ]))),
1683 );
1684 let ck_3elem = ClusteringKey::single(
1685 "tags",
1686 Value::Frozen(Box::new(Value::List(vec![
1687 Value::text("ck_1_0".to_string()),
1688 Value::text("ck_1_1".to_string()),
1689 Value::text("ck_1_2".to_string()),
1690 ]))),
1691 );
1692 let ck_4elem = ClusteringKey::single(
1693 "tags",
1694 Value::Frozen(Box::new(Value::List(vec![
1695 Value::text("ck_2_0".to_string()),
1696 Value::text("ck_2_1".to_string()),
1697 Value::text("ck_2_2".to_string()),
1698 Value::text("ck_2_3".to_string()),
1699 ]))),
1700 );
1701
1702 map.insert(ck_4elem.clone(), "4elem");
1704 map.insert(ck_2elem.clone(), "2elem");
1705 map.insert(ck_3elem.clone(), "3elem");
1706
1707 assert_eq!(map.len(), 3, "All frozen list CKs should be distinct");
1709
1710 let values: Vec<_> = map.values().copied().collect();
1712 assert_eq!(values, vec!["2elem", "3elem", "4elem"]);
1713 }
1714
1715 #[test]
1716 fn test_partition_key_from_bytes_single_int() {
1717 let schema = TableSchema {
1718 keyspace: "ks".to_string(),
1719 table: "tbl".to_string(),
1720 partition_keys: vec![KeyColumn {
1721 name: "id".to_string(),
1722 data_type: "int".to_string(),
1723 position: 0,
1724 }],
1725 clustering_keys: vec![],
1726 columns: vec![],
1727 comments: HashMap::new(),
1728 dropped_columns: HashMap::new(),
1729 };
1730
1731 let original = PartitionKey::single("id", Value::Integer(42));
1732 let bytes = original.to_bytes(&schema).unwrap();
1733 let decoded = PartitionKey::from_bytes(&bytes, &schema).unwrap();
1734 assert_eq!(original, decoded);
1735 }
1736
1737 #[test]
1738 fn test_partition_key_from_bytes_single_uuid() {
1739 let schema = TableSchema {
1740 keyspace: "ks".to_string(),
1741 table: "tbl".to_string(),
1742 partition_keys: vec![KeyColumn {
1743 name: "id".to_string(),
1744 data_type: "uuid".to_string(),
1745 position: 0,
1746 }],
1747 clustering_keys: vec![],
1748 columns: vec![],
1749 comments: HashMap::new(),
1750 dropped_columns: HashMap::new(),
1751 };
1752
1753 let uuid_bytes = [1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
1754 let original = PartitionKey::single("id", Value::Uuid(uuid_bytes));
1755 let bytes = original.to_bytes(&schema).unwrap();
1756 let decoded = PartitionKey::from_bytes(&bytes, &schema).unwrap();
1757 assert_eq!(original, decoded);
1758 }
1759
1760 #[test]
1761 fn test_partition_key_from_bytes_single_text() {
1762 let schema = TableSchema {
1763 keyspace: "ks".to_string(),
1764 table: "tbl".to_string(),
1765 partition_keys: vec![KeyColumn {
1766 name: "name".to_string(),
1767 data_type: "text".to_string(),
1768 position: 0,
1769 }],
1770 clustering_keys: vec![],
1771 columns: vec![],
1772 comments: HashMap::new(),
1773 dropped_columns: HashMap::new(),
1774 };
1775
1776 let original = PartitionKey::single("name", Value::text("hello".to_string()));
1777 let bytes = original.to_bytes(&schema).unwrap();
1778 let decoded = PartitionKey::from_bytes(&bytes, &schema).unwrap();
1779 assert_eq!(original, decoded);
1780 }
1781
1782 #[test]
1783 fn test_partition_key_from_bytes_multi_component() {
1784 let schema = TableSchema {
1785 keyspace: "ks".to_string(),
1786 table: "tbl".to_string(),
1787 partition_keys: vec![
1788 KeyColumn {
1789 name: "tenant".to_string(),
1790 data_type: "text".to_string(),
1791 position: 0,
1792 },
1793 KeyColumn {
1794 name: "id".to_string(),
1795 data_type: "int".to_string(),
1796 position: 1,
1797 },
1798 ],
1799 clustering_keys: vec![],
1800 columns: vec![],
1801 comments: HashMap::new(),
1802 dropped_columns: HashMap::new(),
1803 };
1804
1805 let original = PartitionKey::new(vec![
1806 ("tenant".to_string(), Value::text("acme".to_string())),
1807 ("id".to_string(), Value::Integer(99)),
1808 ]);
1809 let bytes = original.to_bytes(&schema).unwrap();
1810 let decoded = PartitionKey::from_bytes(&bytes, &schema).unwrap();
1811 assert_eq!(original, decoded);
1812 }
1813
1814 #[test]
1815 fn test_partition_key_from_bytes_empty_errors() {
1816 let schema = TableSchema {
1817 keyspace: "ks".to_string(),
1818 table: "tbl".to_string(),
1819 partition_keys: vec![KeyColumn {
1820 name: "id".to_string(),
1821 data_type: "int".to_string(),
1822 position: 0,
1823 }],
1824 clustering_keys: vec![],
1825 columns: vec![],
1826 comments: HashMap::new(),
1827 dropped_columns: HashMap::new(),
1828 };
1829
1830 assert!(PartitionKey::from_bytes(&[], &schema).is_err());
1831 }
1832
1833 #[test]
1834 fn test_clustering_key_cmp_type_mismatch_does_not_panic() {
1835 let key_a = ClusteringKey {
1839 columns: vec![("col".to_string(), Value::Integer(1))],
1840 };
1841 let key_b = ClusteringKey {
1842 columns: vec![("col".to_string(), Value::text("1".to_string()))],
1843 };
1844
1845 let first = key_a.cmp(&key_b);
1847 let second = key_a.cmp(&key_b);
1849 assert_eq!(first, second);
1850
1851 assert_eq!(key_a.cmp(&key_a), Ordering::Equal);
1853 }
1854}