abstract matches pagination logic

This commit is contained in:
Ilion Beyst 2022-08-12 20:21:39 +02:00
parent 7c4314ae23
commit 84748fd60e

View file

@ -1,6 +1,9 @@
pub use crate::db_types::MatchState; pub use crate::db_types::MatchState;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use diesel::associations::BelongsTo; use diesel::associations::BelongsTo;
use diesel::pg::Pg;
use diesel::query_builder::BoxedSelectStatement;
use diesel::query_source::{AppearsInFromClause, Once};
use diesel::{ use diesel::{
BelongingToDsl, ExpressionMethods, JoinOnDsl, NullableExpressionMethods, QueryDsl, RunQueryDsl, BelongingToDsl, ExpressionMethods, JoinOnDsl, NullableExpressionMethods, QueryDsl, RunQueryDsl,
}; };
@ -138,27 +141,12 @@ pub fn list_public_matches(
) -> QueryResult<Vec<FullMatchData>> { ) -> QueryResult<Vec<FullMatchData>> {
conn.transaction(|| { conn.transaction(|| {
// TODO: how can this common logic be abstracted? // TODO: how can this common logic be abstracted?
// TODO: this is not nice. Replace this with proper cursor logic. let query = matches::table
let mut query = matches::table
.filter(matches::is_public.eq(true)) .filter(matches::is_public.eq(true))
.into_boxed(); .into_boxed();
query = match (before, after) { let matches =
(None, None) => query.order_by(matches::created_at.desc()), select_matches_page(query, amount, before, after).get_results::<MatchBase>(conn)?;
(Some(before), None) => query
.filter(matches::created_at.lt(before))
.order_by(matches::created_at.desc()),
(None, Some(after)) => query
.filter(matches::created_at.gt(after))
.order_by(matches::created_at.asc()),
(Some(before), Some(after)) => query
.filter(matches::created_at.lt(before))
.filter(matches::created_at.gt(after))
.order_by(matches::created_at.desc()),
};
let matches = query.limit(amount).get_results::<MatchBase>(conn)?;
fetch_full_match_data(matches, conn) fetch_full_match_data(matches, conn)
}) })
} }
@ -170,31 +158,53 @@ pub fn list_bot_matches(
after: Option<NaiveDateTime>, after: Option<NaiveDateTime>,
conn: &PgConnection, conn: &PgConnection,
) -> QueryResult<Vec<FullMatchData>> { ) -> QueryResult<Vec<FullMatchData>> {
conn.transaction(|| { let query = matches::table
let matches = matches::table .filter(matches::is_public.eq(true))
.filter(matches::is_public.eq(true)) .order_by(matches::created_at.desc())
.filter(matches::created_at.nullable().lt(before)) .inner_join(match_players::table)
.filter(matches::created_at.nullable().gt(after)) .inner_join(
.order_by(matches::created_at.desc()) bot_versions::table.on(match_players::bot_version_id.eq(bot_versions::id.nullable())),
.inner_join(match_players::table) )
.inner_join( .filter(bot_versions::bot_id.eq(bot_id))
bot_versions::table .select((
.on(match_players::bot_version_id.eq(bot_versions::id.nullable())), matches::id,
) matches::state,
.filter(bot_versions::bot_id.eq(bot_id)) matches::log_path,
.limit(amount) matches::created_at,
.select(( matches::winner,
matches::id, matches::is_public,
matches::state, ))
matches::log_path, .into_boxed();
matches::created_at,
matches::winner,
matches::is_public,
))
.get_results::<MatchBase>(conn)?;
fetch_full_match_data(matches, conn) let matches =
}) select_matches_page(query, amount, before, after).get_results::<MatchBase>(conn)?;
fetch_full_match_data(matches, conn)
}
fn select_matches_page<QS>(
query: BoxedSelectStatement<'static, matches::SqlType, QS, Pg>,
amount: i64,
before: Option<NaiveDateTime>,
after: Option<NaiveDateTime>,
) -> BoxedSelectStatement<'static, matches::SqlType, QS, Pg>
where
QS: AppearsInFromClause<matches::table, Count = Once>,
{
// TODO: this is not nice. Replace this with proper cursor logic.
match (before, after) {
(None, None) => query.order_by(matches::created_at.desc()),
(Some(before), None) => query
.filter(matches::created_at.lt(before))
.order_by(matches::created_at.desc()),
(None, Some(after)) => query
.filter(matches::created_at.gt(after))
.order_by(matches::created_at.asc()),
(Some(before), Some(after)) => query
.filter(matches::created_at.lt(before))
.filter(matches::created_at.gt(after))
.order_by(matches::created_at.desc()),
}
.limit(amount)
} }
// TODO: maybe unify this with matchdata? // TODO: maybe unify this with matchdata?