Add TryFromU64 & test Uuid as primary key
This commit is contained in:
parent
333f199c1a
commit
0e0ee0ede6
@ -1,10 +1,7 @@
|
||||
use super::{ColumnTrait, IdenStatic, Iterable};
|
||||
use crate::TryGetable;
|
||||
use crate::{TryFromU64, TryGetable};
|
||||
use sea_query::IntoValueTuple;
|
||||
use std::{
|
||||
fmt::{Debug, Display},
|
||||
str::FromStr,
|
||||
};
|
||||
use std::fmt::{Debug, Display};
|
||||
|
||||
//LINT: composite primary key cannot auto increment
|
||||
pub trait PrimaryKeyTrait: IdenStatic + Iterable {
|
||||
@ -15,7 +12,7 @@ pub trait PrimaryKeyTrait: IdenStatic + Iterable {
|
||||
+ PartialEq
|
||||
+ IntoValueTuple
|
||||
+ TryGetable
|
||||
+ FromStr;
|
||||
+ TryFromU64;
|
||||
|
||||
fn auto_increment() -> bool;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum DbErr {
|
||||
Conn(String),
|
||||
Exec(String),
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::{
|
||||
error::*, ActiveModelTrait, DatabaseConnection, EntityTrait, Insert, PrimaryKeyTrait, Statement,
|
||||
error::*, ActiveModelTrait, DatabaseConnection, EntityTrait, Insert, PrimaryKeyTrait,
|
||||
Statement, TryFromU64,
|
||||
};
|
||||
use sea_query::InsertStatement;
|
||||
use std::{future::Future, marker::PhantomData};
|
||||
@ -82,20 +83,17 @@ async fn exec_insert<A>(
|
||||
where
|
||||
A: ActiveModelTrait,
|
||||
{
|
||||
// TODO: Postgres instead use query_one + returning clause
|
||||
type ValueTypeOf<A> = <<<A as ActiveModelTrait>::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType;
|
||||
let last_insert_id = match db {
|
||||
#[cfg(feature = "sqlx-postgres")]
|
||||
DatabaseConnection::SqlxPostgresPoolConnection(conn) => {
|
||||
let res = conn.query_one(statement).await?.unwrap();
|
||||
res.try_get("", "last_insert_id").unwrap_or_default()
|
||||
}
|
||||
_ => db
|
||||
.execute(statement)
|
||||
.await?
|
||||
.last_insert_id()
|
||||
.to_string()
|
||||
.parse()
|
||||
.unwrap_or_default(),
|
||||
_ => {
|
||||
let last_insert_id = db.execute(statement).await?.last_insert_id();
|
||||
ValueTypeOf::<A>::try_from_u64(last_insert_id)?
|
||||
}
|
||||
};
|
||||
Ok(InsertResult { last_insert_id })
|
||||
}
|
||||
|
@ -405,3 +405,49 @@ impl TryGetable for Option<Decimal> {
|
||||
|
||||
#[cfg(feature = "with-uuid")]
|
||||
try_getable_all!(uuid::Uuid);
|
||||
|
||||
pub trait TryFromU64: Sized {
|
||||
fn try_from_u64(n: u64) -> Result<Self, DbErr>;
|
||||
}
|
||||
|
||||
macro_rules! try_from_u64 {
|
||||
( $type: ty ) => {
|
||||
impl TryFromU64 for $type {
|
||||
fn try_from_u64(n: u64) -> Result<Self, DbErr> {
|
||||
use std::convert::TryInto;
|
||||
n.try_into().map_err(|_| {
|
||||
DbErr::Exec(format!(
|
||||
"fail to convert '{}' into '{}'",
|
||||
n,
|
||||
stringify!($type)
|
||||
))
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
try_from_u64!(i8);
|
||||
try_from_u64!(i16);
|
||||
try_from_u64!(i32);
|
||||
try_from_u64!(i64);
|
||||
try_from_u64!(u8);
|
||||
try_from_u64!(u16);
|
||||
try_from_u64!(u32);
|
||||
try_from_u64!(u64);
|
||||
|
||||
macro_rules! try_from_u64_err {
|
||||
( $type: ty ) => {
|
||||
impl TryFromU64 for $type {
|
||||
fn try_from_u64(_: u64) -> Result<Self, DbErr> {
|
||||
Err(DbErr::Exec(format!(
|
||||
"{} cannot be converted from u64",
|
||||
stringify!($type)
|
||||
)))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "with-uuid")]
|
||||
try_from_u64_err!(uuid::Uuid);
|
||||
|
61
tests/common/bakery_chain/metadata.rs
Normal file
61
tests/common/bakery_chain/metadata.rs
Normal file
@ -0,0 +1,61 @@
|
||||
use sea_orm::entity::prelude::*;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||
pub struct Entity;
|
||||
|
||||
impl EntityName for Entity {
|
||||
fn table_name(&self) -> &str {
|
||||
"metadata"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
||||
pub struct Model {
|
||||
pub uuid: Uuid,
|
||||
pub key: String,
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||
pub enum Column {
|
||||
Uuid,
|
||||
Key,
|
||||
Value,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
|
||||
pub enum PrimaryKey {
|
||||
Uuid,
|
||||
}
|
||||
|
||||
impl PrimaryKeyTrait for PrimaryKey {
|
||||
type ValueType = Uuid;
|
||||
|
||||
fn auto_increment() -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ColumnTrait for Column {
|
||||
type EntityName = Entity;
|
||||
|
||||
fn def(&self) -> ColumnDef {
|
||||
match self {
|
||||
Self::Uuid => ColumnType::Uuid.def(),
|
||||
Self::Key => ColumnType::String(None).def(),
|
||||
Self::Value => ColumnType::String(None).def(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RelationTrait for Relation {
|
||||
fn def(&self) -> RelationDef {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
@ -4,6 +4,7 @@ pub mod cake;
|
||||
pub mod cakes_bakers;
|
||||
pub mod customer;
|
||||
pub mod lineitem;
|
||||
pub mod metadata;
|
||||
pub mod order;
|
||||
|
||||
pub use super::baker::Entity as Baker;
|
||||
@ -12,4 +13,5 @@ pub use super::cake::Entity as Cake;
|
||||
pub use super::cakes_bakers::Entity as CakesBakers;
|
||||
pub use super::customer::Entity as Customer;
|
||||
pub use super::lineitem::Entity as Lineitem;
|
||||
pub use super::metadata::Entity as Metadata;
|
||||
pub use super::order::Entity as Order;
|
||||
|
@ -45,13 +45,14 @@ pub async fn setup(base_url: &str, db_name: &str) -> DatabaseConnection {
|
||||
Database::connect(base_url).await.unwrap()
|
||||
};
|
||||
|
||||
assert!(schema::create_bakery_table(&db).await.is_ok());
|
||||
assert!(schema::create_baker_table(&db).await.is_ok());
|
||||
assert!(schema::create_customer_table(&db).await.is_ok());
|
||||
assert!(schema::create_order_table(&db).await.is_ok());
|
||||
assert!(schema::create_cake_table(&db).await.is_ok());
|
||||
assert!(schema::create_cakes_bakers_table(&db).await.is_ok());
|
||||
assert!(schema::create_lineitem_table(&db).await.is_ok());
|
||||
schema::create_bakery_table(&db).await.unwrap();
|
||||
schema::create_baker_table(&db).await.unwrap();
|
||||
schema::create_customer_table(&db).await.unwrap();
|
||||
schema::create_order_table(&db).await.unwrap();
|
||||
schema::create_cake_table(&db).await.unwrap();
|
||||
schema::create_cakes_bakers_table(&db).await.unwrap();
|
||||
schema::create_lineitem_table(&db).await.unwrap();
|
||||
schema::create_metadata_table(&db).await.unwrap();
|
||||
db
|
||||
}
|
||||
|
||||
|
@ -254,3 +254,20 @@ pub async fn create_cake_table(db: &DbConn) -> Result<ExecResult, DbErr> {
|
||||
|
||||
create_table(db, &stmt).await
|
||||
}
|
||||
|
||||
pub async fn create_metadata_table(db: &DbConn) -> Result<ExecResult, DbErr> {
|
||||
let stmt = sea_query::Table::create()
|
||||
.table(metadata::Entity)
|
||||
.if_not_exists()
|
||||
.col(
|
||||
ColumnDef::new(metadata::Column::Uuid)
|
||||
.uuid()
|
||||
.not_null()
|
||||
.primary_key(),
|
||||
)
|
||||
.col(ColumnDef::new(metadata::Column::Key).string().not_null())
|
||||
.col(ColumnDef::new(metadata::Column::Value).string().not_null())
|
||||
.to_owned();
|
||||
|
||||
create_table(db, &stmt).await
|
||||
}
|
||||
|
41
tests/primary_key_tests.rs
Normal file
41
tests/primary_key_tests.rs
Normal file
@ -0,0 +1,41 @@
|
||||
use sea_orm::{entity::prelude::*, DatabaseConnection, Set};
|
||||
pub mod common;
|
||||
pub use common::{bakery_chain::*, setup::*, TestContext};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[sea_orm_macros::test]
|
||||
#[cfg(any(
|
||||
feature = "sqlx-mysql",
|
||||
feature = "sqlx-sqlite",
|
||||
feature = "sqlx-postgres"
|
||||
))]
|
||||
async fn main() -> Result<(), DbErr> {
|
||||
let ctx = TestContext::new("bakery_chain_schema_primary_key_tests").await;
|
||||
|
||||
create_metadata(&ctx.db).await?;
|
||||
|
||||
ctx.delete().await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn create_metadata(db: &DatabaseConnection) -> Result<(), DbErr> {
|
||||
let metadata = metadata::ActiveModel {
|
||||
uuid: Set(Uuid::new_v4()),
|
||||
key: Set("markup".to_owned()),
|
||||
value: Set("1.18".to_owned()),
|
||||
};
|
||||
|
||||
let res = Metadata::insert(metadata.clone()).exec(db).await;
|
||||
|
||||
if cfg!(feature = "sqlx-postgres") {
|
||||
assert_eq!(metadata.uuid.unwrap(), res?.last_insert_id);
|
||||
} else {
|
||||
assert_eq!(
|
||||
res.unwrap_err(),
|
||||
DbErr::Exec("uuid::Uuid cannot be converted from u64".to_owned())
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user