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