use crate::{ActiveModelTrait, EntityTrait, Iterable, QueryTrait}; use core::marker::PhantomData; use sea_query::{InsertStatement, IntoIden}; #[derive(Clone, Debug)] pub struct Insert where A: ActiveModelTrait, { pub(crate) query: InsertStatement, pub(crate) columns: Vec, pub(crate) model: PhantomData, } impl Default for Insert where A: ActiveModelTrait, { fn default() -> Self { Self::new() } } impl Insert where A: ActiveModelTrait, { pub fn new() -> Self { Self { query: InsertStatement::new() .into_table(A::Entity::default().into_iden()) .to_owned(), columns: Vec::new(), model: PhantomData, } } pub fn one(mut self, m: M) -> Self where M: Into, { let mut am: A = m.into(); let mut columns = Vec::new(); let mut values = Vec::new(); let columns_empty = self.columns.is_empty(); for (idx, col) in ::Column::iter().enumerate() { let av = am.take(col); let av_has_val = av.is_set() || av.is_unchanged(); if columns_empty { self.columns.push(av_has_val); } else if self.columns[idx] != av_has_val { panic!("columns mismatch"); } if av_has_val { columns.push(col); values.push(av.into_value()); } } self.query.columns(columns); self.query.values_panic(values); self } pub fn many(mut self, models: I) -> Self where M: Into, I: IntoIterator, { for model in models.into_iter() { self = self.one(model); } self } } impl QueryTrait for Insert where A: ActiveModelTrait, { type QueryStatement = InsertStatement; fn query(&mut self) -> &mut InsertStatement { &mut self.query } fn as_query(&self) -> &InsertStatement { &self.query } fn into_query(self) -> InsertStatement { self.query } } #[cfg(test)] mod tests { use crate::tests_cfg::cake; use crate::{Insert, QueryTrait, ActiveValue}; use sea_query::PostgresQueryBuilder; #[test] fn insert_1() { assert_eq!( Insert::::new() .one(cake::ActiveModel { id: ActiveValue::unset(), name: ActiveValue::set("Apple Pie".to_owned()), }) .build(PostgresQueryBuilder) .to_string(), r#"INSERT INTO "cake" ("name") VALUES ('Apple Pie')"#, ); } #[test] fn insert_2() { assert_eq!( Insert::::new() .one(cake::ActiveModel { id: ActiveValue::set(1), name: ActiveValue::set("Apple Pie".to_owned()), }) .build(PostgresQueryBuilder) .to_string(), r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie')"#, ); } #[test] fn insert_3() { assert_eq!( Insert::::new() .one(cake::Model { id: 1, name: "Apple Pie".to_owned(), }) .build(PostgresQueryBuilder) .to_string(), r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie')"#, ); } #[test] fn insert_4() { assert_eq!( Insert::::new() .many(vec![ cake::Model { id: 1, name: "Apple Pie".to_owned(), }, cake::Model { id: 2, name: "Orange Scone".to_owned(), } ]) .build(PostgresQueryBuilder) .to_string(), r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie'), (2, 'Orange Scone')"#, ); } #[test] #[should_panic(expected = "columns mismatch")] fn insert_5() { let apple = cake::ActiveModel { name: ActiveValue::set("Apple".to_owned()), ..Default::default() }; let orange = cake::ActiveModel { id: ActiveValue::set(2), name: ActiveValue::set("Orange".to_owned()), }; assert_eq!( Insert::::new() .many(vec![apple, orange]) .build(PostgresQueryBuilder) .to_string(), r#"INSERT INTO "cake" ("id", "name") VALUES (NULL, 'Apple'), (2, 'Orange')"#, ); } }