Skip to main content

use_wide_column/
lib.rs

1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4use core::fmt;
5
6macro_rules! string_newtype {
7    ($(#[$meta:meta])* $name:ident) => {
8        $(#[$meta])*
9        #[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
10        pub struct $name(String);
11
12        impl $name {
13            /// Creates a new string-backed primitive.
14            pub fn new(value: impl Into<String>) -> Self {
15                Self(value.into())
16            }
17
18            /// Returns the stored string value.
19            pub fn as_str(&self) -> &str {
20                &self.0
21            }
22        }
23
24        impl AsRef<str> for $name {
25            fn as_ref(&self) -> &str {
26                self.as_str()
27            }
28        }
29
30        impl From<String> for $name {
31            fn from(value: String) -> Self {
32                Self::new(value)
33            }
34        }
35
36        impl From<&str> for $name {
37            fn from(value: &str) -> Self {
38                Self::new(value)
39            }
40        }
41
42        impl fmt::Display for $name {
43            fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
44                formatter.write_str(self.as_str())
45            }
46        }
47    };
48}
49
50string_newtype! {
51    /// A generic wide-column keyspace name.
52    KeyspaceName
53}
54string_newtype! {
55    /// A generic column-family name.
56    ColumnFamilyName
57}
58string_newtype! {
59    /// A generic wide-column table name.
60    WideTableName
61}
62string_newtype! {
63    /// A wide-column partition key.
64    PartitionKey
65}
66string_newtype! {
67    /// A clustering key within a partition.
68    ClusteringKey
69}
70string_newtype! {
71    /// A wide-column column name.
72    ColumnName
73}
74string_newtype! {
75    /// A wide-column value payload.
76    ColumnValue
77}
78
79/// A column-family descriptor.
80#[derive(Clone, Debug, Eq, PartialEq)]
81pub struct ColumnFamily {
82    name: ColumnFamilyName,
83    columns: Vec<ColumnName>,
84}
85
86impl ColumnFamily {
87    /// Creates a column family with no registered columns.
88    pub fn new(name: ColumnFamilyName) -> Self {
89        Self {
90            name,
91            columns: Vec::new(),
92        }
93    }
94
95    /// Adds a column name.
96    pub fn with_column(mut self, column: ColumnName) -> Self {
97        self.columns.push(column);
98        self
99    }
100
101    /// Returns the family name.
102    pub const fn name(&self) -> &ColumnFamilyName {
103        &self.name
104    }
105
106    /// Returns the registered columns.
107    pub fn columns(&self) -> &[ColumnName] {
108        &self.columns
109    }
110}
111
112/// A generic wide-column row.
113#[derive(Clone, Debug, Eq, PartialEq)]
114pub struct WideColumnRow {
115    partition_key: PartitionKey,
116    clustering_key: Option<ClusteringKey>,
117    columns: Vec<(ColumnName, ColumnValue)>,
118}
119
120impl WideColumnRow {
121    /// Creates a row for a partition key.
122    pub fn new(partition_key: PartitionKey) -> Self {
123        Self {
124            partition_key,
125            clustering_key: None,
126            columns: Vec::new(),
127        }
128    }
129
130    /// Sets the clustering key.
131    pub fn with_clustering_key(mut self, clustering_key: ClusteringKey) -> Self {
132        self.clustering_key = Some(clustering_key);
133        self
134    }
135
136    /// Adds a column value.
137    pub fn with_column(mut self, name: ColumnName, value: ColumnValue) -> Self {
138        self.columns.push((name, value));
139        self
140    }
141
142    /// Returns the partition key.
143    pub const fn partition_key(&self) -> &PartitionKey {
144        &self.partition_key
145    }
146
147    /// Returns the clustering key, if present.
148    pub const fn clustering_key(&self) -> Option<&ClusteringKey> {
149        self.clustering_key.as_ref()
150    }
151
152    /// Returns row columns.
153    pub fn columns(&self) -> &[(ColumnName, ColumnValue)] {
154        &self.columns
155    }
156}
157
158#[cfg(test)]
159mod tests {
160    use super::{
161        ClusteringKey, ColumnFamily, ColumnFamilyName, ColumnName, ColumnValue, KeyspaceName,
162        PartitionKey, WideColumnRow, WideTableName,
163    };
164
165    #[test]
166    fn constructs_wide_column_labels() {
167        assert_eq!(KeyspaceName::new("app").to_string(), "app");
168        assert_eq!(WideTableName::new("events").as_ref(), "events");
169        assert_eq!(ColumnFamilyName::new("profile").as_str(), "profile");
170    }
171
172    #[test]
173    fn builds_families_and_rows() {
174        let family = ColumnFamily::new(ColumnFamilyName::new("profile"))
175            .with_column(ColumnName::new("display_name"));
176        let row = WideColumnRow::new(PartitionKey::new("customer_123"))
177            .with_clustering_key(ClusteringKey::new("2026-05"))
178            .with_column(ColumnName::new("display_name"), ColumnValue::new("Joshua"));
179
180        assert_eq!(family.columns().len(), 1);
181        assert_eq!(row.partition_key().as_str(), "customer_123");
182        assert_eq!(row.columns().len(), 1);
183    }
184}