use crate::event::{flatten_dynamic, FlattenStyle};
use indexmap::IndexMap;
use rhai::{Dynamic, Engine, Map};
pub fn register_functions(engine: &mut Engine) {
engine.register_fn("merge", |lhs: &mut Map, rhs: Map| {
for (k, v) in rhs {
lhs.insert(k, v);
}
});
engine.register_fn("enrich", |lhs: &mut Map, rhs: Map| {
for (k, v) in rhs {
lhs.entry(k).or_insert(v);
}
});
engine.register_fn("+=", |lhs: &mut Map, rhs: Map| {
for (k, v) in rhs {
lhs.insert(k, v);
}
});
engine.register_fn("flatten", |map: Map| -> Map {
let dynamic_map = Dynamic::from(map);
let flattened = flatten_dynamic(&dynamic_map, FlattenStyle::default(), 0);
convert_indexmap_to_rhai_map(flattened)
});
engine.register_fn("flatten", |map: Map, style: &str| -> Map {
let flatten_style = match style {
"dot" => FlattenStyle::Dot,
"bracket" => FlattenStyle::Bracket,
"underscore" => FlattenStyle::Underscore,
_ => FlattenStyle::default(), };
let dynamic_map = Dynamic::from(map);
let flattened = flatten_dynamic(&dynamic_map, flatten_style, 0);
convert_indexmap_to_rhai_map(flattened)
});
engine.register_fn("flatten", |map: Map, style: &str, max_depth: i64| -> Map {
let flatten_style = match style {
"dot" => FlattenStyle::Dot,
"bracket" => FlattenStyle::Bracket,
"underscore" => FlattenStyle::Underscore,
_ => FlattenStyle::default(),
};
let max_depth = if max_depth < 0 { 0 } else { max_depth as usize }; let dynamic_map = Dynamic::from(map);
let flattened = flatten_dynamic(&dynamic_map, flatten_style, max_depth);
convert_indexmap_to_rhai_map(flattened)
});
engine.register_fn("flatten_field", |map: &Map, field_name: &str| -> Map {
let mut result = Map::new();
if let Some(field_value) = map.get(field_name) {
let flattened = flatten_dynamic(field_value, FlattenStyle::default(), 0);
for (key, value) in flattened {
let full_key = if key == "value" {
field_name.to_string()
} else {
format!("{}.{}", field_name, key)
};
result.insert(full_key.into(), value);
}
}
result
});
}
fn convert_indexmap_to_rhai_map(indexmap: IndexMap<String, Dynamic>) -> Map {
let mut map = Map::new();
for (key, value) in indexmap {
map.insert(key.into(), value);
}
map
}
#[cfg(test)]
mod tests {
use rhai::Map;
#[test]
fn test_json_to_dynamic_conversion() {
let json_val = serde_json::json!({
"string": "hello",
"number": 42,
"boolean": true,
"null": null,
"array": [1, 2, 3],
"object": {"nested": "value"}
});
let dynamic = crate::event::json_to_dynamic(&json_val);
if let Some(map) = dynamic.clone().try_cast::<Map>() {
assert_eq!(map.get("string").unwrap().clone().cast::<String>(), "hello");
assert_eq!(map.get("number").unwrap().clone().cast::<i64>(), 42);
assert!(map.get("boolean").unwrap().clone().cast::<bool>());
assert!(map.get("null").unwrap().is_unit());
if let Some(array) = map.get("array").unwrap().clone().try_cast::<rhai::Array>() {
assert_eq!(array.len(), 3);
assert_eq!(array[0].clone().cast::<i64>(), 1);
} else {
panic!("Array field is not a proper Rhai array");
}
if let Some(nested_map) = map.get("object").unwrap().clone().try_cast::<Map>() {
assert_eq!(
nested_map.get("nested").unwrap().clone().cast::<String>(),
"value"
);
} else {
panic!("Object field is not a proper Rhai map");
}
} else {
panic!("Root object is not a proper Rhai map");
}
}
}