use serde_derive::{Deserialize, Serialize};
use std::collections::HashMap;
use crate::{
api_entities::{
common_types::{DehydratedAuthor, DehydratedInstitution, DehydratedSource, Field, Meta},
APIEntity,
},
impl_try_from_for_entity_response, impl_try_from_for_single_entity,
utils::{deserialize_null_default, deserialize_opt_string_from_uint_null_missing},
};
#[derive(Deserialize, Serialize, Debug)]
pub struct WorkIds {
pub openalex: String,
pub doi: Option<String>,
#[serde(
default,
deserialize_with = "deserialize_opt_string_from_uint_null_missing"
)]
pub mag: Option<String>,
pub pmid: Option<String>,
}
#[derive(Deserialize, Serialize, Debug)]
pub struct Location {
#[serde(default)]
pub is_accepted: bool,
pub is_oa: bool,
#[serde(default)]
pub is_published: bool,
pub landing_page_url: Option<String>,
pub license: Option<String>,
pub source: Option<DehydratedSource>,
pub pdf_url: Option<String>,
pub version: Option<String>,
pub license_id: Option<String>,
}
#[derive(Deserialize, Serialize, Debug)]
pub struct OpenAccess {
pub is_oa: bool,
pub oa_status: String,
pub oa_url: Option<String>,
pub any_repository_has_fulltext: bool,
}
#[derive(Deserialize, Serialize, Debug)]
pub struct Authorship {
pub author_position: String,
pub author: DehydratedAuthor,
pub institutions: Vec<DehydratedInstitution>,
}
#[derive(Deserialize, Serialize, Debug)]
pub struct APC {
pub value: u32,
pub currency: String,
pub value_usd: Option<u32>,
pub provenance: String,
}
#[derive(Deserialize, Serialize, Debug)]
pub struct Biblio {
pub volume: Option<String>,
pub issue: Option<String>,
pub first_page: Option<String>,
pub last_page: Option<String>,
}
#[derive(Deserialize, Serialize, Debug)]
pub struct WorkTopic {
pub id: String,
pub display_name: String,
pub score: f32,
pub subfield: Field,
pub field: Field,
pub domain: Field,
}
#[derive(Deserialize, Serialize, Debug)]
pub struct Keyword {
pub id: String,
pub display_name: String,
pub score: f32,
}
#[derive(Deserialize, Serialize, Debug)]
pub struct Concept {
pub id: String,
pub wikidata: String,
pub display_name: String,
pub level: u32,
pub score: f32,
}
#[derive(Deserialize, Serialize, Debug)]
pub struct YearCount {
pub year: u32,
pub cited_by_count: u32,
}
#[derive(Deserialize, Serialize, Debug)]
pub struct MeshTag {
pub descriptor_ui: String,
pub descriptor_name: String,
pub qualifier_ui: String,
pub qualifier_name: Option<String>,
pub is_major_topic: bool,
}
#[derive(Deserialize, Serialize, Debug)]
pub struct Grant {
pub funder: String,
pub funder_display_name: String,
pub award_id: Option<String>,
}
#[derive(Deserialize, Serialize, Debug)]
pub struct CitedByPercentileYear {
pub min: u32,
pub max: u32,
}
#[derive(Deserialize, Serialize, Debug)]
pub struct Work {
#[serde(deserialize_with = "deserialize_null_default")]
pub abstract_inverted_index: HashMap<String, Vec<u32>>,
pub authorships: Vec<Authorship>,
pub apc_list: Option<APC>,
pub apc_paid: Option<APC>,
pub best_oa_location: Option<Location>,
pub biblio: Biblio,
pub cited_by_api_url: String,
pub cited_by_count: u32,
pub concepts: Vec<Concept>,
pub corresponding_author_ids: Vec<String>,
pub corresponding_institution_ids: Vec<String>,
pub countries_distinct_count: u32,
pub counts_by_year: Vec<YearCount>,
pub created_date: String,
pub display_name: Option<String>,
pub doi: Option<String>,
pub fulltext_origin: Option<String>,
pub grants: Vec<Grant>,
pub has_fulltext: bool,
pub id: String,
pub ids: WorkIds,
pub indexed_in: Vec<String>,
pub institutions_distinct_count: u32,
pub is_paratext: bool,
pub is_retracted: bool,
pub keywords: Vec<Keyword>,
pub language: Option<String>,
pub license: Option<String>,
pub locations: Vec<Location>,
pub locations_count: u32,
pub mesh: Vec<MeshTag>,
pub ngrams_url: Option<String>,
pub open_access: OpenAccess,
pub primary_location: Option<Location>,
pub primary_topic: Option<WorkTopic>,
pub publication_date: String,
pub publication_year: u32,
pub referenced_works: Vec<String>,
pub related_works: Vec<String>,
pub sustainable_development_goals: Vec<Keyword>,
pub topics: Vec<WorkTopic>,
pub title: Option<String>,
#[serde(rename = "type")]
pub work_type: String,
pub type_crossref: String,
pub updated_date: String,
pub cited_by_percentile_year: CitedByPercentileYear,
pub fwci: Option<f32>,
pub referenced_works_count: u32,
}
impl Work {
pub fn get_abstract(&self) -> String {
let mut res: Vec<&str> = vec![];
for (s, positions) in self.abstract_inverted_index.iter() {
for pos in positions {
while res.len() <= (*pos as usize) {
res.push("");
}
res[*pos as usize] = s;
}
}
res.join(" ")
}
}
#[derive(Deserialize, Serialize, Debug)]
pub struct WorkResponse {
pub meta: Meta,
pub results: Vec<Work>,
}
impl_try_from_for_single_entity!(Work);
impl_try_from_for_entity_response!(WorkResponse);
impl APIEntity<Work, WorkResponse> for Work {
const API_URL: &'static str = "https://api.openalex.org/works";
}