Insert many
This commit is contained in:
parent
ea091d7438
commit
fcc668399d
@ -31,7 +31,7 @@ pub fn expand_derive_active_model(ident: Ident, data: Data) -> syn::Result<Token
|
||||
let ty: Vec<Type> = fields.into_iter().map(|Field { ty, .. }| ty).collect();
|
||||
|
||||
Ok(quote!(
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct ActiveModel {
|
||||
#(pub #field: sea_orm::ActiveValue<#ty>),*
|
||||
}
|
||||
|
@ -10,6 +10,8 @@ where
|
||||
state: ActiveValueState,
|
||||
}
|
||||
|
||||
pub type Val<V> = ActiveValue<V>;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum ActiveValueState {
|
||||
Set,
|
||||
@ -23,6 +25,18 @@ impl Default for ActiveValueState {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait OneOrManyActiveModel<A>
|
||||
where
|
||||
A: ActiveModelTrait,
|
||||
{
|
||||
fn is_one() -> bool;
|
||||
fn get_one(self) -> A;
|
||||
|
||||
fn is_many() -> bool;
|
||||
fn get_many(self) -> Vec<A>;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn unchanged_active_value_not_intended_for_public_use<V>(value: V) -> ActiveValue<V>
|
||||
where
|
||||
V: Default,
|
||||
@ -30,6 +44,24 @@ where
|
||||
ActiveValue::unchanged(value)
|
||||
}
|
||||
|
||||
pub trait ActiveModelOf<E>
|
||||
where
|
||||
E: EntityTrait,
|
||||
{
|
||||
}
|
||||
|
||||
pub trait ActiveModelTrait: Clone + Debug + Default {
|
||||
type Column: ColumnTrait;
|
||||
|
||||
fn take(&mut self, c: Self::Column) -> ActiveValue<Value>;
|
||||
|
||||
fn get(&self, c: Self::Column) -> ActiveValue<Value>;
|
||||
|
||||
fn set(&mut self, c: Self::Column, v: Value);
|
||||
|
||||
fn unset(&mut self, c: Self::Column);
|
||||
}
|
||||
|
||||
impl<V> ActiveValue<V>
|
||||
where
|
||||
V: Default,
|
||||
@ -99,20 +131,40 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ActiveModelOf<E>
|
||||
impl<A> OneOrManyActiveModel<A> for A
|
||||
where
|
||||
E: EntityTrait,
|
||||
A: ActiveModelTrait,
|
||||
{
|
||||
fn is_one() -> bool {
|
||||
true
|
||||
}
|
||||
fn get_one(self) -> A {
|
||||
self
|
||||
}
|
||||
|
||||
fn is_many() -> bool {
|
||||
false
|
||||
}
|
||||
fn get_many(self) -> Vec<A> {
|
||||
panic!("not many")
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ActiveModelTrait: Clone + Debug {
|
||||
type Column: ColumnTrait;
|
||||
impl<A> OneOrManyActiveModel<A> for Vec<A>
|
||||
where
|
||||
A: ActiveModelTrait,
|
||||
{
|
||||
fn is_one() -> bool {
|
||||
false
|
||||
}
|
||||
fn get_one(self) -> A {
|
||||
panic!("not one")
|
||||
}
|
||||
|
||||
fn take(&mut self, c: Self::Column) -> ActiveValue<Value>;
|
||||
|
||||
fn get(&self, c: Self::Column) -> ActiveValue<Value>;
|
||||
|
||||
fn set(&mut self, c: Self::Column, v: Value);
|
||||
|
||||
fn unset(&mut self, c: Self::Column);
|
||||
fn is_many() -> bool {
|
||||
true
|
||||
}
|
||||
fn get_many(self) -> Vec<A> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::{
|
||||
ColumnTrait, ModelTrait, PrimaryKeyOfModel, PrimaryKeyTrait, QueryHelper, RelationBuilder,
|
||||
RelationTrait, RelationType, Select,
|
||||
ActiveModelOf, ActiveModelTrait, ColumnTrait, Insert, ModelTrait, OneOrManyActiveModel,
|
||||
PrimaryKeyOfModel, PrimaryKeyTrait, QueryHelper, RelationBuilder, RelationTrait, RelationType,
|
||||
Select,
|
||||
};
|
||||
use sea_query::{Iden, IntoValueTuple};
|
||||
use std::fmt::Debug;
|
||||
@ -46,7 +47,7 @@ pub trait EntityTrait: EntityName {
|
||||
/// );
|
||||
/// ```
|
||||
fn find() -> Select<Self> {
|
||||
Select::<Self>::new()
|
||||
Select::new()
|
||||
}
|
||||
|
||||
/// Find a model by primary key
|
||||
@ -94,4 +95,57 @@ pub trait EntityTrait: EntityName {
|
||||
}
|
||||
select
|
||||
}
|
||||
|
||||
fn insert<A, C>(models: C) -> Insert<A>
|
||||
where
|
||||
A: ActiveModelTrait + ActiveModelOf<Self>,
|
||||
C: OneOrManyActiveModel<A>,
|
||||
{
|
||||
if C::is_one() {
|
||||
Insert::new().one(models.get_one())
|
||||
} else if C::is_many() {
|
||||
Insert::new().many(models.get_many())
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::tests_cfg::cake;
|
||||
use crate::{EntityTrait, Val};
|
||||
use sea_query::PostgresQueryBuilder;
|
||||
|
||||
#[test]
|
||||
fn insert_one() {
|
||||
let apple = cake::ActiveModel {
|
||||
name: Val::set("Apple Pie".to_owned()),
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(
|
||||
cake::Entity::insert(apple)
|
||||
.build(PostgresQueryBuilder)
|
||||
.to_string(),
|
||||
r#"INSERT INTO "cake" ("name") VALUES ('Apple Pie')"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_many() {
|
||||
let apple = cake::ActiveModel {
|
||||
name: Val::set("Apple Pie".to_owned()),
|
||||
..Default::default()
|
||||
};
|
||||
let orange = cake::ActiveModel {
|
||||
name: Val::set("Orange Scone".to_owned()),
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(
|
||||
cake::Entity::insert(vec![apple, orange])
|
||||
.build(PostgresQueryBuilder)
|
||||
.to_string(),
|
||||
r#"INSERT INTO "cake" ("name") VALUES ('Apple Pie'), ('Orange Scone')"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ where
|
||||
A: ActiveModelTrait,
|
||||
{
|
||||
pub(crate) query: InsertStatement,
|
||||
pub(crate) columns: Vec<bool>,
|
||||
pub(crate) model: PhantomData<A>,
|
||||
}
|
||||
|
||||
@ -24,6 +25,7 @@ where
|
||||
query: InsertStatement::new()
|
||||
.into_table(E::default().into_iden())
|
||||
.to_owned(),
|
||||
columns: Vec::new(),
|
||||
model: PhantomData,
|
||||
}
|
||||
}
|
||||
@ -35,8 +37,14 @@ where
|
||||
let mut am: A = m.into();
|
||||
let mut columns = Vec::new();
|
||||
let mut values = Vec::new();
|
||||
for col in A::Column::iter() {
|
||||
let columns_empty = self.columns.is_empty();
|
||||
for (idx, col) in A::Column::iter().enumerate() {
|
||||
let av = am.take(col);
|
||||
if columns_empty {
|
||||
self.columns.push(av.is_set());
|
||||
} else if self.columns[idx] != av.is_set() {
|
||||
panic!("columns mismatch");
|
||||
}
|
||||
if !av.is_unset() {
|
||||
columns.push(col);
|
||||
values.push(av.into_value());
|
||||
@ -47,6 +55,17 @@ where
|
||||
self
|
||||
}
|
||||
|
||||
pub fn many<M, I>(mut self, models: I) -> Self
|
||||
where
|
||||
M: Into<A>,
|
||||
I: IntoIterator<Item = M>,
|
||||
{
|
||||
for model in models.into_iter() {
|
||||
self = self.one(model);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Get a mutable ref to the query builder
|
||||
pub fn query(&mut self) -> &mut InsertStatement {
|
||||
&mut self.query
|
||||
@ -74,7 +93,7 @@ where
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::tests_cfg::cake;
|
||||
use crate::{ActiveValue, Insert};
|
||||
use crate::{Insert, Val};
|
||||
use sea_query::PostgresQueryBuilder;
|
||||
|
||||
#[test]
|
||||
@ -82,8 +101,8 @@ mod tests {
|
||||
assert_eq!(
|
||||
Insert::<cake::ActiveModel>::new()
|
||||
.one(cake::ActiveModel {
|
||||
id: ActiveValue::unset(),
|
||||
name: ActiveValue::set("Apple Pie".to_owned()),
|
||||
id: Val::unset(),
|
||||
name: Val::set("Apple Pie".to_owned()),
|
||||
})
|
||||
.build(PostgresQueryBuilder)
|
||||
.to_string(),
|
||||
@ -96,8 +115,8 @@ mod tests {
|
||||
assert_eq!(
|
||||
Insert::<cake::ActiveModel>::new()
|
||||
.one(cake::ActiveModel {
|
||||
id: ActiveValue::set(1),
|
||||
name: ActiveValue::set("Apple Pie".to_owned()),
|
||||
id: Val::set(1),
|
||||
name: Val::set("Apple Pie".to_owned()),
|
||||
})
|
||||
.build(PostgresQueryBuilder)
|
||||
.to_string(),
|
||||
@ -118,4 +137,44 @@ mod tests {
|
||||
r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie')"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_4() {
|
||||
assert_eq!(
|
||||
Insert::<cake::ActiveModel>::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: Val::set("Apple".to_owned()),
|
||||
..Default::default()
|
||||
};
|
||||
let orange = cake::ActiveModel {
|
||||
id: Val::set(2),
|
||||
name: Val::set("Orange".to_owned()),
|
||||
};
|
||||
assert_eq!(
|
||||
Insert::<cake::ActiveModel>::new()
|
||||
.many(vec![apple, orange])
|
||||
.build(PostgresQueryBuilder)
|
||||
.to_string(),
|
||||
r#"INSERT INTO "cake" ("id", "name") VALUES (NULL, 'Apple'), (2, 'Orange')"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user