Merge branch 'master' into serialize-query-result
This commit is contained in:
commit
73ed4b6f81
10
README.md
10
README.md
@ -37,7 +37,7 @@ Use mock connections to write unit tests for your logic.
|
||||
|
||||
Quickly build search models that help you filter, sort and paginate data in APIs.
|
||||
|
||||
## Design goals
|
||||
## Design Goals
|
||||
|
||||
1. Intuitive and ergonomic
|
||||
|
||||
@ -49,4 +49,10 @@ Balance between compile-time checking and compilation speed.
|
||||
|
||||
3. Avoid 'symbol soup'
|
||||
|
||||
Avoid macros with DSL, use derive macros where appropriate. Be friendly with IDE tools.
|
||||
Avoid macros with DSL, use derive macros where appropriate. Be friendly with IDE tools.
|
||||
|
||||
## Test Time
|
||||
|
||||
After some bitterness we realized it is not possible to capture everything compile time. But we don't
|
||||
want to encounter problems at run time either. The solution is to perform checking at 'test time' to
|
||||
uncover problems. These checks will be removed at production so there will be no run time penalty.
|
51
src/connector/executor.rs
Normal file
51
src/connector/executor.rs
Normal file
@ -0,0 +1,51 @@
|
||||
use sqlx::mysql::MySqlQueryResult;
|
||||
use std::{error::Error, fmt};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ExecResult {
|
||||
pub(crate) result: ExecResultHolder,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum ExecResultHolder {
|
||||
SqlxMySql(MySqlQueryResult),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ExecErr;
|
||||
|
||||
// ExecResult //
|
||||
|
||||
impl ExecResult {
|
||||
pub fn last_insert_id(&self) -> u64 {
|
||||
match &self.result {
|
||||
ExecResultHolder::SqlxMySql(result) => {
|
||||
result.last_insert_id()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rows_affected(&self) -> u64 {
|
||||
match &self.result {
|
||||
ExecResultHolder::SqlxMySql(result) => {
|
||||
result.rows_affected()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ExecErr //
|
||||
|
||||
impl Error for ExecErr {}
|
||||
|
||||
impl fmt::Display for ExecErr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<sqlx::Error> for ExecErr {
|
||||
fn from(_: sqlx::Error) -> ExecErr {
|
||||
ExecErr
|
||||
}
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
mod executor;
|
||||
mod select;
|
||||
|
||||
#[cfg(feature = "serialize-query-result")]
|
||||
mod select_json;
|
||||
|
||||
pub use executor::*;
|
||||
pub use select::*;
|
||||
|
||||
#[cfg(feature = "serialize-query-result")]
|
||||
pub use select_json::*;
|
||||
|
||||
@ -21,6 +21,8 @@ pub trait Connector {
|
||||
|
||||
#[async_trait]
|
||||
pub trait Connection {
|
||||
async fn execute(&self, stmt: Statement) -> Result<ExecResult, ExecErr>;
|
||||
|
||||
async fn query_one(&self, stmt: Statement) -> Result<QueryResult, QueryErr>;
|
||||
|
||||
async fn query_all(&self, stmt: Statement) -> Result<Vec<QueryResult>, QueryErr>;
|
||||
|
@ -3,25 +3,32 @@ use std::fmt;
|
||||
|
||||
pub struct Statement {
|
||||
pub sql: String,
|
||||
pub values: Values,
|
||||
pub values: Option<Values>,
|
||||
}
|
||||
|
||||
impl From<(String, Values)> for Statement {
|
||||
fn from(stmt: (String, Values)) -> Statement {
|
||||
Statement {
|
||||
sql: stmt.0,
|
||||
values: stmt.1,
|
||||
values: Some(stmt.1),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Statement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let string = inject_parameters(
|
||||
&self.sql,
|
||||
self.values.0.clone(),
|
||||
&MySqlQueryBuilder::default(),
|
||||
);
|
||||
write!(f, "{}", &string)
|
||||
match &self.values {
|
||||
Some(values) => {
|
||||
let string = inject_parameters(
|
||||
&self.sql,
|
||||
values.0.clone(),
|
||||
&MySqlQueryBuilder::default(),
|
||||
);
|
||||
write!(f, "{}", &string)
|
||||
}
|
||||
None => {
|
||||
write!(f, "{}", &self.sql)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use async_trait::async_trait;
|
||||
use sqlx::{mysql::MySqlRow, MySqlPool};
|
||||
use sqlx::{mysql::{MySqlRow, MySqlArguments, MySqlQueryResult}, MySql, MySqlPool};
|
||||
|
||||
sea_query::sea_query_driver_mysql!();
|
||||
use sea_query_driver_mysql::bind_query;
|
||||
@ -31,10 +31,22 @@ impl Connector for SqlxMySqlConnector {
|
||||
|
||||
#[async_trait]
|
||||
impl Connection for &SqlxMySqlPoolConnection {
|
||||
async fn execute(&self, stmt: Statement) -> Result<ExecResult, ExecErr> {
|
||||
debug_print!("{}", stmt);
|
||||
|
||||
let query = sqlx_query(&stmt);
|
||||
if let Ok(conn) = &mut self.pool.acquire().await {
|
||||
if let Ok(res) = query.execute(conn).await {
|
||||
return Ok(res.into());
|
||||
}
|
||||
}
|
||||
Err(ExecErr)
|
||||
}
|
||||
|
||||
async fn query_one(&self, stmt: Statement) -> Result<QueryResult, QueryErr> {
|
||||
debug_print!("{}", stmt);
|
||||
|
||||
let query = bind_query(sqlx::query(&stmt.sql), &stmt.values);
|
||||
let query = sqlx_query(&stmt);
|
||||
if let Ok(conn) = &mut self.pool.acquire().await {
|
||||
if let Ok(row) = query.fetch_one(conn).await {
|
||||
return Ok(row.into());
|
||||
@ -46,7 +58,7 @@ impl Connection for &SqlxMySqlPoolConnection {
|
||||
async fn query_all(&self, stmt: Statement) -> Result<Vec<QueryResult>, QueryErr> {
|
||||
debug_print!("{}", stmt);
|
||||
|
||||
let query = bind_query(sqlx::query(&stmt.sql), &stmt.values);
|
||||
let query = sqlx_query(&stmt);
|
||||
if let Ok(conn) = &mut self.pool.acquire().await {
|
||||
if let Ok(rows) = query.fetch_all(conn).await {
|
||||
return Ok(rows.into_iter().map(|r| r.into()).collect());
|
||||
@ -63,3 +75,19 @@ impl From<MySqlRow> for QueryResult {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MySqlQueryResult> for ExecResult {
|
||||
fn from(result: MySqlQueryResult) -> ExecResult {
|
||||
ExecResult {
|
||||
result: ExecResultHolder::SqlxMySql(result),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sqlx_query(stmt: &Statement) -> sqlx::query::Query<'_, MySql, MySqlArguments> {
|
||||
let mut query = sqlx::query(&stmt.sql);
|
||||
if let Some(values) = &stmt.values {
|
||||
query = bind_query(query, values);
|
||||
}
|
||||
query
|
||||
}
|
@ -70,7 +70,7 @@ pub trait EntityTrait: EntityName {
|
||||
/// .to_string(),
|
||||
/// [
|
||||
/// r#"SELECT "cake_filling"."cake_id", "cake_filling"."filling_id" FROM "cake_filling""#,
|
||||
/// r#"WHERE "cake_filling"."cake_id" = 2 AND ("cake_filling"."filling_id" = 3)"#,
|
||||
/// r#"WHERE "cake_filling"."cake_id" = 2 AND "cake_filling"."filling_id" = 3"#,
|
||||
/// ].join(" ")
|
||||
/// );
|
||||
/// ```
|
||||
|
@ -116,7 +116,7 @@ mod tests {
|
||||
"SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`,",
|
||||
"`fruit`.`id` AS `B_id`, `fruit`.`name` AS `B_name`, `fruit`.`cake_id` AS `B_cake_id`",
|
||||
"FROM `cake` LEFT JOIN `fruit` ON `cake`.`id` = `fruit`.`cake_id`",
|
||||
"WHERE `cake`.`id` = 1 AND (`fruit`.`id` = 2)",
|
||||
"WHERE `cake`.`id` = 1 AND `fruit`.`id` = 2",
|
||||
].join(" ")
|
||||
);
|
||||
}
|
||||
|
@ -1,12 +1,8 @@
|
||||
use crate::{ColumnTrait, Identity, IntoSimpleExpr, RelationDef};
|
||||
use sea_query::{Alias, Expr, SelectExpr, SelectStatement, SimpleExpr};
|
||||
use sea_query::{Alias, Expr, IntoCondition, SelectExpr, SelectStatement, SimpleExpr};
|
||||
pub use sea_query::{Condition, JoinType, Order};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub trait IntoCondition {
|
||||
fn into_condition(self) -> Condition;
|
||||
}
|
||||
|
||||
pub trait QueryHelper: Sized {
|
||||
fn query(&mut self) -> &mut SelectStatement;
|
||||
|
||||
@ -71,10 +67,10 @@ pub trait QueryHelper: Sized {
|
||||
/// .filter(cake::Column::Id.eq(5))
|
||||
/// .build(MysqlQueryBuilder)
|
||||
/// .to_string(),
|
||||
/// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` = 4 AND (`cake`.`id` = 5)"
|
||||
/// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` = 4 AND `cake`.`id` = 5"
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
///
|
||||
/// Add a condition tree.
|
||||
/// ```
|
||||
/// use sea_orm::{Condition, ColumnTrait, EntityTrait, QueryHelper, tests_cfg::cake, sea_query::MysqlQueryBuilder};
|
||||
@ -92,7 +88,9 @@ pub trait QueryHelper: Sized {
|
||||
/// );
|
||||
/// ```
|
||||
fn filter<F>(mut self, filter: F) -> Self
|
||||
where F: IntoCondition {
|
||||
where
|
||||
F: IntoCondition,
|
||||
{
|
||||
self.query().cond_where(filter.into_condition());
|
||||
self
|
||||
}
|
||||
@ -216,18 +214,6 @@ pub trait QueryHelper: Sized {
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoCondition for SimpleExpr {
|
||||
fn into_condition(self) -> Condition {
|
||||
Condition::all().add(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoCondition for Condition {
|
||||
fn into_condition(self) -> Condition {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
fn join_condition(rel: RelationDef) -> SimpleExpr {
|
||||
let from_tbl = rel.from_tbl.clone();
|
||||
let to_tbl = rel.to_tbl.clone();
|
||||
|
Loading…
x
Reference in New Issue
Block a user