use nodedb_types::Surrogate;
#[derive(
Debug,
Clone,
PartialEq,
Eq,
serde::Serialize,
serde::Deserialize,
zerompk::ToMessagePack,
zerompk::FromMessagePack,
)]
pub struct SumTargetKey {
pub target_collection: String,
pub join_value: String,
}
impl SumTargetKey {
pub fn new(target_collection: impl Into<String>, join_value: impl Into<String>) -> Self {
Self {
target_collection: target_collection.into(),
join_value: join_value.into(),
}
}
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
serde::Serialize,
serde::Deserialize,
zerompk::ToMessagePack,
zerompk::FromMessagePack,
)]
pub struct ResolvedSumTarget {
pub target_collection: Option<String>,
pub join_value: String,
pub surrogate: Surrogate,
}
impl ResolvedSumTarget {
pub fn new(
target_collection: impl Into<String>,
join_value: impl Into<String>,
surrogate: Surrogate,
) -> Self {
Self {
target_collection: Some(target_collection.into()),
join_value: join_value.into(),
surrogate,
}
}
pub fn untargeted(join_value: impl Into<String>, surrogate: Surrogate) -> Self {
Self {
target_collection: None,
join_value: join_value.into(),
surrogate,
}
}
pub fn addresses(&self, target_collection: &str, join_value: &str) -> bool {
self.join_value == join_value
&& self
.target_collection
.as_deref()
.is_none_or(|declared| declared == target_collection)
}
pub fn matches_key(&self, key: &SumTargetKey) -> bool {
self.addresses(&key.target_collection, &key.join_value)
}
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
serde::Serialize,
serde::Deserialize,
zerompk::ToMessagePack,
zerompk::FromMessagePack,
)]
pub struct RedoSumTargets {
pub collection: String,
pub resolved: Vec<ResolvedSumTarget>,
}
pub fn resolved_sum_surrogate(
resolved: &[ResolvedSumTarget],
target_collection: &str,
join_value: &str,
) -> Option<Surrogate> {
resolved
.iter()
.find(|entry| entry.addresses(target_collection, join_value))
.map(|entry| entry.surrogate)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn one_join_value_resolves_per_target_collection() {
let resolved = vec![
ResolvedSumTarget::new("accounts", "acc-1", Surrogate::new(500)),
ResolvedSumTarget::new("audit_totals", "acc-1", Surrogate::new(900)),
];
assert_eq!(
resolved_sum_surrogate(&resolved, "accounts", "acc-1"),
Some(Surrogate::new(500))
);
assert_eq!(
resolved_sum_surrogate(&resolved, "audit_totals", "acc-1"),
Some(Surrogate::new(900))
);
}
#[test]
fn a_foreign_target_is_not_answered_by_a_matching_join_value() {
let resolved = vec![ResolvedSumTarget::new(
"accounts",
"acc-1",
Surrogate::new(500),
)];
assert_eq!(
resolved_sum_surrogate(&resolved, "audit_totals", "acc-1"),
None
);
}
#[test]
fn an_untargeted_entry_answers_any_target() {
let resolved = vec![ResolvedSumTarget::untargeted("acc-1", Surrogate::new(500))];
assert_eq!(
resolved_sum_surrogate(&resolved, "accounts", "acc-1"),
Some(Surrogate::new(500))
);
assert_eq!(
resolved_sum_surrogate(&resolved, "audit_totals", "acc-1"),
Some(Surrogate::new(500))
);
}
}