Skip to main content

tank_core/
row.rs

1use crate::{AsValue, QueryResult, Value, ValueOwned};
2use std::{
3    borrow::Cow,
4    fmt::{self, Debug, Formatter},
5    iter,
6    sync::Arc,
7    vec,
8};
9
10/// Result of a modifying operation (INSERT/UPDATE/DELETE).
11#[derive(Default, Clone, Copy, Debug)]
12pub struct RowsAffected {
13    /// Number of rows modified (if supported by backend).
14    pub rows_affected: Option<u64>,
15    /// Last inserted ID (driver-dependent).
16    pub last_affected_id: Option<i64>,
17}
18
19impl Extend<RowsAffected> for RowsAffected {
20    fn extend<T: IntoIterator<Item = RowsAffected>>(&mut self, iter: T) {
21        for elem in iter {
22            if self.rows_affected.is_some() || elem.rows_affected.is_some() {
23                self.rows_affected = Some(
24                    self.rows_affected.unwrap_or_default() + elem.rows_affected.unwrap_or_default(),
25                );
26            }
27            if elem.last_affected_id.is_some() {
28                self.last_affected_id = elem.last_affected_id;
29            }
30        }
31    }
32}
33
34/// Shared column labels.
35pub type RowLabels = Arc<[String]>;
36/// Row values matching `RowLabels`.
37pub type RowValues = Vec<ValueOwned>;
38
39/// A labeled row, either materialized or decoded from a native driver view.
40pub trait Row: Debug + Send + Sync {
41    /// Column names in result order.
42    fn labels(&self) -> &[String];
43
44    /// Number of columns.
45    fn len(&self) -> usize;
46
47    /// Borrows a stored value or returns a freshly decoded value.
48    /// SQL NULL is a `Value`; `None` means no value at this index.
49    fn value(&self, index: usize) -> Option<Cow<'_, Value<'_>>>;
50
51    fn is_empty(&self) -> bool {
52        self.len() == 0
53    }
54
55    fn get_column(&self, name: &str) -> Option<Cow<'_, Value<'_>>> {
56        self.labels()
57            .iter()
58            .position(|label| label == name)
59            .and_then(|index| self.value(index))
60    }
61
62    /// Iterates values without cloning stored payloads, stopping at a missing cell.
63    fn values(&self) -> impl Iterator<Item = Cow<'_, Value<'_>>> {
64        (0..self.len()).map_while(|index| self.value(index))
65    }
66
67    fn iter(&self) -> impl Iterator<Item = (&str, Cow<'_, Value<'_>>)> {
68        iter::zip(self.labels().iter().map(String::as_str), self.values())
69    }
70
71    /// Consumes the row into an iterator of owned values.
72    fn into_values(self) -> impl Iterator<Item = ValueOwned>
73    where
74        Self: Sized,
75    {
76        let row = self;
77        let mut index = 0;
78        iter::from_fn(move || {
79            let value = row.value(index)?.as_value().into_owned();
80            index += 1;
81            Some(value)
82        })
83    }
84
85    /// Copies names and owns all borrowed value payloads.
86    ///
87    /// Native row views override this to share their cached
88    /// [`RowLabels`] instead of re-allocating it.
89    fn into_owned(self) -> RowOwned
90    where
91        Self: Sized,
92    {
93        RowOwned::new(
94            self.labels().into(),
95            self.values()
96                .map(|value| value.into_owned().into_owned())
97                .collect(),
98        )
99    }
100}
101
102impl<R: Row + ?Sized> Row for &R {
103    #[inline(always)]
104    fn labels(&self) -> &[String] {
105        (**self).labels()
106    }
107
108    #[inline(always)]
109    fn len(&self) -> usize {
110        (**self).len()
111    }
112
113    #[inline(always)]
114    fn value(&self, index: usize) -> Option<Cow<'_, Value<'_>>> {
115        (**self).value(index)
116    }
117
118    #[inline(always)]
119    fn is_empty(&self) -> bool {
120        (**self).is_empty()
121    }
122
123    #[inline(always)]
124    fn get_column(&self, name: &str) -> Option<Cow<'_, Value<'_>>> {
125        (**self).get_column(name)
126    }
127
128    #[inline(always)]
129    fn values(&self) -> impl Iterator<Item = Cow<'_, Value<'_>>> {
130        (**self).values()
131    }
132
133    #[inline(always)]
134    fn iter(&self) -> impl Iterator<Item = (&str, Cow<'_, Value<'_>>)> {
135        (**self).iter()
136    }
137}
138
139/// An owning row with shared column names.
140#[derive(Clone, Default)]
141pub struct RowOwned {
142    pub labels: RowLabels,
143    pub values: RowValues,
144}
145
146impl RowOwned {
147    pub fn new(labels: RowLabels, values: RowValues) -> Self {
148        Self {
149            labels,
150            values: values.into(),
151        }
152    }
153}
154
155impl Debug for RowOwned {
156    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
157        f.debug_struct("RowOwned")
158            .field("labels", &self.labels)
159            .field("len", &self.values.len())
160            .finish()
161    }
162}
163
164impl IntoIterator for RowOwned {
165    type Item = ValueOwned;
166    type IntoIter = vec::IntoIter<ValueOwned>;
167
168    #[inline(always)]
169    fn into_iter(self) -> Self::IntoIter {
170        self.values.into_iter()
171    }
172}
173
174impl Row for RowOwned {
175    #[inline(always)]
176    fn labels(&self) -> &[String] {
177        &self.labels
178    }
179
180    #[inline(always)]
181    fn len(&self) -> usize {
182        self.values.len()
183    }
184
185    #[inline(always)]
186    fn value(&self, index: usize) -> Option<Cow<'_, Value<'_>>> {
187        self.values.get(index).map(Cow::Borrowed)
188    }
189
190    fn into_values(self) -> impl Iterator<Item = ValueOwned> {
191        self.values.into_iter()
192    }
193
194    #[inline(always)]
195    fn into_owned(self) -> RowOwned {
196        self
197    }
198}
199
200impl<R: Row> From<R> for QueryResult<R> {
201    fn from(value: R) -> Self {
202        QueryResult::Row(value)
203    }
204}
205
206impl<R> From<RowsAffected> for QueryResult<R> {
207    fn from(value: RowsAffected) -> Self {
208        QueryResult::Affected(value)
209    }
210}