1use crate::Value;
2
3#[derive(Clone, Debug, PartialEq)]
5pub enum Params {
6 Positional(Vec<Value>),
8 Named(Vec<(String, Value)>),
10}
11
12impl Params {
13 pub fn positional(values: impl Into<Vec<Value>>) -> Self {
15 Self::Positional(values.into())
16 }
17
18 pub fn named<I, K>(pairs: I) -> Self
22 where
23 I: IntoIterator<Item = (K, Value)>,
24 K: Into<String>,
25 {
26 Self::Named(
27 pairs
28 .into_iter()
29 .map(|(name, value)| (name.into(), value))
30 .collect(),
31 )
32 }
33}
34
35impl Default for Params {
36 fn default() -> Self {
37 Self::Positional(Vec::new())
38 }
39}
40
41impl From<()> for Params {
42 fn from(_: ()) -> Self {
43 Self::default()
44 }
45}
46
47impl From<Vec<Value>> for Params {
48 fn from(values: Vec<Value>) -> Self {
49 Self::Positional(values)
50 }
51}
52
53impl<const N: usize> From<[Value; N]> for Params {
54 fn from(values: [Value; N]) -> Self {
55 Self::Positional(values.into())
56 }
57}
58
59impl From<Vec<(String, Value)>> for Params {
60 fn from(values: Vec<(String, Value)>) -> Self {
61 Self::Named(values)
62 }
63}
64
65#[derive(Clone, Debug, PartialEq)]
67pub struct Statement {
68 pub sql: String,
70 pub params: Params,
72 pub want_rows: bool,
74}
75
76impl Statement {
77 pub fn query<P: Into<Params>>(sql: impl Into<String>, params: P) -> Self {
79 Self {
80 sql: sql.into(),
81 params: params.into(),
82 want_rows: true,
83 }
84 }
85
86 pub fn execute<P: Into<Params>>(sql: impl Into<String>, params: P) -> Self {
88 Self {
89 sql: sql.into(),
90 params: params.into(),
91 want_rows: false,
92 }
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use crate::{Params, Statement, Value};
99
100 #[test]
101 fn positional_from_array() {
102 let params: Params = [Value::integer(1), Value::text("kit")].into();
103 match params {
104 Params::Positional(values) => assert_eq!(values.len(), 2),
105 _ => panic!("expected positional"),
106 }
107 }
108
109 #[test]
110 fn named_builder() {
111 let params = Params::named([("name", Value::text("kit"))]);
112 match params {
113 Params::Named(values) => {
114 assert_eq!(values.len(), 1);
115 assert_eq!(values[0].0, "name");
116 }
117 _ => panic!("expected named"),
118 }
119 }
120
121 #[test]
122 fn statement_constructors() {
123 let query = Statement::query("SELECT 1", ());
124 let exec = Statement::execute("DELETE FROM t", ());
125 assert!(query.want_rows);
126 assert!(!exec.want_rows);
127 }
128}