use std::collections::BTreeMap;
use serde_json::Value;
use super::PipelineContext;
use super::resolve::collect_field_values;
use crate::field_def::FieldDefs;
use crate::pipeline::PipelineNode;
pub type FieldValues = BTreeMap<String, Value>;
pub fn declare(inherited: &FieldValues, fields: &FieldDefs) -> FieldValues {
let mut values = inherited.clone();
values.retain(|name, _| !fields.contains_key(name));
values.extend(collect_field_values(fields, &FieldValues::new()));
values
}
pub fn along(path: &[&PipelineNode]) -> FieldValues {
path.iter().fold(FieldValues::new(), |values, node| {
declare(&values, &node.fields)
})
}
impl<F: Fn() -> u64 + Copy> PipelineContext<'_, F> {
pub(super) fn fields_for(&self, node: &PipelineNode) -> FieldValues {
declare(&self.fields, &node.fields)
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
fn node(json: Value) -> PipelineNode {
serde_json::from_value(json).unwrap()
}
fn with_name(id: &str, default: Option<&str>) -> PipelineNode {
let mut field = json!({ "type": "string", "label": "Name" });
if let Some(default) = default {
field["default"] = json!(default);
}
node(json!({ "id": id, "type": "group", "fields": { "name": field } }))
}
#[test]
fn a_node_without_fields_sees_its_containers() {
let (group, step) = (
with_name("g", Some("outer")),
node(json!({ "id": "s", "type": "x" })),
);
assert_eq!(along(&[&group, &step])["name"], "outer");
}
#[test]
fn the_nearest_declaration_wins() {
let (outer, inner) = (with_name("o", Some("outer")), with_name("i", Some("inner")));
assert_eq!(along(&[&outer, &inner])["name"], "inner");
}
#[test]
fn a_declaration_with_no_value_still_shadows() {
let (outer, inner) = (with_name("o", Some("outer")), with_name("i", None));
assert!(!along(&[&outer, &inner]).contains_key("name"));
}
#[test]
fn an_empty_path_has_no_fields() {
assert!(along(&[]).is_empty());
}
}