Redesign primary key

This commit is contained in:
Chris Tsang 2021-05-09 17:36:55 +08:00
parent 3a59d896e4
commit 58f4059c3e
11 changed files with 317 additions and 38 deletions

View File

@ -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" }
sea-orm = { path = "../../", features = [ "sqlx-mysql", "runtime-async-std-native-tls", "debug-print" ] }
sea-query = { path = "../../../sea-query" }
strum = { version = "^0.20", features = [ "derive" ] }

View File

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

View File

@ -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<Self, TypeErr> {
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<super::fruit::Entity> for Entity {
fn to() -> RelationDef {
Relation::Fruit.def()
}
}
impl Model {
pub fn find_fruit(&self) -> Select<super::fruit::Entity> {
Entity::find_related().belongs_to::<Entity>(self)
}
}

View File

@ -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<i32>,
}
#[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<Self, TypeErr> {
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!()
}
}

View File

@ -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!();
}

View File

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

View File

@ -10,7 +10,7 @@ macro_rules! bind_oper {
where
V: Into<Value>,
{
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<dyn Iden> {
fn as_iden(&self) -> Rc<dyn Iden> {
Rc::new(Self::Entity::default()) as Rc<dyn Iden>
}
@ -43,14 +43,14 @@ pub trait ColumnTrait: IdenStatic {
where
V: Into<Value>,
{
Expr::tbl(self.entity_iden(), *self).between(a, b)
Expr::tbl(self.as_iden(), *self).between(a, b)
}
fn not_between<V>(&self, a: V, b: V) -> SimpleExpr
where
V: Into<Value>,
{
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)
}
}

View File

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

View File

@ -0,0 +1,3 @@
use super::IdenStatic;
pub trait PrimaryKeyTrait: IdenStatic {}

View File

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

View File

@ -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!()