oai-pmh 0.5.1

Rust library for the Open Archives Initiative Protocol for Metadata Harvesting
Documentation
use serde::{Deserialize, Serialize};

use crate::Verb;

#[derive(Debug, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Query<T> {
    verb: Verb,
    #[serde(flatten)]
    args: T,
}

impl<T> Query<T> {
    pub fn new(verb: Verb, args: T) -> Self {
        Self { verb, args }
    }
}

macro_rules! metadata_prefix_list_args {
    ($name:ident) => {
        impl $name {
            pub fn new(metadata_prefix: impl Into<String>) -> Self {
                Self {
                    metadata_prefix: metadata_prefix.into(),
                    from: None,
                    until: None,
                    set: None,
                }
            }

            pub fn from(mut self, from: impl Into<String>) -> Self {
                self.from = Some(from.into());
                self
            }

            pub fn until(mut self, until: impl Into<String>) -> Self {
                self.until = Some(until.into());
                self
            }

            pub fn set(mut self, set: impl Into<String>) -> Self {
                self.set = Some(set.into());
                self
            }
        }
    };
}

#[derive(Debug, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetRecordArgs {
    identifier: String,
    metadata_prefix: String,
}

impl GetRecordArgs {
    pub fn new(identifier: impl Into<String>, metadata_prefix: impl Into<String>) -> Self {
        Self {
            identifier: identifier.into(),
            metadata_prefix: metadata_prefix.into(),
        }
    }
}

#[derive(Debug, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ListIdentifiersArgs {
    metadata_prefix: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    from: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    until: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    set: Option<String>,
}
metadata_prefix_list_args!(ListIdentifiersArgs);

#[derive(Debug, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ListMetadataFormatsArgs {
    identifier: String,
}

impl ListMetadataFormatsArgs {
    pub fn new(identifier: impl Into<String>) -> Self {
        Self {
            identifier: identifier.into(),
        }
    }
}

// TODO: ISO8601 (consider chrono in the future for stricter from/until handling)
#[derive(Debug, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ListRecordsArgs {
    metadata_prefix: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    from: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    until: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    set: Option<String>,
}
metadata_prefix_list_args!(ListRecordsArgs);

#[derive(Debug, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ResumableArgs {
    resumption_token: String,
}

impl ResumableArgs {
    pub fn new(resumption_token: impl Into<String>) -> Self {
        Self {
            resumption_token: resumption_token.into(),
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::{
        Verb,
        client::query::{
            GetRecordArgs, ListIdentifiersArgs, ListMetadataFormatsArgs, ListRecordsArgs, Query,
        },
    };

    #[test]
    fn construct_get_record_query() {
        let q = "verb=GetRecord&identifier=oai:archivesspace:/repositories/2/resources/2&metadataPrefix=oai_ead";
        let args = GetRecordArgs::new("oai:archivesspace:/repositories/2/resources/2", "oai_ead");

        let query = Query::new(Verb::GetRecord, args);
        let from_qs = serde_qs::from_str(q).unwrap();
        assert_eq!(query, from_qs);
    }

    #[test]
    fn construct_identify_query() {
        let q = "verb=Identify";

        let query = Query::new(Verb::Identify, ());
        let from_qs = serde_qs::from_str(q).unwrap();
        assert_eq!(query, from_qs);
    }

    #[test]
    fn construct_list_identifiers_query() {
        let q = "verb=ListIdentifiers&metadataPrefix=oai_ead&from=2000-01-01&until=2025-01-01&set=speccol";
        let args = ListIdentifiersArgs::new("oai_ead")
            .from("2000-01-01")
            .until("2025-01-01")
            .set("speccol");

        let query = Query::new(Verb::ListIdentifiers, args);
        let from_qs = serde_qs::from_str(q).unwrap();
        assert_eq!(query, from_qs);
    }

    #[test]
    fn construct_list_metadata_formats_query() {
        let q = "verb=ListMetadataFormats&identifier=oai:archivesspace:/repositories/2/resources/2";
        let args = ListMetadataFormatsArgs::new("oai:archivesspace:/repositories/2/resources/2");

        let query = Query::new(Verb::ListMetadataFormats, args);
        let from_qs = serde_qs::from_str(q).unwrap();
        assert_eq!(query, from_qs);
    }

    #[test]
    fn construct_list_records_query() {
        let q = "verb=ListRecords&metadataPrefix=oai_ead&from=2000-01-01&until=2025-01-01";
        let args = ListRecordsArgs::new("oai_ead")
            .from("2000-01-01")
            .until("2025-01-01");

        let query = Query::new(Verb::ListRecords, args);
        let from_qs = serde_qs::from_str(q).unwrap();
        assert_eq!(query, from_qs);
    }

    #[test]
    fn construct_list_sets_query() {
        let q = "verb=ListSets";

        let query = Query::new(Verb::ListSets, ());
        let from_qs = serde_qs::from_str(q).unwrap();
        assert_eq!(query, from_qs);
    }
}