Repository: SeaQL/sea-orm (rust)

Issue:
Support feteching `T`, `(T, U)`, `(T, U, P)`..etc where they impl `TryGetableMany`
Hi, I think we need a way to fetch data from database without putting into a `Model`, instead we use tuple or single type, here is what's in my mind:
```rust
// where bool: TryGetableMany
let is_locked: Option<bool> = cake::Account::find()
    .select_only()
    .column(account::Column::IsLocked)
    .into_values() // this would return `Selector<?>`
    .one(db)
    .await?;
```

We can also extend this to `TryGetableMany` it self, that would allow us to write:
```rust
let stmt = "select name, count(post.user_id) as post_count .. group by name";
let user_posts = <(String, i32)>::from_statment(stmt, ["name", "post_count"]) // this would return `Selector<?>`
    .one(db)
    .await?;
```

sounds cool?

Pull request:
Support feteching T, (T, U), (T, U, P)..etc where they impl TryGetableMany
Resolve #180

This is not the best API for sure! but we can start with this. One blocker that I got was `SelectorTrait::from_raw_query_result` is a function, which doesn't help when I want to store some data into `SelectGetableValue`, so I used generic type `C` to work around this, but yeah we don't get very ergonomic API.

Patch:
diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
index 09cd26a2..674b3163 100644
--- a/ARCHITECTURE.md
+++ b/ARCHITECTURE.md
@@ -1,7 +1,5 @@
 # Architecture
 
-> Let's dive under the Sea 🤿
-
 To understand the architecture of SeaORM, let's discuss what is an ORM. ORM exists to provide abstractions over common operations you would do against a database and hide the implementation details like the actual SQL queries.
 
 With a good ORM, you shouldn't bother to look under the API surface. Until you do. I hear you say *'abstraction leaks'*, and yes, it does.
