find_by_id and delete_by_id take any Into primary key value (#1362)

This commit is contained in:
Billy Chan 2023-01-11 15:28:10 +08:00 committed by GitHub
parent c49a8ac843
commit 0756adf647
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 64 additions and 19 deletions

View File

@ -256,10 +256,13 @@ pub trait EntityTrait: EntityName {
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
fn find_by_id(values: <Self::PrimaryKey as PrimaryKeyTrait>::ValueType) -> Select<Self> { fn find_by_id<T>(values: T) -> Select<Self>
where
T: Into<<Self::PrimaryKey as PrimaryKeyTrait>::ValueType>,
{
let mut select = Self::find(); let mut select = Self::find();
let mut keys = Self::PrimaryKey::iter(); let mut keys = Self::PrimaryKey::iter();
for v in values.into_value_tuple() { for v in values.into().into_value_tuple() {
if let Some(key) = keys.next() { if let Some(key) = keys.next() {
let col = key.into_column(); let col = key.into_column();
select = select.filter(col.eq(v)); select = select.filter(col.eq(v));
@ -815,10 +818,13 @@ pub trait EntityTrait: EntityName {
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
fn delete_by_id(values: <Self::PrimaryKey as PrimaryKeyTrait>::ValueType) -> DeleteMany<Self> { fn delete_by_id<T>(values: T) -> DeleteMany<Self>
where
T: Into<<Self::PrimaryKey as PrimaryKeyTrait>::ValueType>,
{
let mut delete = Self::delete_many(); let mut delete = Self::delete_many();
let mut keys = Self::PrimaryKey::iter(); let mut keys = Self::PrimaryKey::iter();
for v in values.into_value_tuple() { for v in values.into().into_value_tuple() {
if let Some(key) = keys.next() { if let Some(key) = keys.next() {
let col = key.into_column(); let col = key.into_column();
delete = delete.filter(col.eq(v)); delete = delete.filter(col.eq(v));
@ -910,4 +916,45 @@ mod tests {
assert_eq!(hello::Entity.table_name(), "hello"); assert_eq!(hello::Entity.table_name(), "hello");
assert_eq!(hello::Entity.schema_name(), Some("world")); assert_eq!(hello::Entity.schema_name(), Some("world"));
} }
#[test]
#[cfg(feature = "macros")]
fn entity_model_3() {
use crate::{entity::*, query::*, DbBackend};
use std::borrow::Cow;
mod hello {
use crate as sea_orm;
use crate::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
#[sea_orm(table_name = "hello", schema_name = "world")]
pub struct Model {
#[sea_orm(primary_key, auto_increment = false)]
pub id: String,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}
}
fn delete_by_id<T>(value: T)
where
T: Into<<<hello::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType>,
{
assert_eq!(
hello::Entity::delete_by_id(value)
.build(DbBackend::Sqlite)
.to_string(),
r#"DELETE FROM "world"."hello" WHERE "hello"."id" = 'UUID'"#
);
}
delete_by_id(format!("UUID"));
delete_by_id("UUID".to_string());
delete_by_id("UUID");
delete_by_id(Cow::from("UUID"));
}
} }

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
cast_enum_as_text, error::*, ActiveModelTrait, ConnectionTrait, EntityTrait, IntoActiveModel, cast_enum_as_text, error::*, ActiveModelTrait, ConnectionTrait, EntityTrait, IntoActiveModel,
Iterable, SelectModel, SelectorRaw, Statement, UpdateMany, UpdateOne, Iterable, PrimaryKeyTrait, SelectModel, SelectorRaw, Statement, UpdateMany, UpdateOne,
}; };
use sea_query::{Expr, FromValueTuple, Query, UpdateStatement}; use sea_query::{Expr, FromValueTuple, Query, UpdateStatement};
use std::future::Future; use std::future::Future;
@ -89,20 +89,20 @@ where
A: ActiveModelTrait, A: ActiveModelTrait,
C: ConnectionTrait, C: ConnectionTrait,
{ {
type Entity<A> = <A as ActiveModelTrait>::Entity;
type Model<A> = <Entity<A> as EntityTrait>::Model;
type Column<A> = <Entity<A> as EntityTrait>::Column;
type ValueType<A> = <<Entity<A> as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType;
match db.support_returning() { match db.support_returning() {
true => { true => {
let returning = Query::returning().exprs( let returning = Query::returning()
<A::Entity as EntityTrait>::Column::iter() .exprs(Column::<A>::iter().map(|c| cast_enum_as_text(Expr::col(c), &c)));
.map(|c| cast_enum_as_text(Expr::col(c), &c)),
);
query.returning(returning); query.returning(returning);
let db_backend = db.get_database_backend(); let db_backend = db.get_database_backend();
let found: Option<<A::Entity as EntityTrait>::Model> = let found: Option<Model<A>> =
SelectorRaw::<SelectModel<<A::Entity as EntityTrait>::Model>>::from_statement( SelectorRaw::<SelectModel<Model<A>>>::from_statement(db_backend.build(&query))
db_backend.build(&query), .one(db)
) .await?;
.one(db)
.await?;
// If we got `None` then we are updating a row that does not exist. // If we got `None` then we are updating a row that does not exist.
match found { match found {
Some(model) => Ok(model), Some(model) => Ok(model),
@ -115,12 +115,10 @@ where
// If we updating a row that does not exist then an error will be thrown here. // If we updating a row that does not exist then an error will be thrown here.
Updater::new(query).check_record_exists().exec(db).await?; Updater::new(query).check_record_exists().exec(db).await?;
let primary_key_value = match model.get_primary_key_value() { let primary_key_value = match model.get_primary_key_value() {
Some(val) => FromValueTuple::from_value_tuple(val), Some(val) => ValueType::<A>::from_value_tuple(val),
None => return Err(DbErr::UpdateGetPrimaryKey), None => return Err(DbErr::UpdateGetPrimaryKey),
}; };
let found = <A::Entity as EntityTrait>::find_by_id(primary_key_value) let found = Entity::<A>::find_by_id(primary_key_value).one(db).await?;
.one(db)
.await?;
// If we cannot select the updated row from db by the cached primary key // If we cannot select the updated row from db by the cached primary key
match found { match found {
Some(model) => Ok(model), Some(model) => Ok(model),