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
86impl<R: Row + ?Sized> Row for &R {
87    #[inline(always)]
88    fn labels(&self) -> &[String] {
89        (**self).labels()
90    }
91
92    #[inline(always)]
93    fn len(&self) -> usize {
94        (**self).len()
95    }
96
97    #[inline(always)]
98    fn value(&self, index: usize) -> Option<Cow<'_, Value<'_>>> {
99        (**self).value(index)
100    }
101
102    #[inline(always)]
103    fn is_empty(&self) -> bool {
104        (**self).is_empty()
105    }
106
107    #[inline(always)]
108    fn get_column(&self, name: &str) -> Option<Cow<'_, Value<'_>>> {
109        (**self).get_column(name)
110    }
111
112    #[inline(always)]
113    fn values(&self) -> impl Iterator<Item = Cow<'_, Value<'_>>> {
114        (**self).values()
115    }
116
117    #[inline(always)]
118    fn iter(&self) -> impl Iterator<Item = (&str, Cow<'_, Value<'_>>)> {
119        (**self).iter()
120    }
121}
122
123/// An owning row with shared column names.
124#[derive(Clone, Default)]
125pub struct RowOwned {
126    pub labels: RowLabels,
127    pub values: RowValues,
128}
129
130impl RowOwned {
131    pub fn new(labels: RowLabels, values: RowValues) -> Self {
132        Self {
133            labels,
134            values: values.into(),
135        }
136    }
137}
138
139impl Debug for RowOwned {
140    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
141        f.debug_struct("RowOwned")
142            .field("labels", &self.labels)
143            .field("len", &self.values.len())
144            .finish()
145    }
146}
147
148impl IntoIterator for RowOwned {
149    type Item = ValueOwned;
150    type IntoIter = vec::IntoIter<ValueOwned>;
151
152    #[inline(always)]
153    fn into_iter(self) -> Self::IntoIter {
154        self.values.into_iter()
155    }
156}
157
158impl Row for RowOwned {
159    #[inline(always)]
160    fn labels(&self) -> &[String] {
161        &self.labels
162    }
163
164    #[inline(always)]
165    fn len(&self) -> usize {
166        self.values.len()
167    }
168
169    #[inline(always)]
170    fn value(&self, index: usize) -> Option<Cow<'_, Value<'_>>> {
171        self.values.get(index).map(Cow::Borrowed)
172    }
173
174    fn into_values(self) -> impl Iterator<Item = ValueOwned> {
175        self.values.into_iter()
176    }
177}
178
179impl<R: Row> From<R> for QueryResult<R> {
180    fn from(value: R) -> Self {
181        QueryResult::Row(value)
182    }
183}
184
185impl<R> From<RowsAffected> for QueryResult<R> {
186    fn from(value: RowsAffected) -> Self {
187        QueryResult::Affected(value)
188    }
189}