mik_sql/builder/
insert.rs1use crate::dialect::{Dialect, Postgres, Sqlite};
4use crate::validate::assert_valid_sql_identifier;
5
6use super::types::{QueryResult, Value};
7
8#[derive(Debug)]
10#[must_use = "builder does nothing until .build() is called"]
11pub struct InsertBuilder<D: Dialect> {
12 dialect: D,
13 table: String,
14 columns: Vec<String>,
15 values: Vec<Vec<Value>>,
16 returning: Vec<String>,
17}
18
19impl<D: Dialect> InsertBuilder<D> {
20 pub fn new(dialect: D, table: impl Into<String>) -> Self {
26 let table = table.into();
27 assert_valid_sql_identifier(&table, "table");
28 Self {
29 dialect,
30 table,
31 columns: Vec::new(),
32 values: Vec::new(),
33 returning: Vec::new(),
34 }
35 }
36
37 pub fn columns(mut self, columns: &[&str]) -> Self {
43 for col in columns {
44 assert_valid_sql_identifier(col, "column");
45 }
46 self.columns = columns.iter().map(|s| (*s).to_string()).collect();
47 self
48 }
49
50 pub fn values(mut self, values: Vec<Value>) -> Self {
52 self.values.push(values);
53 self
54 }
55
56 pub fn values_many(mut self, rows: Vec<Vec<Value>>) -> Self {
58 self.values.extend(rows);
59 self
60 }
61
62 pub fn returning(mut self, columns: &[&str]) -> Self {
68 for col in columns {
69 assert_valid_sql_identifier(col, "returning column");
70 }
71 self.returning = columns.iter().map(|s| (*s).to_string()).collect();
72 self
73 }
74
75 pub fn build(self) -> QueryResult {
77 let mut sql = String::new();
78 let mut params = Vec::new();
79 let mut param_idx = 1usize;
80
81 sql.push_str(&format!(
83 "INSERT INTO {} ({})",
84 self.table,
85 self.columns.join(", ")
86 ));
87
88 let mut value_groups = Vec::new();
90 for row in &self.values {
91 let placeholders: Vec<String> = row
92 .iter()
93 .map(|v| {
94 let p = self.dialect.param(param_idx);
95 params.push(v.clone());
96 param_idx += 1;
97 p
98 })
99 .collect();
100 value_groups.push(format!("({})", placeholders.join(", ")));
101 }
102 sql.push_str(&format!(" VALUES {}", value_groups.join(", ")));
103
104 if !self.returning.is_empty() {
106 sql.push_str(&format!(" RETURNING {}", self.returning.join(", ")));
107 }
108
109 QueryResult { sql, params }
110 }
111}
112
113pub fn insert(table: impl Into<String>) -> InsertBuilder<Postgres> {
115 InsertBuilder::new(Postgres, table)
116}
117
118pub fn insert_sqlite(table: impl Into<String>) -> InsertBuilder<Sqlite> {
120 InsertBuilder::new(Sqlite, table)
121}