pubmed_parser/europe_pmc/
citations.rs

1//! Europe PMC `citations` endpoint response parsing.
2
3use serde::{Deserialize, Serialize};
4
5use crate::error::Result;
6
7use super::models::EuropePmcCitation;
8
9/// Parsed response from the Europe PMC `citations` endpoint (one page).
10#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
11#[serde(from = "RawCitationsResponse")]
12pub struct EuropePmcCitationList {
13    /// Total number of citing articles (across all pages).
14    pub hit_count: u64,
15    /// The citing articles on this page.
16    pub citations: Vec<EuropePmcCitation>,
17}
18
19#[derive(Deserialize)]
20#[serde(rename_all = "camelCase")]
21struct RawCitationsResponse {
22    #[serde(default)]
23    hit_count: u64,
24    #[serde(default)]
25    citation_list: RawCitationList,
26}
27
28#[derive(Deserialize, Default)]
29struct RawCitationList {
30    #[serde(default)]
31    citation: Vec<EuropePmcCitation>,
32}
33
34impl From<RawCitationsResponse> for EuropePmcCitationList {
35    fn from(raw: RawCitationsResponse) -> Self {
36        Self {
37            hit_count: raw.hit_count,
38            citations: raw.citation_list.citation,
39        }
40    }
41}
42
43/// Parse a Europe PMC `citations` JSON response.
44pub fn parse_citations_response(json: &str) -> Result<EuropePmcCitationList> {
45    Ok(serde_json::from_str(json)?)
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51
52    #[test]
53    fn test_parse_citations() {
54        let json = r#"{
55            "hitCount": 1,
56            "citationList": {
57                "citation": [
58                    {
59                        "id": "99999",
60                        "source": "MED",
61                        "citationType": "JOURNAL ARTICLE",
62                        "title": "A citing article",
63                        "authorString": "Roe R.",
64                        "journalAbbreviation": "Cell",
65                        "pubYear": 2020,
66                        "volume": "1",
67                        "issue": "1",
68                        "pageInfo": "1-9",
69                        "citedByCount": 7
70                    }
71                ]
72            }
73        }"#;
74
75        let resp = parse_citations_response(json).unwrap();
76        assert_eq!(resp.hit_count, 1);
77        assert_eq!(resp.citations.len(), 1);
78        assert_eq!(resp.citations[0].id.as_deref(), Some("99999"));
79        assert_eq!(resp.citations[0].pub_year.as_deref(), Some("2020"));
80        assert_eq!(resp.citations[0].cited_by_count.as_deref(), Some("7"));
81    }
82}