2023-07-30 20:19:25 +02:00
use rocket ::serde ::{ Deserialize , Serialize } ;
2023-07-25 13:22:11 +02:00
use rocket ::FromForm ;
2023-07-22 13:57:17 +02:00
use sqlx ::{ FromRow , SqlitePool } ;
#[ derive(FromRow, Debug, Serialize, Deserialize) ]
pub struct Boat {
pub id : i64 ,
pub name : String ,
pub amount_seats : i64 ,
pub location_id : i64 ,
pub owner : Option < i64 > ,
pub year_built : Option < i64 > ,
pub boatbuilder : Option < String > ,
#[ serde(default = " bool::default " ) ]
default_shipmaster_only_steering : bool ,
#[ serde(default = " bool::default " ) ]
skull : bool ,
#[ serde(default = " bool::default " ) ]
external : bool ,
}
2023-07-30 20:19:25 +02:00
#[ derive(Serialize, Deserialize) ]
2023-07-30 20:25:59 +02:00
#[ serde(rename_all = " lowercase " ) ]
2023-07-30 20:13:00 +02:00
pub enum BoatDamage {
None ,
Light ,
Locked ,
}
2023-07-30 20:19:25 +02:00
#[ derive(Serialize, Deserialize) ]
2023-07-30 20:13:00 +02:00
pub struct BoatWithDetails {
#[ serde(flatten) ]
boat : Boat ,
damage : BoatDamage ,
on_water : bool ,
}
2023-07-25 13:22:11 +02:00
#[ derive(FromForm) ]
pub struct BoatToAdd < ' r > {
pub name : & ' r str ,
pub amount_seats : i64 ,
pub year_built : Option < i64 > ,
pub boatbuilder : Option < & ' r str > ,
pub default_shipmaster_only_steering : bool ,
pub skull : bool ,
pub external : bool ,
pub location_id : Option < i64 > ,
pub owner : Option < i64 > ,
}
#[ derive(FromForm) ]
pub struct BoatToUpdate < ' r > {
pub id : i32 ,
pub name : & ' r str ,
pub amount_seats : i64 ,
pub year_built : Option < i64 > ,
pub boatbuilder : Option < & ' r str > ,
pub default_shipmaster_only_steering : bool ,
pub skull : bool ,
pub external : bool ,
pub location_id : Option < i64 > ,
pub owner : Option < i64 > ,
}
2023-07-22 13:57:17 +02:00
impl Boat {
pub async fn find_by_id ( db : & SqlitePool , id : i32 ) -> Option < Self > {
sqlx ::query_as! (
Self ,
2023-07-25 13:22:11 +02:00
" SELECT id, name, amount_seats, location_id, owner, year_built, boatbuilder, default_shipmaster_only_steering, skull, external
FROM boat
WHERE id like ? " ,
2023-07-22 13:57:17 +02:00
id
)
. fetch_one ( db )
. await
. ok ( )
}
2023-07-24 13:01:39 +02:00
pub async fn is_locked ( & self , db : & SqlitePool ) -> bool {
sqlx ::query! ( " SELECT * FROM boat_damage WHERE boat_id=? AND lock_boat=true AND user_id_verified is null " , self . id ) . fetch_optional ( db ) . await . unwrap ( ) . is_some ( )
}
2023-07-30 20:21:59 +02:00
pub async fn has_minor_damage ( & self , db : & SqlitePool ) -> bool {
sqlx ::query! ( " SELECT * FROM boat_damage WHERE boat_id=? AND lock_boat=false AND user_id_verified is null " , self . id ) . fetch_optional ( db ) . await . unwrap ( ) . is_some ( )
}
2023-07-24 13:01:39 +02:00
pub async fn on_water ( & self , db : & SqlitePool ) -> bool {
sqlx ::query! (
" SELECT * FROM logbook WHERE boat_id=? AND arrival is null " ,
self . id
)
. fetch_optional ( db )
. await
. unwrap ( )
. is_some ( )
}
2023-07-30 20:13:00 +02:00
pub async fn all ( db : & SqlitePool ) -> Vec < BoatWithDetails > {
let boats = sqlx ::query_as! (
2023-07-22 13:57:17 +02:00
Boat ,
"
SELECT id , name , amount_seats , location_id , owner , year_built , boatbuilder , default_shipmaster_only_steering , skull , external
FROM boat
ORDER BY amount_seats DESC
"
)
. fetch_all ( db )
. await
2023-07-30 20:13:00 +02:00
. unwrap ( ) ; //TODO: fixme
let mut res = Vec ::new ( ) ;
for boat in boats {
2023-07-30 20:21:59 +02:00
let mut damage = BoatDamage ::None ;
if boat . has_minor_damage ( db ) . await {
damage = BoatDamage ::Light ;
}
if boat . is_locked ( db ) . await {
damage = BoatDamage ::Locked ;
}
2023-07-30 20:13:00 +02:00
res . push ( BoatWithDetails {
damage ,
on_water : boat . on_water ( db ) . await ,
boat ,
} )
}
res
2023-07-22 13:57:17 +02:00
}
2023-07-25 13:22:11 +02:00
pub async fn create ( db : & SqlitePool , boat : BoatToAdd < '_ > ) -> bool {
2023-07-22 13:57:17 +02:00
sqlx ::query! (
2023-07-22 16:36:02 +02:00
" INSERT INTO boat(name, amount_seats, year_built, boatbuilder, default_shipmaster_only_steering, skull, external, location_id, owner) VALUES (?,?,?,?,?,?,?,?,?) " ,
2023-07-25 13:22:11 +02:00
boat . name ,
boat . amount_seats ,
boat . year_built ,
boat . boatbuilder ,
boat . default_shipmaster_only_steering ,
boat . skull ,
boat . external ,
boat . location_id ,
boat . owner
2023-07-22 13:57:17 +02:00
)
. execute ( db )
2023-07-22 16:36:02 +02:00
. await . is_ok ( )
2023-07-22 13:57:17 +02:00
}
2023-07-25 13:22:11 +02:00
pub async fn update ( & self , db : & SqlitePool , boat : BoatToUpdate < '_ > ) -> bool {
2023-07-22 15:34:42 +02:00
sqlx ::query! (
" UPDATE boat SET name=?, amount_seats=?, year_built=?, boatbuilder=?, default_shipmaster_only_steering=?, skull=?, external=?, location_id=?, owner=? WHERE id=? " ,
2023-07-25 13:22:11 +02:00
boat . name ,
boat . amount_seats ,
boat . year_built ,
boat . boatbuilder ,
boat . default_shipmaster_only_steering ,
boat . skull ,
boat . external ,
boat . location_id ,
boat . owner ,
2023-07-22 15:34:42 +02:00
self . id
)
. execute ( db )
. await
. is_ok ( )
}
2023-07-22 13:57:17 +02:00
pub async fn delete ( & self , db : & SqlitePool ) {
sqlx ::query! ( " DELETE FROM boat WHERE id=? " , self . id )
. execute ( db )
. await
2023-07-25 13:22:11 +02:00
. unwrap ( ) ; //Okay, because we can only create a Boat of a valid id
2023-07-22 13:57:17 +02:00
}
}
2023-07-22 15:34:42 +02:00
#[ cfg(test) ]
mod test {
2023-07-25 13:22:11 +02:00
use crate ::{
model ::boat ::{ Boat , BoatToAdd } ,
testdb ,
} ;
2023-07-22 15:34:42 +02:00
use sqlx ::SqlitePool ;
#[ sqlx::test ]
fn test_find_correct_id ( ) {
let pool = testdb! ( ) ;
let boat = Boat ::find_by_id ( & pool , 1 ) . await . unwrap ( ) ;
assert_eq! ( boat . id , 1 ) ;
}
#[ sqlx::test ]
fn test_find_wrong_id ( ) {
let pool = testdb! ( ) ;
let boat = Boat ::find_by_id ( & pool , 1337 ) . await ;
assert! ( boat . is_none ( ) ) ;
}
#[ sqlx::test ]
fn test_all ( ) {
let pool = testdb! ( ) ;
let res = Boat ::all ( & pool ) . await ;
assert! ( res . len ( ) > 3 ) ;
}
#[ sqlx::test ]
fn test_succ_create ( ) {
let pool = testdb! ( ) ;
assert_eq! (
Boat ::create (
& pool ,
2023-07-25 13:22:11 +02:00
BoatToAdd {
name : " new-boat-name " . into ( ) ,
amount_seats : 42 ,
year_built : None ,
boatbuilder : " Best Boatbuilder " . into ( ) ,
default_shipmaster_only_steering : true ,
skull : true ,
external : false ,
location_id : Some ( 1 ) ,
owner : None
}
2023-07-22 15:34:42 +02:00
)
. await ,
true
) ;
}
#[ sqlx::test ]
fn test_duplicate_name_create ( ) {
let pool = testdb! ( ) ;
assert_eq! (
Boat ::create (
& pool ,
2023-07-25 13:22:11 +02:00
BoatToAdd {
name : " Haichenbach " . into ( ) ,
amount_seats : 42 ,
year_built : None ,
boatbuilder : " Best Boatbuilder " . into ( ) ,
default_shipmaster_only_steering : true ,
skull : true ,
external : false ,
location_id : Some ( 1 ) ,
owner : None
}
2023-07-22 15:34:42 +02:00
)
. await ,
false
) ;
}
}