Merge pull request #117 from SeaQL/primary-key-type

`InsertResult` to return the primary key's type
This commit is contained in:
Chris Tsang 2021-09-03 14:15:11 +08:00 committed by GitHub
commit 76596da46a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 523 additions and 109 deletions

View File

@ -87,7 +87,7 @@ let pear = fruit::ActiveModel {
};
// insert one
let res: InsertResult = Fruit::insert(pear).exec(db).await?;
let res = Fruit::insert(pear).exec(db).await?;
println!("InsertResult: {}", res.last_insert_id);

View File

@ -27,6 +27,8 @@ pub enum PrimaryKey {
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}

View File

@ -28,6 +28,8 @@ pub enum PrimaryKey {
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = (i32, i32);
fn auto_increment() -> bool {
false
}

View File

@ -27,6 +27,8 @@ pub enum PrimaryKey {
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}

View File

@ -29,6 +29,8 @@ pub enum PrimaryKey {
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}

View File

@ -20,7 +20,7 @@ pub async fn insert_and_update(db: &DbConn) -> Result<(), DbErr> {
name: Set("pear".to_owned()),
..Default::default()
};
let res: InsertResult = Fruit::insert(pear).exec(db).await?;
let res = Fruit::insert(pear).exec(db).await?;
println!();
println!("Inserted: last_insert_id = {}\n", res.last_insert_id);

View File

@ -27,6 +27,8 @@ pub enum PrimaryKey {
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}

View File

@ -117,6 +117,31 @@ impl Entity {
format_ident!("{}", auto_increment)
}
pub fn get_primary_key_rs_type(&self) -> TokenStream {
let types = self
.primary_keys
.iter()
.map(|primary_key| {
self.columns
.iter()
.find(|col| col.name.eq(&primary_key.name))
.unwrap()
.get_rs_type()
.to_string()
})
.collect::<Vec<_>>();
if !types.is_empty() {
let value_type = if types.len() > 1 {
vec!["(".to_owned(), types.join(", "), ")".to_owned()]
} else {
types
};
value_type.join("").parse().unwrap()
} else {
TokenStream::new()
}
}
pub fn get_conjunct_relations_via_snake_case(&self) -> Vec<Ident> {
self.conjunct_relations
.iter()
@ -151,7 +176,7 @@ mod tests {
columns: vec![
Column {
name: "id".to_owned(),
col_type: ColumnType::String(None),
col_type: ColumnType::Integer(None),
auto_increment: false,
not_null: false,
unique: false,
@ -373,6 +398,16 @@ mod tests {
);
}
#[test]
fn test_get_primary_key_rs_type() {
let entity = setup();
assert_eq!(
entity.get_primary_key_rs_type().to_string(),
entity.columns[0].get_rs_type().to_string()
);
}
#[test]
fn test_get_conjunct_relations_via_snake_case() {
let entity = setup();

View File

@ -173,8 +173,11 @@ impl EntityWriter {
pub fn gen_impl_primary_key(entity: &Entity) -> TokenStream {
let primary_key_auto_increment = entity.get_primary_key_auto_increment();
let value_type = entity.get_primary_key_rs_type();
quote! {
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = #value_type;
fn auto_increment() -> bool {
#primary_key_auto_increment
}

View File

@ -29,6 +29,8 @@ pub enum PrimaryKey {
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}

View File

@ -30,6 +30,8 @@ pub enum PrimaryKey {
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = (i32, i32);
fn auto_increment() -> bool {
false
}

View File

@ -29,6 +29,8 @@ pub enum PrimaryKey {
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}

View File

@ -31,6 +31,8 @@ pub enum PrimaryKey {
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}

View File

@ -31,6 +31,8 @@ pub enum PrimaryKey {
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}

View File

@ -102,24 +102,11 @@ impl From<PgRow> for QueryResult {
impl From<PgQueryResult> for ExecResult {
fn from(result: PgQueryResult) -> ExecResult {
ExecResult {
result: ExecResultHolder::SqlxPostgres {
last_insert_id: 0,
rows_affected: result.rows_affected(),
},
result: ExecResultHolder::SqlxPostgres(result),
}
}
}
pub(crate) fn query_result_into_exec_result(res: QueryResult) -> Result<ExecResult, DbErr> {
let last_insert_id: i32 = res.try_get("", "last_insert_id")?;
Ok(ExecResult {
result: ExecResultHolder::SqlxPostgres {
last_insert_id: last_insert_id as u64,
rows_affected: 0,
},
})
}
fn sqlx_query(stmt: &Statement) -> sqlx::query::Query<'_, Postgres, PgArguments> {
let mut query = sqlx::query(&stmt.sql);
if let Some(values) = &stmt.values {

View File

@ -221,16 +221,18 @@ where
let exec = E::insert(am).exec(db);
let res = exec.await?;
// TODO: if the entity does not have auto increment primary key, then last_insert_id is a wrong value
if <E::PrimaryKey as PrimaryKeyTrait>::auto_increment() && res.last_insert_id != 0 {
// FIXME: Assumed valid last_insert_id is not equals to Default::default()
if <E::PrimaryKey as PrimaryKeyTrait>::auto_increment()
&& res.last_insert_id != <E::PrimaryKey as PrimaryKeyTrait>::ValueType::default()
{
let find = E::find_by_id(res.last_insert_id).one(db);
let found = find.await;
let model: Option<E::Model> = found?;
match model {
Some(model) => Ok(model.into_active_model()),
None => Err(DbErr::Exec(format!(
"Failed to find inserted item: {} {}",
"Failed to find inserted item: {}",
E::default().to_string(),
res.last_insert_id
))),
}
} else {

View File

@ -1,7 +1,18 @@
use super::{ColumnTrait, IdenStatic, Iterable};
use crate::{TryFromU64, TryGetableMany};
use sea_query::IntoValueTuple;
use std::fmt::Debug;
//LINT: composite primary key cannot auto increment
pub trait PrimaryKeyTrait: IdenStatic + Iterable {
type ValueType: Sized
+ Default
+ Debug
+ PartialEq
+ IntoValueTuple
+ TryGetableMany
+ TryFromU64;
fn auto_increment() -> bool;
}

View File

@ -1,4 +1,4 @@
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub enum DbErr {
Conn(String),
Exec(String),

View File

@ -8,10 +8,7 @@ pub(crate) enum ExecResultHolder {
#[cfg(feature = "sqlx-mysql")]
SqlxMySql(sqlx::mysql::MySqlQueryResult),
#[cfg(feature = "sqlx-postgres")]
SqlxPostgres {
last_insert_id: u64,
rows_affected: u64,
},
SqlxPostgres(sqlx::postgres::PgQueryResult),
#[cfg(feature = "sqlx-sqlite")]
SqlxSqlite(sqlx::sqlite::SqliteQueryResult),
#[cfg(feature = "mock")]
@ -26,7 +23,9 @@ impl ExecResult {
#[cfg(feature = "sqlx-mysql")]
ExecResultHolder::SqlxMySql(result) => result.last_insert_id(),
#[cfg(feature = "sqlx-postgres")]
ExecResultHolder::SqlxPostgres { last_insert_id, .. } => last_insert_id.to_owned(),
ExecResultHolder::SqlxPostgres(_) => {
panic!("Should not retrieve last_insert_id this way")
}
#[cfg(feature = "sqlx-sqlite")]
ExecResultHolder::SqlxSqlite(result) => {
let last_insert_rowid = result.last_insert_rowid();
@ -46,7 +45,7 @@ impl ExecResult {
#[cfg(feature = "sqlx-mysql")]
ExecResultHolder::SqlxMySql(result) => result.rows_affected(),
#[cfg(feature = "sqlx-postgres")]
ExecResultHolder::SqlxPostgres { rows_affected, .. } => rows_affected.to_owned(),
ExecResultHolder::SqlxPostgres(result) => result.rows_affected(),
#[cfg(feature = "sqlx-sqlite")]
ExecResultHolder::SqlxSqlite(result) => result.rows_affected(),
#[cfg(feature = "mock")]

View File

@ -1,15 +1,25 @@
use crate::{error::*, ActiveModelTrait, DatabaseConnection, Insert, Statement};
use crate::{
error::*, ActiveModelTrait, DatabaseConnection, EntityTrait, Insert, PrimaryKeyTrait,
Statement, TryFromU64,
};
use sea_query::InsertStatement;
use std::future::Future;
use std::{future::Future, marker::PhantomData};
#[derive(Clone, Debug)]
pub struct Inserter {
pub struct Inserter<A>
where
A: ActiveModelTrait,
{
query: InsertStatement,
model: PhantomData<A>,
}
#[derive(Clone, Debug)]
pub struct InsertResult {
pub last_insert_id: u64,
#[derive(Debug)]
pub struct InsertResult<A>
where
A: ActiveModelTrait,
{
pub last_insert_id: <<<A as ActiveModelTrait>::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType,
}
impl<A> Insert<A>
@ -17,54 +27,79 @@ where
A: ActiveModelTrait,
{
#[allow(unused_mut)]
pub fn exec(
pub fn exec<'a>(
self,
db: &DatabaseConnection,
) -> impl Future<Output = Result<InsertResult, DbErr>> + '_ {
db: &'a DatabaseConnection,
) -> impl Future<Output = Result<InsertResult<A>, DbErr>> + 'a
where
A: 'a,
{
// so that self is dropped before entering await
let mut query = self.query;
#[cfg(feature = "sqlx-postgres")]
if let DatabaseConnection::SqlxPostgresPoolConnection(_) = db {
use crate::{EntityTrait, Iterable};
use sea_query::{Alias, Expr, Query};
for key in <A::Entity as EntityTrait>::PrimaryKey::iter() {
use crate::{sea_query::Query, Iterable};
if <A::Entity as EntityTrait>::PrimaryKey::iter().count() > 0 {
query.returning(
Query::select()
.expr_as(Expr::col(key), Alias::new("last_insert_id"))
.to_owned(),
.columns(<A::Entity as EntityTrait>::PrimaryKey::iter())
.take(),
);
}
}
Inserter::new(query).exec(db)
Inserter::<A>::new(query).exec(db)
}
}
impl Inserter {
impl<A> Inserter<A>
where
A: ActiveModelTrait,
{
pub fn new(query: InsertStatement) -> Self {
Self { query }
Self {
query,
model: PhantomData,
}
}
pub fn exec(
pub fn exec<'a>(
self,
db: &DatabaseConnection,
) -> impl Future<Output = Result<InsertResult, DbErr>> + '_ {
db: &'a DatabaseConnection,
) -> impl Future<Output = Result<InsertResult<A>, DbErr>> + 'a
where
A: 'a,
{
let builder = db.get_database_backend();
exec_insert(builder.build(&self.query), db)
}
}
// Only Statement impl Send
async fn exec_insert(statement: Statement, db: &DatabaseConnection) -> Result<InsertResult, DbErr> {
// TODO: Postgres instead use query_one + returning clause
let result = match db {
async fn exec_insert<A>(
statement: Statement,
db: &DatabaseConnection,
) -> Result<InsertResult<A>, DbErr>
where
A: ActiveModelTrait,
{
type PrimaryKey<A> = <<A as ActiveModelTrait>::Entity as EntityTrait>::PrimaryKey;
type ValueTypeOf<A> = <PrimaryKey<A> as PrimaryKeyTrait>::ValueType;
let last_insert_id = match db {
#[cfg(feature = "sqlx-postgres")]
DatabaseConnection::SqlxPostgresPoolConnection(conn) => {
use crate::{sea_query::Iden, Iterable};
let cols = PrimaryKey::<A>::iter()
.map(|col| col.to_string())
.collect::<Vec<_>>();
let res = conn.query_one(statement).await?.unwrap();
crate::query_result_into_exec_result(res)?
res.try_get_many("", cols.as_ref()).unwrap_or_default()
}
_ => {
let last_insert_id = db.execute(statement).await?.last_insert_id();
ValueTypeOf::<A>::try_from_u64(last_insert_id)
.ok()
.unwrap_or_default()
}
_ => db.execute(statement).await?,
};
Ok(InsertResult {
last_insert_id: result.last_insert_id(),
})
Ok(InsertResult { last_insert_id })
}

View File

@ -17,6 +17,10 @@ pub(crate) enum QueryResultRow {
Mock(crate::MockRow),
}
pub trait TryGetable: Sized {
fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result<Self, TryGetError>;
}
pub enum TryGetError {
DbErr(DbErr),
Null,
@ -31,12 +35,6 @@ impl From<TryGetError> for DbErr {
}
}
pub trait TryGetable {
fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result<Self, TryGetError>
where
Self: Sized;
}
// QueryResult //
impl QueryResult {
@ -46,6 +44,13 @@ impl QueryResult {
{
Ok(T::try_get(self, pre, col)?)
}
pub fn try_get_many<T>(&self, pre: &str, cols: &[String]) -> Result<T, DbErr>
where
T: TryGetableMany,
{
Ok(T::try_get_many(self, pre, cols)?)
}
}
impl fmt::Debug for QueryResultRow {
@ -283,3 +288,135 @@ impl TryGetable for Decimal {
#[cfg(feature = "with-uuid")]
try_getable_all!(uuid::Uuid);
// TryGetableMany //
pub trait TryGetableMany: Sized {
fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError>;
}
impl<T> TryGetableMany for T
where
T: TryGetable,
{
fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
try_get_many_with_slice_len_of(1, cols)?;
T::try_get(res, pre, &cols[0])
}
}
impl<T> TryGetableMany for (T, T)
where
T: TryGetable,
{
fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
try_get_many_with_slice_len_of(2, cols)?;
Ok((
T::try_get(res, pre, &cols[0])?,
T::try_get(res, pre, &cols[1])?,
))
}
}
impl<T> TryGetableMany for (T, T, T)
where
T: TryGetable,
{
fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
try_get_many_with_slice_len_of(3, cols)?;
Ok((
T::try_get(res, pre, &cols[0])?,
T::try_get(res, pre, &cols[1])?,
T::try_get(res, pre, &cols[2])?,
))
}
}
fn try_get_many_with_slice_len_of(len: usize, cols: &[String]) -> Result<(), TryGetError> {
if cols.len() < len {
Err(TryGetError::DbErr(DbErr::Query(format!(
"Expect {} column names supplied but got slice of length {}",
len,
cols.len()
))))
} else {
Ok(())
}
}
// TryFromU64 //
pub trait TryFromU64: Sized {
fn try_from_u64(n: u64) -> Result<Self, DbErr>;
}
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)
)))
}
}
};
}
macro_rules! try_from_u64_tuple {
( $type: ty ) => {
try_from_u64_err!(($type, $type));
try_from_u64_err!(($type, $type, $type));
};
}
macro_rules! try_from_u64_numeric {
( $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_tuple!($type);
};
}
try_from_u64_numeric!(i8);
try_from_u64_numeric!(i16);
try_from_u64_numeric!(i32);
try_from_u64_numeric!(i64);
try_from_u64_numeric!(u8);
try_from_u64_numeric!(u16);
try_from_u64_numeric!(u32);
try_from_u64_numeric!(u64);
macro_rules! try_from_u64_string {
( $type: ty ) => {
impl TryFromU64 for $type {
fn try_from_u64(n: u64) -> Result<Self, DbErr> {
Ok(n.to_string())
}
}
try_from_u64_tuple!($type);
};
}
try_from_u64_string!(String);
macro_rules! try_from_u64_dummy {
( $type: ty ) => {
try_from_u64_err!($type);
try_from_u64_err!(($type, $type));
try_from_u64_err!(($type, $type, $type));
};
}
#[cfg(feature = "with-uuid")]
try_from_u64_dummy!(uuid::Uuid);

View File

@ -93,7 +93,7 @@
//! };
//!
//! // insert one
//! let res: InsertResult = Fruit::insert(pear).exec(db).await?;
//! let res = Fruit::insert(pear).exec(db).await?;
//!
//! println!("InsertResult: {}", res.last_insert_id);
//! # Ok(())

View File

@ -28,6 +28,8 @@ pub enum PrimaryKey {
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}

View File

@ -29,6 +29,8 @@ pub enum PrimaryKey {
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = (i32, i32);
fn auto_increment() -> bool {
false
}

View File

@ -35,6 +35,8 @@ pub enum PrimaryKey {
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = (i32, i32);
fn auto_increment() -> bool {
false
}

View File

@ -41,6 +41,8 @@ pub enum PrimaryKey {
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}

View File

@ -30,6 +30,8 @@ pub enum PrimaryKey {
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}

View File

@ -31,6 +31,8 @@ pub enum PrimaryKey {
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}

View File

@ -29,6 +29,8 @@ pub enum PrimaryKey {
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}

View File

@ -35,6 +35,8 @@ pub enum PrimaryKey {
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}

View File

@ -28,6 +28,8 @@ pub enum PrimaryKey {
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = (i32, i32);
fn auto_increment() -> bool {
false
}

View File

@ -29,6 +29,8 @@ pub enum PrimaryKey {
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}

View File

@ -33,6 +33,8 @@ pub enum PrimaryKey {
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}

View 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 {}

View File

@ -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;

View File

@ -33,6 +33,8 @@ pub enum PrimaryKey {
}
impl PrimaryKeyTrait for PrimaryKey {
type ValueType = i32;
fn auto_increment() -> bool {
true
}

View File

@ -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
}

View File

@ -271,3 +271,20 @@ pub async fn create_cake_table(db: &DbConn) -> Result<ExecResult, DbErr> {
create_table(db, &stmt, Cake).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
}

View File

@ -7,7 +7,7 @@ pub async fn test_create_baker(db: &DbConn) {
profit_margin: Set(10.4),
..Default::default()
};
let bakery_insert_res: InsertResult = Bakery::insert(seaside_bakery)
let bakery_insert_res = Bakery::insert(seaside_bakery)
.exec(db)
.await
.expect("could not insert bakery");
@ -30,7 +30,7 @@ pub async fn test_create_baker(db: &DbConn) {
bakery_id: Set(Some(bakery_insert_res.last_insert_id as i32)),
..Default::default()
};
let res: InsertResult = Baker::insert(baker_bob)
let res = Baker::insert(baker_bob)
.exec(db)
.await
.expect("could not insert baker");

View File

@ -8,7 +8,7 @@ pub async fn test_create_cake(db: &DbConn) {
profit_margin: Set(10.4),
..Default::default()
};
let bakery_insert_res: InsertResult = Bakery::insert(seaside_bakery)
let bakery_insert_res = Bakery::insert(seaside_bakery)
.exec(db)
.await
.expect("could not insert bakery");
@ -23,7 +23,7 @@ pub async fn test_create_cake(db: &DbConn) {
bakery_id: Set(Some(bakery_insert_res.last_insert_id as i32)),
..Default::default()
};
let baker_insert_res: InsertResult = Baker::insert(baker_bob)
let baker_insert_res = Baker::insert(baker_bob)
.exec(db)
.await
.expect("could not insert baker");
@ -38,7 +38,7 @@ pub async fn test_create_cake(db: &DbConn) {
..Default::default()
};
let cake_insert_res: InsertResult = Cake::insert(mud_cake)
let cake_insert_res = Cake::insert(mud_cake)
.exec(db)
.await
.expect("could not insert cake");
@ -53,10 +53,18 @@ pub async fn test_create_cake(db: &DbConn) {
baker_id: Set(baker_insert_res.last_insert_id as i32),
..Default::default()
};
let _cake_baker_res: InsertResult = CakesBakers::insert(cake_baker)
let cake_baker_res = CakesBakers::insert(cake_baker.clone())
.exec(db)
.await
.expect("could not insert cake_baker");
assert_eq!(
cake_baker_res.last_insert_id,
if cfg!(feature = "sqlx-postgres") {
(cake_baker.cake_id.unwrap(), cake_baker.baker_id.unwrap())
} else {
Default::default()
}
);
assert!(cake.is_some());
let cake_model = cake.unwrap();

View File

@ -10,7 +10,7 @@ pub async fn test_create_lineitem(db: &DbConn) {
profit_margin: Set(10.4),
..Default::default()
};
let bakery_insert_res: InsertResult = Bakery::insert(seaside_bakery)
let bakery_insert_res = Bakery::insert(seaside_bakery)
.exec(db)
.await
.expect("could not insert bakery");
@ -26,7 +26,7 @@ pub async fn test_create_lineitem(db: &DbConn) {
bakery_id: Set(Some(bakery_insert_res.last_insert_id as i32)),
..Default::default()
};
let baker_insert_res: InsertResult = Baker::insert(baker_bob)
let baker_insert_res = Baker::insert(baker_bob)
.exec(db)
.await
.expect("could not insert baker");
@ -41,7 +41,7 @@ pub async fn test_create_lineitem(db: &DbConn) {
..Default::default()
};
let cake_insert_res: InsertResult = Cake::insert(mud_cake)
let cake_insert_res = Cake::insert(mud_cake)
.exec(db)
.await
.expect("could not insert cake");
@ -52,10 +52,18 @@ pub async fn test_create_lineitem(db: &DbConn) {
baker_id: Set(baker_insert_res.last_insert_id as i32),
..Default::default()
};
let _cake_baker_res: InsertResult = CakesBakers::insert(cake_baker)
let cake_baker_res = CakesBakers::insert(cake_baker.clone())
.exec(db)
.await
.expect("could not insert cake_baker");
assert_eq!(
cake_baker_res.last_insert_id,
if cfg!(feature = "sqlx-postgres") {
(cake_baker.cake_id.unwrap(), cake_baker.baker_id.unwrap())
} else {
Default::default()
}
);
// Customer
let customer_kate = customer::ActiveModel {
@ -63,7 +71,7 @@ pub async fn test_create_lineitem(db: &DbConn) {
notes: Set(Some("Loves cheese cake".to_owned())),
..Default::default()
};
let customer_insert_res: InsertResult = Customer::insert(customer_kate)
let customer_insert_res = Customer::insert(customer_kate)
.exec(db)
.await
.expect("could not insert customer");
@ -76,7 +84,7 @@ pub async fn test_create_lineitem(db: &DbConn) {
placed_at: Set(Utc::now().naive_utc()),
..Default::default()
};
let order_insert_res: InsertResult = Order::insert(order_1)
let order_insert_res = Order::insert(order_1)
.exec(db)
.await
.expect("could not insert order");
@ -89,7 +97,7 @@ pub async fn test_create_lineitem(db: &DbConn) {
quantity: Set(1),
..Default::default()
};
let lineitem_insert_res: InsertResult = Lineitem::insert(lineitem_1)
let lineitem_insert_res = Lineitem::insert(lineitem_1)
.exec(db)
.await
.expect("could not insert lineitem");
@ -105,7 +113,7 @@ pub async fn test_create_lineitem(db: &DbConn) {
assert_eq!(lineitem_model.price, dec!(7.55));
let cake: Option<cake::Model> = Cake::find_by_id(lineitem_model.cake_id as u64)
let cake: Option<cake::Model> = Cake::find_by_id(lineitem_model.cake_id)
.one(db)
.await
.expect("could not find cake");

View File

@ -10,7 +10,7 @@ pub async fn test_create_order(db: &DbConn) {
profit_margin: Set(10.4),
..Default::default()
};
let bakery_insert_res: InsertResult = Bakery::insert(seaside_bakery)
let bakery_insert_res = Bakery::insert(seaside_bakery)
.exec(db)
.await
.expect("could not insert bakery");
@ -26,7 +26,7 @@ pub async fn test_create_order(db: &DbConn) {
bakery_id: Set(Some(bakery_insert_res.last_insert_id as i32)),
..Default::default()
};
let baker_insert_res: InsertResult = Baker::insert(baker_bob)
let baker_insert_res = Baker::insert(baker_bob)
.exec(db)
.await
.expect("could not insert baker");
@ -41,7 +41,7 @@ pub async fn test_create_order(db: &DbConn) {
..Default::default()
};
let cake_insert_res: InsertResult = Cake::insert(mud_cake)
let cake_insert_res = Cake::insert(mud_cake)
.exec(db)
.await
.expect("could not insert cake");
@ -52,10 +52,18 @@ pub async fn test_create_order(db: &DbConn) {
baker_id: Set(baker_insert_res.last_insert_id as i32),
..Default::default()
};
let _cake_baker_res: InsertResult = CakesBakers::insert(cake_baker)
let cake_baker_res = CakesBakers::insert(cake_baker.clone())
.exec(db)
.await
.expect("could not insert cake_baker");
assert_eq!(
cake_baker_res.last_insert_id,
if cfg!(feature = "sqlx-postgres") {
(cake_baker.cake_id.unwrap(), cake_baker.baker_id.unwrap())
} else {
Default::default()
}
);
// Customer
let customer_kate = customer::ActiveModel {
@ -63,7 +71,7 @@ pub async fn test_create_order(db: &DbConn) {
notes: Set(Some("Loves cheese cake".to_owned())),
..Default::default()
};
let customer_insert_res: InsertResult = Customer::insert(customer_kate)
let customer_insert_res = Customer::insert(customer_kate)
.exec(db)
.await
.expect("could not insert customer");
@ -76,7 +84,7 @@ pub async fn test_create_order(db: &DbConn) {
placed_at: Set(Utc::now().naive_utc()),
..Default::default()
};
let order_insert_res: InsertResult = Order::insert(order_1)
let order_insert_res = Order::insert(order_1)
.exec(db)
.await
.expect("could not insert order");
@ -89,7 +97,7 @@ pub async fn test_create_order(db: &DbConn) {
quantity: Set(2),
..Default::default()
};
let _lineitem_insert_res: InsertResult = Lineitem::insert(lineitem_1)
let _lineitem_insert_res = Lineitem::insert(lineitem_1)
.exec(db)
.await
.expect("could not insert lineitem");
@ -103,7 +111,7 @@ pub async fn test_create_order(db: &DbConn) {
let order_model = order.unwrap();
assert_eq!(order_model.total, dec!(15.10));
let customer: Option<customer::Model> = Customer::find_by_id(order_model.customer_id as u64)
let customer: Option<customer::Model> = Customer::find_by_id(order_model.customer_id)
.one(db)
.await
.expect("could not find customer");
@ -111,7 +119,7 @@ pub async fn test_create_order(db: &DbConn) {
let customer_model = customer.unwrap();
assert_eq!(customer_model.name, "Kate");
let bakery: Option<bakery::Model> = Bakery::find_by_id(order_model.bakery_id as i64)
let bakery: Option<bakery::Model> = Bakery::find_by_id(order_model.bakery_id)
.one(db)
.await
.expect("could not find bakery");

View File

@ -10,7 +10,7 @@ pub async fn test_delete_cake(db: &DbConn) {
profit_margin: Set(10.4),
..Default::default()
};
let bakery_insert_res: InsertResult = Bakery::insert(seaside_bakery)
let bakery_insert_res = Bakery::insert(seaside_bakery)
.exec(db)
.await
.expect("could not insert bakery");

View File

@ -1,4 +1,4 @@
use sea_orm::{entity::*, DbConn, InsertResult};
use sea_orm::{entity::*, DbConn};
pub use super::common::bakery_chain::*;
@ -15,7 +15,7 @@ pub async fn test_create_bakery(db: &DbConn) {
profit_margin: Set(10.4),
..Default::default()
};
let res: InsertResult = Bakery::insert(seaside_bakery)
let res = Bakery::insert(seaside_bakery)
.exec(db)
.await
.expect("could not insert bakery");
@ -37,7 +37,7 @@ pub async fn test_create_customer(db: &DbConn) {
notes: Set(Some("Loves cheese cake".to_owned())),
..Default::default()
};
let res: InsertResult = Customer::insert(customer_kate)
let res = Customer::insert(customer_kate)
.exec(db)
.await
.expect("could not insert customer");

View File

@ -8,7 +8,7 @@ pub async fn test_update_cake(db: &DbConn) {
profit_margin: Set(10.4),
..Default::default()
};
let bakery_insert_res: InsertResult = Bakery::insert(seaside_bakery)
let bakery_insert_res = Bakery::insert(seaside_bakery)
.exec(db)
.await
.expect("could not insert bakery");
@ -22,7 +22,7 @@ pub async fn test_update_cake(db: &DbConn) {
..Default::default()
};
let cake_insert_res: InsertResult = Cake::insert(mud_cake)
let cake_insert_res = Cake::insert(mud_cake)
.exec(db)
.await
.expect("could not insert cake");
@ -62,7 +62,7 @@ pub async fn test_update_bakery(db: &DbConn) {
profit_margin: Set(10.4),
..Default::default()
};
let bakery_insert_res: InsertResult = Bakery::insert(seaside_bakery)
let bakery_insert_res = Bakery::insert(seaside_bakery)
.exec(db)
.await
.expect("could not insert bakery");
@ -130,11 +130,10 @@ pub async fn test_update_deleted_customer(db: &DbConn) {
assert_eq!(Customer::find().count(db).await.unwrap(), init_n_customers);
let customer: Option<customer::Model> =
Customer::find_by_id(customer_id.clone().unwrap() as i64)
.one(db)
.await
.expect("could not find customer");
let customer: Option<customer::Model> = Customer::find_by_id(customer_id.clone().unwrap())
.one(db)
.await
.expect("could not find customer");
assert_eq!(customer, None);
}

View 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?;
assert_eq!(
res.last_insert_id,
if cfg!(feature = "sqlx-postgres") {
metadata.uuid.unwrap()
} else {
Default::default()
}
);
Ok(())
}

View File

@ -67,7 +67,7 @@ async fn init_setup(db: &DatabaseConnection) {
..Default::default()
};
let cake_insert_res: InsertResult = Cake::insert(mud_cake)
let cake_insert_res = Cake::insert(mud_cake)
.exec(db)
.await
.expect("could not insert cake");
@ -78,10 +78,18 @@ async fn init_setup(db: &DatabaseConnection) {
..Default::default()
};
let _cake_baker_res: InsertResult = CakesBakers::insert(cake_baker)
let cake_baker_res = CakesBakers::insert(cake_baker.clone())
.exec(db)
.await
.expect("could not insert cake_baker");
assert_eq!(
cake_baker_res.last_insert_id,
if cfg!(feature = "sqlx-postgres") {
(cake_baker.cake_id.unwrap(), cake_baker.baker_id.unwrap())
} else {
Default::default()
}
);
let customer_kate = customer::ActiveModel {
name: Set("Kate".to_owned()),
@ -183,7 +191,7 @@ async fn find_baker_least_sales(db: &DatabaseConnection) -> Option<baker::Model>
results.sort_by(|a, b| b.cakes_sold.cmp(&a.cakes_sold));
Baker::find_by_id(results.last().unwrap().id as i64)
Baker::find_by_id(results.last().unwrap().id)
.one(db)
.await
.unwrap()
@ -200,7 +208,7 @@ async fn create_cake(db: &DatabaseConnection, baker: baker::Model) -> Option<cak
..Default::default()
};
let cake_insert_res: InsertResult = Cake::insert(new_cake)
let cake_insert_res = Cake::insert(new_cake)
.exec(db)
.await
.expect("could not insert cake");
@ -211,10 +219,18 @@ async fn create_cake(db: &DatabaseConnection, baker: baker::Model) -> Option<cak
..Default::default()
};
let _cake_baker_res: InsertResult = CakesBakers::insert(cake_baker)
let cake_baker_res = CakesBakers::insert(cake_baker.clone())
.exec(db)
.await
.expect("could not insert cake_baker");
assert_eq!(
cake_baker_res.last_insert_id,
if cfg!(feature = "sqlx-postgres") {
(cake_baker.cake_id.unwrap(), cake_baker.baker_id.unwrap())
} else {
Default::default()
}
);
Cake::find_by_id(cake_insert_res.last_insert_id)
.one(db)