1- use backend:: Backend ;
1+ use backend:: { Backend , SupportsDefaultKeyword } ;
2+ use connection:: Connection ;
23use expression:: { Expression , SelectableExpression , NonAggregate } ;
34use persistable:: { Insertable , InsertValues } ;
45use query_builder:: * ;
5- use query_source:: Table ;
6+ use query_dsl:: { ExecuteDsl , LoadDsl } ;
7+ use query_source:: { Queryable , Table } ;
68use result:: QueryResult ;
79use super :: returning_clause:: * ;
10+ use types:: HasSqlType ;
811
912/// The structure returned by [`insert`](fn.insert.html). The only thing that can be done with it
1013/// is call `into`.
@@ -24,26 +27,64 @@ impl<T, Op> IncompleteInsertStatement<T, Op> {
2427 }
2528
2629 /// Specify which table the data passed to `insert` should be added to.
27- pub fn into < S > ( self , target : S ) -> InsertStatement < S , T , Op > where
28- InsertStatement < S , T , Op > : AsQuery ,
30+ pub fn into < S > ( self , target : S ) -> T :: InsertStatement where
31+ T : IntoInsertStatement < S , Op , NoReturningClause > ,
2932 {
30- InsertStatement {
31- operator : self . operator ,
33+ self . records . into_insert_statement ( target, self . operator , NoReturningClause )
34+ }
35+ }
36+
37+ pub trait IntoInsertStatement < Tab , Op =Insert , Ret =NoReturningClause > {
38+ type InsertStatement ;
39+
40+ fn into_insert_statement ( self , target : Tab , operator : Op , returning : Ret )
41+ -> Self :: InsertStatement ;
42+ }
43+
44+ impl < ' a , T , Tab , Op , Ret > IntoInsertStatement < Tab , Op , Ret > for & ' a [ T ] {
45+ type InsertStatement = BatchInsertStatement < Tab , Self , Op , Ret > ;
46+
47+ fn into_insert_statement ( self , target : Tab , operator : Op , returning : Ret )
48+ -> Self :: InsertStatement
49+ {
50+ BatchInsertStatement {
51+ operator : operator,
3252 target : target,
33- records : self . records ,
34- returning : NoReturningClause ,
53+ records : self ,
54+ returning : returning ,
3555 }
3656 }
3757}
3858
59+ impl < ' a , T , Tab , Op , Ret > IntoInsertStatement < Tab , Op , Ret > for & ' a Vec < T > {
60+ type InsertStatement = <& ' a [ T ] as IntoInsertStatement < Tab , Op , Ret > >:: InsertStatement ;
61+
62+ fn into_insert_statement ( self , target : Tab , operator : Op , returning : Ret )
63+ -> Self :: InsertStatement
64+ {
65+ ( & * * self ) . into_insert_statement ( target, operator, returning)
66+ }
67+ }
68+
3969#[ derive( Debug , Copy , Clone ) ]
40- pub struct InsertStatement < T , U , Op , Ret =NoReturningClause > {
70+ pub struct InsertStatement < T , U , Op = Insert , Ret =NoReturningClause > {
4171 operator : Op ,
4272 target : T ,
4373 records : U ,
4474 returning : Ret ,
4575}
4676
77+ impl < T , U , Op , Ret > InsertStatement < T , U , Op , Ret > {
78+ pub fn new ( target : T , records : U , operator : Op , returning : Ret ) -> Self {
79+ InsertStatement {
80+ operator : operator,
81+ target : target,
82+ records : records,
83+ returning : returning,
84+ }
85+ }
86+ }
87+
4788impl < T , U , Op , Ret , DB > QueryFragment < DB > for InsertStatement < T , U , Op , Ret > where
4889 DB : Backend ,
4990 T : Table ,
@@ -148,6 +189,140 @@ impl<T, U, Op> InsertStatement<T, U, Op, NoReturningClause> {
148189 }
149190}
150191
192+ #[ derive( Debug , Clone , Copy ) ]
193+ /// The result of calling `insert(records).into(some_table)` when `records` is
194+ /// a slice or a `Vec`. When calling methods from `ExecuteDsl` or `LoadDsl`.
195+ /// When the given slice is empty, this struct will not execute any queries.
196+ /// When the given slice is not empty, this will execute a single bulk insert
197+ /// on backends which support the `DEFAULT` keyword, and one query per record
198+ /// on backends which do not (SQLite).
199+ pub struct BatchInsertStatement < T , U , Op =Insert , Ret =NoReturningClause > {
200+ operator : Op ,
201+ target : T ,
202+ records : U ,
203+ returning : Ret ,
204+ }
205+
206+ impl < T , U , Op , Ret > BatchInsertStatement < T , U , Op , Ret > {
207+ fn into_insert_statement ( self ) -> InsertStatement < T , U , Op , Ret > {
208+ InsertStatement :: new (
209+ self . target ,
210+ self . records ,
211+ self . operator ,
212+ self . returning ,
213+ )
214+ }
215+ }
216+
217+ impl < T , U , Op > BatchInsertStatement < T , U , Op > {
218+ /// Specify what expression is returned after execution of the `insert`.
219+ /// # Examples
220+ ///
221+ /// ### Inserting records:
222+ ///
223+ /// ```rust
224+ /// # #[macro_use] extern crate diesel;
225+ /// # include!("src/doctest_setup.rs");
226+ /// #
227+ /// # table! {
228+ /// # users {
229+ /// # id -> Integer,
230+ /// # name -> VarChar,
231+ /// # }
232+ /// # }
233+ /// #
234+ /// # #[cfg(feature = "postgres")]
235+ /// # fn main() {
236+ /// # use self::users::dsl::*;
237+ /// # let connection = establish_connection();
238+ /// let new_users = vec![
239+ /// NewUser { name: "Timmy".to_string(), },
240+ /// NewUser { name: "Jimmy".to_string(), },
241+ /// ];
242+ ///
243+ /// let inserted_names = diesel::insert(&new_users)
244+ /// .into(users)
245+ /// .returning(name)
246+ /// .get_results(&connection);
247+ /// assert_eq!(Ok(vec!["Timmy".to_string(), "Jimmy".to_string()]), inserted_names);
248+ /// # }
249+ /// # #[cfg(not(feature = "postgres"))]
250+ /// # fn main() {}
251+ /// ```
252+ pub fn returning < E > ( self , returns : E )
253+ -> BatchInsertStatement < T , U , Op , ReturningClause < E > >
254+ {
255+ BatchInsertStatement {
256+ operator : self . operator ,
257+ target : self . target ,
258+ records : self . records ,
259+ returning : ReturningClause ( returns) ,
260+ }
261+ }
262+ }
263+
264+ impl < ' a , T , U , Op , Ret , Conn , DB > ExecuteDsl < Conn , DB >
265+ for BatchInsertStatement < T , & ' a [ U ] , Op , Ret > where
266+ Conn : Connection < Backend =DB > ,
267+ DB : Backend + SupportsDefaultKeyword ,
268+ InsertStatement < T , & ' a [ U ] , Op , Ret > : ExecuteDsl < Conn > ,
269+ {
270+ fn execute ( self , conn : & Conn ) -> QueryResult < usize > {
271+ if self . records . is_empty ( ) {
272+ Ok ( 0 )
273+ } else {
274+ self . into_insert_statement ( ) . execute ( conn)
275+ }
276+ }
277+ }
278+
279+ #[ cfg( feature="sqlite" ) ]
280+ impl < ' a , T , U , Op , Ret > ExecuteDsl < :: sqlite:: SqliteConnection >
281+ for BatchInsertStatement < T , & ' a [ U ] , Op , Ret > where
282+ InsertStatement < T , & ' a U , Op , Ret > : ExecuteDsl < :: sqlite:: SqliteConnection > ,
283+ T : Copy ,
284+ Op : Copy ,
285+ Ret : Copy ,
286+ {
287+ fn execute ( self , conn : & :: sqlite:: SqliteConnection ) -> QueryResult < usize > {
288+ let mut result = 0 ;
289+ for record in self . records {
290+ result += InsertStatement :: new ( self . target , record, self . operator , self . returning )
291+ . execute ( conn) ?;
292+ }
293+ Ok ( result)
294+ }
295+ }
296+
297+ impl < ' a , T , U , Op , Ret , Conn , ST > LoadDsl < Conn >
298+ for BatchInsertStatement < T , & ' a [ U ] , Op , Ret > where
299+ Conn : Connection ,
300+ Conn :: Backend : HasSqlType < ST > ,
301+ InsertStatement < T , & ' a [ U ] , Op , Ret > : LoadDsl < Conn , SqlType =ST > ,
302+ {
303+ type SqlType = ST ;
304+
305+ fn load < ' b , V > ( self , conn : & Conn ) -> QueryResult < Vec < V > > where
306+ V : Queryable < Self :: SqlType , Conn :: Backend > + ' b ,
307+ {
308+ if self . records . is_empty ( ) {
309+ Ok ( Vec :: new ( ) )
310+ } else {
311+ self . into_insert_statement ( ) . load ( conn)
312+ }
313+ }
314+
315+ fn get_result < V > ( self , conn : & Conn ) -> QueryResult < V > where
316+ V : Queryable < Self :: SqlType , Conn :: Backend > ,
317+ {
318+ if self . records . is_empty ( ) {
319+ Err ( :: result:: Error :: NotFound )
320+ } else {
321+ self . into_insert_statement ( ) . get_result ( conn)
322+ }
323+ }
324+ }
325+
151326#[ derive( Debug , Copy , Clone ) ]
152327pub struct Insert ;
153328
0 commit comments