Skip to main content

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}