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