z_osmf 0.13.5

The Rust z/OSMF Client
Documentation
use std::marker::PhantomData;
use std::sync::Arc;

use chrono::NaiveDate;
use serde::{Deserialize, Serialize};
use z_osmf_macros::{Endpoint, Getters};

use crate::convert::TryFromResponse;
use crate::{ClientCore, Result};

use super::{de_optional_y_n, ser_optional_y_n, DatasetMigratedRecall};

#[derive(Clone, Debug, Deserialize, Eq, Getters, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct MemberAttributesBase {
    #[serde(rename = "member")]
    name: Arc<str>,
    #[getter(copy)]
    #[serde(default, rename = "vers")]
    version: Option<i32>,
    #[getter(copy)]
    #[serde(default, rename = "mod")]
    modification_level: Option<i32>,
    #[getter(copy)]
    #[serde(default, rename = "c4date")]
    creation_date: Option<NaiveDate>,
    #[getter(copy)]
    #[serde(default, rename = "m4date")]
    modification_date: Option<NaiveDate>,
    #[getter(copy)]
    #[serde(default, rename = "cnorc")]
    current_number_of_records: Option<i32>,
    #[getter(copy)]
    #[serde(default, rename = "inorc")]
    initial_number_of_records: Option<i32>,
    #[getter(copy)]
    #[serde(default, rename = "mnorc")]
    modified_number_of_records: Option<i32>,
    #[serde(default, rename = "mtime")]
    modified_time: Option<Arc<str>>,
    #[serde(default, rename = "msec")]
    modified_seconds: Option<Arc<str>>,
    #[serde(default)]
    user: Option<Arc<str>>,
    #[getter(copy)]
    #[serde(
        default,
        rename = "sclm",
        deserialize_with = "de_optional_y_n",
        serialize_with = "ser_optional_y_n"
    )]
    modified_by_sclm: Option<bool>,
    #[serde(default, rename = "ac")]
    authorization_code: Option<Arc<str>>,
    #[serde(default)]
    amode: Option<Arc<str>>,
    #[serde(default, rename = "attr")]
    attributes: Option<Arc<str>>,
    #[serde(default)]
    rmode: Option<Arc<str>>,
    #[serde(default)]
    size: Option<Arc<str>>,
    #[serde(default)]
    ttr: Option<Arc<str>>,
    #[serde(default)]
    ssi: Option<Arc<str>>,
}

#[derive(Clone, Debug, Deserialize, Eq, Getters, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct MemberAttributesName {
    #[serde(rename = "member")]
    name: Arc<str>,
}

#[derive(Clone, Debug, Deserialize, Eq, Getters, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct MemberList<T> {
    items: Arc<[T]>,
    #[getter(copy)]
    json_version: i32,
    #[getter(copy)]
    more_rows: Option<bool>,
    #[getter(copy)]
    returned_rows: i32,
    #[getter(copy)]
    total_rows: Option<i32>,
}

impl<T> TryFromResponse for MemberList<T>
where
    T: for<'de> Deserialize<'de>,
{
    async fn try_from_response(value: reqwest::Response) -> Result<Self> {
        let ResponseJson {
            items,
            returned_rows,
            more_rows,
            total_rows,
            json_version,
        } = value.json().await?;

        Ok(MemberList {
            items,
            json_version,
            more_rows,
            returned_rows,
            total_rows,
        })
    }
}

#[derive(Clone, Debug, Endpoint)]
#[endpoint(method = get, path = "/zosmf/restfiles/ds/{dataset}/member")]
pub struct MemberListBuilder<T>
where
    T: TryFromResponse,
{
    core: Arc<ClientCore>,

    #[endpoint(path)]
    dataset: Arc<str>,
    #[endpoint(query = "start")]
    start: Option<Arc<str>>,
    #[endpoint(query = "pattern")]
    pattern: Option<Arc<str>>,
    #[endpoint(header = "X-IBM-Max-Items")]
    max_items: Option<i32>,
    #[endpoint(skip_setter, builder_fn = build_attributes)]
    attributes: Option<Attrs>,
    #[endpoint(skip_builder)]
    include_total: Option<bool>,
    #[endpoint(header = "X-IBM-Migrated-Recall")]
    migrated_recall: Option<DatasetMigratedRecall>,

    target_type: PhantomData<T>,
}

impl<T> MemberListBuilder<T>
where
    T: TryFromResponse,
{
    pub fn attributes_base(self) -> MemberListBuilder<MemberList<MemberAttributesBase>> {
        MemberListBuilder {
            core: self.core,
            dataset: self.dataset,
            start: self.start,
            pattern: self.pattern,
            max_items: self.max_items,
            attributes: Some(Attrs::Base),
            include_total: self.include_total,
            migrated_recall: self.migrated_recall,
            target_type: PhantomData,
        }
    }

    pub fn attributes_member(self) -> MemberListBuilder<MemberList<MemberAttributesName>> {
        MemberListBuilder {
            core: self.core,
            dataset: self.dataset,
            start: self.start,
            pattern: self.pattern,
            max_items: self.max_items,
            attributes: Some(Attrs::Member),
            include_total: self.include_total,
            migrated_recall: self.migrated_recall,
            target_type: PhantomData,
        }
    }
}

#[derive(Clone, Copy, Debug)]
enum Attrs {
    Base,
    Member,
}

impl std::fmt::Display for Attrs {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{}",
            match self {
                Attrs::Base => "base",
                Attrs::Member => "member",
            }
        )
    }
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct ResponseJson<T> {
    items: Arc<[T]>,
    returned_rows: i32,
    #[serde(default)]
    more_rows: Option<bool>,
    #[serde(default)]
    total_rows: Option<i32>,
    #[serde(rename = "JSONversion")]
    json_version: i32,
}

fn build_attributes<T>(
    request_builder: reqwest::RequestBuilder,
    member_list_builder: &MemberListBuilder<T>,
) -> reqwest::RequestBuilder
where
    T: TryFromResponse,
{
    let MemberListBuilder {
        attributes,
        include_total,
        ..
    } = member_list_builder;
    let key = "X-IBM-Attributes";

    match (attributes, include_total) {
        (None, Some(true)) => request_builder.header(key, "member,total"),
        (Some(attr), total) => request_builder.header(
            key,
            format!(
                "{}{}",
                attr,
                if *total == Some(true) { ",total" } else { "" }
            ),
        ),
        _ => request_builder,
    }
}

#[cfg(test)]
mod tests {
    use crate::tests::*;

    #[test]
    fn example_1() {
        let zosmf = get_zosmf();

        let manual_request = zosmf
            .core
            .client
            .get("https://test.com/zosmf/restfiles/ds/NOTSYS1.PROCLIB/member")
            .build()
            .unwrap();

        let list_members = zosmf
            .datasets()
            .members("NOTSYS1.PROCLIB")
            .get_request()
            .unwrap();

        assert_eq!(
            format!("{:?}", manual_request),
            format!("{:?}", list_members)
        );
    }

    #[test]
    fn example_2() {
        let zosmf = get_zosmf();

        let manual_request = zosmf
            .core
            .client
            .get("https://test.com/zosmf/restfiles/ds/NOTSYS1.PROCLIB/member")
            .header("X-IBM-Attributes", "base")
            .build()
            .unwrap();

        let list_members_base = zosmf
            .datasets()
            .members("NOTSYS1.PROCLIB")
            .attributes_base()
            .get_request()
            .unwrap();

        assert_eq!(
            format!("{:?}", manual_request),
            format!("{:?}", list_members_base)
        );
    }
}