#![cfg(feature = "sqlx-dep")]
#![deny(clippy::future_not_send)]
#![allow(dead_code)]
mod parent {
use sea_orm::entity::prelude::*;
#[sea_orm::model]
#[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel)]
#[sea_orm(table_name = "sf_parent")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub name: String,
#[sea_orm(has_many)]
pub children: HasMany<super::child::Entity>,
#[sea_orm(has_one)]
pub detail: HasOne<super::detail::Entity>,
}
impl ActiveModelBehavior for ActiveModel {}
}
mod child {
use sea_orm::entity::prelude::*;
#[sea_orm::model]
#[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel)]
#[sea_orm(table_name = "sf_child")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub parent_id: Option<i32>,
#[sea_orm(belongs_to, from = "parent_id", to = "id")]
pub parent: BelongsTo<Option<super::parent::Entity>>,
}
impl ActiveModelBehavior for ActiveModel {}
}
mod detail {
use sea_orm::entity::prelude::*;
#[sea_orm::model]
#[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel)]
#[sea_orm(table_name = "sf_detail")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub parent_id: i32,
#[sea_orm(belongs_to, from = "parent_id", to = "id")]
pub parent: BelongsTo<super::parent::Entity>,
}
impl ActiveModelBehavior for ActiveModel {}
}
mod post {
use sea_orm::entity::prelude::*;
#[sea_orm::model]
#[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel)]
#[sea_orm(table_name = "sf_post")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub title: String,
#[sea_orm(has_many, via = "post_tag")]
pub tags: HasMany<super::tag::Entity>,
}
impl ActiveModelBehavior for ActiveModel {}
}
mod tag {
use sea_orm::entity::prelude::*;
#[sea_orm::model]
#[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel)]
#[sea_orm(table_name = "sf_tag")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub name: String,
#[sea_orm(has_many, via = "post_tag")]
pub posts: HasMany<super::post::Entity>,
}
impl ActiveModelBehavior for ActiveModel {}
}
mod post_tag {
use sea_orm::entity::prelude::*;
#[sea_orm::model]
#[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel)]
#[sea_orm(table_name = "sf_post_tag")]
pub struct Model {
#[sea_orm(primary_key, auto_increment = false)]
pub post_id: i32,
#[sea_orm(primary_key, auto_increment = false)]
pub tag_id: i32,
#[sea_orm(belongs_to, from = "post_id", to = "id")]
pub post: BelongsTo<super::post::Entity>,
#[sea_orm(belongs_to, from = "tag_id", to = "id")]
pub tag: BelongsTo<super::tag::Entity>,
}
impl ActiveModelBehavior for ActiveModel {}
}
mod node {
use sea_orm::entity::prelude::*;
#[sea_orm::model]
#[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel)]
#[sea_orm(table_name = "sf_node")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
#[sea_orm(enum_name = "ParentId")]
pub parent_ref: Option<i32>,
#[sea_orm(self_ref, relation_enum = "Parent", from = "ParentId", to = "id")]
pub parent: BelongsTo<Option<Entity>>,
}
impl ActiveModelBehavior for ActiveModel {}
}
mod standalone {
use sea_orm::entity::prelude::*;
#[sea_orm::model]
#[derive(Debug, Clone, PartialEq, Eq, DeriveEntityModel)]
#[sea_orm(table_name = "sf_standalone")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub name: String,
}
impl ActiveModelBehavior for ActiveModel {}
}
use sea_orm::entity::prelude::async_trait;
use sea_orm::{
ActiveModelAction, ConnectionTrait, DatabaseConnection, DatabaseExecutor, DatabaseTransaction,
DbErr, TransactionTrait,
};
fn assert_send<T: Send>(_: T) {}
fn generic_every_method<C: TransactionTrait>(
db: &C,
active: parent::ActiveModelEx,
model: parent::Model,
model_ex: parent::ModelEx,
) {
assert_send(active.clone().insert(db));
assert_send(active.clone().update(db));
assert_send(active.clone().save(db));
assert_send(active.clone().delete(db));
assert_send(active.action(ActiveModelAction::Save, db));
assert_send(model.cascade_delete(db));
assert_send(model_ex.delete(db));
}
fn generic_has_one<C: TransactionTrait>(db: &C, active: detail::ActiveModelEx) {
assert_send(active.insert(db));
}
fn generic_belongs_to<C: TransactionTrait>(db: &C, active: child::ActiveModelEx) {
assert_send(active.insert(db));
}
fn generic_many_to_many<C: TransactionTrait>(
db: &C,
post: post::ActiveModelEx,
junction: post_tag::ActiveModelEx,
) {
assert_send(post.insert(db));
assert_send(junction.insert(db));
}
fn generic_self_ref<C: TransactionTrait>(db: &C, active: node::ActiveModelEx) {
assert_send(active.insert(db));
}
fn generic_no_relations<C: TransactionTrait>(db: &C, active: standalone::ActiveModelEx) {
assert_send(active.insert(db));
}
async fn repository_helper<C>(db: &C, name: &str) -> Result<parent::ModelEx, DbErr>
where
C: ConnectionTrait + TransactionTrait,
{
parent::ActiveModel::builder()
.set_name(name)
.insert(db)
.await
}
fn repository_helper_is_send<C: ConnectionTrait + TransactionTrait>(db: &C) {
assert_send(repository_helper(db, "a"));
}
async fn impl_trait_helper(
db: &(impl ConnectionTrait + TransactionTrait),
name: &str,
) -> Result<parent::ModelEx, DbErr> {
parent::ActiveModel::builder()
.set_name(name)
.insert(db)
.await
}
async fn nested_helper<C>(db: &C, name: &str) -> Result<parent::ModelEx, DbErr>
where
C: ConnectionTrait + TransactionTrait,
{
let txn = db.begin().await?;
parent::ActiveModel::builder()
.set_name(name)
.insert(&txn)
.await
}
fn nested_helper_is_send<C: ConnectionTrait + TransactionTrait>(db: &C) {
assert_send(nested_helper(db, "a"));
}
fn concrete_connection(db: &DatabaseConnection, active: parent::ActiveModelEx) {
assert_send(active.insert(db));
}
fn concrete_transaction(db: &DatabaseTransaction, active: parent::ActiveModelEx) {
assert_send(active.insert(db));
}
fn concrete_executor(db: &DatabaseExecutor<'_>, active: parent::ActiveModelEx) {
assert_send(active.insert(db));
}
struct CustomConnection {
inner: DatabaseConnection,
}
#[async_trait::async_trait]
impl TransactionTrait for CustomConnection {
type Transaction = DatabaseTransaction;
async fn begin(&self) -> Result<Self::Transaction, DbErr> {
self.inner.begin().await
}
async fn begin_with_config(
&self,
isolation_level: Option<sea_orm::IsolationLevel>,
access_mode: Option<sea_orm::AccessMode>,
) -> Result<Self::Transaction, DbErr> {
self.inner
.begin_with_config(isolation_level, access_mode)
.await
}
async fn begin_with_options(
&self,
options: sea_orm::TransactionOptions,
) -> Result<Self::Transaction, DbErr> {
self.inner.begin_with_options(options).await
}
async fn transaction<F, T, E>(&self, callback: F) -> Result<T, sea_orm::TransactionError<E>>
where
F: for<'c> FnOnce(
&'c Self::Transaction,
) -> std::pin::Pin<
Box<dyn std::future::Future<Output = Result<T, E>> + Send + 'c>,
> + Send,
T: Send,
E: std::fmt::Display + std::fmt::Debug + Send,
{
self.inner.transaction(callback).await
}
async fn transaction_with_config<F, T, E>(
&self,
callback: F,
isolation_level: Option<sea_orm::IsolationLevel>,
access_mode: Option<sea_orm::AccessMode>,
) -> Result<T, sea_orm::TransactionError<E>>
where
F: for<'c> FnOnce(
&'c Self::Transaction,
) -> std::pin::Pin<
Box<dyn std::future::Future<Output = Result<T, E>> + Send + 'c>,
> + Send,
T: Send,
E: std::fmt::Display + std::fmt::Debug + Send,
{
self.inner
.transaction_with_config(callback, isolation_level, access_mode)
.await
}
}
fn custom_connection_works(db: &CustomConnection, active: parent::ActiveModelEx) {
assert_send(active.insert(db));
}
fn assert_transaction_trait_bounds<C>()
where
C: TransactionTrait + Sync,
C::Transaction: TransactionTrait<Transaction = C::Transaction> + Send,
{
}
#[test]
fn transaction_trait_implementors_satisfy_bounds() {
assert_transaction_trait_bounds::<DatabaseConnection>();
assert_transaction_trait_bounds::<DatabaseTransaction>();
assert_transaction_trait_bounds::<DatabaseExecutor<'_>>();
assert_transaction_trait_bounds::<CustomConnection>();
}
#[test]
fn generated_active_model_ex_mutation_futures_are_send() {
let _ = parent::ActiveModel::builder();
let _ = child::ActiveModel::builder();
}