Select filters

This commit is contained in:
Chris Tsang 2021-05-08 16:22:28 +08:00
parent 3f5b0080da
commit 8e4271da79
6 changed files with 172 additions and 16 deletions

View File

@ -1,6 +1,6 @@
use super::{ColumnTrait, Identity, ModelTrait, RelationTrait}; use super::{ColumnTrait, Identity, ModelTrait, RelationTrait};
use crate::Select; use crate::Select;
use sea_query::Iden; use sea_query::{Expr, Iden, Value};
use std::fmt::Debug; use std::fmt::Debug;
pub use strum::IntoEnumIterator as Iterable; pub use strum::IntoEnumIterator as Iterable;
@ -20,4 +20,20 @@ pub trait EntityTrait: Iden + Default + Debug {
fn find<'s>() -> Select<'s, Self> { fn find<'s>() -> Select<'s, Self> {
Select::new(Self::default()) Select::new(Self::default())
} }
fn find_one<'s>() -> Select<'s, Self> {
let mut select = Self::find();
select.query().limit(1);
select
}
fn find_one_by<'s, V>(v: V) -> Select<'s, Self>
where
V: Into<Value>,
{
let select = Self::find_one();
let select =
select.filter(Expr::tbl(Self::default(), Self::primary_key().into_iden()).eq(v));
select
}
} }

View File

@ -1,6 +1,69 @@
use crate::EntityTrait;
pub use sea_query::ColumnType; pub use sea_query::ColumnType;
use sea_query::Iden; use sea_query::{Expr, Iden, SimpleExpr, Value};
use std::rc::Rc;
pub trait ColumnTrait: Iden { macro_rules! bind_oper {
fn col_type(&self) -> ColumnType; ( $op: ident ) => {
fn $op<V>(&'static self, v: V) -> SimpleExpr
where
V: Into<Value>,
{
Expr::tbl(self.entity_iden(), *self).$op(v)
}
};
}
pub trait ColumnTrait: Iden + Copy {
type Entity: EntityTrait;
fn col_type(&self) -> ColumnType;
fn entity_iden(&'static self) -> Rc<dyn Iden> {
Rc::new(Self::Entity::default()) as Rc<dyn Iden>
}
bind_oper!(eq);
bind_oper!(ne);
bind_oper!(gt);
bind_oper!(gte);
bind_oper!(lt);
bind_oper!(lte);
fn between<V>(&'static self, a: V, b: V) -> SimpleExpr
where
V: Into<Value>,
{
Expr::tbl(self.entity_iden(), *self).between(a, b)
}
fn not_between<V>(&'static self, a: V, b: V) -> SimpleExpr
where
V: Into<Value>,
{
Expr::tbl(self.entity_iden(), *self).not_between(a, b)
}
fn like(&'static self, s: &str) -> SimpleExpr {
Expr::tbl(self.entity_iden(), *self).like(s)
}
fn not_like(&'static self, s: &str) -> SimpleExpr {
Expr::tbl(self.entity_iden(), *self).not_like(s)
}
fn starts_with(&'static self, s: &str) -> SimpleExpr {
let pattern = format!("{}%", s);
Expr::tbl(self.entity_iden(), *self).like(&pattern)
}
fn ends_with(&'static self, s: &str) -> SimpleExpr {
let pattern = format!("%{}", s);
Expr::tbl(self.entity_iden(), *self).like(&pattern)
}
fn contains(&'static self, s: &str) -> SimpleExpr {
let pattern = format!("%{}%", s);
Expr::tbl(self.entity_iden(), *self).like(&pattern)
}
} }

View File

@ -12,6 +12,14 @@ pub trait IntoIdentity {
fn into_identity(self) -> Identity; fn into_identity(self) -> Identity;
} }
impl Identity {
pub fn into_iden(self) -> Rc<dyn Iden> {
match self {
Self::Unary(iden) => iden,
}
}
}
impl<T> IntoIdentity for T impl<T> IntoIdentity for T
where where
T: IntoIden, T: IntoIden,

View File

@ -12,5 +12,6 @@ pub use driver::*;
pub use entity::*; pub use entity::*;
pub use query::*; pub use query::*;
pub use sea_query;
pub use sea_query::Iden; pub use sea_query::Iden;
pub use strum::EnumIter; pub use strum::EnumIter;

View File

@ -2,7 +2,7 @@ use crate::{EntityTrait, Identity, Iterable, RelationDef, Statement};
use core::fmt::Debug; use core::fmt::Debug;
use core::marker::PhantomData; use core::marker::PhantomData;
pub use sea_query::JoinType; pub use sea_query::JoinType;
use sea_query::{Expr, Iden, IntoIden, QueryBuilder, SelectStatement}; use sea_query::{Expr, Iden, IntoIden, QueryBuilder, SelectStatement, SimpleExpr};
use std::rc::Rc; use std::rc::Rc;
#[derive(Debug)] #[derive(Debug)]
@ -54,6 +54,11 @@ where
self self
} }
pub fn filter(mut self, expr: SimpleExpr) -> Self {
self.select.and_where(expr);
self
}
pub fn left_join(self, relation: RelationDef) -> Self { pub fn left_join(self, relation: RelationDef) -> Self {
self.prepare_join(JoinType::LeftJoin, relation) self.prepare_join(JoinType::LeftJoin, relation)
} }
@ -89,16 +94,77 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::tests_cfg::cake; use crate::tests_cfg::cake;
use crate::EntityTrait; use crate::{ColumnTrait, EntityTrait};
use sea_query::MySqlQueryBuilder; use sea_query::MysqlQueryBuilder;
#[test] #[test]
fn test_1() { fn test_1() {
assert_eq!( assert_eq!(
cake::Entity::find() cake::Entity::find().build(MysqlQueryBuilder).to_string(),
.build(MySqlQueryBuilder::default())
.to_string(),
"SELECT `cake`.`id`, `cake`.`name` FROM `cake`" "SELECT `cake`.`id`, `cake`.`name` FROM `cake`"
); );
} }
#[test]
fn test_2() {
assert_eq!(
cake::Entity::find()
.filter(cake::Column::Id.eq(5))
.build(MysqlQueryBuilder)
.to_string(),
"SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` = 5"
);
}
#[test]
fn test_3() {
assert_eq!(
cake::Entity::find()
.filter(cake::Column::Name.like("cheese"))
.build(MysqlQueryBuilder)
.to_string(),
"SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE 'cheese'"
);
assert_eq!(
cake::Entity::find()
.filter(cake::Column::Name.starts_with("cheese"))
.build(MysqlQueryBuilder)
.to_string(),
"SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE 'cheese%'"
);
assert_eq!(
cake::Entity::find()
.filter(cake::Column::Name.ends_with("cheese"))
.build(MysqlQueryBuilder)
.to_string(),
"SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE '%cheese'"
);
assert_eq!(
cake::Entity::find()
.filter(cake::Column::Name.contains("cheese"))
.build(MysqlQueryBuilder)
.to_string(),
"SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE '%cheese%'"
);
}
#[test]
fn test_4() {
assert_eq!(
cake::Entity::find_one()
.build(MysqlQueryBuilder)
.to_string(),
"SELECT `cake`.`id`, `cake`.`name` FROM `cake` LIMIT 1"
);
}
#[test]
fn test_5() {
assert_eq!(
cake::Entity::find_one_by(11)
.build(MysqlQueryBuilder)
.to_string(),
"SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` = 11 LIMIT 1"
);
}
} }

