Skip to content

Commit

Permalink
revise: removes the null-based metadata fields
Browse files Browse the repository at this point in the history
  • Loading branch information
claymcleod committed Oct 16, 2023
1 parent 95521bb commit 00ffb54
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 227 deletions.
92 changes: 0 additions & 92 deletions packages/ccdi-models/src/metadata/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,95 +25,3 @@ pub enum Field {
/// An unowned field.
Unowned(unowned::Field),
}

macro_rules! unowned_field_or_null {
($name: ident, $as: ty, $inner: ty) => {
/// An unowned metadata field or null.
#[derive(Clone, Debug, Deserialize, Eq, Serialize, PartialEq, ToSchema)]
#[schema(as = $as)]
#[serde(untagged)]
pub enum $name {
/// An unowned value representing the field.
#[schema(value_type = field::$inner)]
Unowned($inner),

/// A null field.
Null,
}
};
}

unowned_field_or_null!(SexOrNull, field::SexOrNull, Sex);
unowned_field_or_null!(EthnicityOrNull, field::EthnicityOrNull, Ethnicity);

macro_rules! multiple_unowned_fields_or_null {
($name: ident, $as: ty, $inner: ty) => {
/// Multiple unowned metadata fields or null.
#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq, ToSchema)]
#[schema(as = $as)]
#[serde(untagged)]
pub enum $name {
/// Multiple unowned values representing the field(s).
#[schema(value_type = Vec<field::$inner>)]
MultipleUnowned(Vec<$inner>),

/// A null field.
Null,
}
};
}

multiple_unowned_fields_or_null!(RacesOrNull, field::RacesOrNull, Race);

#[allow(unused_macros)]
macro_rules! owned_field_or_null {
($name: ident, $as: ty, $inner: ty) => {
/// An owned metadata field.
#[derive(Clone, Debug, Deserialize, Eq, Serialize, PartialEq, ToSchema)]
#[schema(as = $as)]
#[serde(untagged)]
pub enum $name {
/// An owned value representing the field.
#[schema(value_type = field::$inner)]
Owned($inner),

/// A null field.
Null,
}
};
}

macro_rules! multiple_owned_fields_or_null {
($name: ident, $as: ty, $inner: ty) => {
/// Multiple owned metadata fields or null.
#[derive(Clone, Debug, Deserialize, Eq, Serialize, PartialEq, ToSchema)]
#[schema(as = $as)]
#[serde(untagged)]
pub enum $name {
/// Multiple owned values representing the field(s).
#[schema(value_type = Vec<field::$inner>)]
MultipleOwned(Vec<$inner>),

/// A null field.
Null,
}
};
}

multiple_owned_fields_or_null!(IdentifiersOrNull, field::IdentifiersOrNull, Identifier);

#[cfg(test)]
mod tests {
use serde_test::assert_tokens;
use serde_test::Token;

use super::*;

#[test]
fn it_serializes_null_correctly() {
let field = SexOrNull::Null;

assert_tokens(&field, &[Token::Unit]);
assert_eq!(serde_json::to_string(&field).unwrap(), "null");
}
}
62 changes: 24 additions & 38 deletions packages/ccdi-models/src/subject/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@ use serde::Serialize;
use utoipa::ToSchema;

use crate::metadata::field;
use crate::metadata::field::EthnicityOrNull;
use crate::metadata::field::IdentifiersOrNull;
use crate::metadata::field::RacesOrNull;
use crate::metadata::field::SexOrNull;

use ccdi_cde as cde;

Expand All @@ -21,23 +17,23 @@ pub use builder::Builder;
#[schema(as = models::subject::Metadata)]
pub struct Metadata {
/// The sex of the subject.
#[schema(value_type = field::SexOrNull, nullable = true)]
sex: SexOrNull,
#[schema(value_type = field::Sex, nullable = true)]
sex: Option<field::Sex>,

/// The race(s) of the subject.
#[schema(value_type = field::RacesOrNull, nullable = true)]
race: RacesOrNull,
#[schema(value_type = Vec<field::Race>, nullable = true)]
race: Option<Vec<field::Race>>,

/// The ethnicity of the subject.
#[schema(value_type = field::EthnicityOrNull, nullable = true)]
ethnicity: EthnicityOrNull,
#[schema(value_type = field::Ethnicity, nullable = true)]
ethnicity: Option<field::Ethnicity>,

/// The identifiers for the subject.
///
/// Note that this list of identifiers *must* include the main identifier
/// for the [`Subject`].
#[schema(value_type = field::IdentifiersOrNull, nullable = true)]
identifiers: IdentifiersOrNull,
#[schema(value_type = Vec<field::Identifier>, nullable = true)]
identifiers: Option<Vec<field::Identifier>>,
}

