Skip to main content

mysql_common/
params.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 std::{
10    collections::{
11        HashMap,
12        hash_map::{Entry, Entry::Occupied},
13    },
14    fmt,
15};
16
17use crate::value::{Value, convert::ToValue};
18
19/// Missing named parameter for a statement
20#[derive(Debug, Eq, PartialEq, Clone, thiserror::Error)]
21#[error(
22    "Missing named parameter `{}` for statement",
23    String::from_utf8_lossy(_0)
24)]
25pub struct MissingNamedParameterError(pub Vec<u8>);
26
27#[derive(Debug, PartialEq, Eq, Clone, Copy, thiserror::Error, Hash)]
28pub enum ParamsConfusionError {
29    #[error("Named params given where positional params are expected")]
30    NamedParamsForPositionalQuery,
31    #[error("Positional params given where named params are expected")]
32    PositionalParamsForNamedQuery,
33}
34
35#[derive(Debug, PartialEq, Eq, Clone, thiserror::Error)]
36pub enum ParamsError {
37    #[error(transparent)]
38    Missing(#[from] MissingNamedParameterError),
39    #[error(transparent)]
40    Confusion(#[from] ParamsConfusionError),
41}
42
43/// Representations of parameters of a prepared statement.
44#[derive(Clone, PartialEq)]
45pub enum Params {
46    Empty,
47    Named(HashMap<Vec<u8>, Value>),
48    Positional(Vec<Value>),
49}
50
51impl fmt::Debug for Params {
52    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53        match self {
54            Self::Empty => write!(f, "Empty"),
55            Self::Named(arg0) => {
56                let arg0 = arg0
57                    .iter()
58                    .map(|(k, v)| (String::from_utf8_lossy(k), v))
59                    .collect::<HashMap<_, _>>();
60                f.debug_tuple("Named").field(&arg0).finish()
61            }
62            Self::Positional(arg0) => f.debug_tuple("Positional").field(arg0).finish(),
63        }
64    }
65}
66
67impl Params {
68    /// Converts [`Params`] into a vector of values given the named parameters.
69    ///
70    /// `named_params` (if any) must follow the order they were given in the corresponding SQL
71    /// statement.
72    pub fn into_values(self, named_params: Option<&[Vec<u8>]>) -> Result<Vec<Value>, ParamsError> {
73        match self {
74            Params::Empty => match named_params {
75                Some(params) => {
76                    if let Some(first) = params.first() {
77                        Err(MissingNamedParameterError(first.clone()).into())
78                    } else {
79                        Ok(vec![])
80                    }
81                }
82                None => Ok(vec![]),
83            },
84            Params::Positional(values) => match named_params {
85                Some(named_params) if !named_params.is_empty() => {
86                    Err(ParamsConfusionError::PositionalParamsForNamedQuery.into())
87                }
88                _ => Ok(values),
89            },
90            Params::Named(map) => match named_params {
91                Some(named_params) if !named_params.is_empty() => {
92                    let mut values = vec![Value::NULL; named_params.len()];
93                    let mut indexes = Vec::with_capacity(named_params.len());
94                    for (name, value) in map {
95                        let mut first = None;
96                        for (i, _) in named_params.iter().enumerate().filter(|(_, x)| **x == name) {
97                            indexes.push(i);
98                            if first.is_none() {
99                                first = Some(i);
100                            } else {
101                                values[i] = value.clone();
102                            }
103                        }
104                        if let Some(first) = first {
105                            values[first] = value;
106                        }
107                    }
108                    if indexes.len() != named_params.len() {
109                        indexes.sort_unstable();
110                        match indexes.into_iter().enumerate().find(|x| x.0 != x.1) {
111                            Some((missing, _)) => {
112                                Err(MissingNamedParameterError(named_params[missing].clone())
113                                    .into())
114                            }
115                            None => {
116                                match named_params.last() {
117                                    Some(last) => {
118                                        Err(MissingNamedParameterError(last.clone()).into())
119                                    }
120                                    None => {
121                                        // unreachable
122                                        Ok(values)
123                                    }
124                                }
125                            }
126                        }
127                    } else {
128                        Ok(values)
129                    }
130                }
131                _ => Err(ParamsConfusionError::NamedParamsForPositionalQuery.into()),
132            },
133        }
134    }
135
136    /// Will convert named parameters into positional assuming order passed in `named_params`
137    /// attribute.
138    #[deprecated = "use `into_values` instead"]
139    pub fn into_positional(
140        self,
141        named_params: &[Vec<u8>],
142    ) -> Result<Params, MissingNamedParameterError> {
143        match self {
144            Params::Named(mut map) => {
145                let mut params: Vec<Value> = Vec::new();
146                'params: for (i, name) in named_params.iter().enumerate() {
147                    match map.entry(name.clone()) {
148                        Occupied(entry) => {
149                            let mut x = named_params.len() - 1;
150                            while x > i {
151                                if *name == named_params[x] {
152                                    params.push(entry.get().clone());
153                                    continue 'params;
154                                }
155                                x -= 1;
156                            }
157                            params.push(entry.remove());
158                        }
159                        _ => return Err(MissingNamedParameterError(name.clone())),
160                    }
161                }
162                Ok(Params::Positional(params))
163            }
164            params => Ok(params),
165        }
166    }
167}
168
169impl<'a, T: Into<Params> + Clone> From<&'a T> for Params {
170    fn from(x: &'a T) -> Params {
171        x.clone().into()
172    }
173}
174
175impl<T> From<Vec<T>> for Params
176where
177    Value: From<T>,
178{
179    fn from(x: Vec<T>) -> Params {
180        let mut raw_params: Vec<Value> = Vec::new();
181        for v in x.into_iter() {
182            raw_params.push(Value::from(v));
183        }
184        if raw_params.is_empty() {
185            Params::Empty
186        } else {
187            Params::Positional(raw_params)
188        }
189    }
190}
191
192impl<N, V> From<Vec<(N, V)>> for Params
193where
194    Vec<u8>: From<N>,
195    Value: From<V>,
196{
197    fn from(x: Vec<(N, V)>) -> Params {
198        let mut map = HashMap::default();
199        for (name, value) in x.into_iter() {
200            let name: Vec<u8> = name.into();
201            match map.entry(name) {
202                Entry::Vacant(entry) => entry.insert(Value::from(value)),
203                Entry::Occupied(entry) => {
204                    panic!(
205                        "Redefinition of named parameter `{}'",
206                        String::from_utf8_lossy(entry.key())
207                    );
208                }
209            };
210        }
211        Params::Named(map)
212    }
213}
214
215impl<'a> From<&'a [&'a dyn ToValue]> for Params {
216    fn from(x: &'a [&'a dyn ToValue]) -> Params {
217        let mut raw_params: Vec<Value> = Vec::new();
218        for v in x {
219            raw_params.push(v.to_value());
220        }
221        if raw_params.is_empty() {
222            Params::Empty
223        } else {
224            Params::Positional(raw_params)
225        }
226    }
227}
228
229impl From<()> for Params {
230    fn from(_: ()) -> Params {
231        Params::Empty
232    }
233}
234
235macro_rules! into_params_impl {
236    ($([$A:ident,$a:ident]),*) => (
237        impl<$($A: Into<Value>,)*> From<($($A,)*)> for Params {
238            fn from(x: ($($A,)*)) -> Params {
239                let ($($a,)*) = x;
240                Params::Positional(vec![
241                    $($a.into(),)*
242                ])
243            }
244        }
245    );
246}
247
248into_params_impl!([A, a]);
249into_params_impl!([A, a], [B, b]);
250into_params_impl!([A, a], [B, b], [C, c]);
251into_params_impl!([A, a], [B, b], [C, c], [D, d]);
252into_params_impl!([A, a], [B, b], [C, c], [D, d], [E, e]);
253into_params_impl!([A, a], [B, b], [C, c], [D, d], [E, e], [F, f]);
254into_params_impl!([A, a], [B, b], [C, c], [D, d], [E, e], [F, f], [G, g]);
255into_params_impl!(
256    [A, a],
257    [B, b],
258    [C, c],
259    [D, d],
260    [E, e],
261    [F, f],
262    [G, g],
263    [H, h]
264);
265into_params_impl!(
266    [A, a],
267    [B, b],
268    [C, c],
269    [D, d],
270    [E, e],
271    [F, f],
272    [G, g],
273    [H, h],
274    [I, i]
275);
276into_params_impl!(
277    [A, a],
278    [B, b],
279    [C, c],
280    [D, d],
281    [E, e],
282    [F, f],
283    [G, g],
284    [H, h],
285    [I, i],
286    [J, j]
287);
288into_params_impl!(
289    [A, a],
290    [B, b],
291    [C, c],
292    [D, d],
293    [E, e],
294    [F, f],
295    [G, g],
296    [H, h],
297    [I, i],
298    [J, j],
299    [K, k]
300);
301into_params_impl!(
302    [A, a],
303    [B, b],
304    [C, c],
305    [D, d],
306    [E, e],
307    [F, f],
308    [G, g],
309    [H, h],
310    [I, i],
311    [J, j],
312    [K, k],
313    [L, l]
314);