Skip to content

Commit

Permalink
feat: added the full support to query drivers. TODO: refactor sql que…
Browse files Browse the repository at this point in the history
…ry code as it becomes a litte bit ugly
  • Loading branch information
thibault-cne committed Apr 11, 2024
1 parent 946cd9b commit bb93a7e
Show file tree
Hide file tree
Showing 15 changed files with 478 additions and 224 deletions.
31 changes: 31 additions & 0 deletions crates/api/src/driver.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use rocket::serde::json::Json;
use rocket::{get, routes, State};

use application::{self, models::Drivers};
use infrastructure::ConnectionPool;
use shared::prelude::*;

#[get("/<series>/drivers?<param..>")]
pub fn driver(
db: &State<ConnectionPool>,
series: Series,
param: shared::parameters::GetDriversParameter,
) -> Result<Json<Response<Vec<Drivers>>>> {
let conn = &mut db.from_series(series).get().unwrap();

let query = application::driver::DriverQueryBuilder::filter(param.into()).build();

let res = query.query_and_count::<Drivers>(conn);

let response = Response {
data: res.0,
pagination: res.1,
series,
};

Ok(Json(response))
}

pub fn handlers() -> Vec<rocket::Route> {
routes![driver]
}
8 changes: 6 additions & 2 deletions crates/api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
#![allow(clippy::too_many_arguments)]

pub mod circuit;
mod circuit;
mod driver;