impl Metadata {
Expand All @@ -49,8 +45,7 @@ impl Metadata {
/// use ccdi_cde as cde;
/// use ccdi_models as models;
///
/// use models::metadata::field::SexOrNull;
/// use models::metadata::field::unowned::Sex;
/// use models::metadata::field::Sex;
/// use models::subject::metadata::Builder;
///
/// let metadata = Builder::default()
Expand All @@ -59,12 +54,10 @@ impl Metadata {
///
/// assert_eq!(
/// metadata.sex(),
/// &SexOrNull::Unowned(
/// Sex::new(cde::v1::Sex::Female, None, None)
/// )
/// &Some(Sex::new(cde::v1::Sex::Female, None, None))
/// );
/// ```
pub fn sex(&self) -> &SexOrNull {
pub fn sex(&self) -> &Option<field::Sex> {
&self.sex
}

Expand All @@ -76,8 +69,7 @@ impl Metadata {
/// use ccdi_cde as cde;
/// use ccdi_models as models;
///
/// use models::metadata::field::RacesOrNull;
/// use models::metadata::field::unowned::Race;
/// use models::metadata::field::Race;
/// use models::subject::metadata::Builder;
///
/// let metadata = Builder::default()
Expand All @@ -86,14 +78,10 @@ impl Metadata {
///
/// assert_eq!(
/// metadata.race(),
/// &RacesOrNull::MultipleUnowned(
/// vec![
/// Race::new(cde::v1::Race::Asian, None, None)
/// ]
/// )
/// &Some(vec![Race::new(cde::v1::Race::Asian, None, None)])
/// );
/// ```
pub fn race(&self) -> &RacesOrNull {
pub fn race(&self) -> &Option<Vec<field::Race>> {
&self.race
}

Expand All @@ -105,8 +93,7 @@ impl Metadata {
/// use ccdi_cde as cde;
/// use ccdi_models as models;
///
/// use models::metadata::field::EthnicityOrNull;
/// use models::metadata::field::unowned::Ethnicity;
/// use models::metadata::field::Ethnicity;
/// use models::subject::metadata::Builder;
///
/// let metadata = Builder::default()
Expand All @@ -115,10 +102,10 @@ impl Metadata {
///
/// assert_eq!(
/// metadata.ethnicity(),
/// &EthnicityOrNull::Unowned(Ethnicity::new(cde::v2::Ethnicity::NotHispanicOrLatino, None, None))
/// &Some(Ethnicity::new(cde::v2::Ethnicity::NotHispanicOrLatino, None, None))
/// );
/// ```
pub fn ethnicity(&self) -> &EthnicityOrNull {
pub fn ethnicity(&self) -> &Option<field::Ethnicity> {
&self.ethnicity
}

Expand All @@ -130,8 +117,7 @@ impl Metadata {
/// use ccdi_cde as cde;
/// use ccdi_models as models;
///
/// use models::metadata::field::IdentifiersOrNull;
/// use models::metadata::field::owned::Identifier;
/// use models::metadata::field::Identifier;
/// use models::subject::metadata::Builder;
///
/// let metadata = Builder::default()
Expand All @@ -145,7 +131,7 @@ impl Metadata {
///
/// assert_eq!(
/// metadata.identifiers(),
/// &IdentifiersOrNull::MultipleOwned(
/// &Some(
/// vec![
/// Identifier::new(
/// cde::v1::Identifier::parse("organization:Name", ":").unwrap(),
Expand All @@ -155,7 +141,7 @@ impl Metadata {
/// )
/// );
/// ```
pub fn identifiers(&self) -> &IdentifiersOrNull {
pub fn identifiers(&self) -> &Option<Vec<field::Identifier>> {
&self.identifiers
}

Expand All @@ -174,10 +160,10 @@ impl Metadata {
/// ```
pub fn random(identifier: cde::v1::Identifier) -> Metadata {
Metadata {
sex: SexOrNull::Unowned(rand::random()),
race: RacesOrNull::MultipleUnowned(vec![rand::random()]),
ethnicity: EthnicityOrNull::Unowned(rand::random()),
identifiers: IdentifiersOrNull::MultipleOwned(vec![field::owned::Identifier::new(
sex: Some(rand::random()),
race: Some(vec![rand::random()]),
ethnicity: Some(rand::random()),
identifiers: Some(vec![field::owned::Identifier::new(
identifier,
None,
None,
Expand Down
53 changes: 16 additions & 37 deletions packages/ccdi-models/src/subject/metadata/builder.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,22 @@
//! A builder for [`Metadata`].

use crate::metadata::field;
use crate::metadata::field::EthnicityOrNull;
use crate::metadata::field::IdentifiersOrNull;
use crate::metadata::field::RacesOrNull;
use crate::metadata::field::SexOrNull;
use crate::subject::Metadata;

/// A builder for [`Metadata`].
#[derive(Clone, Debug, Default)]
pub struct Builder {
/// The sex of the subject.
sex: Option<field::unowned::Sex>,
sex: Option<field::Sex>,

/// The race of the subject.
race: Option<Vec<field::unowned::Race>>,
race: Option<Vec<field::Race>>,

/// The ethnicity of the subject.
ethnicity: Option<field::unowned::Ethnicity>,
ethnicity: Option<field::Ethnicity>,

/// The identifiers for the subject.
identifiers: Option<Vec<field::owned::Identifier>>,
identifiers: Option<Vec<field::Identifier>>,
}

impl Builder {
Expand All @@ -32,13 +28,13 @@ impl Builder {
/// use ccdi_cde as cde;
/// use ccdi_models as models;
///
/// use models::metadata::field::unowned::Sex;
/// use models::metadata::field::Sex;
/// use models::subject::metadata::Builder;
///
/// let field = Sex::new(cde::v1::Sex::Unknown, None, None);
/// let builder = Builder::default().sex(field);
/// ```
pub fn sex(mut self, sex: field::unowned::Sex) -> Self {
pub fn sex(mut self, sex: field::Sex) -> Self {
self.sex = Some(sex);
self
}
Expand All @@ -51,13 +47,13 @@ impl Builder {
/// use ccdi_cde as cde;
/// use ccdi_models as models;
///
/// use models::metadata::field::unowned::Race;
/// use models::metadata::field::Race;
/// use models::subject::metadata::Builder;
///
/// let field = Race::new(cde::v1::Race::Unknown, None, None);
/// let builder = Builder::default().append_race(field);
/// ```
pub fn append_race(mut self, race: field::unowned::Race) -> Self {
pub fn append_race(mut self, race: field::Race) -> Self {
let mut inner = self.race.unwrap_or_default();
inner.push(race);

Expand All @@ -74,13 +70,13 @@ impl Builder {
/// use ccdi_cde as cde;
/// use ccdi_models as models;
///
/// use models::metadata::field::unowned::Ethnicity;
/// use models::metadata::field::Ethnicity;
/// use models::subject::metadata::Builder;
///
/// let field = Ethnicity::new(cde::v2::Ethnicity::Unknown, None, None);
/// let builder = Builder::default().ethnicity(field);
/// ```
pub fn ethnicity(mut self, ethnicity: field::unowned::Ethnicity) -> Self {
pub fn ethnicity(mut self, ethnicity: field::Ethnicity) -> Self {
self.ethnicity = Some(ethnicity);
self
}
Expand All @@ -93,7 +89,7 @@ impl Builder {
/// use ccdi_cde as cde;
/// use ccdi_models as models;
///
/// use models::metadata::field::owned::Identifier;
/// use models::metadata::field::Identifier;
/// use models::subject::metadata::Builder;
///
/// let field = Identifier::new(
Expand All @@ -107,7 +103,7 @@ impl Builder {
///
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
pub fn append_identifier(mut self, identifier: field::owned::Identifier) -> Self {
pub fn append_identifier(mut self, identifier: field::Identifier) -> Self {
let mut inner = self.identifiers.unwrap_or_default();
inner.push(identifier);

Expand All @@ -128,28 +124,11 @@ impl Builder {
/// let builder = Builder::default();
/// ```
pub fn build(self) -> Metadata {
let sex = self.sex.map(SexOrNull::Unowned).unwrap_or(SexOrNull::Null);

let race = self
.race
.map(RacesOrNull::MultipleUnowned)
.unwrap_or(RacesOrNull::Null);

let ethnicity = self
.ethnicity
.map(EthnicityOrNull::Unowned)
.unwrap_or(EthnicityOrNull::Null);

let identifiers = self
.identifiers
.map(IdentifiersOrNull::MultipleOwned)
.unwrap_or(IdentifiersOrNull::Null);

Metadata {
sex,
race,
ethnicity,
identifiers,
sex: self.sex,
race: self.race,
ethnicity: self.ethnicity,
identifiers: self.identifiers,
}
}
}
6 changes: 0 additions & 6 deletions packages/ccdi-openapi/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,6 @@ a variety of query parameters.",
field::Ethnicity,
field::Identifier,
// Fields or null.
field::SexOrNull,
field::RacesOrNull,
field::EthnicityOrNull,
field::IdentifiersOrNull,
// Models.
models::Subject,
models::subject::Kind,
Expand Down
Loading

0 comments on commit 00ffb54

Please sign in to comment.