1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
use crate::error::Result;
use crate::query::works::{WorksCombined, WorksFilter, WorksQuery};
use crate::query::*;
use std::borrow::Cow;

/// filters supported for the `/members` route
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum MembersFilter {
    /// Member has made their references public for one or more of their prefixes
    HasPublicReferences,
    /// metadata for works where references are either `open`, `limited` (to Metadata Plus subscribers) or `closed`
    ReferenceVisibility(Visibility),
    /// count of DOIs for material published more than two years ago
    BlackfileDoiCount(i32),
    /// count of DOIs for material published within last two years
    CurrentDoiCount(i32),
}

impl MembersFilter {
    /// the key name for the filter element
    pub fn name(&self) -> &str {
        match self {
            MembersFilter::HasPublicReferences => "has-public-references",
            MembersFilter::ReferenceVisibility(_) => "reference-visibility",
            MembersFilter::BlackfileDoiCount(_) => "blackfile-doi-count",
            MembersFilter::CurrentDoiCount(_) => "current-doi-count",
        }
    }
}

impl ParamFragment for MembersFilter {
    fn key(&self) -> Cow<str> {
        Cow::Borrowed(self.name())
    }

    fn value(&self) -> Option<Cow<str>> {
        match self {
            MembersFilter::HasPublicReferences => None,
            MembersFilter::ReferenceVisibility(vis) => Some(Cow::Borrowed(vis.as_str())),
            MembersFilter::BlackfileDoiCount(num) => Some(Cow::Owned(num.to_string())),
            MembersFilter::CurrentDoiCount(num) => Some(Cow::Owned(num.to_string())),
        }
    }
}

impl Filter for MembersFilter {}

impl_common_query!(MembersQuery, MembersFilter);

/// constructs the request payload for the `/members` route
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Members {
    /// target a specific member at `/members/{id}`
    Identifier(String),
    /// target all members that match the query at `/members?query...`
    Query(MembersQuery),
    /// target a `Work` for a specific funder at `/members/{id}/works?query..`
    Works(WorksCombined),
}

impl CrossrefRoute for Members {
    fn route(&self) -> Result<String> {
        match self {
            Members::Identifier(s) => Ok(format!("{}/{}", Component::Members.route()?, s)),
            Members::Query(query) => {
                let query = query.route()?;
                if query.is_empty() {
                    Component::Members.route()
                } else {
                    Ok(format!("{}?{}", Component::Members.route()?, query))
                }
            }
            Members::Works(combined) => {
                let query = combined.query.route()?;
                if query.is_empty() {
                    Ok(format!(
                        "{}/{}/{}",
                        Component::Members.route()?,
                        combined.id,
                        Component::Works.route()?
                    ))
                } else {
                    Ok(format!(
                        "{}/{}/{}?{}",
                        Component::Members.route()?,
                        combined.id,
                        Component::Works.route()?,
                        query
                    ))
                }
            }
        }
    }
}

impl CrossrefQuery for Members {
    fn resource_component(self) -> ResourceComponent {
        ResourceComponent::Members(self)
    }
}