vector_vrl_functions/
set_semantic_meaning.rs

1use std::collections::BTreeMap;
2use std::ops::{Deref, DerefMut};
3use vrl::diagnostic::Label;
4use vrl::path::{OwnedTargetPath, PathPrefix};
5use vrl::prelude::*;
6
7#[derive(Debug, Default, Clone)]
8pub struct MeaningList(pub BTreeMap<String, OwnedTargetPath>);
9
10impl Deref for MeaningList {
11    type Target = BTreeMap<String, OwnedTargetPath>;
12
13    fn deref(&self) -> &Self::Target {
14        &self.0
15    }
16}
17
18impl DerefMut for MeaningList {
19    fn deref_mut(&mut self) -> &mut Self::Target {
20        &mut self.0
21    }
22}
23
24#[derive(Clone, Copy, Debug)]
25pub struct SetSemanticMeaning;
26
27impl Function for SetSemanticMeaning {
28    fn identifier(&self) -> &'static str {
29        "set_semantic_meaning"
30    }
31
32    fn parameters(&self) -> &'static [Parameter] {
33        &[
34            Parameter {
35                keyword: "target",
36                kind: kind::ANY,
37                required: true,
38            },
39            Parameter {
40                keyword: "meaning",
41                kind: kind::BYTES,
42                required: true,
43            },
44        ]
45    }
46
47    fn examples(&self) -> &'static [Example] {
48        &[Example {
49            title: "Sets custom field semantic meaning",
50            source: r#"set_semantic_meaning(.foo, "bar")"#,
51            result: Ok("null"),
52        }]
53    }
54
55    fn compile(
56        &self,
57        state: &TypeState,
58        ctx: &mut FunctionCompileContext,
59        arguments: ArgumentList,
60    ) -> Compiled {
61        let span = ctx.span();
62        let query = arguments.required_query("target")?;
63
64        let meaning = arguments
65            .required_literal("meaning", state)?
66            .try_bytes_utf8_lossy()
67            .expect("meaning not bytes")
68            .into_owned();
69
70        let path = if let Some(path) = query.external_path() {
71            path
72        } else {
73            // Semantic meaning can only be assigned to external fields.
74            let mut labels = vec![Label::primary(
75                "this path must point to an event or metadata",
76                span,
77            )];
78
79            if let Some(variable) = query.as_variable() {
80                labels.push(Label::context(
81                    format!(
82                        "maybe you meant \".{}\" or \"%{}\"?",
83                        variable.ident(),
84                        variable.ident()
85                    ),
86                    span,
87                ));
88            }
89
90            let error = ExpressionError::Error {
91                message: "semantic meaning is not valid for local variables".to_owned(),
92                labels,
93                notes: vec![],
94            };
95
96            return Err(Box::new(error) as Box<dyn DiagnosticMessage>);
97        };
98
99        let exists = match path.prefix {
100            PathPrefix::Event => state.external.target_kind(),
101            PathPrefix::Metadata => state.external.metadata_kind(),
102        }
103        .at_path(&path.path)
104        .contains_any_defined();
105
106        // Reject assigning meaning to non-existing field.
107        if !exists {
108            let error = ExpressionError::Error {
109                message: "semantic meaning defined for non-existing field".to_owned(),
110                labels: vec![
111                    Label::primary("cannot assign semantic meaning to non-existing field", span),
112                    Label::context(
113                        format!("field \".{}\" is not known to exist for all events", &path),
114                        span,
115                    ),
116                ],
117                notes: vec![],
118            };
119
120            return Err(Box::new(error) as Box<dyn DiagnosticMessage>);
121        }
122
123        if let Some(list) = ctx.get_external_context_mut::<MeaningList>() {
124            let duplicate = list.get(&meaning).filter(|&p| p != &path);
125
126            // Disallow a single VRL program from assigning the same semantic meaning to two
127            // different fields.
128            if let Some(duplicate) = duplicate {
129                let error = ExpressionError::Error {
130                    message: "semantic meaning referencing two different fields".to_owned(),
131                    labels: vec![
132                        Label::primary(
133                            format!(
134                                "semantic meaning \"{}\" must reference a single field",
135                                &meaning
136                            ),
137                            span,
138                        ),
139                        Label::context(
140                            format!("already referencing field \".{}\"", &duplicate),
141                            span,
142                        ),
143                    ],
144                    notes: vec![],
145                };
146
147                return Err(Box::new(error) as Box<dyn DiagnosticMessage>);
148            }
149
150            list.insert(meaning, path);
151        };
152
153        Ok(SetSemanticMeaningFn.as_expr())
154    }
155}
156
157#[derive(Debug, Clone)]
158struct SetSemanticMeaningFn;
159
160impl FunctionExpression for SetSemanticMeaningFn {
161    fn resolve(&self, _ctx: &mut Context) -> Resolved {
162        Ok(Value::Null)
163    }
164
165    fn type_def(&self, _: &TypeState) -> TypeDef {
166        TypeDef::null().infallible().impure()
167    }
168}