use thing_matcher::{Identifier as MIdentifier, Thing as MThing};
use crate::models::{
identifier::{IdentifierType, ThingIdentifier},
thing::Thing,
};
pub fn to_matcher_thing(t: &Thing) -> MThing {
let mut b = MThing::builder().name(t.name.trim());
for alt in t
.alternate_names
.iter()
.map(|s| s.trim())
.filter(|s| !s.is_empty())
{
b = b.add_alternate_name(alt);
}
if let Some(d) = t.description.as_deref().map(str::trim).filter(|s| !s.is_empty()) {
b = b.description(d);
}
if let Some(d) = t
.disambiguating_description
.as_deref()
.map(str::trim)
.filter(|s| !s.is_empty())
{
b = b.disambiguating_description(d);
}
if let Some(u) = t.url.as_deref().map(str::trim).filter(|s| !s.is_empty()) {
b = b.url(u);
}
if let Some(u) = t
.main_entity_of_page
.as_deref()
.map(str::trim)
.filter(|s| !s.is_empty())
{
b = b.main_entity_of_page(u);
}
if let Some(o) = t.owner.as_deref().map(str::trim).filter(|s| !s.is_empty()) {
b = b.owner(o);
}
if let Some(img) = t.images.iter().find(|s| !s.trim().is_empty()) {
b = b.image(img.trim());
}
if let Some(at) = t.additional_type.as_deref().map(str::trim).filter(|s| !s.is_empty()) {
b = b.add_additional_type(at);
}
if let Some(so) = t.subject_of.as_deref().map(str::trim).filter(|s| !s.is_empty()) {
b = b.add_subject_of(so);
}
let same_as: Vec<String> = t
.same_as
.iter()
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty())
.collect();
if !same_as.is_empty() {
b = b.same_as(same_as);
}
let ids: Vec<MIdentifier> = t
.identifiers
.iter()
.filter_map(thing_identifier_to_matcher)
.collect();
if !ids.is_empty() {
b = b.identifiers(ids);
}
b.build()
}
fn thing_identifier_to_matcher(id: &ThingIdentifier) -> Option<MIdentifier> {
MIdentifier::new(map_identifier_property(&id.property_id), id.value.trim())
}
pub fn map_identifier_property(t: &IdentifierType) -> &str {
match t {
IdentifierType::Doi => "doi",
IdentifierType::Isbn => "isbn",
IdentifierType::Issn => "issn",
IdentifierType::Gtin => "gtin",
IdentifierType::Sku => "sku",
IdentifierType::Mpn => "mpn",
IdentifierType::SerialNumber => "serialNumber",
IdentifierType::Uri => "uri",
IdentifierType::Uuid => "uuid",
IdentifierType::Custom(s) => s.as_str(),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn round_trip_basic() {
let mut svc = Thing::new("Pride and Prejudice");
svc.alternate_names = vec!["First Impressions".into()];
svc.description = Some("A novel.".into());
svc.additional_type = Some("https://schema.org/Book".into());
svc.identifiers = vec![ThingIdentifier::isbn("9780141439518")];
let m = to_matcher_thing(&svc);
assert_eq!(m.name.as_deref(), Some("Pride and Prejudice"));
assert_eq!(m.alternate_names.len(), 1);
assert_eq!(m.additional_types.len(), 1);
assert_eq!(m.additional_types[0], "https://schema.org/Book");
assert_eq!(m.identifiers.len(), 1);
assert_eq!(m.identifiers[0].property_id, "isbn");
assert_eq!(m.identifiers[0].value, "9780141439518");
}
#[test]
fn images_collapse_to_first() {
let mut svc = Thing::new("Thing");
svc.images = vec!["https://a.example/1.jpg".into(), "https://b.example/2.jpg".into()];
let m = to_matcher_thing(&svc);
assert_eq!(m.image.as_deref(), Some("https://a.example/1.jpg"));
}
#[test]
fn custom_identifier_passes_through() {
let mut svc = Thing::new("Thing");
svc.identifiers = vec![ThingIdentifier::new(
IdentifierType::Custom("OpenLibrary".into()),
"OL1394865W",
)];
let m = to_matcher_thing(&svc);
assert_eq!(m.identifiers[0].property_id, "OpenLibrary");
}
}