hdbconnect_impl/base/
row.rs

1use crate::{
2    HdbResult,
3    base::{OAM, RsCore},
4    conn::AmConnCore,
5    protocol::parts::{HdbValue, ResultSetMetadata},
6    usage_err,
7};
8use serde_db::de::DeserializableRow;
9use std::sync::Arc;
10
11/// A single line of a `ResultSet`, consisting of the contained `HdbValue`s and
12/// a reference to the metadata.
13///
14/// `Row` has several methods that support an efficient data transfer into your own data structures.
15///
16/// You also can access individual values with `row[idx]`, or iterate over the values (with
17/// `row.iter()` or `for value in row {...}`).
18pub struct Row {
19    metadata: Arc<ResultSetMetadata>,
20    value_iter: <Vec<HdbValue<'static>> as IntoIterator>::IntoIter,
21}
22
23impl Row {
24    /// Factory for row.
25    pub(crate) fn new(metadata: Arc<ResultSetMetadata>, values: Vec<HdbValue<'static>>) -> Self {
26        Self {
27            metadata,
28            value_iter: values.into_iter(),
29        }
30    }
31
32    /// Converts the entire Row into a rust value.
33    ///
34    /// # Errors
35    ///
36    /// `HdbError::Deserialization` if deserialization into the target type is not possible.
37    pub fn try_into<'de, T>(self) -> HdbResult<T>
38    where
39        T: serde::de::Deserialize<'de>,
40    {
41        trace!("Row::into_typed()");
42        Ok(DeserializableRow::try_into(self)?)
43    }
44
45    /// Removes and returns the next value.
46    pub fn next_value(&mut self) -> Option<HdbValue<'static>> {
47        self.value_iter.next()
48    }
49
50    /// Conveniently combines `next_value()` and the value's `try_into()`.
51    ///
52    /// # Errors
53    ///
54    /// `HdbError::Usage` if there is no more element.
55    ///
56    /// `HdbError::Deserialization` if deserialization into the target type is not possible.
57    pub fn next_try_into<'de, T>(&mut self) -> HdbResult<T>
58    where
59        T: serde::de::Deserialize<'de>,
60    {
61        self.next_value()
62            .ok_or_else(|| usage_err!("no more value"))?
63            .try_into()
64    }
65
66    /// Returns the length of the row.
67    #[must_use]
68    pub fn len(&self) -> usize {
69        trace!("Row::len()");
70        self.value_iter.len()
71    }
72
73    /// Returns true if the row contains no value.
74    #[must_use]
75    pub fn is_empty(&self) -> bool {
76        self.value_iter.as_slice().is_empty()
77    }
78
79    /// Converts itself in the single contained value.
80    ///
81    /// # Errors
82    ///
83    /// `HdbError::Usage` if the row is empty or has more than one value.
84    pub fn into_single_value(mut self) -> HdbResult<HdbValue<'static>> {
85        if self.len() > 1 {
86            Err(usage_err!("Row has more than one field"))
87        } else {
88            Ok(self
89                .next_value()
90                .ok_or_else(|| usage_err!("Row is empty"))?)
91        }
92    }
93
94    /// Returns the metadata.
95    #[must_use]
96    pub fn metadata(&self) -> &ResultSetMetadata {
97        trace!("Row::metadata()");
98        &(self.metadata)
99    }
100
101    #[allow(clippy::ref_option)]
102    #[cfg(feature = "sync")]
103    pub(crate) fn parse_sync(
104        md: Arc<ResultSetMetadata>,
105        o_am_rscore: &OAM<RsCore>,
106        am_conn_core: &AmConnCore,
107        rdr: &mut std::io::Cursor<Vec<u8>>,
108    ) -> HdbResult<Self> {
109        let mut values = Vec::<HdbValue>::new();
110
111        let md0 = Arc::as_ref(&md);
112
113        // for col_idx in 0..md.len() {
114        for col_md in &**md0 {
115            let value = HdbValue::parse_sync(
116                col_md.type_id(),
117                col_md.is_array_type(),
118                col_md.scale(),
119                col_md.is_nullable(),
120                am_conn_core,
121                o_am_rscore,
122                rdr,
123            )?;
124            values.push(value);
125        }
126        let row = Self::new(md, values);
127        Ok(row)
128    }
129
130    #[allow(clippy::ref_option)]
131    #[cfg(feature = "async")]
132    pub(crate) async fn parse_async(
133        md: Arc<ResultSetMetadata>,
134        o_am_rscore: &OAM<RsCore>,
135        am_conn_core: &AmConnCore,
136        rdr: &mut std::io::Cursor<Vec<u8>>,
137    ) -> HdbResult<Self> {
138        let mut values = Vec::<HdbValue>::new();
139
140        let md0 = Arc::as_ref(&md);
141
142        // for col_idx in 0..md.len() {
143        for col_md in &**md0 {
144            let value = HdbValue::parse_async(
145                col_md.type_id(),
146                col_md.is_array_type(),
147                col_md.scale(),
148                col_md.is_nullable(),
149                am_conn_core,
150                o_am_rscore,
151                rdr,
152            )
153            .await?;
154            values.push(value);
155        }
156        let row = Self::new(md, values);
157        Ok(row)
158    }
159}
160
161/// Support indexing.
162impl std::ops::Index<usize> for Row {
163    type Output = HdbValue<'static>;
164    fn index(&self, idx: usize) -> &HdbValue<'static> {
165        &self.value_iter.as_slice()[idx]
166    }
167}
168
169impl std::ops::IndexMut<usize> for Row {
170    fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
171        &mut self.value_iter.as_mut_slice()[idx]
172    }
173}
174
175/// Row is an iterator with item `HdbValue`.
176impl Iterator for Row {
177    type Item = HdbValue<'static>;
178    fn next(&mut self) -> Option<HdbValue<'static>> {
179        self.next_value()
180    }
181}
182
183impl std::fmt::Display for Row {
184    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
185        for v in self.value_iter.as_slice() {
186            write!(fmt, "{v}, ")?;
187        }
188        Ok(())
189    }
190}
191
192impl std::fmt::Debug for Row {
193    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
194        for (v, md) in self.value_iter.as_slice().iter().zip(self.metadata.iter()) {
195            write!(fmt, "{v:?}:[{}], ", md.type_id())?;
196        }
197        Ok(())
198    }
199}