Skip to main content

scitadel_core/models/
search.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3
4use super::{PaperId, SearchId};
5
6/// Outcome status for a single source in a search run.
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
8#[serde(rename_all = "lowercase")]
9pub enum SourceStatus {
10    Success,
11    Partial,
12    Failed,
13    Skipped,
14}
15
16impl std::fmt::Display for SourceStatus {
17    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18        match self {
19            Self::Success => write!(f, "success"),
20            Self::Partial => write!(f, "partial"),
21            Self::Failed => write!(f, "failed"),
22            Self::Skipped => write!(f, "skipped"),
23        }
24    }
25}
26
27/// Per-source result metadata for a search run.
28#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
29pub struct SourceOutcome {
30    pub source: String,
31    pub status: SourceStatus,
32    #[serde(default)]
33    pub result_count: i32,
34    #[serde(default)]
35    pub latency_ms: f64,
36    pub error: Option<String>,
37}
38
39/// Immutable search run record.
40#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
41pub struct Search {
42    pub id: SearchId,
43    pub query: String,
44    #[serde(default)]
45    pub sources: Vec<String>,
46    #[serde(default)]
47    pub parameters: serde_json::Value,
48    #[serde(default)]
49    pub source_outcomes: Vec<SourceOutcome>,
50    #[serde(default)]
51    pub total_candidates: i32,
52    #[serde(default)]
53    pub total_papers: i32,
54    pub created_at: DateTime<Utc>,
55}
56
57impl Search {
58    #[must_use]
59    pub fn new(query: impl Into<String>) -> Self {
60        Self {
61            id: SearchId::new(),
62            query: query.into(),
63            sources: Vec::new(),
64            parameters: serde_json::Value::Object(serde_json::Map::new()),
65            source_outcomes: Vec::new(),
66            total_candidates: 0,
67            total_papers: 0,
68            created_at: Utc::now(),
69        }
70    }
71}
72
73/// Join record: search -> paper, with per-source rank/score.
74#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
75pub struct SearchResult {
76    pub search_id: SearchId,
77    pub paper_id: PaperId,
78    pub source: String,
79    pub rank: Option<i32>,
80    pub score: Option<f64>,
81    #[serde(default)]
82    pub raw_metadata: serde_json::Value,
83}