Skip to main content

sql_peas/
cursor.rs

1use std::collections::HashMap;
2use std::convert::TryFrom;
3use std::ops::{Deref, Index};
4use std::rc::Rc;
5
6use crate::columns::Bindable;
7use crate::error::{Error, Result};
8use crate::statement::{State, Statement};
9use crate::value::Value;
10
11/// An iterator for a prepared statement.
12pub struct Cursor<'m> {
13    column_count: usize,
14    statement: &'m Statement,
15    poisoned: bool,
16}
17
18/* FIXME - Impossible?
19/// An iterator for a prepared statement with ownership.
20pub struct CursorWithOwnership<'l> {
21    column_count: usize,
22    statement: Statement,
23    poisoned: bool,
24}
25*/
26
27/// A row.
28#[derive(Debug)]
29pub struct Row {
30    column_names: Rc<Vec<String>>,
31    column_mapping: Rc<HashMap<String, usize>>,
32    values: Vec<Value>,
33}
34
35/// A type suitable for indexing columns in a row.
36pub trait RowIndex: std::fmt::Debug + std::fmt::Display {
37    /// Check if the index is present in a row.
38    fn contains(&self, row: &Row) -> bool;
39
40    /// Identify the ordinal position.
41    ///
42    /// The first column has index 0.
43    fn index(self, row: &Row) -> usize;
44}
45
46macro_rules! implement(
47    ($type:ident<$($lifetime:lifetime),+>) => {
48        impl<$($lifetime),+> $type<$($lifetime),+> {
49            /// Bind values to parameters.
50            ///
51            /// In case of integer indices, the first parameter has index 1. See `Statement::bind`
52            /// for further details.
53            pub fn bind<T: Bindable>(self, value: T) -> Result<Self> {
54                #[allow(unused_mut)]
55                let mut cursor = self.reset()?;
56                cursor.statement.bind(value)?;
57                Ok(cursor)
58            }
59
60            /// Bind values to parameters via an iterator.
61            ///
62            /// See `Statement::bind_iter` for further details.
63            #[allow(unused_mut)]
64            pub fn bind_iter<T, U>(self, value: T) -> Result<Self>
65            where
66                T: IntoIterator<Item = U>,
67                U: Bindable,
68            {
69                let mut cursor = self.reset()?;
70                cursor.statement.bind_iter(value)?;
71                Ok(cursor)
72            }
73
74            /// Reset the internal state.
75            #[allow(unused_mut)]
76            pub fn reset(mut self) -> Result<Self> {
77                self.statement.reset()?;
78                self.poisoned = false;
79                Ok(self)
80            }
81
82            /// Advance to the next row and read all columns.
83            pub fn try_next(&mut self) -> Result<Option<Vec<Value>>> {
84                if self.statement.next()? == State::Done {
85                    return Ok(None);
86                }
87                let mut values = Vec::with_capacity(self.column_count);
88                for index in 0..self.column_count {
89                    values.push(self.statement.read(index)?);
90                }
91                Ok(Some(values))
92            }
93        }
94
95        impl<$($lifetime),+> Deref for $type<$($lifetime),+> {
96            type Target = Statement;
97
98            #[inline]
99            fn deref(&self) -> &Self::Target {
100                &self.statement
101            }
102        }
103
104        impl<$($lifetime),+> Iterator for $type<$($lifetime),+> {
105            type Item = Result<Row>;
106
107            fn next(&mut self) -> Option<Self::Item> {
108                if self.poisoned {
109                    return None;
110                }
111                match self.try_next() {
112                    Ok(value) => {
113                        value.map(|values| Ok(Row {
114                            column_names: self.statement.column_names.clone(),
115                            column_mapping: self.statement.column_mapping(),
116                            values,
117                        }))
118                    }
119                    Err(error) => {
120                        self.poisoned = true;
121                        Some(Err(error))
122                    }
123                }
124            }
125        }
126    }
127);
128
129implement!(Cursor<'m>);
130/* FIXME - Impossible?
131implement!(CursorWithOwnership<'l>);
132
133impl<'l> From<CursorWithOwnership<'l>> for Statement<'l> {
134    #[inline]
135    fn from(cursor: CursorWithOwnership<'l>) -> Self {
136        cursor.statement
137    }
138}
139*/
140
141impl Row {
142    /// Check if the row contains a column.
143    ///
144    /// In case of integer indices, the first column has index 0.
145    #[inline]
146    pub fn contains<T>(&self, column: T) -> bool
147    where
148        T: RowIndex,
149    {
150        column.contains(self)
151    }
152
153    /// Read the value in a column.
154    ///
155    /// In case of integer indices, the first column has index 0.
156    ///
157    /// # Panics
158    ///
159    /// Panics if the column can not be read.
160    #[inline]
161    pub fn read<'l, T, U>(&'l self, column: U) -> T
162    where
163        T: TryFrom<&'l Value, Error = Error>,
164        U: RowIndex,
165    {
166        self.try_read(column).unwrap()
167    }
168
169    /// Take the value from a column.
170    ///
171    /// In case of integer indices, the first column has index 0. Any subsequent invocation will
172    /// result in `Value::Null`.
173    #[inline]
174    pub fn take<U>(&mut self, column: U) -> Value
175    where
176        U: RowIndex,
177    {
178        let index = column.index(self);
179        std::mem::take(&mut self.values[index])
180    }
181
182    /// Try to read the value in a column.
183    ///
184    /// In case of integer indices, the first column has index 0.
185    #[inline]
186    pub fn try_read<'l, T, U>(&'l self, column: U) -> Result<T>
187    where
188        T: TryFrom<&'l Value, Error = Error>,
189        U: RowIndex,
190    {
191        if !column.contains(self) {
192            raise!("the index is out of range ({column})");
193        }
194        T::try_from(&self.values[column.index(self)])
195    }
196
197    /// Iterate over the names and values.
198    pub fn iter(&self) -> impl Iterator<Item = (&'_ str, &'_ Value)> + use<'_> {
199        self.column_names.iter().map(|column_name| {
200            (
201                column_name.as_str(),
202                &self.values[self.column_mapping[column_name]],
203            )
204        })
205    }
206}
207
208impl From<Row> for Vec<Value> {
209    #[inline]
210    fn from(row: Row) -> Self {
211        row.values
212    }
213}
214
215impl<T> Index<T> for Row
216where
217    T: RowIndex,
218{
219    type Output = Value;
220
221    fn index(&self, index: T) -> &Value {
222        &self.values[index.index(self)]
223    }
224}
225
226impl RowIndex for &str {
227    #[inline]
228    fn contains(&self, row: &Row) -> bool {
229        row.column_mapping.contains_key(*self)
230    }
231
232    #[inline]
233    fn index(self, row: &Row) -> usize {
234        debug_assert!(RowIndex::contains(&self, row), "the index is out of range");
235        row.column_mapping[self]
236    }
237}
238
239impl RowIndex for usize {
240    #[inline]
241    fn contains(&self, row: &Row) -> bool {
242        self < &row.values.len()
243    }
244
245    #[inline]
246    fn index(self, row: &Row) -> usize {
247        debug_assert!(RowIndex::contains(&self, row), "the index is out of range");
248        self
249    }
250}
251
252pub fn new<'m>(statement: &'m Statement) -> Cursor<'m> {
253    Cursor {
254        column_count: statement.column_count(),
255        statement,
256        poisoned: false,
257    }
258}
259
260/* FIXME - Impossible?
261pub fn new_with_ownership(statement: Statement<'_>) -> CursorWithOwnership<'_> {
262    CursorWithOwnership {
263        column_count: statement.column_count(),
264        statement,
265        poisoned: false,
266    }
267}
268*/