//! Discover page query models. use chrono::{DateTime, Utc}; use serde::Serialize; use sqlx::FromRow; use super::super::id_types::{CustomLinkId, ItemId, UserId}; use super::super::validated_types::{Slug, Username}; /// A flattened item row returned by the discover/search query. #[derive(Debug, Clone, FromRow)] #[allow(dead_code)] // Fields populated by sqlx query, read during type conversion pub struct DbDiscoverItemRow { /// Item primary key. pub id: ItemId, /// Item title. pub title: String, /// Item description. pub description: Option, /// Price in cents. pub price_cents: i32, /// Content type. pub item_type: super::super::ItemType, /// When the item was created. pub created_at: DateTime, /// Creator's username (joined from users). pub username: Username, /// The creator's settlement currency (joined from users). Carried on the row /// because the discover feed mixes creators, so the page has no single /// currency it could apply to every price it renders. pub settlement_currency: crate::currency::SettlementCurrency, /// Parent project title (joined from projects). pub project_title: String, /// Number of completed purchases. pub sales_count: i64, /// Primary tag name (joined from item_tags/tags), or NULL if no primary tag. pub primary_tag_name: Option, /// Whether PWYW pricing is enabled. pub pwyw_enabled: bool, /// Minimum price in cents when PWYW is enabled. pub pwyw_min_cents: Option, /// Which kind of match this row is: `2` = holds at least one typed word, /// `1` = holds none and is here on character overlap alone. `None` when not /// searching. /// /// Ranks ahead of [`Self::match_score`], and the two scores are not /// comparable across the boundary: tier 2 uses `ts_rank`, tier 1 uses /// per-word trigram. That is safe because the tier is decided by a count, /// not by either score. See [`crate::db::discover::MATCH_TIER_LEXICAL`]. pub match_tier: Option, /// How many of the typed words this row holds, and how many were typed. /// /// Drives the per-row "Matched 3 of 5 words" label. `None` when not /// searching, or on the 1-2 character path where there are no words to /// count. Counted separately from [`Self::match_score`] on purpose: the /// score folds in field weighting, so a row holding every typed word but /// only in its description scores 0.5, and a label derived from it would /// undercount. pub matched_terms: Option, /// Denominator for [`Self::matched_terms`]. pub query_terms: Option, /// Rank within the row's own tier (set when searching, `None` otherwise). pub match_score: Option, /// AI disclosure tier, drives the badge / row label on Discover. pub ai_tier: super::super::AiTier, } /// A flattened project row returned by the discover projects query. #[derive(Debug, Clone, FromRow)] #[allow(dead_code)] // Fields populated by sqlx query, read during type conversion pub struct DbDiscoverProjectRow { /// Project URL slug. pub slug: Slug, /// Project title. pub title: String, /// Project description. pub description: Option, /// Project category. pub project_type: super::super::ProjectType, /// When the project was created. pub created_at: DateTime, /// Creator's username (joined from users). pub username: Username, /// Number of public items in this project. pub item_count: i64, /// Which kind of match this row is. See [`DbDiscoverItemRow::match_tier`]. pub match_tier: Option, /// See [`DbDiscoverItemRow::matched_terms`]. pub matched_terms: Option, /// See [`DbDiscoverItemRow::query_terms`]. pub query_terms: Option, /// Rank within the row's own tier (set when searching, `None` otherwise). pub match_score: Option, /// Category name (joined from project_categories), or NULL if uncategorized. pub category_name: Option, /// Category slug (joined from project_categories), or NULL if uncategorized. pub category_slug: Option, } /// An item_type value paired with the number of matching items. #[derive(Debug, Clone, FromRow)] pub struct DbItemTypeCount { /// The item_type category value. pub category: String, /// Number of matching items of this type. pub count: i64, } /// A user-defined external link shown on their profile. #[derive(Debug, Clone, FromRow, Serialize)] pub struct DbCustomLink { /// Database primary key. pub id: CustomLinkId, /// Owning user's ID. pub user_id: UserId, /// Full URL. pub url: String, /// Display title for the link. pub title: String, /// Optional description shown below the title. pub description: Option, /// Position in the user's link list. pub sort_order: i32, /// When the link was created. pub created_at: DateTime, /// When the link was last modified. pub updated_at: DateTime, }