pub mod handlers {
use crate::*;
use rocket::Route;

pub fn handlers() -> Vec<Route> {
circuit::handlers().into_iter().collect()
circuit::handlers()
.into_iter()
.chain(driver::handlers())
.collect()
}
}
27 changes: 22 additions & 5 deletions crates/application/src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,16 @@ impl CircuitQueryBuilder {
.results_table()
.constructors_table()
.drivers_table()
.and_status()
.and_circuits()
.and_races()
.and_results()
.and_drivers()
.and_constructors()
.and_grid()
.and_fastest()
.and_result()
.and_round()
.and_year()
.stmt
.paginate(page)
.per_page(limit)
Expand All @@ -59,8 +63,9 @@ impl CircuitQueryBuilder {
fn one_of(&self) -> bool {
self.filter.driver_ref.is_some()
|| self.filter.constructor_ref.is_some()
|| self.filter.circuit_ref.is_some()
|| self.filter.status.is_some()
|| self.filter.grid.is_some()
|| self.filter.fastest.is_some()
|| self.filter.result.is_some()
|| self.filter.year.is_some()
|| self.filter.round.is_some()
Expand All @@ -72,11 +77,11 @@ impl SqlBuilder for CircuitQueryBuilder {
&mut self.stmt
}

fn check_and_races(&self) -> bool {
fn check_and_circuits(&self) -> bool {
self.one_of()
}

fn check_and_results(&self) -> bool {
fn check_and_races(&self) -> bool {
self.one_of()
}

Expand All @@ -92,7 +97,7 @@ impl SqlBuilder for CircuitQueryBuilder {
}

fn check_and_status(&self) -> Option<SimpleExpr> {
None
self.filter.status.as_ref().map(|s| Expr::value(**s))
}

fn check_and_grid(&self) -> Option<SimpleExpr> {
Expand All @@ -102,4 +107,16 @@ impl SqlBuilder for CircuitQueryBuilder {
fn check_and_result(&self) -> Option<SimpleExpr> {
self.filter.result.as_ref().map(|r| Expr::value(**r))
}

fn check_and_round(&self) -> Option<SimpleExpr> {
self.filter.round.as_ref().map(|r| Expr::value(**r))
}

fn check_and_year(&self) -> Option<SimpleExpr> {
self.filter.year.as_ref().map(|y| Expr::value(**y))
}

fn check_and_fastest(&self) -> Option<SimpleExpr> {
self.filter.fastest.as_ref().map(|f| Expr::value(**f))
}
}
272 changes: 272 additions & 0 deletions crates/application/src/driver.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
use sea_query::{Expr, Func, IntoTableRef, Query, SelectStatement, SimpleExpr};

use shared::filters::GetDriversFilter;

use crate::{
iden::*,
pagination::{Paginate, Paginated},
sql::*,
};

pub struct DriverQueryBuilder {
stmt: SelectStatement,
filter: GetDriversFilter,
}

impl DriverQueryBuilder {
pub fn filter(filter: GetDriversFilter) -> Self {
let stmt = Query::select()
.distinct()
.from(Drivers::Table)
.columns(
[
Drivers::DriverId,
Drivers::DriverRef,
Drivers::Number,
Drivers::Code,
Drivers::Forename,
Drivers::Surname,
Drivers::Dob,
Drivers::Nationality,
Drivers::Url,
]
.into_iter()
.map(|c| (Drivers::Table, c)),
)
.to_owned();

Self { stmt, filter }
}

fn one_of(&self) -> bool {
self.filter.year.is_some()
|| self.filter.constructor_ref.is_some()
|| self.filter.status.is_some()
|| self.filter.grid.is_some()
|| self.filter.result.is_some()
|| self.filter.circuit_ref.is_some()
|| self.filter.fastest.is_some()
}

pub fn build(mut self) -> Paginated {
let page: u64 = self.filter.page.unwrap_or_default().0;
let limit: u64 = self.filter.limit.unwrap_or_default().0;

self.join(
|s| {
s.filter.year.is_some()
|| s.filter.circuit_ref.is_some()
|| s.filter.driver_standing.is_some()
},
Races::Table,
)
.join(Self::one_of, Results::Table)
.join(|s| s.filter.circuit_ref.is_some(), Circuits::Table)
.join(|s| s.filter.constructor_ref.is_some(), Constructors::Table)
.join(
|s| s.filter.driver_standing.is_some(),
DriverStandings::Table,
)
.and_clause_one()
.and_clause_two()
.and_where(|s| {
s.filter
.year
.map(|year| Expr::col((Races::Table, Races::Year)).eq(Expr::value(*year)))
})
.and_clause_three()
.stmt
.to_owned()
.paginate(page)
.per_page(limit)
}

fn and_clause_one(&mut self) -> &mut Self {
if self.filter.driver_standing.is_none() {
return self;
}

self.and_where(|s| {
if s.filter.year.is_some() || s.filter.constructor_ref.is_some() {
Some(
Expr::col((Drivers::Table, Drivers::DriverId))
.equals((Results::Table, Results::DriverId)),
)
} else {
None
}
})
.and_where(|s| {
s.filter.year.map(|_| {
Expr::col((Results::Table, Results::RaceId)).equals((Races::Table, Races::RaceId))
})
})
.and_where(|s| {
s.filter.constructor_ref.as_ref().map(|constructor_ref| {
Expr::col((Results::Table, Results::ConstructorId))
.equals((Constructors::Table, Constructors::ConstructorId))
.and(
Expr::col((Constructors::Table, Constructors::ConstructorRef))
.eq(Expr::value(&**constructor_ref)),
)
})
})
.and_where(|s| {
s.filter.driver_standing.as_ref().map(|driver_standings| {
Expr::col((DriverStandings::Table, DriverStandings::PositionText))
.eq(Expr::value(**driver_standings))
})
})
.and_where(|_| {
Some(
Expr::col((DriverStandings::Table, DriverStandings::RaceId))
.equals((Races::Table, Races::RaceId)),
)
})
.and_where(|_| {
Some(
Expr::col((DriverStandings::Table, DriverStandings::DriverId))
.equals((Drivers::Table, Drivers::DriverId)),
)
})
}

fn and_clause_two(&mut self) -> &mut Self {
if self.filter.driver_standing.is_some() {
return self;
}

self.and_where(|s| {
if s.one_of() {
Some(
Expr::col((Drivers::Table, Drivers::DriverId))
.equals((Results::Table, Results::DriverId)),
)
} else {
None
}
})
.and_where(|s| {
if s.filter.year.is_some() || s.filter.circuit_ref.is_some() {
Some(
Expr::col((Results::Table, Results::RaceId))
.equals((Races::Table, Races::RaceId)),
)
} else {
None
}
})
.and_where(|s| {
s.filter.circuit_ref.as_ref().map(|circuit_ref| {
Expr::col((Races::Table, Races::CircuitId))
.equals((Circuits::Table, Circuits::CircuitId))
.and(
Expr::col((Circuits::Table, Circuits::CircuitRef))
.eq(Expr::value(&**circuit_ref)),
)
})
})
.and_where(|s| {
s.filter.constructor_ref.as_ref().map(|constructor_ref| {
Expr::col((Results::Table, Results::ConstructorId))
.equals((Constructors::Table, Constructors::ConstructorId))
.and(
Expr::col((Constructors::Table, Constructors::ConstructorRef))
.eq(Expr::value(&**constructor_ref)),
)
})
})
.and_where(|s| {
s.filter.status.map(|status| {
Expr::col((Results::Table, Results::StatusId)).eq(Expr::value(*status))
})
})
.and_where(|s| {
s.filter
.grid
.map(|grid| Expr::col((Results::Table, Results::Grid)).eq(Expr::value(*grid)))
})
.and_where(|s| {
s.filter
.fastest
.map(|fastest| Expr::col((Results::Table, Results::Rank)).eq(Expr::value(*fastest)))
})
.and_where(|s| {
s.filter.result.map(|result| {
Expr::col((Results::Table, Results::PositionText)).eq(Expr::value(*result))
})
})
}

fn and_clause_three(&mut self) -> &mut Self {
if let Some(round) = self.filter.round.map(|r| *r) {
return self.and_where(|_| {
Some(Expr::col((Races::Table, Races::Round)).eq(Expr::value(round)))
});
}

if self.filter.driver_standing.is_some() {
if let Some(year) = self.filter.year.map(|y| *y) {
return self.and_where(|_| {
Some(
Expr::col((Races::Table, Races::Round)).in_subquery(
Query::select()
.expr(Func::max(Expr::col(Races::Round)))
.from(Races::Table)
.and_where(
Expr::col((Races::Table, Races::Year)).eq(Expr::value(year)),
)
.to_owned(),
),
)
});
} else {
return self.and_where(|_| {
Some(
Expr::tuple(
[
Expr::col((Races::Table, Races::Year)),
Expr::col((Races::Table, Races::Round)),
]
.map(Into::into),
)
.in_subquery(
Query::select()
.column(Races::Year)
.expr(Func::max(Expr::col(Races::Round)))
.from(Races::Table)
.group_by_col(Races::Year)
.to_owned(),
),
)
});
}
}

self
}

fn join<F, R>(&mut self, f: F, table: R) -> &mut Self
where
F: FnOnce(&Self) -> bool,
R: IntoTableRef,
{
if f(self) {
self.stmt
.join(sea_query::JoinType::Join, table, Expr::val(1).eq(1));
}

self
}

fn and_where<F>(&mut self, f: F) -> &mut Self
where
F: FnOnce(&Self) -> Option<SimpleExpr>,
{
if let Some(expr) = f(self) {
self.stmt.and_where(expr);
}

self
}
}
Loading

0 comments on commit bb93a7e

Please sign in to comment.