use serde::{Deserialize, Serialize};
use crate::enums::{Nucleotide, PrimingMethod, QuantityUnit, SampleType};
use crate::types::{DocumentationRef, Id, SampleRef, TargetRef, TccRef};
use super::target::XRef;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Sample {
pub id: Id,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub description: Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub documentation: Vec<DocumentationRef>,
#[serde(rename = "xRef", skip_serializing_if = "Vec::is_empty", default)]
pub x_refs: Vec<XRef>,
#[serde(rename = "annotation", skip_serializing_if = "Vec::is_empty", default)]
pub annotations: Vec<Annotation>,
#[serde(rename = "type", skip_serializing_if = "Vec::is_empty", default)]
pub types: Vec<SampleTypeEntry>,
#[serde(
rename = "interRunCalibrator",
skip_serializing_if = "Option::is_none",
default
)]
pub inter_run_calibrator: Option<bool>,
#[serde(
rename = "doubleStranded",
skip_serializing_if = "Option::is_none",
default
)]
pub double_stranded: Option<bool>,
#[serde(rename = "quantity", skip_serializing_if = "Vec::is_empty", default)]
pub quantities: Vec<Quantity>,
#[serde(
rename = "calibratorSample",
skip_serializing_if = "Option::is_none",
default
)]
pub calibrator_sample: Option<bool>,
#[serde(
rename = "cdnaSynthesisMethod",
skip_serializing_if = "Option::is_none",
default
)]
pub cdna_synthesis_method: Option<CdnaSynthesisMethod>,
#[serde(
rename = "templateQuantity",
skip_serializing_if = "Option::is_none",
default
)]
pub template_quantity: Option<TemplateQuantity>,
}
impl Sample {
#[must_use]
pub fn new(id: Id) -> Self {
Self {
id,
description: None,
documentation: Vec::new(),
x_refs: Vec::new(),
annotations: Vec::new(),
types: Vec::new(),
inter_run_calibrator: None,
double_stranded: None,
quantities: Vec::new(),
calibrator_sample: None,
cdna_synthesis_method: None,
template_quantity: None,
}
}
#[must_use]
pub fn reference(&self) -> SampleRef {
self.id.clone().into()
}
#[must_use]
pub fn type_for(&self, target: &str) -> SampleType {
self.types
.iter()
.find(|t| {
t.target_id
.as_ref()
.is_some_and(|tid| tid.as_str() == target)
})
.or_else(|| self.types.iter().find(|t| t.target_id.is_none()))
.map_or(SampleType::Unknown, |t| t.value)
}
#[must_use]
pub fn is_inter_run_calibrator(&self) -> bool {
self.inter_run_calibrator.unwrap_or(false)
}
#[must_use]
pub fn is_calibrator_sample(&self) -> bool {
self.calibrator_sample.unwrap_or(false)
}
#[must_use]
pub fn is_double_stranded(&self) -> bool {
self.double_stranded.unwrap_or(false)
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SampleTypeEntry {
pub value: SampleType,
#[serde(rename = "targetId", skip_serializing_if = "Option::is_none", default)]
pub target_id: Option<TargetRef>,
}
impl SampleTypeEntry {
#[must_use]
pub fn for_all_targets(value: SampleType) -> Self {
Self {
value,
target_id: None,
}
}
#[must_use]
pub fn for_target(value: SampleType, target: TargetRef) -> Self {
Self {
value,
target_id: Some(target),
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Annotation {
pub property: String,
pub value: String,
}
impl Annotation {
pub fn new(property: impl Into<String>, value: impl Into<String>) -> Self {
Self {
property: property.into(),
value: value.into(),
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Quantity {
pub value: f64,
pub unit: QuantityUnit,
#[serde(rename = "targetId", skip_serializing_if = "Option::is_none", default)]
pub target_id: Option<TargetRef>,
}
impl Quantity {
#[must_use]
pub fn new(value: f64, unit: QuantityUnit) -> Self {
Self {
value,
unit,
target_id: None,
}
}
}
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
pub struct CdnaSynthesisMethod {
#[serde(skip_serializing_if = "Option::is_none", default)]
pub enzyme: Option<String>,
#[serde(
rename = "primingMethod",
skip_serializing_if = "Option::is_none",
default
)]
pub priming_method: Option<PrimingMethod>,
#[serde(
rename = "dnaseTreatment",
skip_serializing_if = "Option::is_none",
default
)]
pub dnase_treatment: Option<bool>,
#[serde(
rename = "thermalCyclingConditions",
skip_serializing_if = "Option::is_none",
default
)]
pub thermal_cycling_conditions: Option<TccRef>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TemplateQuantity {
pub conc: f64,
pub nucleotide: Nucleotide,
}