zer_blocking/keys/
exact.rs1use zer_core::{record::Record, schema::Schema};
2
3use crate::normalize::normalize_text;
4use super::BlockingKey;
5
6pub struct ExactFieldKey {
7 field: String,
8}
9
10impl ExactFieldKey {
11 pub fn new(field: &str) -> Self {
12 Self { field: field.into() }
13 }
14}
15
16impl BlockingKey for ExactFieldKey {
17 fn name(&self) -> &str {
18 "exact"
19 }
20
21 fn extract(&self, record: &Record, _schema: &Schema) -> Vec<String> {
22 let cow = record.field_as_str(&self.field);
23 let raw = match cow.as_deref() {
24 Some(s) => s,
25 None => return vec![],
26 };
27
28 let normalized = normalize_text(raw);
29 if normalized.is_empty() {
30 return vec![];
31 }
32
33 vec![normalized]
34 }
35}
36
37#[cfg(test)]
38mod tests {
39 use super::*;
40 use zer_core::{record::FieldValue, schema::{SchemaBuilder, FieldKind}};
41
42 fn schema() -> Schema {
43 SchemaBuilder::new().field("category", FieldKind::Categorical).build().unwrap()
44 }
45
46 #[test]
47 fn exact_normalizes_and_matches() {
48 let k = ExactFieldKey::new("category");
49 let s = schema();
50 let r1 = Record::new(1).insert("category", FieldValue::Text("Eenmanszaak".into()));
51 let r2 = Record::new(2).insert("category", FieldValue::Text("EENMANSZAAK".into()));
52 assert_eq!(k.extract(&r1, &s), k.extract(&r2, &s));
53 }
54
55 #[test]
56 fn exact_empty_field_returns_empty() {
57 let k = ExactFieldKey::new("category");
58 let r = Record::new(1).insert("category", FieldValue::Text("".into()));
59 assert!(k.extract(&r, &schema()).is_empty());
60 }
61
62 #[test]
63 fn exact_missing_field_returns_empty() {
64 let k = ExactFieldKey::new("category");
65 let r = Record::new(1);
66 assert!(k.extract(&r, &schema()).is_empty());
67 }
68}