Skip to main content

zer_blocking/keys/
suffix.rs

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