use crate::text::{normalize_optional_text, normalize_optional_text_ref};
use crate::Result;
use crate::{Confidence, ReviewStatus, SourceRef};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[derive(Clone, Debug, PartialEq)]
pub struct Provenance {
pub source: SourceRef,
pub confidence: Confidence,
pub review_status: ReviewStatus,
pub extraction_method: Option<String>,
pub extractor_id: Option<String>,
pub reviewer_id: Option<String>,
pub reviewed_at: Option<String>,
pub notes: Option<String>,
}
impl Provenance {
pub fn new(source: SourceRef, confidence: Confidence) -> Self {
Self {
source,
confidence,
review_status: ReviewStatus::default(),
extraction_method: None,
extractor_id: None,
reviewer_id: None,
reviewed_at: None,
notes: None,
}
}
pub fn with_review_status(mut self, review_status: ReviewStatus) -> Self {
self.review_status = review_status;
self
}
pub fn with_extraction_method(mut self, extraction_method: impl Into<String>) -> Result<Self> {
self.extraction_method =
normalize_optional_text("extraction_method", Some(extraction_method.into()))?;
Ok(self)
}
pub fn with_extractor_id(mut self, extractor_id: impl Into<String>) -> Result<Self> {
self.extractor_id = normalize_optional_text("extractor_id", Some(extractor_id.into()))?;
Ok(self)
}
pub fn with_reviewer_id(mut self, reviewer_id: impl Into<String>) -> Result<Self> {
self.reviewer_id = normalize_optional_text("reviewer_id", Some(reviewer_id.into()))?;
Ok(self)
}
pub fn with_reviewed_at(mut self, reviewed_at: impl Into<String>) -> Result<Self> {
self.reviewed_at = normalize_optional_text("reviewed_at", Some(reviewed_at.into()))?;
Ok(self)
}
pub fn with_notes(mut self, notes: impl Into<String>) -> Result<Self> {
self.notes = normalize_optional_text("notes", Some(notes.into()))?;
Ok(self)
}
pub fn validate(&self) -> Result<()> {
self.to_wire().map(|_| ())
}
fn from_wire(wire: ProvenanceWire) -> Result<Self> {
wire.source.validate()?;
Ok(Self {
source: wire.source,
confidence: wire.confidence,
review_status: wire.review_status,
extraction_method: normalize_optional_text(
"extraction_method",
wire.extraction_method,
)?,
extractor_id: normalize_optional_text("extractor_id", wire.extractor_id)?,
reviewer_id: normalize_optional_text("reviewer_id", wire.reviewer_id)?,
reviewed_at: normalize_optional_text("reviewed_at", wire.reviewed_at)?,
notes: normalize_optional_text("notes", wire.notes)?,
})
}
fn to_wire(&self) -> Result<ProvenanceWire> {
self.source.validate()?;
Ok(ProvenanceWire {
source: self.source.clone(),
confidence: self.confidence,
review_status: self.review_status,
extraction_method: normalize_optional_text_ref(
"extraction_method",
self.extraction_method.as_ref(),
)?,
extractor_id: normalize_optional_text_ref("extractor_id", self.extractor_id.as_ref())?,
reviewer_id: normalize_optional_text_ref("reviewer_id", self.reviewer_id.as_ref())?,
reviewed_at: normalize_optional_text_ref("reviewed_at", self.reviewed_at.as_ref())?,
notes: normalize_optional_text_ref("notes", self.notes.as_ref())?,
})
}
}
impl Serialize for Provenance {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
self.to_wire()
.map_err(serde::ser::Error::custom)?
.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for Provenance {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let wire = ProvenanceWire::deserialize(deserializer)?;
Self::from_wire(wire).map_err(serde::de::Error::custom)
}
}
#[derive(Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
struct ProvenanceWire {
source: SourceRef,
confidence: Confidence,
review_status: ReviewStatus,
#[serde(skip_serializing_if = "Option::is_none")]
extraction_method: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
extractor_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
reviewer_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
reviewed_at: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
notes: Option<String>,
}