libhoney/
builder.rs

1use std::collections::HashMap;
2
3use serde_json::Value;
4
5use crate::client::Options;
6use crate::errors::Result;
7use crate::event::Event;
8use crate::fields::FieldHolder;
9
10/// Shorthand type for the function to be passed to the `add_dynamic_field` calls
11pub type DynamicFieldFunc = fn() -> Value;
12
13impl FieldHolder for Builder {
14    fn add(&mut self, data: HashMap<String, Value>) {
15        self.fields.extend(data);
16    }
17
18    /// add_field adds a field to the current (event/builder) fields
19    fn add_field(&mut self, name: &str, value: Value) {
20        self.fields.insert(name.to_string(), value);
21    }
22
23    /// add_func iterates over the results from func (until Err) and adds the results to
24    /// the event/builder fields
25    fn add_func<F>(&mut self, func: F)
26    where
27        F: Fn() -> Result<(String, Value)>,
28    {
29        while let Ok((name, value)) = func() {
30            self.add_field(&name, value);
31        }
32    }
33}
34
35/// Builder is used to create templates for new events, specifying default fields and
36/// override settings.
37#[derive(Debug, Clone)]
38pub struct Builder {
39    /// Client Options
40    pub options: Options,
41    pub(crate) fields: HashMap<String, Value>,
42    dynamic_fields: Vec<(String, DynamicFieldFunc)>,
43}
44
45impl Builder {
46    /// Creates a new event Builder with emtpy Static or Dynamic fields.
47    pub fn new(options: Options) -> Self {
48        Self {
49            options,
50            fields: HashMap::new(),
51            dynamic_fields: Vec::new(),
52        }
53    }
54
55    /// add_dynamic_field adds a dynamic field to the builder. Any events created from
56    /// this builder will get this metric added.
57    pub fn add_dynamic_field(&mut self, name: &str, func: DynamicFieldFunc) {
58        self.dynamic_fields.push((name.to_string(), func));
59    }
60
61    /// new_event creates a new Event prepopulated with fields, dynamic field values, and
62    /// configuration inherited from the builder.
63    pub fn new_event(&self) -> Event {
64        let mut e = Event::new(&self.options);
65        e.fields = self.fields.clone();
66        for (name, func) in &self.dynamic_fields {
67            e.add_field(name, func())
68        }
69        e
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76
77    #[test]
78    fn test_builder_add() {
79        let mut builder = Builder::new(Options::default());
80        let mut d: HashMap<String, Value> = HashMap::new();
81        d.insert("key".to_string(), Value::String("value".to_string()));
82        builder.add(d);
83
84        assert!(builder.fields.contains_key("key"));
85        assert_eq!(builder.fields["key"], Value::String("value".to_string()));
86    }
87
88    #[test]
89    fn test_builder_add_conflict() {
90        let mut builder = Builder::new(Options::default());
91        let mut data1: HashMap<String, Value> = HashMap::new();
92        data1.insert("key".to_string(), Value::String("value".to_string()));
93        builder.add(data1);
94        let mut data2: HashMap<String, Value> = HashMap::new();
95        data2.insert("key".to_string(), serde_json::json!(["1", "2"]));
96        builder.add(data2);
97
98        assert_eq!(builder.fields["key"], serde_json::json!(["1", "2"]));
99    }
100}