typed_sql/query/
insert.rs1use super::Select;
2use crate::{CheckedSql, Table, ToSql};
3use std::marker::PhantomData;
4
5pub trait Insertable {
6 fn write_columns(sql: &mut String);
7
8 fn write_values(&self, sql: &mut String);
9}
10
11impl<I: Insertable> Insertable for &I {
12 fn write_columns(sql: &mut String) {
13 I::write_columns(sql);
14 }
15
16 fn write_values(&self, sql: &mut String) {
17 (*self).write_values(sql);
18 }
19}
20
21pub struct Values<I> {
22 iter: I,
23}
24
25impl<I> Values<I> {
26 pub(crate) fn new(iter: I) -> Self {
27 Self { iter }
28 }
29}
30
31pub struct InsertSelect<S, I: ?Sized> {
32 select: S,
33 _insertable: PhantomData<I>,
34}
35
36impl<S, I: ?Sized> InsertSelect<S, I> {
37 pub(crate) fn new(select: S) -> Self {
38 Self {
39 select,
40 _insertable: PhantomData,
41 }
42 }
43}
44
45impl<S, I> Insertable for InsertSelect<S, I>
46where
47 S: Select,
48 I: Insertable + ?Sized,
49{
50 fn write_columns(sql: &mut String) {
51 I::write_columns(sql);
52 }
53
54 fn write_values(&self, sql: &mut String) {
55 self.select.write_sql_unchecked(sql);
56 }
57}
58
59pub struct InsertStatement<T: ?Sized, V> {
60 values: V,
61 _table: PhantomData<T>,
62}
63
64impl<T, I> InsertStatement<T, I>
65where
66 T: Table + ?Sized,
67{
68 pub(crate) fn new(values: I) -> Self {
69 Self {
70 values,
71 _table: PhantomData,
72 }
73 }
74
75 fn write_insert<I2: Insertable>(&self, sql: &mut String) {
76 sql.push_str("INSERT INTO ");
77 sql.push_str(T::NAME);
78 sql.push('(');
79 I2::write_columns(sql);
80 sql.push(')');
81 sql.push_str(" VALUES ");
82 }
83}
84
85impl<T, I> ToSql for InsertStatement<T, I>
86where
87 T: Table + ?Sized,
88 I: Insertable,
89{
90 fn write_sql_unchecked(&self, sql: &mut String) {
91 self.write_insert::<I>(sql);
92
93 sql.push('(');
94 self.values.write_values(sql);
95 sql.push(')');
96 }
97}
98
99impl<T, I> ToSql for InsertStatement<T, Values<I>>
100where
101 T: Table,
102 I: IntoIterator + Clone,
103 I::Item: Insertable,
104{
105 fn write_sql_unchecked(&self, sql: &mut String) {
106 self.write_insert::<I::Item>(sql);
107
108 let mut values = self.values.iter.clone().into_iter().peekable();
109 loop {
110 if let Some(value) = values.next() {
111 sql.push('(');
112 value.write_values(sql);
113 sql.push(')');
114
115 if values.peek().is_some() {
116 sql.push(',');
117 continue;
118 }
119 }
120 break;
121 }
122 }
123}
124
125impl<T, I: CheckedSql> CheckedSql for InsertSelect<T, I> {}