View File

@ -1,9 +1,9 @@
use crate::{ use crate::{
ColumnTrait, ColumnType, EntityTrait, Identity, IntoIdentity, ModelTrait, QueryResult, RelationDef, ColumnTrait, ColumnType, EntityTrait, EnumIter, Iden, Identity, IntoIdentity, ModelTrait,
RelationTrait, TypeErr, EnumIter, Iden QueryResult, RelationDef, RelationTrait, TypeErr,
}; };
#[derive(Iden, Default, Debug)] #[derive(Default, Debug, Iden)]
#[iden = "cake"] #[iden = "cake"]
pub struct Entity; pub struct Entity;
@ -13,13 +13,13 @@ pub struct Model {
pub name: String, pub name: String,
} }
#[derive(Iden, EnumIter)] #[derive(Copy, Clone, Iden, EnumIter)]
pub enum Column { pub enum Column {
Id, Id,
Name, Name,
} }
#[derive(EnumIter)] #[derive(Copy, Clone, EnumIter)]
pub enum Relation {} pub enum Relation {}
impl EntityTrait for Entity { impl EntityTrait for Entity {
@ -44,6 +44,8 @@ impl ModelTrait for Model {
} }
impl ColumnTrait for Column { impl ColumnTrait for Column {
type Entity = Entity;
fn col_type(&self) -> ColumnType { fn col_type(&self) -> ColumnType {
match self { match self {
Self::Id => ColumnType::Integer(None), Self::Id => ColumnType::Integer(None),