fish_lib/models/
fishing_history_entry.rs

1use crate::config::ConfigInterface;
2use crate::game::errors::resource::GameResourceError;
3use crate::game::errors::GameResult;
4use crate::traits::model::Model;
5use crate::utils::math::float_interpolate;
6use chrono::{DateTime, Utc};
7use diesel::{AsChangeset, Insertable, Queryable, Selectable};
8use serde::{Deserialize, Serialize};
9use std::sync::Arc;
10
11#[derive(
12    Debug, Default, Serialize, Deserialize, Clone, PartialEq, Queryable, Selectable, AsChangeset,
13)]
14#[diesel(table_name = crate::schema::fish_fishing_history_entries)]
15#[diesel(check_for_backend(diesel::pg::Pg))]
16pub struct FishingHistoryEntry {
17    /// Primary key of this fishing history entry in the database
18    pub id: i64,
19    /// The primary key of the user this fishing history entry belongs to
20    pub user_id: i64,
21    /// The species ID this fishing history entry is associated with (species are defined in the config)
22    pub species_id: i32,
23    /// When the dataset was created
24    pub created_at: DateTime<Utc>,
25    /// When the dataset was last updated
26    pub updated_at: DateTime<Utc>,
27    /// How often the specimen of this species was caught by the user
28    pub caught_count: i32,
29    /// How often the specimen of this species was sold by the user
30    pub sold_count: i32,
31    /// Smallest catch size ratio (0-1) relative to species' min/max size range
32    pub smallest_catch_size_ratio: f32,
33    /// Largest catch size ratio (0-1) relative to species' min/max size range
34    pub largest_catch_size_ratio: f32,
35    /// When a specimen of this species was last caught
36    pub last_catch: DateTime<Utc>,
37    /// When a specimen of this species was first sold
38    pub first_sell: Option<DateTime<Utc>>,
39    /// When a specimen of this species was last sold
40    pub last_sell: Option<DateTime<Utc>>,
41}
42
43impl FishingHistoryEntry {
44    pub fn get_first_catch(&self) -> DateTime<Utc> {
45        self.created_at
46    }
47
48    pub fn register_catch(&mut self, total_size_ratio: f32, catch_time: DateTime<Utc>) {
49        if total_size_ratio < self.smallest_catch_size_ratio {
50            self.smallest_catch_size_ratio = total_size_ratio;
51        } else if total_size_ratio > self.largest_catch_size_ratio {
52            self.largest_catch_size_ratio = total_size_ratio;
53        }
54        self.last_catch = catch_time;
55        self.caught_count = self.caught_count.saturating_add(1);
56    }
57
58    pub fn register_sell(&mut self, sell_time: DateTime<Utc>) {
59        if self.sold_count == 0 {
60            self.first_sell = Some(sell_time);
61        }
62        self.last_sell = Some(sell_time);
63        self.sold_count = self.sold_count.saturating_add(1);
64    }
65
66    pub fn get_smallest_size_mm(&self, config: Arc<dyn ConfigInterface>) -> GameResult<f32> {
67        let data = config
68            .get_species_data(self.species_id)
69            .ok_or_else(|| GameResourceError::species_not_found(self.species_id))?;
70        Ok(float_interpolate(
71            data.min_size_baby_mm as f32,
72            data.max_size_adult_mm as f32,
73            self.smallest_catch_size_ratio,
74        ))
75    }
76
77    pub fn get_largest_size_mm(&self, config: Arc<dyn ConfigInterface>) -> GameResult<f32> {
78        let data = config
79            .get_species_data(self.species_id)
80            .ok_or_else(|| GameResourceError::species_not_found(self.species_id))?;
81        Ok(float_interpolate(
82            data.min_size_baby_mm as f32,
83            data.max_size_adult_mm as f32,
84            self.largest_catch_size_ratio,
85        ))
86    }
87
88    pub fn get_smallest_weight_g(&self, config: Arc<dyn ConfigInterface>) -> GameResult<f32> {
89        let data = config
90            .get_species_data(self.species_id)
91            .ok_or_else(|| GameResourceError::species_not_found(self.species_id))?;
92        Ok(float_interpolate(
93            data.min_weight_baby_g as f32,
94            data.max_weight_adult_g as f32,
95            self.smallest_catch_size_ratio,
96        ))
97    }
98
99    pub fn get_largest_weight_g(&self, config: Arc<dyn ConfigInterface>) -> GameResult<f32> {
100        let data = config
101            .get_species_data(self.species_id)
102            .ok_or_else(|| GameResourceError::species_not_found(self.species_id))?;
103        Ok(float_interpolate(
104            data.min_weight_baby_g as f32,
105            data.max_weight_adult_g as f32,
106            self.largest_catch_size_ratio,
107        ))
108    }
109}
110
111impl Model for FishingHistoryEntry {
112    type Table = crate::schema::fish_fishing_history_entries::table;
113    type PrimaryKeyType = i64;
114    type InsertType = NewFishingHistoryEntry;
115
116    fn table() -> Self::Table {
117        crate::schema::fish_fishing_history_entries::table
118    }
119
120    fn id(&self) -> Self::PrimaryKeyType {
121        self.id
122    }
123}
124
125#[derive(Insertable)]
126#[diesel(table_name = crate::schema::fish_fishing_history_entries)]
127#[diesel(check_for_backend(diesel::pg::Pg))]
128pub struct NewFishingHistoryEntry {
129    pub user_id: i64,
130    pub species_id: i32,
131    pub caught_count: i32,
132    pub sold_count: i32,
133    pub smallest_catch_size_ratio: f32,
134    pub largest_catch_size_ratio: f32,
135}