cassandra_cpp/cassandra/
row.rs

1use bigdecimal::BigDecimal;
2
3use crate::cassandra::error::*;
4
5use crate::cassandra::inet::Inet;
6use crate::cassandra::iterator::{MapIterator, SetIterator, UserTypeIterator};
7
8use crate::cassandra::util::{Protected, ProtectedInner};
9use crate::cassandra::uuid::Uuid;
10use crate::cassandra::value::Value;
11use crate::cassandra_sys::cass_false;
12use crate::cassandra_sys::cass_iterator_free;
13use crate::cassandra_sys::cass_iterator_from_row;
14use crate::cassandra_sys::cass_iterator_get_column;
15use crate::cassandra_sys::cass_iterator_next;
16use crate::cassandra_sys::cass_row_get_column;
17use crate::cassandra_sys::cass_row_get_column_by_name_n;
18use crate::cassandra_sys::cass_true;
19use crate::cassandra_sys::CassIterator as _CassIterator;
20use crate::cassandra_sys::CassRow as _Row;
21use crate::LendingIterator;
22use std::fmt;
23use std::fmt::Debug;
24use std::fmt::Display;
25use std::fmt::Formatter;
26use std::marker::PhantomData;
27use std::os::raw::c_char;
28
29/// A collection of column values. Read-only, so thread-safe.
30//
31// Borrowed immutably.
32pub struct Row<'a>(*const _Row, PhantomData<&'a _Row>);
33
34unsafe impl Sync for Row<'_> {}
35unsafe impl Send for Row<'_> {}
36
37impl ProtectedInner<*const _Row> for Row<'_> {
38    fn inner(&self) -> *const _Row {
39        self.0
40    }
41}
42
43impl Protected<*const _Row> for Row<'_> {
44    fn build(inner: *const _Row) -> Self {
45        if inner.is_null() {
46            panic!("Unexpected null pointer")
47        };
48        Row(inner, PhantomData)
49    }
50}
51
52impl Debug for Row<'_> {
53    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
54        let mut iter = self.iter();
55        while let Some(column) = iter.next() {
56            write!(f, "{:?}\t", Value::build(column.inner()))?;
57        }
58        Ok(())
59    }
60}
61
62impl Display for Row<'_> {
63    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
64        let mut iter = self.iter();
65        while let Some(column) = iter.next() {
66            write!(f, "{}\t", Value::build(column.inner()))?;
67        }
68        Ok(())
69    }
70}
71
72/// Auto inferencing conversion from Cassandra to Rust.
73pub trait AsRustType<T> {
74    /// Convert Cassandra column by index.
75    fn get(&self, index: usize) -> Result<T>;
76
77    /// Convert Cassandra column by name.
78    fn get_by_name<S>(&self, name: S) -> Result<T>
79    where
80        S: Into<String>;
81}
82
83impl AsRustType<bool> for Row<'_> {
84    fn get(&self, index: usize) -> Result<bool> {
85        let col = self.get_column(index)?;
86        col.get_bool()
87    }
88
89    fn get_by_name<S>(&self, name: S) -> Result<bool>
90    where
91        S: Into<String>,
92    {
93        self.get_column_by_name(name)?.get_bool()
94    }
95}
96
97impl AsRustType<String> for Row<'_> {
98    fn get(&self, index: usize) -> Result<String> {
99        let col = self.get_column(index)?;
100        col.get_string()
101    }
102
103    fn get_by_name<S>(&self, name: S) -> Result<String>
104    where
105        S: Into<String>,
106    {
107        let col = self.get_column_by_name(name)?;
108        col.get_string()
109    }
110}
111
112impl AsRustType<f64> for Row<'_> {
113    fn get(&self, index: usize) -> Result<f64> {
114        let col = self.get_column(index)?;
115        col.get_f64()
116    }
117
118    fn get_by_name<S>(&self, name: S) -> Result<f64>
119    where
120        S: Into<String>,
121    {
122        let col = self.get_column_by_name(name)?;
123        col.get_f64()
124    }
125}
126
127impl AsRustType<f32> for Row<'_> {
128    fn get(&self, index: usize) -> Result<f32> {
129        let col = self.get_column(index)?;
130        col.get_f32()
131    }
132
133    fn get_by_name<S>(&self, name: S) -> Result<f32>
134    where
135        S: Into<String>,
136    {
137        let col = self.get_column_by_name(name)?;
138        col.get_f32()
139    }
140}
141
142impl AsRustType<i64> for Row<'_> {
143    fn get(&self, index: usize) -> Result<i64> {
144        let col = self.get_column(index)?;
145        col.get_i64()
146    }
147
148    fn get_by_name<S>(&self, name: S) -> Result<i64>
149    where
150        S: Into<String>,
151    {
152        let col = self.get_column_by_name(name)?;
153        col.get_i64()
154    }
155}
156
157impl AsRustType<i32> for Row<'_> {
158    fn get(&self, index: usize) -> Result<i32> {
159        let col = self.get_column(index)?;
160        col.get_i32()
161    }
162
163    fn get_by_name<S>(&self, name: S) -> Result<i32>
164    where
165        S: Into<String>,
166    {
167        let col = self.get_column_by_name(name)?;
168        col.get_i32()
169    }
170}
171
172impl AsRustType<i16> for Row<'_> {
173    fn get(&self, index: usize) -> Result<i16> {
174        let col = self.get_column(index)?;
175        col.get_i16()
176    }
177
178    fn get_by_name<S>(&self, name: S) -> Result<i16>
179    where
180        S: Into<String>,
181    {
182        let col = self.get_column_by_name(name)?;
183        col.get_i16()
184    }
185}
186
187impl AsRustType<i8> for Row<'_> {
188    fn get(&self, index: usize) -> Result<i8> {
189        let col = self.get_column(index)?;
190        col.get_i8()
191    }
192
193    fn get_by_name<S>(&self, name: S) -> Result<i8>
194    where
195        S: Into<String>,
196    {
197        let col = self.get_column_by_name(name)?;
198        col.get_i8()
199    }
200}
201
202impl AsRustType<u32> for Row<'_> {
203    fn get(&self, index: usize) -> Result<u32> {
204        let col = self.get_column(index)?;
205        col.get_u32()
206    }
207
208    fn get_by_name<S>(&self, name: S) -> Result<u32>
209    where
210        S: Into<String>,
211    {
212        let col = self.get_column_by_name(name)?;
213        col.get_u32()
214    }
215}
216
217impl AsRustType<Inet> for Row<'_> {
218    fn get(&self, index: usize) -> Result<Inet> {
219        let col = self.get_column(index)?;
220        col.get_inet()
221    }
222
223    fn get_by_name<S>(&self, name: S) -> Result<Inet>
224    where
225        S: Into<String>,
226    {
227        let col = self.get_column_by_name(name)?;
228        col.get_inet()
229    }
230}
231
232impl<'a> AsRustType<SetIterator<'a>> for Row<'a> {
233    // The iterator is newly-created here, but it borrows the data it iterates
234    // over from the row (i.e., from its underlying result). Thus its lifetime
235    // parameter is the same as the row's.
236    fn get(&self, index: usize) -> Result<SetIterator<'a>> {
237        let col = self.get_column(index)?;
238        col.get_set()
239    }
240
241    fn get_by_name<S>(&self, name: S) -> Result<SetIterator<'a>>
242    where
243        S: Into<String>,
244    {
245        let col = self.get_column_by_name(name)?;
246        col.get_set()
247    }
248}
249
250impl<'a> AsRustType<MapIterator<'a>> for Row<'a> {
251    // The iterator is newly-created here, but it borrows the data it iterates
252    // over from the row (i.e., from its underlying result). Thus its lifetime
253    // parameter is the same as the row's.
254    fn get(&self, index: usize) -> Result<MapIterator<'a>> {
255        let col = self.get_column(index)?;
256        col.get_map()
257    }
258
259    fn get_by_name<S>(&self, name: S) -> Result<MapIterator<'a>>
260    where
261        S: Into<String>,
262    {
263        let col = self.get_column_by_name(name)?;
264        col.get_map()
265    }
266}
267
268impl<'a> AsRustType<UserTypeIterator<'a>> for Row<'a> {
269    // The iterator is newly-created here, but it borrows the data it iterates
270    // over from the row (i.e., from its underlying result). Thus its lifetime
271    // parameter is the same as the row's.
272    fn get(&self, index: usize) -> Result<UserTypeIterator<'a>> {
273        let col = self.get_column(index)?;
274        col.get_user_type()
275    }
276
277    fn get_by_name<S>(&self, name: S) -> Result<UserTypeIterator<'a>>
278    where
279        S: Into<String>,
280    {
281        let col = self.get_column_by_name(name)?;
282        col.get_user_type()
283    }
284}
285
286impl AsRustType<Uuid> for Row<'_> {
287    fn get(&self, index: usize) -> Result<Uuid> {
288        let col = self.get_column(index)?;
289        col.get_uuid()
290    }
291
292    fn get_by_name<S>(&self, name: S) -> Result<Uuid>
293    where
294        S: Into<String>,
295    {
296        let col = self.get_column_by_name(name)?;
297        col.get_uuid()
298    }
299}
300
301impl AsRustType<uuid::Uuid> for Row<'_> {
302    fn get(&self, index: usize) -> Result<uuid::Uuid> {
303        let col = self.get_column(index)?;
304        col.get_uuid().map(|x| x.into())
305    }
306
307    fn get_by_name<S>(&self, name: S) -> Result<uuid::Uuid>
308    where
309        S: Into<String>,
310    {
311        let col = self.get_column_by_name(name)?;
312        col.get_uuid().map(|x| x.into())
313    }
314}
315
316impl AsRustType<Vec<u8>> for Row<'_> {
317    fn get(&self, index: usize) -> Result<Vec<u8>> {
318        let col = self.get_column(index)?;
319        col.get_bytes().map(|b| b.to_vec())
320    }
321
322    fn get_by_name<S>(&self, name: S) -> Result<Vec<u8>>
323    where
324        S: Into<String>,
325    {
326        let col = self.get_column_by_name(name)?;
327        col.get_bytes().map(|b| b.to_vec())
328    }
329}
330
331impl AsRustType<BigDecimal> for Row<'_> {
332    fn get(&self, index: usize) -> Result<BigDecimal> {
333        let col = self.get_column(index)?;
334        col.get_decimal().map(|x| x.into())
335    }
336
337    fn get_by_name<S>(&self, name: S) -> Result<BigDecimal>
338    where
339        S: Into<String>,
340    {
341        let col = self.get_column_by_name(name)?;
342        col.get_decimal().map(|x| x.into())
343    }
344}
345
346impl<'a> Row<'a> {
347    /// Get a particular column by index
348    pub fn get_column(&self, index: usize) -> Result<Value<'a>> {
349        unsafe {
350            let col = cass_row_get_column(self.0, index);
351            if col.is_null() {
352                Err(CassErrorCode::LIB_INDEX_OUT_OF_BOUNDS.to_error())
353            } else {
354                Ok(Value::build(col))
355            }
356        }
357    }
358
359    /// Get a particular column by name
360    pub fn get_column_by_name<S>(&self, name: S) -> Result<Value<'a>>
361    where
362        S: Into<String>,
363    {
364        unsafe {
365            let name_str = name.into();
366            let name_ptr = name_str.as_ptr() as *const c_char;
367            let col = cass_row_get_column_by_name_n(self.0, name_ptr, name_str.len());
368            if col.is_null() {
369                Err(CassErrorCode::LIB_INDEX_OUT_OF_BOUNDS.to_error())
370            } else {
371                Ok(Value::build(col))
372            }
373        }
374    }
375
376    /// Creates a new iterator for the specified row. This can be
377    /// used to iterate over columns in a row.
378    pub fn iter(&'a self) -> RowIterator<'a> {
379        unsafe { RowIterator(cass_iterator_from_row(self.0), PhantomData) }
380    }
381}
382
383/// An iterator over the columns in a row
384///
385/// A Cassandra iterator is a `LendingIterator` because it borrows from some
386/// underlying value, but owns a single item. Each time `next()` is invoked it
387/// decodes the current item into that item, thus invalidating its previous
388/// value.
389#[derive(Debug)]
390pub struct RowIterator<'a>(*mut _CassIterator, PhantomData<&'a _Row>);
391
392// The underlying C type has no thread-local state, and forbids only concurrent
393// mutation/free: https://datastax.github.io/cpp-driver/topics/#thread-safety
394unsafe impl Send for RowIterator<'_> {}
395unsafe impl Sync for RowIterator<'_> {}
396
397impl Drop for RowIterator<'_> {
398    fn drop(&mut self) {
399        unsafe { cass_iterator_free(self.0) }
400    }
401}
402
403impl LendingIterator for RowIterator<'_> {
404    type Item<'a> = Value<'a> where Self: 'a;
405
406    fn next(&mut self) -> Option<<Self as LendingIterator>::Item<'_>> {
407        unsafe {
408            match cass_iterator_next(self.0) {
409                cass_false => None,
410                cass_true => Some(Value::build(cass_iterator_get_column(self.0))),
411            }
412        }
413    }
414}