diff --git a/examples/sqlx-mysql/Cargo.toml b/examples/sqlx-mysql/Cargo.toml index b2e70b7a..ee0478bb 100644 --- a/examples/sqlx-mysql/Cargo.toml +++ b/examples/sqlx-mysql/Cargo.toml @@ -6,5 +6,6 @@ publish = false [dependencies] async-std = { version = "^1.9", features = [ "attributes" ] } -sea-orm = { path = "../../", features = [ "sqlx-mysql", "runtime-async-std-native-tls" ] } -# sea-query = { path = "../../../sea-query" } \ No newline at end of file +sea-orm = { path = "../../", features = [ "sqlx-mysql", "runtime-async-std-native-tls", "debug-print" ] } +sea-query = { path = "../../../sea-query" } +strum = { version = "^0.20", features = [ "derive" ] } \ No newline at end of file diff --git a/examples/sqlx-mysql/import.sh b/examples/sqlx-mysql/import.sh new file mode 100644 index 00000000..dfc5d218 --- /dev/null +++ b/examples/sqlx-mysql/import.sh @@ -0,0 +1,4 @@ +cp ../../src/tests_cfg/cake.rs src/example_cake.rs +cp ../../src/tests_cfg/fruit.rs src/example_fruit.rs + +sed -i 's/^use crate::/use sea_orm::/g' src/*.rs \ No newline at end of file diff --git a/examples/sqlx-mysql/src/example_cake.rs b/examples/sqlx-mysql/src/example_cake.rs new file mode 100644 index 00000000..9438ac22 --- /dev/null +++ b/examples/sqlx-mysql/src/example_cake.rs @@ -0,0 +1,122 @@ +use sea_orm::{ + ColumnTrait, ColumnType, EntityTrait, EnumIter, Iden, IdenStatic, + ModelTrait, QueryResult, Related, RelationDef, RelationTrait, Select, TypeErr, Value, PrimaryKeyTrait +}; + +#[derive(Default, Debug, Iden)] +#[iden = "cake"] +pub struct Entity; + +#[derive(Clone, Debug, Default, PartialEq)] +pub struct Model { + pub id: i32, + pub name: String, +} + +#[derive(Copy, Clone, Debug, Iden, EnumIter)] +pub enum Column { + Id, + Name, +} + +#[derive(Copy, Clone, Debug, Iden, EnumIter)] +pub enum PrimaryKey { + Id, +} + +#[derive(Copy, Clone, Debug, EnumIter)] +pub enum Relation { + Fruit, +} + +impl EntityTrait for Entity { + type Model = Model; + + type Column = Column; + + type PrimaryKey = PrimaryKey; + + type Relation = Relation; +} + +// TODO: implement with derive macro +impl ModelTrait for Model { + type Column = Column; + + fn get(&self, c: Self::Column) -> Value { + match c { + Column::Id => self.id.clone().into(), + Column::Name => self.name.clone().into(), + } + } + + fn set(&mut self, c: Self::Column, v: Value) { + match c { + Column::Id => self.id = v.unwrap(), + Column::Name => self.name = v.unwrap(), + } + } + + fn from_query_result(row: QueryResult) -> Result { + Ok(Self { + id: row.try_get(Column::Id.as_str())?, + name: row.try_get(Column::Name.as_str())?, + }) + } +} + +// TODO: implement with derive macro +impl IdenStatic for Column { + fn as_str(&self) -> &str { + match self { + Self::Id => "id", + Self::Name => "name", + } + } +} + +impl ColumnTrait for Column { + type Entity = Entity; + + fn def(&self) -> ColumnType { + match self { + Self::Id => ColumnType::Integer(None), + Self::Name => ColumnType::String(None), + } + } +} + +// TODO: implement with derive macro +impl IdenStatic for PrimaryKey { + fn as_str(&self) -> &str { + match self { + Self::Id => "id", + } + } +} + +// TODO: implement with derive macro +impl PrimaryKeyTrait for PrimaryKey {} + +impl RelationTrait for Relation { + fn def(&self) -> RelationDef { + match self { + Self::Fruit => Entity::has_many(super::fruit::Entity) + .from(Column::Id) + .to(super::fruit::Column::CakeId) + .into(), + } + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Fruit.def() + } +} + +impl Model { + pub fn find_fruit(&self) -> Select { + Entity::find_related().belongs_to::(self) + } +} diff --git a/examples/sqlx-mysql/src/example_fruit.rs b/examples/sqlx-mysql/src/example_fruit.rs new file mode 100644 index 00000000..46a5bb9a --- /dev/null +++ b/examples/sqlx-mysql/src/example_fruit.rs @@ -0,0 +1,110 @@ +use sea_orm::{ + ColumnTrait, ColumnType, EntityTrait, EnumIter, Iden, IdenStatic, + ModelTrait, QueryResult, RelationDef, RelationTrait, TypeErr, Value, PrimaryKeyTrait +}; + +#[derive(Default, Debug, Iden)] +#[iden = "fruit"] +pub struct Entity; + +#[derive(Clone, Debug, Default, PartialEq)] +pub struct Model { + pub id: i32, + pub name: String, + pub cake_id: Option, +} + +#[derive(Copy, Clone, Debug, Iden, EnumIter)] +pub enum Column { + Id, + Name, + CakeId, +} + +#[derive(Copy, Clone, Debug, Iden, EnumIter)] +pub enum PrimaryKey { + Id, +} + +#[derive(Copy, Clone, Debug, EnumIter)] +pub enum Relation {} + +impl EntityTrait for Entity { + type Model = Model; + + type Column = Column; + + type PrimaryKey = PrimaryKey; + + type Relation = Relation; +} + +// TODO: implement with derive macro +impl ModelTrait for Model { + type Column = Column; + + fn get(&self, c: Self::Column) -> Value { + match c { + Column::Id => self.id.clone().into(), + Column::Name => self.name.clone().into(), + Column::CakeId => self.cake_id.clone().into(), + } + } + + fn set(&mut self, c: Self::Column, v: Value) { + match c { + Column::Id => self.id = v.unwrap(), + Column::Name => self.name = v.unwrap(), + Column::CakeId => self.cake_id = v.unwrap(), + } + } + + fn from_query_result(row: QueryResult) -> Result { + Ok(Self { + id: row.try_get(Column::Id.as_str())?, + name: row.try_get(Column::Name.as_str())?, + cake_id: row.try_get(Column::CakeId.as_str())?, + }) + } +} + +// TODO: implement with derive macro +impl IdenStatic for Column { + fn as_str(&self) -> &str { + match self { + Self::Id => "id", + Self::Name => "name", + Self::CakeId => "cake_id", + } + } +} + +impl ColumnTrait for Column { + type Entity = Entity; + + fn def(&self) -> ColumnType { + match self { + Self::Id => ColumnType::Integer(None), + Self::Name => ColumnType::String(None), + Self::CakeId => ColumnType::Integer(None), + } + } +} + +// TODO: implement with derive macro +impl IdenStatic for PrimaryKey { + fn as_str(&self) -> &str { + match self { + Self::Id => "id", + } + } +} + +// TODO: implement with derive macro +impl PrimaryKeyTrait for PrimaryKey {} + +impl RelationTrait for Relation { + fn def(&self) -> RelationDef { + panic!() + } +} diff --git a/examples/sqlx-mysql/src/main.rs b/examples/sqlx-mysql/src/main.rs index 164923e2..72048897 100644 --- a/examples/sqlx-mysql/src/main.rs +++ b/examples/sqlx-mysql/src/main.rs @@ -1,4 +1,10 @@ -use sea_orm::{tests_cfg::*, Database, EntityTrait}; +use sea_orm::{Database, EntityTrait}; + +mod example_cake; +mod example_fruit; + +use example_cake as cake; +use example_fruit as fruit; #[async_std::main] async fn main() { @@ -10,20 +16,20 @@ async fn main() { println!(); println!("find all"); - println!(); let cakes = cake::Entity::find().all(&db).await.unwrap(); + println!(); for cc in cakes.iter() { println!("{:?}", cc); println!(); } println!("find one by primary key"); - println!(); let cheese = cake::Entity::find_one(&db, 1).await.unwrap(); + println!(); println!("{:?}", cheese); println!(); } diff --git a/src/entity/base.rs b/src/entity/base.rs index 0c40d67d..75c1390c 100644 --- a/src/entity/base.rs +++ b/src/entity/base.rs @@ -1,6 +1,6 @@ use crate::{ - ColumnTrait, Connection, Database, Identity, ModelTrait, QueryErr, RelationBuilder, - RelationTrait, RelationType, Select, + ColumnTrait, Connection, Database, ModelTrait, QueryErr, RelationBuilder, + RelationTrait, RelationType, Select, PrimaryKeyTrait }; use async_trait::async_trait; use sea_query::{Expr, Iden, IntoIden, Value}; @@ -15,7 +15,7 @@ pub trait EntityTrait: Iden + Default + Debug + 'static { type Relation: RelationTrait + Iterable; - fn primary_key() -> Identity; + type PrimaryKey: PrimaryKeyTrait + Iterable; fn auto_increment() -> bool { true @@ -63,10 +63,11 @@ pub trait EntityTrait: Iden + Default + Debug + 'static { let builder = db.get_query_builder_backend(); let stmt = { let mut select = Self::find(); - match Self::primary_key() { - Identity::Unary(iden) => { - select = select.filter(Expr::tbl(Self::default(), iden).eq(v)); - } + if let Some(key) = Self::PrimaryKey::iter().next() { + // TODO: supporting composite primary key + select = select.filter(Expr::tbl(Self::default(), key).eq(v)); + } else { + panic!("undefined primary key"); } select.build(builder) }; diff --git a/src/entity/column.rs b/src/entity/column.rs index bf4d1c64..1e453489 100644 --- a/src/entity/column.rs +++ b/src/entity/column.rs @@ -10,7 +10,7 @@ macro_rules! bind_oper { where V: Into, { - Expr::tbl(self.entity_iden(), *self).$op(v) + Expr::tbl(self.as_iden(), *self).$op(v) } }; } @@ -28,7 +28,7 @@ pub trait ColumnTrait: IdenStatic { fn def(&self) -> ColumnType; - fn entity_iden(&self) -> Rc { + fn as_iden(&self) -> Rc { Rc::new(Self::Entity::default()) as Rc } @@ -43,14 +43,14 @@ pub trait ColumnTrait: IdenStatic { where V: Into, { - Expr::tbl(self.entity_iden(), *self).between(a, b) + Expr::tbl(self.as_iden(), *self).between(a, b) } fn not_between(&self, a: V, b: V) -> SimpleExpr where V: Into, { - Expr::tbl(self.entity_iden(), *self).not_between(a, b) + Expr::tbl(self.as_iden(), *self).not_between(a, b) } /// ``` @@ -65,7 +65,7 @@ pub trait ColumnTrait: IdenStatic { /// ); /// ``` fn like(&self, s: &str) -> SimpleExpr { - Expr::tbl(self.entity_iden(), *self).like(s) + Expr::tbl(self.as_iden(), *self).like(s) } /// ``` @@ -80,7 +80,7 @@ pub trait ColumnTrait: IdenStatic { /// ); /// ``` fn not_like(&self, s: &str) -> SimpleExpr { - Expr::tbl(self.entity_iden(), *self).not_like(s) + Expr::tbl(self.as_iden(), *self).not_like(s) } /// ``` @@ -96,7 +96,7 @@ pub trait ColumnTrait: IdenStatic { /// ``` fn starts_with(&self, s: &str) -> SimpleExpr { let pattern = format!("{}%", s); - Expr::tbl(self.entity_iden(), *self).like(&pattern) + Expr::tbl(self.as_iden(), *self).like(&pattern) } /// ``` @@ -112,7 +112,7 @@ pub trait ColumnTrait: IdenStatic { /// ``` fn ends_with(&self, s: &str) -> SimpleExpr { let pattern = format!("%{}", s); - Expr::tbl(self.entity_iden(), *self).like(&pattern) + Expr::tbl(self.as_iden(), *self).like(&pattern) } /// ``` @@ -128,6 +128,6 @@ pub trait ColumnTrait: IdenStatic { /// ``` fn contains(&self, s: &str) -> SimpleExpr { let pattern = format!("%{}%", s); - Expr::tbl(self.entity_iden(), *self).like(&pattern) + Expr::tbl(self.as_iden(), *self).like(&pattern) } } diff --git a/src/entity/mod.rs b/src/entity/mod.rs index 546663c1..ff9ab047 100644 --- a/src/entity/mod.rs +++ b/src/entity/mod.rs @@ -2,10 +2,12 @@ mod base; mod column; mod identity; mod model; +mod primary_key; mod relation; pub use base::*; pub use column::*; pub use identity::*; pub use model::*; +pub use primary_key::*; pub use relation::*; diff --git a/src/entity/primary_key.rs b/src/entity/primary_key.rs new file mode 100644 index 00000000..357b1314 --- /dev/null +++ b/src/entity/primary_key.rs @@ -0,0 +1,3 @@ +use super::IdenStatic; + +pub trait PrimaryKeyTrait: IdenStatic {} \ No newline at end of file diff --git a/src/tests_cfg/cake.rs b/src/tests_cfg/cake.rs index ad79779b..9951a857 100644 --- a/src/tests_cfg/cake.rs +++ b/src/tests_cfg/cake.rs @@ -1,6 +1,6 @@ use crate::{ - ColumnTrait, ColumnType, EntityTrait, EnumIter, Iden, IdenStatic, Identity, IntoIdentity, - ModelTrait, QueryResult, Related, RelationDef, RelationTrait, Select, TypeErr, Value, + ColumnTrait, ColumnType, EntityTrait, EnumIter, Iden, IdenStatic, + ModelTrait, QueryResult, Related, RelationDef, RelationTrait, Select, TypeErr, Value, PrimaryKeyTrait }; #[derive(Default, Debug, Iden)] @@ -19,6 +19,11 @@ pub enum Column { Name, } +#[derive(Copy, Clone, Debug, Iden, EnumIter)] +pub enum PrimaryKey { + Id, +} + #[derive(Copy, Clone, Debug, EnumIter)] pub enum Relation { Fruit, @@ -29,11 +34,9 @@ impl EntityTrait for Entity { type Column = Column; - type Relation = Relation; + type PrimaryKey = PrimaryKey; - fn primary_key() -> Identity { - Column::Id.into_identity() - } + type Relation = Relation; } // TODO: implement with derive macro @@ -66,8 +69,8 @@ impl ModelTrait for Model { impl IdenStatic for Column { fn as_str(&self) -> &str { match self { - Column::Id => "id", - Column::Name => "name", + Self::Id => "id", + Self::Name => "name", } } } @@ -83,6 +86,18 @@ impl ColumnTrait for Column { } } +// TODO: implement with derive macro +impl IdenStatic for PrimaryKey { + fn as_str(&self) -> &str { + match self { + Self::Id => "id", + } + } +} + +// TODO: implement with derive macro +impl PrimaryKeyTrait for PrimaryKey {} + impl RelationTrait for Relation { fn def(&self) -> RelationDef { match self { diff --git a/src/tests_cfg/fruit.rs b/src/tests_cfg/fruit.rs index 8e595394..93c9e4a3 100644 --- a/src/tests_cfg/fruit.rs +++ b/src/tests_cfg/fruit.rs @@ -1,6 +1,6 @@ use crate::{ - ColumnTrait, ColumnType, EntityTrait, EnumIter, Iden, IdenStatic, Identity, IntoIdentity, - ModelTrait, QueryResult, RelationDef, RelationTrait, TypeErr, Value, + ColumnTrait, ColumnType, EntityTrait, EnumIter, Iden, IdenStatic, + ModelTrait, QueryResult, RelationDef, RelationTrait, TypeErr, Value, PrimaryKeyTrait }; #[derive(Default, Debug, Iden)] @@ -21,6 +21,11 @@ pub enum Column { CakeId, } +#[derive(Copy, Clone, Debug, Iden, EnumIter)] +pub enum PrimaryKey { + Id, +} + #[derive(Copy, Clone, Debug, EnumIter)] pub enum Relation {} @@ -29,11 +34,9 @@ impl EntityTrait for Entity { type Column = Column; - type Relation = Relation; + type PrimaryKey = PrimaryKey; - fn primary_key() -> Identity { - Column::Id.into_identity() - } + type Relation = Relation; } // TODO: implement with derive macro @@ -69,9 +72,9 @@ impl ModelTrait for Model { impl IdenStatic for Column { fn as_str(&self) -> &str { match self { - Column::Id => "id", - Column::Name => "name", - Column::CakeId => "cake_id", + Self::Id => "id", + Self::Name => "name", + Self::CakeId => "cake_id", } } } @@ -88,6 +91,18 @@ impl ColumnTrait for Column { } } +// TODO: implement with derive macro +impl IdenStatic for PrimaryKey { + fn as_str(&self) -> &str { + match self { + Self::Id => "id", + } + } +} + +// TODO: implement with derive macro +impl PrimaryKeyTrait for PrimaryKey {} + impl RelationTrait for Relation { fn def(&self) -> RelationDef { panic!()