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 pub fn new(value: impl Into<String>) -> Self {
15 Self(value.into())
16 }
17
18 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 KeyspaceName
53}
54string_newtype! {
55 ColumnFamilyName
57}
58string_newtype! {
59 WideTableName
61}
62string_newtype! {
63 PartitionKey
65}
66string_newtype! {
67 ClusteringKey
69}
70string_newtype! {
71 ColumnName
73}
74string_newtype! {
75 ColumnValue
77}
78
79#[derive(Clone, Debug, Eq, PartialEq)]
81pub struct ColumnFamily {
82 name: ColumnFamilyName,
83 columns: Vec<ColumnName>,
84}
85
86impl ColumnFamily {
87 pub fn new(name: ColumnFamilyName) -> Self {
89 Self {
90 name,
91 columns: Vec::new(),
92 }
93 }
94
95 pub fn with_column(mut self, column: ColumnName) -> Self {
97 self.columns.push(column);
98 self
99 }
100
101 pub const fn name(&self) -> &ColumnFamilyName {
103 &self.name
104 }
105
106 pub fn columns(&self) -> &[ColumnName] {
108 &self.columns
109 }
110}
111
112#[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 pub fn new(partition_key: PartitionKey) -> Self {
123 Self {
124 partition_key,
125 clustering_key: None,
126 columns: Vec::new(),
127 }
128 }
129
130 pub fn with_clustering_key(mut self, clustering_key: ClusteringKey) -> Self {
132 self.clustering_key = Some(clustering_key);
133 self
134 }
135
136 pub fn with_column(mut self, name: ColumnName, value: ColumnValue) -> Self {
138 self.columns.push((name, value));
139 self
140 }
141
142 pub const fn partition_key(&self) -> &PartitionKey {
144 &self.partition_key
145 }
146
147 pub const fn clustering_key(&self) -> Option<&ClusteringKey> {
149 self.clustering_key.as_ref()
150 }
151
152 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}