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 crate::Select;
use sea_query::Iden;
use sea_query::{Expr, Iden, Value};
use std::fmt::Debug;
pub use strum::IntoEnumIterator as Iterable;
@ -20,4 +20,20 @@ pub trait EntityTrait: Iden + Default + Debug {
fn find<'s>() -> Select<'s, Self> {
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;
use sea_query::Iden;
use sea_query::{Expr, Iden, SimpleExpr, Value};
use std::rc::Rc;
pub trait ColumnTrait: Iden {
fn col_type(&self) -> ColumnType;
macro_rules! bind_oper {
( $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;
}
impl Identity {
pub fn into_iden(self) -> Rc<dyn Iden> {
match self {
Self::Unary(iden) => iden,
}
}
}
impl<T> IntoIdentity for T
where
T: IntoIden,

View File

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

View File

@ -2,7 +2,7 @@ use crate::{EntityTrait, Identity, Iterable, RelationDef, Statement};
use core::fmt::Debug;
use core::marker::PhantomData;
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;
#[derive(Debug)]
@ -54,6 +54,11 @@ where
self
}
pub fn filter(mut self, expr: SimpleExpr) -> Self {
self.select.and_where(expr);
self
}
pub fn left_join(self, relation: RelationDef) -> Self {
self.prepare_join(JoinType::LeftJoin, relation)
}
@ -89,16 +94,77 @@ where
#[cfg(test)]
mod tests {
use crate::tests_cfg::cake;
use crate::EntityTrait;
use sea_query::MySqlQueryBuilder;
use crate::{ColumnTrait, EntityTrait};
use sea_query::MysqlQueryBuilder;
#[test]
fn test_1() {
assert_eq!(
cake::Entity::find()
.build(MySqlQueryBuilder::default())
.to_string(),
cake::Entity::find().build(MysqlQueryBuilder).to_string(),
"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::{
ColumnTrait, ColumnType, EntityTrait, Identity, IntoIdentity, ModelTrait, QueryResult, RelationDef,
RelationTrait, TypeErr, EnumIter, Iden
ColumnTrait, ColumnType, EntityTrait, EnumIter, Iden, Identity, IntoIdentity, ModelTrait,
QueryResult, RelationDef, RelationTrait, TypeErr,
};
#[derive(Iden, Default, Debug)]
#[derive(Default, Debug, Iden)]
#[iden = "cake"]
pub struct Entity;
@ -13,13 +13,13 @@ pub struct Model {
pub name: String,
}
#[derive(Iden, EnumIter)]
#[derive(Copy, Clone, Iden, EnumIter)]
pub enum Column {
Id,
Name,
}
#[derive(EnumIter)]
#[derive(Copy, Clone, EnumIter)]
pub enum Relation {}
impl EntityTrait for Entity {
@ -44,6 +44,8 @@ impl ModelTrait for Model {
}
impl ColumnTrait for Column {
type Entity = Entity;
fn col_type(&self) -> ColumnType {
match self {
Self::Id => ColumnType::Integer(None),