Skip to main content

zer_blocking/keys/
suffix.rs

1use zer_core::{record::Record, schema::Schema};
2
3use super::BlockingKey;
4use crate::normalize::normalize_digits_only;
5
6/// Blocking key that extracts the last N digits from a field value.
7pub struct SuffixKey {
8    field: String,
9    n: usize,
10}
11
12impl SuffixKey {
13    pub fn new(field: &str, n: usize) -> Self {
14        Self {
15            field: field.into(),
16            n,
17        }
18    }
19}
20
21impl BlockingKey for SuffixKey {
22    fn name(&self) -> &str {
23        "suffix"
24    }
25
26    fn extract(&self, record: &Record, _schema: &Schema) -> Vec<String> {
27        let cow = record.field_as_str(&self.field);
28        let raw = match cow.as_deref() {
29            Some(s) => s,
30            None => return vec![],
31        };
32
33        let digits = normalize_digits_only(raw);
34        if digits.len() < self.n {
35            return vec![];
36        }
37
38        let suffix = digits[digits.len() - self.n..].to_string();
39        vec![suffix]
40    }
41}
42
43#[cfg(test)]
44mod tests {
45    use super::*;
46    use zer_core::{
47        record::FieldValue,
48        schema::{FieldKind, SchemaBuilder},
49    };
50
51    fn schema() -> Schema {
52        SchemaBuilder::new()
53            .field("phone", FieldKind::Phone)
54            .build()
55            .unwrap()
56    }
57
58    #[test]
59    fn suffix_strips_punctuation_and_takes_last_n() {
60        let k = SuffixKey::new("phone", 7);
61        let r = Record::new(1).insert("phone", FieldValue::Text("555-123-4567".into()));
62        assert_eq!(k.extract(&r, &schema()), vec!["1234567"]);
63    }
64
65    #[test]
66    fn suffix_too_short_returns_empty() {
67        let k = SuffixKey::new("phone", 7);
68        let r = Record::new(1).insert("phone", FieldValue::Text("12345".into()));
69        assert!(k.extract(&r, &schema()).is_empty());
70    }
71
72    #[test]
73    fn same_last_digits_collide() {
74        let k = SuffixKey::new("phone", 4);
75        let s = schema();
76        let r1 = Record::new(1).insert("phone", FieldValue::Text("06-1234".into()));
77        let r2 = Record::new(2).insert("phone", FieldValue::Text("+31-20-001234".into()));
78        assert_eq!(k.extract(&r1, &s), k.extract(&r2, &s));
79    }
80}