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        hash_map::{Entry, Entry::Occupied},
12        HashMap,
13    },
14    error::Error,
15    fmt,
16};
17
18use crate::value::{convert::ToValue, Value};
19
20/// `FromValue` conversion error.
21#[derive(Debug, Eq, PartialEq, Clone)]
22pub struct MissingNamedParameterError(pub Vec<u8>);
23
24impl fmt::Display for MissingNamedParameterError {
25    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26        write!(
27            f,
28            "Missing named parameter `{}` for statement",
29            String::from_utf8_lossy(&self.0)
30        )
31    }
32}
33
34impl Error for MissingNamedParameterError {
35    fn description(&self) -> &str {
36        "Missing named parameter for statement"
37    }
38}
39
40/// Representations of parameters of a prepared statement.
41#[derive(Clone, PartialEq)]
42pub enum Params {
43    Empty,
44    Named(HashMap<Vec<u8>, Value>),
45    Positional(Vec<Value>),
46}
47
48impl fmt::Debug for Params {
49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50        match self {
51            Self::Empty => write!(f, "Empty"),
52            Self::Named(arg0) => {
53                let arg0 = arg0
54                    .iter()
55                    .map(|(k, v)| (String::from_utf8_lossy(k), v))
56                    .collect::<HashMap<_, _>>();
57                f.debug_tuple("Named").field(&arg0).finish()
58            }
59            Self::Positional(arg0) => f.debug_tuple("Positional").field(arg0).finish(),
60        }
61    }
62}
63
64impl Params {
65    /// Will convert named parameters into positional assuming order passed in `named_params`
66    /// attribute.
67    pub fn into_positional(
68        self,
69        named_params: &[Vec<u8>],
70    ) -> Result<Params, MissingNamedParameterError> {
71        match self {
72            Params::Named(mut map) => {
73                let mut params: Vec<Value> = Vec::new();
74                'params: for (i, name) in named_params.iter().enumerate() {
75                    match map.entry(name.clone()) {
76                        Occupied(entry) => {
77                            let mut x = named_params.len() - 1;
78                            while x > i {
79                                if *name == named_params[x] {
80                                    params.push(entry.get().clone());
81                                    continue 'params;
82                                }
83                                x -= 1;
84                            }
85                            params.push(entry.remove());
86                        }
87                        _ => return Err(MissingNamedParameterError(name.clone())),
88                    }
89                }
90                Ok(Params::Positional(params))
91            }
92            params => Ok(params),
93        }
94    }
95}
96
97impl<'a, T: Into<Params> + Clone> From<&'a T> for Params {
98    fn from(x: &'a T) -> Params {
99        x.clone().into()
100    }
101}
102
103impl<T> From<Vec<T>> for Params
104where
105    Value: From<T>,
106{
107    fn from(x: Vec<T>) -> Params {
108        let mut raw_params: Vec<Value> = Vec::new();
109        for v in x.into_iter() {
110            raw_params.push(Value::from(v));
111        }
112        if raw_params.is_empty() {
113            Params::Empty
114        } else {
115            Params::Positional(raw_params)
116        }
117    }
118}
119
120impl<N, V> From<Vec<(N, V)>> for Params
121where
122    Vec<u8>: From<N>,
123    Value: From<V>,
124{
125    fn from(x: Vec<(N, V)>) -> Params {
126        let mut map = HashMap::default();
127        for (name, value) in x.into_iter() {
128            let name: Vec<u8> = name.into();
129            match map.entry(name) {
130                Entry::Vacant(entry) => entry.insert(Value::from(value)),
131                Entry::Occupied(entry) => {
132                    panic!(
133                        "Redefinition of named parameter `{}'",
134                        String::from_utf8_lossy(entry.key())
135                    );
136                }
137            };
138        }
139        Params::Named(map)
140    }
141}
142
143impl<'a> From<&'a [&'a dyn ToValue]> for Params {
144    fn from(x: &'a [&'a dyn ToValue]) -> Params {
145        let mut raw_params: Vec<Value> = Vec::new();
146        for v in x {
147            raw_params.push(v.to_value());
148        }
149        if raw_params.is_empty() {
150            Params::Empty
151        } else {
152            Params::Positional(raw_params)
153        }
154    }
155}
156
157impl From<()> for Params {
158    fn from(_: ()) -> Params {
159        Params::Empty
160    }
161}
162
163macro_rules! into_params_impl {
164    ($([$A:ident,$a:ident]),*) => (
165        impl<$($A: Into<Value>,)*> From<($($A,)*)> for Params {
166            fn from(x: ($($A,)*)) -> Params {
167                let ($($a,)*) = x;
168                Params::Positional(vec![
169                    $($a.into(),)*
170                ])
171            }
172        }
173    );
174}
175
176into_params_impl!([A, a]);
177into_params_impl!([A, a], [B, b]);
178into_params_impl!([A, a], [B, b], [C, c]);
179into_params_impl!([A, a], [B, b], [C, c], [D, d]);
180into_params_impl!([A, a], [B, b], [C, c], [D, d], [E, e]);
181into_params_impl!([A, a], [B, b], [C, c], [D, d], [E, e], [F, f]);
182into_params_impl!([A, a], [B, b], [C, c], [D, d], [E, e], [F, f], [G, g]);
183into_params_impl!(
184    [A, a],
185    [B, b],
186    [C, c],
187    [D, d],
188    [E, e],
189    [F, f],
190    [G, g],
191    [H, h]
192);
193into_params_impl!(
194    [A, a],
195    [B, b],
196    [C, c],
197    [D, d],
198    [E, e],
199    [F, f],
200    [G, g],
201    [H, h],
202    [I, i]
203);
204into_params_impl!(
205    [A, a],
206    [B, b],
207    [C, c],
208    [D, d],
209    [E, e],
210    [F, f],
211    [G, g],
212    [H, h],
213    [I, i],
214    [J, j]
215);
216into_params_impl!(
217    [A, a],
218    [B, b],
219    [C, c],
220    [D, d],
221    [E, e],
222    [F, f],
223    [G, g],
224    [H, h],
225    [I, i],
226    [J, j],
227    [K, k]
228);
229into_params_impl!(
230    [A, a],
231    [B, b],
232    [C, c],
233    [D, d],
234    [E, e],
235    [F, f],
236    [G, g],
237    [H, h],
238    [I, i],
239    [J, j],
240    [K, k],
241    [L, l]
242);