Skip to main content

tank_core/
row.rs

1use crate::{QueryResult, Value};
2use std::{
3    iter::{self},
4    slice,
5    sync::Arc,
6};
7
8/// Result of a modifying operation (INSERT/UPDATE/DELETE).
9#[derive(Default, Clone, Copy, Debug)]
10pub struct RowsAffected {
11    /// Number of rows modified (if supported by backend).
12    pub rows_affected: Option<u64>,
13    /// Last inserted ID (driver-dependent).
14    pub last_affected_id: Option<i64>,
15}
16
17/// Shared columns labels.
18pub type RowLabels = Arc<[String]>;
19/// Row values matching `RowLabels`.
20pub type RowValues = Box<[Value]>;
21
22/// Row with column labels.
23#[derive(Default, Clone, Debug)]
24pub struct Row {
25    /// Shared reference to column names for efficient storage.
26    pub labels: RowLabels,
27    /// Data values for this specific row.
28    pub values: RowValues,
29}
30
31impl Row {
32    /// Creates a new row from labels and values.
33    pub fn new(names: RowLabels, values: RowValues) -> Self {
34        Self {
35            labels: names,
36            values,
37        }
38    }
39    /// Accesses the column names associated with this row.
40    pub fn names(&self) -> &[String] {
41        &self.labels
42    }
43    /// Accesses the raw values in this row.
44    pub fn values(&self) -> &[Value] {
45        &self.values
46    }
47    /// Retrieves a value by its column name. Returns `None` if the column doesn't exist.
48    pub fn get_column(&self, name: &str) -> Option<&Value> {
49        self.labels
50            .iter()
51            .position(|v| v == name)
52            .map(|i| &self.values()[i])
53    }
54    /// Returns the number of columns in the row.
55    pub fn len(&self) -> usize {
56        self.values.len()
57    }
58}
59
60impl<'s> IntoIterator for &'s Row {
61    type Item = (&'s String, &'s Value);
62    type IntoIter = iter::Zip<slice::Iter<'s, String>, slice::Iter<'s, Value>>;
63    fn into_iter(self) -> Self::IntoIter {
64        iter::zip(self.labels.iter(), self.values.iter())
65    }
66}
67
68impl<'s> IntoIterator for &'s mut Row {
69    type Item = (&'s String, &'s mut Value);
70    type IntoIter = iter::Zip<slice::Iter<'s, String>, slice::IterMut<'s, Value>>;
71    fn into_iter(self) -> Self::IntoIter {
72        iter::zip(self.labels.iter(), self.values.iter_mut())
73    }
74}
75
76impl Extend<RowsAffected> for RowsAffected {
77    fn extend<T: IntoIterator<Item = RowsAffected>>(&mut self, iter: T) {
78        for elem in iter {
79            if self.rows_affected.is_some() || elem.rows_affected.is_some() {
80                self.rows_affected = Some(
81                    self.rows_affected.unwrap_or_default() + elem.rows_affected.unwrap_or_default(),
82                );
83            }
84            if elem.last_affected_id.is_some() {
85                self.last_affected_id = elem.last_affected_id;
86            }
87        }
88    }
89}
90
91impl From<Row> for RowValues {
92    fn from(value: Row) -> Self {
93        value.values
94    }
95}
96
97impl<'a> From<&'a Row> for &'a RowValues {
98    fn from(value: &'a Row) -> Self {
99        &value.values
100    }
101}
102
103impl From<Row> for QueryResult {
104    fn from(value: Row) -> Self {
105        QueryResult::Row(value)
106    }
107}
108
109impl From<RowsAffected> for QueryResult {
110    fn from(value: RowsAffected) -> Self {
111        QueryResult::Affected(value)
112    }
113}