nativeclick/convert/
raw_row.rs1use std::borrow::Cow;
2
3use crate::{FromSql, NativeclickError, Result, Row, ToSql, Type, Value};
4
5#[derive(Debug, Default, Clone)]
8pub struct RawRow(Vec<Option<(String, Type, Value)>>);
9
10impl Row for RawRow {
11 const COLUMN_COUNT: Option<usize> = None;
12
13 fn column_names() -> Option<Vec<Cow<'static, str>>> {
14 None
15 }
16
17 fn deserialize_row(map: Vec<(&str, &Type, Value)>) -> Result<Self> {
18 Ok(Self(
19 map.into_iter()
20 .map(|(name, type_, value)| Some((name.to_string(), type_.clone(), value)))
21 .collect(),
22 ))
23 }
24
25 fn serialize_row(
26 self,
27 _type_hints: &indexmap::IndexMap<String, Type>,
28 ) -> Result<Vec<(Cow<'static, str>, Value)>> {
29 Ok(self
30 .0
31 .into_iter()
32 .map(|x| x.expect("cannot serialize a Row which has been retrieved from"))
33 .map(|(name, _, value)| (Cow::Owned(name), value))
34 .collect())
35 }
36}
37
38pub trait RowIndex {
39 fn get<'a, I: IntoIterator<Item = &'a str>>(&self, columns: I) -> Option<usize>;
40}
41
42impl RowIndex for usize {
43 fn get<'a, I: IntoIterator<Item = &'a str>>(&self, columns: I) -> Option<usize> {
44 let count = columns.into_iter().count();
45 if count >= *self { Some(*self) } else { None }
46 }
47}
48
49impl RowIndex for str {
50 fn get<'a, I: IntoIterator<Item = &'a str>>(&self, columns: I) -> Option<usize> {
51 columns.into_iter().position(|x| x == self)
52 }
53}
54
55impl<T: RowIndex + ?Sized> RowIndex for &T {
56 fn get<'a, I: IntoIterator<Item = &'a str>>(&self, columns: I) -> Option<usize> {
57 (*self).get(columns)
58 }
59}
60
61impl RawRow {
62 pub fn is_empty(&self) -> bool {
64 self.0.is_empty()
65 }
66
67 pub fn len(&self) -> usize {
69 self.0.len()
70 }
71
72 pub fn try_get<I: RowIndex, T: FromSql>(&mut self, index: I) -> Result<T> {
74 let index = index
75 .get(
76 self.0
77 .iter()
78 .map(|x| x.as_ref().map(|x| &*x.0).unwrap_or("")),
79 )
80 .ok_or(NativeclickError::OutOfBounds)?;
81 let (_, type_, value) = self
82 .0
83 .get_mut(index)
84 .unwrap()
85 .take()
86 .ok_or(NativeclickError::DoubleFetch)?;
87 crate::from_sql_resolved(&type_, value)
88 }
89
90 pub fn get<I: RowIndex, T: FromSql>(&mut self, index: I) -> T {
95 self.try_get(index).expect("failed to convert column")
96 }
97
98 pub fn try_set_typed(
100 &mut self,
101 name: impl ToString,
102 type_: Option<Type>,
103 value: impl ToSql,
104 ) -> Result<()> {
105 let name = name.to_string();
106 let value = value.to_sql(type_.as_ref())?;
107 let type_ = type_.unwrap_or_else(|| value.guess_type());
108
109 let current_position = self
110 .0
111 .iter()
112 .map(|x| x.as_ref().map(|x| &*x.0).unwrap_or(""))
113 .position(|x| x == &*name);
114
115 if let Some(current_position) = current_position {
116 self.0[current_position].as_mut().unwrap().1 = type_;
117 self.0[current_position].as_mut().unwrap().2 = value;
118 } else {
119 self.0.push(Some((name, type_, value)));
120 }
121 Ok(())
122 }
123
124 pub fn try_set(&mut self, name: impl ToString, value: impl ToSql) -> Result<()> {
126 self.try_set_typed(name, None, value)
127 }
128
129 pub fn set(&mut self, name: impl ToString, value: impl ToSql) {
131 self.try_set(name, value).expect("failed to convert column");
132 }
133
134 pub fn set_typed(&mut self, name: impl ToString, type_: Option<Type>, value: impl ToSql) {
136 self.try_set_typed(name, type_, value)
137 .expect("failed to convert column");
138 }
139}