Skip to main content

gingr/mapping/
mod.rs

1//! Promotion helpers from quarantined Gingr records into source-agnostic candidates.
2//!
3//! Mapping code may read Gingr-shaped DTOs, but the values it returns are domain
4//! candidates plus caller-owned source refs. Provider ids stay at this boundary;
5//! the domain does not learn Gingr vocabulary.
6//!
7//! ```rust
8//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
9//! use std::collections::BTreeMap;
10//!
11//! use domain::source;
12//! use gingr::{endpoint, mapping, response};
13//!
14//! let provider_record = response::OwnerRecord {
15//!     id: endpoint::OwnerId::new(501),
16//!     first_name: Some("Sam".to_owned()),
17//!     last_name: Some("Rivera".to_owned()),
18//!     email: Some(response::provider::Email::new("sam@example.test")),
19//!     cell_phone: None,
20//!     unknown: BTreeMap::new(),
21//! };
22//!
23//! let source_ref = source::RecordRef::new(
24//!     source::System::Gingr,
25//!     source::record::Id::try_new(provider_record.id.to_string())?,
26//! );
27//! let promoted = mapping::customer::contact_candidate(&provider_record)?;
28//!
29//! assert_eq!(source_ref.system(), source::System::Gingr);
30//! assert_eq!(source_ref.record_id().as_str(), "501");
31//! assert_eq!(promoted.provider_owner_id, endpoint::OwnerId::new(501));
32//! assert!(promoted.email.is_some());
33//! # Ok(())
34//! # }
35//! ```
36
37/// Gingr customer mapper boundary that promotes provider payloads into domain candidates.
38pub mod customer;
39/// Gingr pet mapper boundary that promotes provider payloads into domain candidates.
40pub mod pet;
41/// Gingr retail mapper boundary that promotes provider payloads into domain candidates.
42pub mod retail;
43
44/// Result type returned by fallible mapping operations.
45pub type Result<T> = core::result::Result<T, Error>;
46
47#[derive(Debug, Clone, PartialEq, Eq, strum::Display)]
48/// Gingr fields required by DTO-to-domain mapping routines.
49pub enum ProviderField {
50    #[strum(to_string = "owner name")]
51    /// Required Gingr owner-name field for customer mapping.
52    OwnerName,
53    #[strum(to_string = "animal name")]
54    /// Required Gingr animal-name field for pet mapping.
55    AnimalName,
56    #[strum(to_string = "retail item name")]
57    /// Required Gingr retail item name for product mapping.
58    RetailItemName,
59    #[strum(to_string = "retail item sku")]
60    /// Required Gingr retail SKU for product matching.
61    RetailItemSku,
62    #[strum(to_string = "retail item category")]
63    /// Required Gingr retail category for merchandising mapping.
64    RetailItemCategory,
65}
66
67#[derive(Debug, thiserror::Error, Clone, PartialEq, Eq)]
68/// Errors raised when provider values cannot safely cross this Gingr boundary.
69pub enum Error {
70    #[error("missing required Gingr provider field: {field}")]
71    /// DTO mapping cannot proceed because Gingr omitted a required field.
72    MissingRequiredProviderField {
73        /// Provider field required before this mapping can create a source-backed candidate.
74        field: ProviderField,
75    },
76    #[error("invalid domain value promoted from Gingr provider field {field}: {reason}")]
77    /// Signals that a domain value cannot be represented safely in storage.
78    InvalidDomainValue {
79        /// Provider field whose promoted value failed NVA domain validation.
80        field: ProviderField,
81        /// Validation reason returned by the downstream domain type or mapper.
82        reason: String,
83    },
84}