Files
herbapi/herbapi-api/src/db/models.rs
T
florian.berthold e3b1d5ff6d Add bilingual native_range and wildlife_value fields (DE/EN) to species
Migration 011 adds native_range_de, native_range_en, wildlife_value_de,
wildlife_value_en columns. Backend INSERT/UPDATE queries updated ($64→$68).
Frontend species and cultivar detail pages use pick_desc() for language selection.
2026-03-15 21:57:23 +01:00

492 lines
16 KiB
Rust

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
use uuid::Uuid;
// --- Pagination ---
#[derive(Debug, Deserialize)]
pub struct PaginationParams {
pub page: Option<i64>,
pub per_page: Option<i64>,
pub search: Option<String>,
}
impl PaginationParams {
pub fn limit(&self) -> i64 {
self.per_page.unwrap_or(25).min(100)
}
pub fn offset(&self) -> i64 {
(self.page.unwrap_or(1) - 1).max(0) * self.limit()
}
}
#[derive(Debug, Serialize)]
pub struct PaginatedResponse<T: Serialize> {
pub data: Vec<T>,
pub total: i64,
pub page: i64,
pub per_page: i64,
}
// --- Families ---
#[derive(Debug, FromRow, Serialize)]
pub struct Family {
pub id: Uuid,
pub slug: String,
pub name_scientific: String,
pub name_en: Option<String>,
pub name_de: Option<String>,
pub description: Option<String>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Deserialize)]
pub struct CreateFamily {
pub name_scientific: String,
pub name_en: Option<String>,
pub name_de: Option<String>,
pub description: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct UpdateFamily {
pub name_scientific: Option<String>,
pub name_en: Option<String>,
pub name_de: Option<String>,
pub description: Option<String>,
}
// --- Species ---
#[derive(Debug, FromRow, Serialize)]
pub struct Species {
pub id: Uuid,
pub slug: String,
pub family_id: Uuid,
pub name_scientific: String,
pub name_en: Option<String>,
pub name_de: Option<String>,
pub description: Option<String>,
pub description_de: Option<String>,
pub description_en: Option<String>,
pub soil_moisture: Option<String>,
pub drainage_requirement: Option<String>,
pub organic_matter_pct: Option<f64>,
pub nitrogen_ppm: Option<i32>,
pub phosphorus_ppm: Option<i32>,
pub potassium_ppm: Option<i32>,
pub boron_ppm: Option<f64>,
pub calcium_ppm: Option<i32>,
pub copper_ppm: Option<f64>,
pub iron_ppm: Option<f64>,
pub magnesium_ppm: Option<i32>,
pub manganese_ppm: Option<f64>,
pub molybdenum_ppm: Option<f64>,
pub sulfur_ppm: Option<i32>,
pub zinc_ppm: Option<f64>,
pub ph_min: Option<f64>,
pub ph_max: Option<f64>,
pub soil_texture_preference: Option<Vec<String>>,
pub hardiness_zone_usda: Option<String>,
pub hardiness_zone_at: Option<String>,
pub min_temp: Option<f64>,
pub max_temp: Option<f64>,
pub drought_tolerance: Option<String>,
pub water_requirement_mm_week: Option<f64>,
pub waterlogging_tolerance: Option<bool>,
pub salt_tolerance: Option<String>,
pub edibility_rating: Option<i16>,
pub food_uses: Option<String>,
pub food_uses_de: Option<String>,
pub food_uses_en: Option<String>,
pub medicinal_uses: Option<String>,
pub medicinal_uses_de: Option<String>,
pub medicinal_uses_en: Option<String>,
pub other_uses: Option<String>,
pub other_uses_de: Option<String>,
pub other_uses_en: Option<String>,
pub native_range: Option<String>,
pub native_range_de: Option<String>,
pub native_range_en: Option<String>,
pub invasiveness: Option<String>,
pub pollination_type: Option<String>,
pub plant_layer: Option<String>,
pub nitrogen_fixer: Option<bool>,
pub dynamic_accumulator: Option<bool>,
pub dynamic_accumulator_nutrients: Option<Vec<String>>,
pub attracts_pollinators: Option<bool>,
pub attracts_beneficial_insects: Option<bool>,
pub wildlife_value: Option<String>,
pub wildlife_value_de: Option<String>,
pub wildlife_value_en: Option<String>,
pub mulch_plant: Option<bool>,
pub ground_cover_quality: Option<String>,
pub allelopathic: Option<bool>,
pub guild_role: Option<Vec<String>>,
pub succession_stage: Option<String>,
pub heavy_metal_tolerance: Option<bool>,
pub wikidata_qid: Option<String>,
pub gbif_id: Option<String>,
pub eppo_code: Option<String>,
pub pfaf_url: Option<String>,
pub nectar_value: Option<i16>,
pub pollen_value: Option<i16>,
pub wild_bee_count: Option<i32>,
pub wild_bee_specialist_count: Option<i32>,
pub butterfly_moth_count: Option<i32>,
pub caterpillar_host_count: Option<i32>,
pub caterpillar_specialist_count: Option<i32>,
pub hoverfly_count: Option<i32>,
pub beetle_count: Option<i32>,
pub bird_count: Option<i32>,
pub mammal_count: Option<i32>,
pub native_status: Option<String>,
pub naturadb_tags: Option<String>,
pub primary_image_key: Option<String>,
pub source_urls: Option<Vec<String>>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Deserialize)]
pub struct CreateSpecies {
pub family_id: Uuid,
pub name_scientific: String,
pub name_en: Option<String>,
pub name_de: Option<String>,
pub description: Option<String>,
pub description_de: Option<String>,
pub description_en: Option<String>,
pub soil_moisture: Option<String>,
pub drainage_requirement: Option<String>,
pub ph_min: Option<f64>,
pub ph_max: Option<f64>,
pub soil_texture_preference: Option<Vec<String>>,
pub hardiness_zone_usda: Option<String>,
pub hardiness_zone_at: Option<String>,
pub min_temp: Option<f64>,
pub max_temp: Option<f64>,
pub drought_tolerance: Option<String>,
pub salt_tolerance: Option<String>,
pub edibility_rating: Option<i16>,
pub food_uses: Option<String>,
pub food_uses_de: Option<String>,
pub food_uses_en: Option<String>,
pub medicinal_uses: Option<String>,
pub medicinal_uses_de: Option<String>,
pub medicinal_uses_en: Option<String>,
pub other_uses: Option<String>,
pub other_uses_de: Option<String>,
pub other_uses_en: Option<String>,
pub native_range: Option<String>,
pub native_range_de: Option<String>,
pub native_range_en: Option<String>,
pub invasiveness: Option<String>,
pub pollination_type: Option<String>,
pub plant_layer: Option<String>,
pub nitrogen_fixer: Option<bool>,
pub dynamic_accumulator: Option<bool>,
pub dynamic_accumulator_nutrients: Option<Vec<String>>,
pub attracts_pollinators: Option<bool>,
pub attracts_beneficial_insects: Option<bool>,
pub wildlife_value: Option<String>,
pub wildlife_value_de: Option<String>,
pub wildlife_value_en: Option<String>,
pub mulch_plant: Option<bool>,
pub ground_cover_quality: Option<String>,
pub allelopathic: Option<bool>,
pub guild_role: Option<Vec<String>>,
pub succession_stage: Option<String>,
pub heavy_metal_tolerance: Option<bool>,
pub wikidata_qid: Option<String>,
pub gbif_id: Option<String>,
pub eppo_code: Option<String>,
pub pfaf_url: Option<String>,
pub nectar_value: Option<i16>,
pub pollen_value: Option<i16>,
pub wild_bee_count: Option<i32>,
pub wild_bee_specialist_count: Option<i32>,
pub butterfly_moth_count: Option<i32>,
pub caterpillar_host_count: Option<i32>,
pub caterpillar_specialist_count: Option<i32>,
pub hoverfly_count: Option<i32>,
pub beetle_count: Option<i32>,
pub bird_count: Option<i32>,
pub mammal_count: Option<i32>,
pub native_status: Option<String>,
pub naturadb_tags: Option<String>,
pub source_urls: Option<Vec<String>>,
}
pub type UpdateSpecies = CreateSpecies;
// --- Cultivars ---
#[derive(Debug, FromRow, Serialize)]
pub struct Cultivar {
pub id: Uuid,
pub slug: String,
pub species_id: Uuid,
pub name: String,
pub name_en: Option<String>,
pub name_de: Option<String>,
pub name_scientific: Option<String>,
pub description: Option<String>,
pub description_de: Option<String>,
pub description_en: Option<String>,
pub is_organic: bool,
pub perennial: bool,
pub growing_time_days: Option<i32>,
pub planting_depth_cm: Option<f64>,
pub row_spacing_cm: Option<f64>,
pub plant_spacing_cm: Option<f64>,
pub days_to_germination: Option<i32>,
pub germination_temp_c: Option<f64>,
pub light_requirement: Option<String>,
pub stratification_required: Option<bool>,
pub stratification_days: Option<i32>,
pub scarification_required: Option<bool>,
pub seed_viability_years: Option<i32>,
pub storage_temp_c: Option<f64>,
pub storage_humidity: Option<String>,
pub storage_notes: Option<String>,
pub min_temp: Option<f64>,
pub max_temp: Option<f64>,
pub humidity: Option<String>,
pub light: Option<String>,
pub frost_tolerance: Option<String>,
pub min_light_hours_day: Option<f64>,
pub optimal_light_hours_day: Option<f64>,
pub greenhouse_min_temp_c: Option<f64>,
pub indoor_season_extension_weeks: Option<i32>,
pub ventilation_requirement: Option<String>,
pub heating_required: Option<bool>,
pub indoor_sowing_months: Option<Vec<i32>>,
pub direct_sowing_months: Option<Vec<i32>>,
pub transplanting_months: Option<Vec<i32>>,
pub glasshouse_months: Option<Vec<i32>>,
pub harvesting_months: Option<Vec<i32>>,
pub indoor_sowing_weeks: Option<Vec<i32>>,
pub direct_sowing_weeks: Option<Vec<i32>>,
pub transplanting_weeks: Option<Vec<i32>>,
pub glasshouse_weeks: Option<Vec<i32>>,
pub harvesting_weeks: Option<Vec<i32>>,
pub succession_planting_days: Option<i32>,
pub planting_notes: Option<String>,
pub propagation_methods: Option<Vec<String>>,
pub cutting_season: Option<String>,
pub rootstock_species_id: Option<Uuid>,
pub years_to_first_harvest: Option<i32>,
pub productive_lifespan_years: Option<i32>,
pub expected_yield_kg_per_m2: Option<f64>,
pub yield_unit: Option<String>,
pub expected_yield_value: Option<f64>,
pub harvest_window_days: Option<i32>,
pub storage_method: Option<Vec<String>>,
pub shelf_life_days: Option<i32>,
pub cold_storage_days: Option<i32>,
pub pollination_group: Option<String>,
pub self_fertile: Option<bool>,
pub rootstock_compatibility: Option<String>,
pub wikidata_qid: Option<String>,
pub gbif_id: Option<String>,
pub pfaf_url: Option<String>,
pub primary_image_key: Option<String>,
pub source_urls: Option<Vec<String>>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Deserialize)]
pub struct CreateCultivar {
pub species_id: Uuid,
pub name: String,
pub name_en: Option<String>,
pub name_de: Option<String>,
pub name_scientific: Option<String>,
pub description: Option<String>,
pub description_de: Option<String>,
pub description_en: Option<String>,
pub is_organic: Option<bool>,
pub perennial: Option<bool>,
pub growing_time_days: Option<i32>,
pub planting_depth_cm: Option<f64>,
pub row_spacing_cm: Option<f64>,
pub plant_spacing_cm: Option<f64>,
pub days_to_germination: Option<i32>,
pub germination_temp_c: Option<f64>,
pub light_requirement: Option<String>,
pub stratification_required: Option<bool>,
pub stratification_days: Option<i32>,
pub scarification_required: Option<bool>,
pub seed_viability_years: Option<i32>,
pub storage_temp_c: Option<f64>,
pub storage_humidity: Option<String>,
pub storage_notes: Option<String>,
pub min_temp: Option<f64>,
pub max_temp: Option<f64>,
pub humidity: Option<String>,
pub light: Option<String>,
pub frost_tolerance: Option<String>,
pub min_light_hours_day: Option<f64>,
pub optimal_light_hours_day: Option<f64>,
pub greenhouse_min_temp_c: Option<f64>,
pub indoor_season_extension_weeks: Option<i32>,
pub ventilation_requirement: Option<String>,
pub heating_required: Option<bool>,
pub indoor_sowing_months: Option<Vec<i32>>,
pub direct_sowing_months: Option<Vec<i32>>,
pub transplanting_months: Option<Vec<i32>>,
pub glasshouse_months: Option<Vec<i32>>,
pub harvesting_months: Option<Vec<i32>>,
pub indoor_sowing_weeks: Option<Vec<i32>>,
pub direct_sowing_weeks: Option<Vec<i32>>,
pub transplanting_weeks: Option<Vec<i32>>,
pub glasshouse_weeks: Option<Vec<i32>>,
pub harvesting_weeks: Option<Vec<i32>>,
pub succession_planting_days: Option<i32>,
pub planting_notes: Option<String>,
pub propagation_methods: Option<Vec<String>>,
pub cutting_season: Option<String>,
pub rootstock_species_id: Option<Uuid>,
pub years_to_first_harvest: Option<i32>,
pub productive_lifespan_years: Option<i32>,
pub expected_yield_kg_per_m2: Option<f64>,
pub yield_unit: Option<String>,
pub expected_yield_value: Option<f64>,
pub harvest_window_days: Option<i32>,
pub storage_method: Option<Vec<String>>,
pub shelf_life_days: Option<i32>,
pub cold_storage_days: Option<i32>,
pub pollination_group: Option<String>,
pub self_fertile: Option<bool>,
pub rootstock_compatibility: Option<String>,
pub wikidata_qid: Option<String>,
pub gbif_id: Option<String>,
pub pfaf_url: Option<String>,
pub source_urls: Option<Vec<String>>,
}
pub type UpdateCultivar = CreateCultivar;
// --- Suppliers ---
#[derive(Debug, FromRow, Serialize)]
pub struct Supplier {
pub id: Uuid,
pub slug: String,
pub name: String,
pub url: Option<String>,
pub is_organic: bool,
pub is_demeter: bool,
pub country: Option<String>,
pub notes: Option<String>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Deserialize)]
pub struct CreateSupplier {
pub name: String,
pub url: Option<String>,
pub is_organic: Option<bool>,
pub is_demeter: Option<bool>,
pub country: Option<String>,
pub notes: Option<String>,
}
pub type UpdateSupplier = CreateSupplier;
#[derive(Debug, FromRow, Serialize)]
pub struct CultivarSupplier {
pub id: Uuid,
pub cultivar_id: Uuid,
pub supplier_id: Uuid,
pub article_number: Option<String>,
pub product_url: Option<String>,
pub price_eur: Option<f64>,
pub pack_size: Option<f64>,
pub pack_unit: Option<String>,
pub last_checked_at: Option<DateTime<Utc>>,
pub created_at: DateTime<Utc>,
}
#[derive(Debug, Deserialize)]
pub struct CreateCultivarSupplier {
pub supplier_id: Uuid,
pub article_number: Option<String>,
pub product_url: Option<String>,
pub price_eur: Option<f64>,
pub pack_size: Option<f64>,
pub pack_unit: Option<String>,
}
// --- Companion Relationships ---
#[derive(Debug, FromRow, Serialize)]
pub struct CompanionRelationship {
pub id: Uuid,
pub species_a_id: Uuid,
pub species_b_id: Uuid,
pub relationship: String,
pub mechanism: Option<String>,
pub source_url: Option<String>,
pub created_at: DateTime<Utc>,
}
#[derive(Debug, Deserialize)]
pub struct CreateCompanion {
pub species_a_id: Uuid,
pub species_b_id: Uuid,
pub relationship: String,
pub mechanism: Option<String>,
pub source_url: Option<String>,
}
// --- Images ---
#[derive(Debug, FromRow, Serialize)]
pub struct Image {
pub id: Uuid,
pub entity_type: String,
pub entity_id: Uuid,
pub s3_key: String,
pub caption: Option<String>,
pub source_url: Option<String>,
pub license: Option<String>,
pub is_primary: bool,
pub created_at: DateTime<Utc>,
}
// --- Users ---
#[derive(Debug, FromRow, Serialize)]
pub struct User {
pub id: Uuid,
pub email: String,
pub name: Option<String>,
pub nickname: Option<String>,
pub avatar_url: Option<String>,
pub provider: String,
pub provider_id: Option<String>,
pub admin: bool,
pub inserted_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
// --- Search ---
#[derive(Debug, Serialize)]
pub struct SearchResult {
pub entity_type: String,
pub id: Uuid,
pub slug: String,
pub name: String,
pub description: Option<String>,
pub rank: f32,
}