diff --git a/README.md b/README.md
index 2285c77c..1c0e83d1 100644
--- a/README.md
+++ b/README.md
@@ -239,7 +239,7 @@ fruit::Entity::delete_many()
 
 1. [Design](https://github.com/SeaQL/sea-orm/tree/master/DESIGN.md)
 1. [Architecture](https://github.com/SeaQL/sea-orm/tree/master/ARCHITECTURE.md)
-1. [Change Log](https://github.com/SeaQL/sea-orm/tree/master/CHANGELOG.md)
+1. [Compare with Diesel](https://www.sea-ql.org/SeaORM/docs/internal-design/diesel)
 
 ## License
 
diff --git a/src/entity/base_entity.rs b/src/entity/base_entity.rs
index 764f2524..7ba1e965 100644
--- a/src/entity/base_entity.rs
+++ b/src/entity/base_entity.rs
@@ -293,7 +293,7 @@ pub trait EntityTrait: EntityName {
     /// assert_eq!(
     ///     db.into_transaction_log(),
     ///     vec![Transaction::from_sql_and_values(
-    ///         DbBackend::Postgres, r#"INSERT INTO "cake" ("name") VALUES ($1) RETURNING "id""#, vec!["Apple Pie".into()]
+    ///         DbBackend::Postgres, r#"INSERT INTO "cake" ("name") VALUES ($1)"#, vec!["Apple Pie".into()]
     ///     )]);
     /// ```
     fn insert<A>(model: A) -> Insert<A>
@@ -344,7 +344,7 @@ pub trait EntityTrait: EntityName {
     /// assert_eq!(
     ///     db.into_transaction_log(),
     ///     vec![Transaction::from_sql_and_values(
-    ///         DbBackend::Postgres, r#"INSERT INTO "cake" ("name") VALUES ($1), ($2) RETURNING "id""#,
+    ///         DbBackend::Postgres, r#"INSERT INTO "cake" ("name") VALUES ($1), ($2)"#,
     ///         vec!["Apple Pie".into(), "Orange Scone".into()]
     ///     )]);
     /// ```
diff --git a/src/entity/link.rs b/src/entity/link.rs
index d0c262d7..97c9af1b 100644
--- a/src/entity/link.rs
+++ b/src/entity/link.rs
@@ -1,7 +1,5 @@
-use crate::{
-    join_tbl_on_condition, unpack_table_ref, EntityTrait, QuerySelect, RelationDef, Select,
-};
-use sea_query::{Alias, IntoIden, JoinType, SeaRc};
+use crate::{EntityTrait, QuerySelect, RelationDef, Select};
+use sea_query::JoinType;
 
 pub type LinkDef = RelationDef;
 
@@ -14,20 +12,8 @@ pub trait Linked {
 
     fn find_linked(&self) -> Select<Self::ToEntity> {
         let mut select = Select::new();
-        for (i, rel) in self.link().into_iter().rev().enumerate() {
-            let from_tbl = Alias::new(&format!("r{}", i)).into_iden();
-            let to_tbl = if i > 0 {
-                Alias::new(&format!("r{}", i - 1)).into_iden()
-            } else {
-                unpack_table_ref(&rel.to_tbl)
-            };
-
-            select.query().join_as(
-                JoinType::InnerJoin,
-                unpack_table_ref(&rel.from_tbl),
-                SeaRc::clone(&from_tbl),
-                join_tbl_on_condition(from_tbl, to_tbl, rel.from_col, rel.to_col),
-            );
+        for rel in self.link().into_iter().rev() {
+            select = select.join_rev(JoinType::InnerJoin, rel);
         }
         select
     }
diff --git a/src/entity/model.rs b/src/entity/model.rs
index ce4a3a4c..c6129ad7 100644
--- a/src/entity/model.rs
+++ b/src/entity/model.rs
@@ -24,8 +24,7 @@ pub trait ModelTrait: Clone + Send + Debug {
     where
         L: Linked<FromEntity = Self::Entity>,
     {
-        let tbl_alias = &format!("r{}", l.link().len() - 1);
-        l.find_linked().belongs_to_tbl_alias(self, tbl_alias)
+        l.find_linked().belongs_to(self)
     }
 }
 
diff --git a/src/executor/insert.rs b/src/executor/insert.rs
index d580f110..1f4936ba 100644
--- a/src/executor/insert.rs
+++ b/src/executor/insert.rs
@@ -1,5 +1,5 @@
 use crate::{
-    error::*, ActiveModelTrait, DatabaseConnection, DbBackend, EntityTrait, Insert, PrimaryKeyTrait,
+    error::*, ActiveModelTrait, DatabaseConnection, EntityTrait, Insert, PrimaryKeyTrait,
     Statement, TryFromU64,
 };
 use sea_query::InsertStatement;
@@ -37,7 +37,8 @@ where
         // TODO: extract primary key's value from query
         // so that self is dropped before entering await
         let mut query = self.query;
-        if db.get_database_backend() == DbBackend::Postgres {
+        #[cfg(feature = "sqlx-postgres")]
+        if let DatabaseConnection::SqlxPostgresPoolConnection(_) = db {
             use crate::{sea_query::Query, Iterable};
             if <A::Entity as EntityTrait>::PrimaryKey::iter().count() > 0 {
                 query.returning(
@@ -85,13 +86,14 @@ where
 {
     type PrimaryKey<A> = <<A as ActiveModelTrait>::Entity as EntityTrait>::PrimaryKey;
     type ValueTypeOf<A> = <PrimaryKey<A> as PrimaryKeyTrait>::ValueType;
-    let last_insert_id = match db.get_database_backend() {
-        DbBackend::Postgres => {
+    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 = db.query_one(statement).await?.unwrap();
+            let res = conn.query_one(statement).await?.unwrap();
             res.try_get_many("", cols.as_ref()).unwrap_or_default()
         }
         _ => {
diff --git a/src/executor/paginator.rs b/src/executor/paginator.rs
index 608d9dc1..24822111 100644
--- a/src/executor/paginator.rs
+++ b/src/executor/paginator.rs
@@ -1,4 +1,4 @@
-use crate::{error::*, DatabaseConnection, DbBackend, SelectorTrait};
+use crate::{error::*, DatabaseConnection, SelectorTrait};
 use async_stream::stream;
 use futures::Stream;
 use sea_query::{Alias, Expr, SelectStatement};
@@ -63,8 +63,11 @@ where
             Some(res) => res,
             None => return Ok(0),
         };
-        let num_items = match builder {
-            DbBackend::Postgres => result.try_get::<i64>("", "num_items")? as usize,
+        let num_items = match self.db {
+            #[cfg(feature = "sqlx-postgres")]
+            DatabaseConnection::SqlxPostgresPoolConnection(_) => {
+                result.try_get::<i64>("", "num_items")? as usize
+            }
             _ => result.try_get::<i32>("", "num_items")? as usize,
         };
         Ok(num_items)
@@ -189,7 +192,7 @@ mod tests {
         (db, vec![page1, page2, page3])
     }
 
-    fn setup_num_items() -> (DatabaseConnection, i64) {
+    fn setup_num_items() -> (DatabaseConnection, i32) {
         let num_items = 3;
         let db = MockDatabase::new(DbBackend::Postgres)
             .append_query_results(vec![vec![maplit::btreemap! {
diff --git a/src/executor/query.rs b/src/executor/query.rs
index ae09f97c..c39c2211 100644
--- a/src/executor/query.rs
+++ b/src/executor/query.rs
@@ -1,6 +1,6 @@
 #[cfg(feature = "mock")]
 use crate::debug_print;
-use crate::DbErr;
+use crate::{DbErr, SelectGetableValue, SelectorRaw, Statement};
 use std::fmt;
 
 #[derive(Debug)]
@@ -302,6 +302,79 @@ try_getable_all!(uuid::Uuid);
 
 pub trait TryGetableMany: Sized {
     fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError>;
+
+    /// ```
+    /// # #[cfg(feature = "mock")]
+    /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend};
+    /// #
+    /// # let db = MockDatabase::new(DbBackend::Postgres)
+    /// #     .append_query_results(vec![vec![
+    /// #         maplit::btreemap! {
+    /// #             "name" => Into::<Value>::into("Chocolate Forest"),
+    /// #             "num_of_cakes" => Into::<Value>::into(1),
+    /// #         },
+    /// #         maplit::btreemap! {
+    /// #             "name" => Into::<Value>::into("New York Cheese"),
+    /// #             "num_of_cakes" => Into::<Value>::into(1),
+    /// #         },
+    /// #     ]])
+    /// #     .into_connection();
+    /// #
+    /// use sea_orm::{entity::*, query::*, tests_cfg::cake, EnumIter, TryGetableMany};
+    ///
+    /// #[derive(EnumIter)]
+    /// enum ResultCol {
+    ///     Name,
+    ///     NumOfCakes,
+    /// }
+    ///
+    /// // this can be derived using derive_more crate
+    /// impl std::fmt::Display for ResultCol {
+    ///     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+    ///         match self {
+    ///             Self::Name => write!(f, "name"),
+    ///             Self::NumOfCakes => write!(f, "num_of_cakes"),
+    ///         }
+    ///     }
+    /// }
+    ///
+    /// # let _: Result<(), DbErr> = smol::block_on(async {
+    /// #
+    /// let res: Vec<(String, i32)> =
+    ///     <(String, i32)>::find_by_statement::<ResultCol>(Statement::from_sql_and_values(
+    ///         DbBackend::Postgres,
+    ///         r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#,
+    ///         vec![],
+    ///     ))
+    ///     .all(&db)
+    ///     .await?;
+    ///
+    /// assert_eq!(
+    ///     res,
+    ///     vec![
+    ///         ("Chocolate Forest".to_owned(), 1),
+    ///         ("New York Cheese".to_owned(), 1),
+    ///     ]
+    /// );
+    /// #
+    /// # Ok(())
+    /// # });
+    ///
+    /// assert_eq!(
+    ///     db.into_transaction_log(),
+    ///     vec![Transaction::from_sql_and_values(
+    ///         DbBackend::Postgres,
+    ///         r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#,
+    ///         vec![]
+    ///     ),]
+    /// );
+    /// ```
+    fn find_by_statement<C>(stmt: Statement) -> SelectorRaw<SelectGetableValue<Self, C>>
+    where
+        C: sea_strum::IntoEnumIterator + ToString,
+    {
+        SelectorRaw::<SelectGetableValue<Self, C>>::with_columns(stmt)
+    }
 }
 
 impl<T> TryGetableMany for T
@@ -314,6 +387,15 @@ where
     }
 }
 
+impl<T> TryGetableMany for (T,)
+where
+    T: TryGetableMany,
+{
+    fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
+        T::try_get_many(res, pre, cols).map(|r| (r,))
+    }
+}
+
 impl<A, B> TryGetableMany for (A, B)
 where
     A: TryGetable,
diff --git a/src/executor/select.rs b/src/executor/select.rs
index 959091c0..ebc5ad11 100644
--- a/src/executor/select.rs
+++ b/src/executor/select.rs
@@ -1,7 +1,7 @@
 use crate::{
     error::*, DatabaseConnection, EntityTrait, FromQueryResult, IdenStatic, Iterable, JsonValue,
     ModelTrait, Paginator, PrimaryKeyToColumn, QueryResult, Select, SelectA, SelectB, SelectTwo,
-    SelectTwoMany, Statement,
+    SelectTwoMany, Statement, TryGetableMany,
 };
 use sea_query::SelectStatement;
 use std::marker::PhantomData;
@@ -30,6 +30,16 @@ pub trait SelectorTrait {
     fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr>;
 }
 
+#[derive(Debug)]
+pub struct SelectGetableValue<T, C>
+where
+    T: TryGetableMany,
+    C: sea_strum::IntoEnumIterator + ToString,
+{
+    columns: PhantomData<C>,
+    model: PhantomData<T>,
+}
+
 #[derive(Debug)]
 pub struct SelectModel<M>
 where
@@ -47,6 +57,19 @@ where
     model: PhantomData<(M, N)>,
 }
 
+impl<T, C> SelectorTrait for SelectGetableValue<T, C>
+where
+    T: TryGetableMany,
+    C: sea_strum::IntoEnumIterator + ToString,
+{
+    type Item = T;
+
+    fn from_raw_query_result(res: QueryResult) -> Result<Self::Item, DbErr> {
+        let cols: Vec<String> = C::iter().map(|col| col.to_string()).collect();
+        T::try_get_many(&res, "", &cols).map_err(Into::into)
+    }
+}
+
 impl<M> SelectorTrait for SelectModel<M>
 where
     M: FromQueryResult + Sized,
@@ -103,6 +126,73 @@ where
         }
     }
 
+    /// ```
+    /// # #[cfg(feature = "mock")]
+    /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend};
+    /// #
+    /// # let db = MockDatabase::new(DbBackend::Postgres)
+    /// #     .append_query_results(vec![vec![
+    /// #         maplit::btreemap! {
+    /// #             "name" => Into::<Value>::into("Chocolate Forest"),
+    /// #             "num_of_cakes" => Into::<Value>::into(1),
+    /// #         },
+    /// #         maplit::btreemap! {
+    /// #             "name" => Into::<Value>::into("New York Cheese"),
+    /// #             "num_of_cakes" => Into::<Value>::into(1),
+    /// #         },
+    /// #     ]])
+    /// #     .into_connection();
+    /// #
+    /// use sea_orm::{entity::*, query::*, tests_cfg::cake, EnumIter, TryGetableMany};
+    ///
+    /// #[derive(EnumIter)]
+    /// enum ResultCol {
+    ///     Name,
+    /// }
+    ///
+    /// // this can be derived using derive_more crate
+    /// impl std::fmt::Display for ResultCol {
+    ///     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+    ///         match self {
+    ///             Self::Name => write!(f, "name"),
+    ///         }
+    ///     }
+    /// }
+    ///
+    /// # let _: Result<(), DbErr> = smol::block_on(async {
+    /// #
+    /// let res: Vec<String> = cake::Entity::find()
+    ///     .select_only()
+    ///     .column(cake::Column::Name)
+    ///     .into_values::<_, ResultCol>()
+    ///     .all(&db)
+    ///     .await?;
+    ///
+    /// assert_eq!(
+    ///     res,
+    ///     vec!["Chocolate Forest".to_owned(), "New York Cheese".to_owned(),]
+    /// );
+    /// #
+    /// # Ok(())
+    /// # });
+    ///
+    /// assert_eq!(
+    ///     db.into_transaction_log(),
+    ///     vec![Transaction::from_sql_and_values(
+    ///         DbBackend::Postgres,
+    ///         r#"SELECT "cake"."name" FROM "cake""#,
+    ///         vec![]
+    ///     ),]
+    /// );
+    /// ```
+    pub fn into_values<T, C>(self) -> Selector<SelectGetableValue<T, C>>
+    where
+        T: TryGetableMany,
+        C: sea_strum::IntoEnumIterator + ToString,
+    {
+        Selector::<SelectGetableValue<T, C>>::with_columns(self.query)
+    }
+
     pub async fn one(self, db: &DatabaseConnection) -> Result<Option<E::Model>, DbErr> {
         self.into_model().one(db).await
     }
@@ -228,6 +318,22 @@ impl<S> Selector<S>
 where
     S: SelectorTrait,
 {
+    /// Create `Selector` from Statment and columns. Executing this `Selector`
+    /// will return a type `T` which implement `TryGetableMany`.
+    pub fn with_columns<T, C>(query: SelectStatement) -> Selector<SelectGetableValue<T, C>>
+    where
+        T: TryGetableMany,
+        C: sea_strum::IntoEnumIterator + ToString,
+    {
+        Selector {
+            query,
+            selector: SelectGetableValue {
+                columns: PhantomData,
+                model: PhantomData,
+            },
+        }
+    }
+
     pub async fn one(mut self, db: &DatabaseConnection) -> Result<Option<S::Item>, DbErr> {
         let builder = db.get_database_backend();
         self.query.limit(1);
@@ -275,6 +381,22 @@ where
         }
     }
 
+    /// Create `SelectorRaw` from Statment and columns. Executing this `SelectorRaw` will
+    /// return a type `T` which implement `TryGetableMany`.
+    pub fn with_columns<T, C>(stmt: Statement) -> SelectorRaw<SelectGetableValue<T, C>>
+    where
+        T: TryGetableMany,
+        C: sea_strum::IntoEnumIterator + ToString,
+    {
+        SelectorRaw {
+            stmt,
+            selector: SelectGetableValue {
+                columns: PhantomData,
+                model: PhantomData,
+            },
+        }
+    }
+
     /// ```
     /// # #[cfg(feature = "mock")]
     /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend};
diff --git a/src/lib.rs b/src/lib.rs
index a1dc83f7..7ffbbf9b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -335,7 +335,7 @@
 //!
 //! 1. [Design](https://github.com/SeaQL/sea-orm/tree/master/DESIGN.md)
 //! 1. [Architecture](https://github.com/SeaQL/sea-orm/tree/master/ARCHITECTURE.md)
-//! 1. [Change Log](https://github.com/SeaQL/sea-orm/tree/master/CHANGELOG.md)
+//! 1. [Compare with Diesel](https://www.sea-ql.org/SeaORM/docs/internal-design/diesel)
 //!
 //! ## License
 //!
diff --git a/src/query/helper.rs b/src/query/helper.rs
index 43fed28a..d93595f1 100644
--- a/src/query/helper.rs
+++ b/src/query/helper.rs
@@ -2,11 +2,10 @@ use crate::{
     ColumnTrait, EntityTrait, Identity, IntoIdentity, IntoSimpleExpr, Iterable, ModelTrait,
     PrimaryKeyToColumn, RelationDef,
 };
+pub use sea_query::{Condition, ConditionalStatement, DynIden, JoinType, Order, OrderedStatement};
 use sea_query::{
-    Alias, Expr, Iden, IntoCondition, LockType, SeaRc, SelectExpr, SelectStatement, SimpleExpr,
-    TableRef,
+    Expr, IntoCondition, LockType, SeaRc, SelectExpr, SelectStatement, SimpleExpr, TableRef,
 };
-pub use sea_query::{Condition, ConditionalStatement, DynIden, JoinType, Order, OrderedStatement};
 
 // LINT: when the column does not appear in tables selected from
 // LINT: when there is a group by clause, but some columns don't have aggregate functions
@@ -269,48 +268,6 @@ pub trait QueryFilter: Sized {
     ///     "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` = 4 OR `cake`.`id` = 5"
     /// );
     /// ```
-    ///
-    /// Add a runtime-built condition tree.
-    /// ```
-    /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend};
-    /// struct Input {
-    ///     name: Option<String>,
-    /// }
-    /// let input = Input { name: Some("cheese".to_owned()) };
-    ///
-    /// let mut conditions = Condition::all();
-    /// if let Some(name) = input.name {
-    ///     conditions = conditions.add(cake::Column::Name.contains(&name));
-    /// }
-    ///
-    /// assert_eq!(
-    ///     cake::Entity::find()
-    ///         .filter(conditions)
-    ///         .build(DbBackend::MySql)
-    ///         .to_string(),
-    ///     "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE '%cheese%'"
-    /// );
-    /// ```
-    ///
-    /// Add a runtime-built condition tree, functional-way.
-    /// ```
-    /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend};
-    /// struct Input {
-    ///     name: Option<String>,
-    /// }
-    /// let input = Input { name: Some("cheese".to_owned()) };
-    ///
-    /// assert_eq!(
-    ///     cake::Entity::find()
-    ///         .filter(
-    ///             Condition::all()
-    ///                 .add_option(input.name.map(|n| cake::Column::Name.contains(&n)))
-    ///         )
-    ///         .build(DbBackend::MySql)
-    ///         .to_string(),
-    ///     "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE '%cheese%'"
-    /// );
-    /// ```
     fn filter<F>(mut self, filter: F) -> Self
     where
         F: IntoCondition,
@@ -330,35 +287,14 @@ pub trait QueryFilter: Sized {
         }
         self
     }
-
-    fn belongs_to_tbl_alias<M>(mut self, model: &M, tbl_alias: &str) -> Self
-    where
-        M: ModelTrait,
-    {
-        for key in <M::Entity as EntityTrait>::PrimaryKey::iter() {
-            let col = key.into_column();
-            let expr = Expr::tbl(Alias::new(tbl_alias), col).eq(model.get(col));
-            self = self.filter(expr);
-        }
-        self
-    }
 }
 
-pub(crate) fn join_condition(rel: RelationDef) -> SimpleExpr {
+fn join_condition(rel: RelationDef) -> SimpleExpr {
     let from_tbl = unpack_table_ref(&rel.from_tbl);
     let to_tbl = unpack_table_ref(&rel.to_tbl);
     let owner_keys = rel.from_col;
     let foreign_keys = rel.to_col;
 
-    join_tbl_on_condition(from_tbl, to_tbl, owner_keys, foreign_keys)
-}
-
-pub(crate) fn join_tbl_on_condition(
-    from_tbl: SeaRc<dyn Iden>,
-    to_tbl: SeaRc<dyn Iden>,
-    owner_keys: Identity,
-    foreign_keys: Identity,
-) -> SimpleExpr {
     match (owner_keys, foreign_keys) {
         (Identity::Unary(o1), Identity::Unary(f1)) => {
             Expr::tbl(SeaRc::clone(&from_tbl), o1).equals(SeaRc::clone(&to_tbl), f1)
diff --git a/src/query/join.rs b/src/query/join.rs
index 50592933..19dc3160 100644
--- a/src/query/join.rs
+++ b/src/query/join.rs
@@ -74,9 +74,8 @@ where
 
 #[cfg(test)]
 mod tests {
-    use crate::tests_cfg::{cake, cake_filling, cake_filling_price, entity_linked, filling, fruit};
+    use crate::tests_cfg::{cake, cake_filling, cake_filling_price, filling, fruit};
     use crate::{ColumnTrait, DbBackend, EntityTrait, ModelTrait, QueryFilter, QueryTrait};
-    use pretty_assertions::assert_eq;
 
     #[test]
     fn join_1() {
@@ -189,7 +188,7 @@ mod tests {
         assert_eq!(
             find_filling.build(DbBackend::MySql).to_string(),
             [
-                "SELECT `filling`.`id`, `filling`.`name`, `filling`.`vendor_id` FROM `filling`",
+                "SELECT `filling`.`id`, `filling`.`name` FROM `filling`",
                 "INNER JOIN `cake_filling` ON `cake_filling`.`filling_id` = `filling`.`id`",
                 "INNER JOIN `cake` ON `cake`.`id` = `cake_filling`.`cake_id`",
             ]
@@ -244,15 +243,15 @@ mod tests {
 
         assert_eq!(
             cake_model
-                .find_linked(entity_linked::CakeToFilling)
+                .find_linked(cake::CakeToFilling)
                 .build(DbBackend::MySql)
                 .to_string(),
             [
-                r#"SELECT `filling`.`id`, `filling`.`name`, `filling`.`vendor_id`"#,
+                r#"SELECT `filling`.`id`, `filling`.`name`"#,
                 r#"FROM `filling`"#,
-                r#"INNER JOIN `cake_filling` AS `r0` ON `r0`.`filling_id` = `filling`.`id`"#,
-                r#"INNER JOIN `cake` AS `r1` ON `r1`.`id` = `r0`.`cake_id`"#,
-                r#"WHERE `r1`.`id` = 12"#,
+                r#"INNER JOIN `cake_filling` ON `cake_filling`.`filling_id` = `filling`.`id`"#,
+                r#"INNER JOIN `cake` ON `cake`.`id` = `cake_filling`.`cake_id`"#,
+                r#"WHERE `cake`.`id` = 12"#,
             ]
             .join(" ")
         );
@@ -260,60 +259,17 @@ mod tests {
 
     #[test]
     fn join_11() {
-        let cake_model = cake::Model {
-            id: 18,
-            name: "".to_owned(),
-        };
-
-        assert_eq!(
-            cake_model
-                .find_linked(entity_linked::CakeToFillingVendor)
-                .build(DbBackend::MySql)
-                .to_string(),
-            [
-                r#"SELECT `vendor`.`id`, `vendor`.`name`"#,
-                r#"FROM `vendor`"#,
-                r#"INNER JOIN `filling` AS `r0` ON `r0`.`vendor_id` = `vendor`.`id`"#,
-                r#"INNER JOIN `cake_filling` AS `r1` ON `r1`.`filling_id` = `r0`.`id`"#,
-                r#"INNER JOIN `cake` AS `r2` ON `r2`.`id` = `r1`.`cake_id`"#,
-                r#"WHERE `r2`.`id` = 18"#,
-            ]
-            .join(" ")
-        );
-    }
-
-    #[test]
-    fn join_12() {
-        assert_eq!(
-            cake::Entity::find()
-                .find_also_linked(entity_linked::CakeToFilling)
-                .build(DbBackend::MySql)
-                .to_string(),
-            [
-                r#"SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`,"#,
-                r#"`filling`.`id` AS `B_id`, `filling`.`name` AS `B_name`, `filling`.`vendor_id` AS `B_vendor_id`"#,
-                r#"FROM `cake`"#,
-                r#"LEFT JOIN `cake_filling` ON `cake`.`id` = `cake_filling`.`cake_id`"#,
-                r#"LEFT JOIN `filling` ON `cake_filling`.`filling_id` = `filling`.`id`"#,
-            ]
-            .join(" ")
-        );
-    }
-
-    #[test]
-    fn join_13() {
         assert_eq!(
             cake::Entity::find()
-                .find_also_linked(entity_linked::CakeToFillingVendor)
+                .find_also_linked(cake::CakeToFilling)
                 .build(DbBackend::MySql)
                 .to_string(),
             [
                 r#"SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`,"#,
-                r#"`vendor`.`id` AS `B_id`, `vendor`.`name` AS `B_name`"#,
+                r#"`filling`.`id` AS `B_id`, `filling`.`name` AS `B_name`"#,
                 r#"FROM `cake`"#,
                 r#"LEFT JOIN `cake_filling` ON `cake`.`id` = `cake_filling`.`cake_id`"#,
                 r#"LEFT JOIN `filling` ON `cake_filling`.`filling_id` = `filling`.`id`"#,
-                r#"LEFT JOIN `vendor` ON `filling`.`vendor_id` = `vendor`.`id`"#,
             ]
             .join(" ")
         );


Test patch:
diff --git a/src/tests_cfg/cake.rs b/src/tests_cfg/cake.rs
index 8628492b..920e1fea 100644
--- a/src/tests_cfg/cake.rs
+++ b/src/tests_cfg/cake.rs
@@ -31,4 +31,20 @@ impl Related<super::filling::Entity> for Entity {
     }
 }
 
+#[derive(Debug)]
+pub struct CakeToFilling;
+
+impl Linked for CakeToFilling {
+    type FromEntity = Entity;
+
+    type ToEntity = super::filling::Entity;
+
+    fn link(&self) -> Vec<RelationDef> {
+        vec![
+            super::cake_filling::Relation::Cake.def().rev(),
+            super::cake_filling::Relation::Filling.def(),
+        ]
+    }
+}
+
 impl ActiveModelBehavior for ActiveModel {}
diff --git a/src/tests_cfg/cake_expanded.rs b/src/tests_cfg/cake_expanded.rs
index b4306313..0eeb0738 100644
--- a/src/tests_cfg/cake_expanded.rs
+++ b/src/tests_cfg/cake_expanded.rs
@@ -75,4 +75,20 @@ impl Related<super::filling::Entity> for Entity {
     }
 }
 
+#[derive(Debug)]
+pub struct CakeToFilling;
+
+impl Linked for CakeToFilling {
+    type FromEntity = Entity;
+
+    type ToEntity = super::filling::Entity;
+
+    fn link(&self) -> Vec<RelationDef> {
+        vec![
+            super::cake_filling::Relation::Cake.def().rev(),
+            super::cake_filling::Relation::Filling.def(),
+        ]
+    }
+}
+
 impl ActiveModelBehavior for ActiveModel {}
diff --git a/src/tests_cfg/entity_linked.rs b/src/tests_cfg/entity_linked.rs
deleted file mode 100644
index a4057a6c..00000000
--- a/src/tests_cfg/entity_linked.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-use crate::entity::prelude::*;
-
-#[derive(Debug)]
-pub struct CakeToFilling;
-
-impl Linked for CakeToFilling {
-    type FromEntity = super::cake::Entity;
-
-    type ToEntity = super::filling::Entity;
-
-    fn link(&self) -> Vec<RelationDef> {
-        vec![
-            super::cake_filling::Relation::Cake.def().rev(),
-            super::cake_filling::Relation::Filling.def(),
-        ]
-    }
-}
-
-#[derive(Debug)]
-pub struct CakeToFillingVendor;
-
-impl Linked for CakeToFillingVendor {
-    type FromEntity = super::cake::Entity;
-
-    type ToEntity = super::vendor::Entity;
-
-    fn link(&self) -> Vec<RelationDef> {
-        vec![
-            super::cake_filling::Relation::Cake.def().rev(),
-            super::cake_filling::Relation::Filling.def(),
-            super::filling::Relation::Vendor.def(),
-        ]
-    }
-}
diff --git a/src/tests_cfg/filling.rs b/src/tests_cfg/filling.rs
index 4de591c5..14f7a849 100644
--- a/src/tests_cfg/filling.rs
+++ b/src/tests_cfg/filling.rs
@@ -9,7 +9,6 @@ pub struct Entity;
 pub struct Model {
     pub id: i32,
     pub name: String,
-    pub vendor_id: Option<i32>,
     #[sea_orm(ignore)]
     pub ignored_attr: i32,
 }
@@ -19,7 +18,6 @@ pub struct Model {
 pub enum Column {
     Id,
     Name,
-    VendorId,
 }
 
 // Then, customize each column names here.
@@ -48,9 +46,7 @@ impl PrimaryKeyTrait for PrimaryKey {
 }
 
 #[derive(Copy, Clone, Debug, EnumIter)]
-pub enum Relation {
-    Vendor,
-}
+pub enum Relation {}
 
 impl ColumnTrait for Column {
     type EntityName = Entity;
@@ -59,19 +55,13 @@ impl ColumnTrait for Column {
         match self {
             Self::Id => ColumnType::Integer.def(),
             Self::Name => ColumnType::String(None).def(),
-            Self::VendorId => ColumnType::Integer.def().nullable(),
         }
     }
 }
 
 impl RelationTrait for Relation {
     fn def(&self) -> RelationDef {
-        match self {
-            Self::Vendor => Entity::belongs_to(super::vendor::Entity)
-                .from(Column::VendorId)
-                .to(super::vendor::Column::Id)
-                .into(),
-        }
+        panic!()
     }
 }
 
diff --git a/src/tests_cfg/mod.rs b/src/tests_cfg/mod.rs
index 6bc86aed..81d553ac 100644
--- a/src/tests_cfg/mod.rs
+++ b/src/tests_cfg/mod.rs
@@ -4,10 +4,8 @@ pub mod cake;
 pub mod cake_expanded;
 pub mod cake_filling;
 pub mod cake_filling_price;
-pub mod entity_linked;
 pub mod filling;
 pub mod fruit;
-pub mod vendor;
 
 pub use cake::Entity as Cake;
 pub use cake_expanded::Entity as CakeExpanded;
@@ -15,4 +13,3 @@ pub use cake_filling::Entity as CakeFilling;
 pub use cake_filling_price::Entity as CakeFillingPrice;
 pub use filling::Entity as Filling;
 pub use fruit::Entity as Fruit;
-pub use vendor::Entity as Vendor;
diff --git a/src/tests_cfg/vendor.rs b/src/tests_cfg/vendor.rs
deleted file mode 100644
index 12b6affb..00000000
--- a/src/tests_cfg/vendor.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-use crate as sea_orm;
-use crate::entity::prelude::*;
-
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
-#[sea_orm(table_name = "vendor")]
-pub struct Model {
-    #[sea_orm(primary_key)]
-    pub id: i32,
-    pub name: String,
-}
-
-#[derive(Copy, Clone, Debug, EnumIter)]
-pub enum Relation {}
-
-impl RelationTrait for Relation {
-    fn def(&self) -> RelationDef {
-        panic!()
-    }
-}
-
-impl Related<super::filling::Entity> for Entity {
-    fn to() -> RelationDef {
-        super::filling::Relation::Vendor.def()
-    }
-}
-
-impl ActiveModelBehavior for ActiveModel {}
diff --git a/tests/relational_tests.rs b/tests/relational_tests.rs
index e3138bb3..caef9c3c 100644
--- a/tests/relational_tests.rs
+++ b/tests/relational_tests.rs
@@ -708,26 +708,6 @@ pub async fn linked() -> Result<(), DbErr> {
         ]
     );
 
-    let baker_bob = Baker::find()
-        .filter(baker::Column::Id.eq(1))
-        .one(&ctx.db)
-        .await?
-        .unwrap();
-
-    let baker_bob_customers = baker_bob
-        .find_linked(baker::BakedForCustomer)
-        .all(&ctx.db)
-        .await?;
-
-    assert_eq!(
-        baker_bob_customers,
-        vec![customer::Model {
-            id: 2,
-            name: "Kara".to_owned(),
-            notes: Some("Loves all cakes".to_owned()),
-        }]
-    );
-
     ctx.delete().await;
 
     Ok(())