feat(api): build bingo card generation
This commit is contained in:
94
src/api/bingo_card.rs
Normal file
94
src/api/bingo_card.rs
Normal file
@ -0,0 +1,94 @@
|
||||
use std::sync::Arc;
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::rng;
|
||||
use sqlx::PgPool;
|
||||
use sqlx::postgres::PgQueryResult;
|
||||
use uuid::Uuid;
|
||||
use crate::model;
|
||||
use crate::model::bingo_card::BingoCard;
|
||||
use crate::model::database::BingoCardField;
|
||||
use crate::model::database::Train;
|
||||
|
||||
pub(crate) async fn get(id: Uuid, db: Arc<PgPool>) -> sqlx::Result<BingoCard> {
|
||||
let card = sqlx::query_as!(
|
||||
crate::model::database::BingoCard,
|
||||
"SELECT uuid as id FROM bingo_cards WHERE uuid = $1",
|
||||
id,
|
||||
).fetch_one(db.as_ref()).await?;
|
||||
let mut raw_fields = get_fields_with_train(card.id, db.clone())
|
||||
.await?;
|
||||
raw_fields.sort_by(|a, b| (a.y * 5 + a.x).partial_cmp(&(b.y * 5 + b.x)).unwrap());
|
||||
raw_fields.truncate(24);
|
||||
raw_fields.shrink_to_fit();
|
||||
let fields: [Train; 24] = raw_fields
|
||||
.into_iter()
|
||||
.map(|field| field.train)
|
||||
.collect::<Vec<Train>>()
|
||||
.try_into()
|
||||
.unwrap_or_else(|v: Vec<Train>| panic!("Expected a Vec of length 24 but it was {}", v.len()));
|
||||
Ok(BingoCard {
|
||||
id: card.id,
|
||||
fields
|
||||
})
|
||||
}
|
||||
|
||||
async fn get_fields_with_train(id: Uuid, db: Arc<PgPool>) -> sqlx::Result<Vec<BingoCardField>> {
|
||||
sqlx::query_as(
|
||||
"SELECT c.uuid, c.x_pos, c.y_pos, c.card_uuid, t.uuid, t.tz_id, t.name FROM bingo_card c LEFT JOIN triebzug t ON t.uuid = c.triebzug WHERE card_uuid = $1"
|
||||
)
|
||||
.bind(id)
|
||||
.fetch_all(db.as_ref())
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn generate(db: Arc<PgPool>) -> sqlx::Result<BingoCard> {
|
||||
let card_id = Uuid::new_v4();
|
||||
let mut all_trains = fetch_all(db.clone()).await?;
|
||||
all_trains.shuffle(&mut rng());
|
||||
all_trains.truncate(24);
|
||||
all_trains.shrink_to_fit();
|
||||
let trains = all_trains.to_owned();
|
||||
let fields = trains
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(idx, train)| BingoCardField {
|
||||
uuid: Uuid::new_v4(),
|
||||
x: (idx as i32).rem_euclid(5),
|
||||
y: (idx as i32).div_euclid(5),
|
||||
train,
|
||||
card_id
|
||||
})
|
||||
.collect::<Vec<BingoCardField>>();
|
||||
let card = model::database::BingoCard {
|
||||
id: card_id,
|
||||
};
|
||||
save_card(card, db.clone()).await?;
|
||||
for field in fields {
|
||||
save_card_field(field, db.clone()).await?;
|
||||
}
|
||||
get(card_id, db.clone()).await
|
||||
}
|
||||
|
||||
async fn save_card(card: model::database::BingoCard, db: Arc<PgPool>) -> sqlx::Result<PgQueryResult> {
|
||||
sqlx::query!(
|
||||
"INSERT INTO bingo_cards VALUES ($1, NOW(), NOW() + interval '7 day')",
|
||||
card.id
|
||||
).execute(db.as_ref()).await
|
||||
}
|
||||
|
||||
async fn save_card_field(field: BingoCardField, db: Arc<PgPool>) -> sqlx::Result<PgQueryResult> {
|
||||
sqlx::query!(
|
||||
"INSERT INTO bingo_card VALUES ($1, $2, $3, $4, $5)",
|
||||
field.uuid,
|
||||
field.x,
|
||||
field.y,
|
||||
field.train.uuid,
|
||||
field.card_id
|
||||
).execute(db.as_ref()).await
|
||||
}
|
||||
|
||||
async fn fetch_all(db: Arc<PgPool>) -> sqlx::Result<Vec<Train>> {
|
||||
sqlx::query_as("SELECT * FROM triebzug")
|
||||
.fetch_all(db.as_ref())
|
||||
.await
|
||||
}
|
@ -1,2 +1,3 @@
|
||||
pub(crate) mod handlers;
|
||||
mod db_vendo_navigator;
|
||||
pub(crate) mod bingo_card;
|
||||
mod db_vendo_navigator;
|
||||
|
Reference in New Issue
Block a user