rudb_bind/parameters.rs
1//! The values a statement's parameters were given.
2
3use rudb_common::Value;
4
5/// What a prepared statement was handed, by identifier.
6///
7/// A parameter is written `?`, `?1`, `$1` or `$name`, and the parser gives every one of them an
8/// identifier: the number for a positional parameter, the word for a named one, and the position
9/// for a bare `?`. So a set of values is a list of identifier and value pairs whatever the statement
10/// was written with, and there is one lookup rather than two.
11///
12/// A list rather than a map. There are a handful of parameters in a statement, never a thousand, and
13/// keeping the order they were given in is worth more here than a hash: it is what the error about
14/// unused values lists them in.
15#[derive(Debug, Clone, Default, PartialEq)]
16pub struct Parameters {
17 values: Vec<(String, Value)>,
18}
19
20impl Parameters {
21 /// No values, which is what an ordinary statement binds with.
22 #[must_use]
23 pub const fn new() -> Self {
24 Self { values: Vec::new() }
25 }
26
27 /// Values by position, numbered from one, which is what `?` and `$1` want.
28 #[must_use]
29 pub fn positional(values: Vec<Value>) -> Self {
30 let values = values
31 .into_iter()
32 .enumerate()
33 .map(|(at, value)| ((at + 1).to_string(), value))
34 .collect();
35 Self { values }
36 }
37
38 /// Gives one parameter a value, replacing whatever it had.
39 pub fn set(&mut self, name: impl Into<String>, value: Value) {
40 let name = name.into();
41 match self.values.iter_mut().find(|(held, _)| same(held, &name)) {
42 Some(slot) => slot.1 = value,
43 None => self.values.push((name, value)),
44 }
45 }
46
47 /// What one parameter was given, if it was given anything.
48 #[must_use]
49 pub fn get(&self, name: &str) -> Option<&Value> {
50 self.values.iter().find(|(held, _)| same(held, name)).map(|(_, value)| value)
51 }
52
53 /// Whether nothing was provided.
54 #[must_use]
55 pub fn is_empty(&self) -> bool {
56 self.values.is_empty()
57 }
58
59 /// How many were provided.
60 #[must_use]
61 pub fn len(&self) -> usize {
62 self.values.len()
63 }
64
65 /// The identifiers, in the order they were given.
66 pub fn names(&self) -> impl Iterator<Item = &str> {
67 self.values.iter().map(|(name, _)| name.as_str())
68 }
69}
70
71/// Whether two identifiers are the same parameter.
72///
73/// Without regard to case, which is measured rather than assumed: duckdb v1.4.1 runs
74/// `PREPARE p AS SELECT $A` with `EXECUTE p(a := 1)`. It is the one place the dialect folds case,
75/// and it does not fold identifiers anywhere else.
76fn same(left: &str, right: &str) -> bool {
77 left.eq_ignore_ascii_case(right)
78}