mysql_common/row/
mod.rs

1// Copyright (c) 2017 Anatoly Ikorsky
2//
3// Licensed under the Apache License, Version 2.0
4// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
5// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. All files in the project carrying such notice may not be copied,
7// modified, or distributed except according to those terms.
8
9use crate::{
10    io::ParseBuf,
11    misc::unexpected_buf_eof,
12    packets::{Column, NullBitmap},
13    proto::{Binary, MyDeserialize, Text},
14    value::{
15        convert::{from_value, from_value_opt, FromValue, FromValueError},
16        BinValue, SerializationSide, TextValue, Value, ValueDeserializer,
17    },
18};
19use std::{borrow::Cow, fmt, io, marker::PhantomData, ops::Index, sync::Arc};
20
21pub mod convert;
22
23/// Client side representation of a MySql row.
24///
25/// It allows you to move column values out of a row with `Row::take` method but note that it
26/// makes row incomplete. Calls to `from_row_opt` on incomplete row will return
27/// `Error::FromRowError` and also numerical indexing on taken columns will panic.
28#[derive(Clone, PartialEq)]
29pub struct Row {
30    values: Vec<Option<Value>>,
31    columns: Arc<[Column]>,
32}
33
34impl fmt::Debug for Row {
35    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36        let mut debug = f.debug_struct("Row");
37        for (val, column) in self.values.iter().zip(self.columns.iter()) {
38            match *val {
39                Some(ref val) => {
40                    debug.field(column.name_str().as_ref(), val);
41                }
42                None => {
43                    debug.field(column.name_str().as_ref(), &"<taken>");
44                }
45            }
46        }
47        debug.finish()
48    }
49}
50
51/// Creates `Row` from values and columns.
52pub fn new_row(values: Vec<Value>, columns: Arc<[Column]>) -> Row {
53    assert!(values.len() == columns.len());
54    Row {
55        values: values.into_iter().map(Some).collect::<Vec<_>>(),
56        columns,
57    }
58}
59
60/// Creates `Row` from values (cells may be missing).
61#[doc(hidden)]
62pub fn new_row_raw(values: Vec<Option<Value>>, columns: Arc<[Column]>) -> Row {
63    assert!(values.len() == columns.len());
64    Row { values, columns }
65}
66
67impl Row {
68    /// Returns length of a row.
69    pub fn len(&self) -> usize {
70        self.values.len()
71    }
72
73    /// Returns true if the row has a length of 0.
74    pub fn is_empty(&self) -> bool {
75        self.values.is_empty()
76    }
77
78    /// Returns columns of this row.
79    pub fn columns_ref(&self) -> &[Column] {
80        &self.columns
81    }
82
83    /// Returns columns of this row.
84    pub fn columns(&self) -> Arc<[Column]> {
85        self.columns.clone()
86    }
87
88    /// Returns reference to the value of a column with index `index` if it exists and wasn't taken
89    /// by `Row::take` method.
90    ///
91    /// Non panicking version of `row[usize]`.
92    pub fn as_ref(&self, index: usize) -> Option<&Value> {
93        self.values.get(index).and_then(|x| x.as_ref())
94    }
95
96    /// Will copy value at index `index` if it was not taken by `Row::take` earlier,
97    /// then will convert it to `T`.
98    pub fn get<T, I>(&self, index: I) -> Option<T>
99    where
100        T: FromValue,
101        I: ColumnIndex,
102    {
103        index.idx(&self.columns).and_then(|idx| {
104            self.values
105                .get(idx)
106                .and_then(|x| x.as_ref())
107                .map(|x| from_value::<T>(x.clone()))
108        })
109    }
110
111    /// Will copy value at index `index` if it was not taken by `Row::take` or `Row::take_opt`
112    /// earlier, then will attempt convert it to `T`. Unlike `Row::get`, `Row::get_opt` will
113    /// allow you to directly handle errors if the value could not be converted to `T`.
114    pub fn get_opt<T, I>(&self, index: I) -> Option<Result<T, FromValueError>>
115    where
116        T: FromValue,
117        I: ColumnIndex,
118    {
119        index
120            .idx(&self.columns)
121            .and_then(|idx| self.values.get(idx))
122            .and_then(|x| x.as_ref())
123            .map(|x| from_value_opt::<T>(x.clone()))
124    }
125
126    /// Will take value of a column with index `index` if it exists and wasn't taken earlier then
127    /// will converts it to `T`.
128    pub fn take<T, I>(&mut self, index: I) -> Option<T>
129    where
130        T: FromValue,
131        I: ColumnIndex,
132    {
133        index.idx(&self.columns).and_then(|idx| {
134            self.values
135                .get_mut(idx)
136                .and_then(|x| x.take())
137                .map(from_value::<T>)
138        })
139    }
140
141    /// Will take value of a column with index `index` if it exists and wasn't taken earlier then
142    /// will attempt to convert it to `T`. Unlike `Row::take`, `Row::take_opt` will allow you to
143    /// directly handle errors if the value could not be converted to `T`.
144    pub fn take_opt<T, I>(&mut self, index: I) -> Option<Result<T, FromValueError>>
145    where
146        T: FromValue,
147        I: ColumnIndex,
148    {
149        index
150            .idx(&self.columns)
151            .and_then(|idx| self.values.get_mut(idx))
152            .and_then(|x| x.take())
153            .map(from_value_opt::<T>)
154    }
155
156    /// Unwraps values of a row.
157    ///
158    /// # Panics
159    ///
160    /// Panics if any of columns was taken by `take` method.
161    pub fn unwrap(self) -> Vec<Value> {
162        self.values
163            .into_iter()
164            .map(|x| x.expect("Can't unwrap row if some of columns was taken"))
165            .collect()
166    }
167
168    /// Unwraps values as is (taken cells will be `None`).
169    #[doc(hidden)]
170    pub fn unwrap_raw(self) -> Vec<Option<Value>> {
171        self.values
172    }
173
174    #[doc(hidden)]
175    pub fn place(&mut self, index: usize, value: Value) {
176        self.values[index] = Some(value);
177    }
178}
179
180impl Index<usize> for Row {
181    type Output = Value;
182
183    fn index(&self, index: usize) -> &Value {
184        self.values[index].as_ref().unwrap()
185    }
186}
187
188impl<'a> Index<&'a str> for Row {
189    type Output = Value;
190
191    fn index<'r>(&'r self, index: &'a str) -> &'r Value {
192        for (i, column) in self.columns.iter().enumerate() {
193            if column.name_ref() == index.as_bytes() {
194                return self.values[i].as_ref().unwrap();
195            }
196        }
197        panic!("No such column: `{}` in row {:?}", index, self);
198    }
199}
200
201/// Things that may be used as an index of a row column.
202pub trait ColumnIndex {
203    fn idx(&self, columns: &[Column]) -> Option<usize>;
204}
205
206impl ColumnIndex for usize {
207    fn idx(&self, columns: &[Column]) -> Option<usize> {
208        if *self >= columns.len() {
209            None
210        } else {
211            Some(*self)
212        }
213    }
214}
215
216impl ColumnIndex for &'_ str {
217    fn idx(&self, columns: &[Column]) -> Option<usize> {
218        for (i, c) in columns.iter().enumerate() {
219            if c.name_ref() == self.as_bytes() {
220                return Some(i);
221            }
222        }
223        None
224    }
225}
226
227/// Row deserializer.
228///
229/// `S` – serialization side (see [`SerializationSide`]);
230/// `P` – protocol.
231#[derive(Debug, Clone, PartialEq)]
232pub struct RowDeserializer<S, P>(Row, PhantomData<(S, P)>);
233
234impl<S, P> RowDeserializer<S, P> {
235    pub fn into_inner(self) -> Row {
236        self.0
237    }
238}
239
240impl<S, P> From<RowDeserializer<S, P>> for Row {
241    fn from(x: RowDeserializer<S, P>) -> Self {
242        x.0
243    }
244}
245
246impl<'de, T> MyDeserialize<'de> for RowDeserializer<T, Text> {
247    const SIZE: Option<usize> = None;
248    type Ctx = Arc<[Column]>;
249
250    fn deserialize(columns: Self::Ctx, buf: &mut ParseBuf<'de>) -> io::Result<Self> {
251        let mut values = Vec::with_capacity(columns.len());
252
253        for _ in 0..columns.len() {
254            values.push(Some(
255                ValueDeserializer::<TextValue>::deserialize((), &mut *buf)?.0,
256            ))
257        }
258
259        Ok(Self(Row { values, columns }, PhantomData))
260    }
261}
262
263impl<'de, S: SerializationSide> MyDeserialize<'de> for RowDeserializer<S, Binary> {
264    const SIZE: Option<usize> = None;
265    type Ctx = Arc<[Column]>;
266
267    fn deserialize(columns: Self::Ctx, buf: &mut ParseBuf<'de>) -> io::Result<Self> {
268        use Value::*;
269
270        buf.checked_eat_u8().ok_or_else(unexpected_buf_eof)?;
271
272        let bitmap = NullBitmap::<S, Cow<'de, [u8]>>::deserialize(columns.len(), &mut *buf)?;
273        let mut values = Vec::with_capacity(columns.len());
274
275        for (i, column) in columns.iter().enumerate() {
276            if bitmap.is_null(i) {
277                values.push(Some(NULL))
278            } else {
279                values.push(Some(
280                    ValueDeserializer::<BinValue>::deserialize(
281                        (column.column_type(), column.flags()),
282                        &mut *buf,
283                    )?
284                    .0,
285                ));
286            }
287        }
288
289        Ok(Self(Row { values, columns }, PhantomData))
290    }
291}