1use std::{
10 collections::{
11 HashMap,
12 hash_map::{Entry, Entry::Occupied},
13 },
14 fmt,
15};
16
17use crate::value::{Value, convert::ToValue};
18
19#[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#[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 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 Ok(values)
123 }
124 }
125 }
126 }
127 } else {
128 Ok(values)
129 }
130 }
131 _ => Err(ParamsConfusionError::NamedParamsForPositionalQuery.into()),
132 },
133 }
134 }
135
136 #[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);