vrl/compiler/
target.rs

1#![allow(clippy::module_name_repetitions)]
2use std::convert::AsRef;
3
4use crate::path::OwnedTargetPath;
5use crate::path::PathPrefix;
6use crate::value::{Secrets, Value};
7
8/// Any target object you want to remap using VRL has to implement this trait.
9pub trait Target: std::fmt::Debug + SecretTarget {
10    /// Insert a given [`Value`] in the provided [`Target`].
11    ///
12    /// The `path` parameter determines _where_ in the given target the value
13    /// should be inserted.
14    ///
15    /// A path consists of "path segments". Each segment can be one of:
16    ///
17    /// * regular path segments:
18    ///
19    ///   ```txt
20    ///   .foo.bar.baz
21    ///   ```
22    ///
23    /// * quoted path segments:
24    ///
25    ///   ```txt
26    ///   .foo."bar.baz"
27    ///   ```
28    ///
29    /// * path indices:
30    ///
31    ///   ```txt
32    ///   .foo[2][-1]
33    ///   ```
34    ///
35    /// # Errors
36    ///
37    /// Error indicating insertion failure.
38    fn target_insert(&mut self, path: &OwnedTargetPath, value: Value) -> Result<(), String>;
39
40    /// Get a value for a given path, or `None` if no value is found.
41    ///
42    /// See [`Target::target_insert`] for more details.
43    ///
44    /// # Errors
45    /// Error indicating retrieval failure.
46    fn target_get(&self, path: &OwnedTargetPath) -> Result<Option<&Value>, String>;
47
48    /// Get a mutable reference to the value for a given path, or `None` if no
49    /// value is found.
50    ///
51    /// See [`Target::target_insert`] for more details.
52    ///
53    /// # Errors
54    ///
55    /// Error indicating retrieval failure.
56    fn target_get_mut(&mut self, path: &OwnedTargetPath) -> Result<Option<&mut Value>, String>;
57
58    /// Remove the given path from the object.
59    ///
60    /// Returns the removed object, if any.
61    ///
62    /// If `compact` is true, after deletion, if an empty object or array is
63    /// left behind, it should be removed as well, cascading up to the root.
64    ///
65    /// # Errors
66    ///
67    /// Error indicating removal failure.
68    fn target_remove(
69        &mut self,
70        path: &OwnedTargetPath,
71        compact: bool,
72    ) -> Result<Option<Value>, String>;
73}
74
75/// The Secret trait defines methods for managing secret data associated with a [`Target`] struct.
76pub trait SecretTarget {
77    /// Retrieves the value associated with the given key.
78    ///
79    /// # Parameters
80    /// - `key`: A string slice representing the key.
81    ///
82    /// # Returns
83    /// - `Option<&str>`: An optional reference to the value if found; `None` otherwise.
84    fn get_secret(&self, key: &str) -> Option<&str>;
85
86    /// Inserts a new key-value pair into the secrets.
87    ///
88    /// # Parameters
89    /// - `key`: A string slice representing the key.
90    /// - `value`: A string slice representing the value.
91    fn insert_secret(&mut self, key: &str, value: &str);
92
93    /// Removes the key-value pair associated with the given key.
94    ///
95    /// # Parameters
96    /// - `key`: A string slice representing the key.
97    fn remove_secret(&mut self, key: &str);
98}
99
100#[derive(Debug)]
101pub struct TargetValueRef<'a> {
102    pub value: &'a mut Value,
103    pub metadata: &'a mut Value,
104    pub secrets: &'a mut Secrets,
105}
106
107impl Target for TargetValueRef<'_> {
108    fn target_insert(&mut self, target_path: &OwnedTargetPath, value: Value) -> Result<(), String> {
109        match target_path.prefix {
110            PathPrefix::Event => self.value.insert(&target_path.path, value),
111            PathPrefix::Metadata => self.metadata.insert(&target_path.path, value),
112        };
113        Ok(())
114    }
115
116    fn target_get(&self, target_path: &OwnedTargetPath) -> Result<Option<&Value>, String> {
117        let value = match target_path.prefix {
118            PathPrefix::Event => self.value.get(&target_path.path),
119            PathPrefix::Metadata => self.metadata.get(&target_path.path),
120        };
121        Ok(value)
122    }
123
124    fn target_get_mut(
125        &mut self,
126        target_path: &OwnedTargetPath,
127    ) -> Result<Option<&mut Value>, String> {
128        let value = match target_path.prefix {
129            PathPrefix::Event => self.value.get_mut(&target_path.path),
130            PathPrefix::Metadata => self.metadata.get_mut(&target_path.path),
131        };
132        Ok(value)
133    }
134
135    fn target_remove(
136        &mut self,
137        target_path: &OwnedTargetPath,
138        compact: bool,
139    ) -> Result<Option<Value>, String> {
140        let prev_value = match target_path.prefix {
141            PathPrefix::Event => self.value.remove(&target_path.path, compact),
142            PathPrefix::Metadata => self.metadata.remove(&target_path.path, compact),
143        };
144        Ok(prev_value)
145    }
146}
147
148impl SecretTarget for TargetValueRef<'_> {
149    fn get_secret(&self, key: &str) -> Option<&str> {
150        self.secrets.get_secret(key)
151    }
152
153    fn insert_secret(&mut self, key: &str, value: &str) {
154        self.secrets.insert_secret(key, value);
155    }
156
157    fn remove_secret(&mut self, key: &str) {
158        self.secrets.remove_secret(key);
159    }
160}
161
162#[derive(Debug)]
163pub struct TargetValue {
164    pub value: Value,
165    pub metadata: Value,
166    pub secrets: Secrets,
167}
168
169impl Target for TargetValue {
170    fn target_insert(&mut self, target_path: &OwnedTargetPath, value: Value) -> Result<(), String> {
171        match target_path.prefix {
172            PathPrefix::Event => self.value.insert(&target_path.path, value),
173            PathPrefix::Metadata => self.metadata.insert(&target_path.path, value),
174        };
175        Ok(())
176    }
177
178    fn target_get(&self, target_path: &OwnedTargetPath) -> Result<Option<&Value>, String> {
179        let value = match target_path.prefix {
180            PathPrefix::Event => self.value.get(&target_path.path),
181            PathPrefix::Metadata => self.metadata.get(&target_path.path),
182        };
183        Ok(value)
184    }
185
186    fn target_get_mut(
187        &mut self,
188        target_path: &OwnedTargetPath,
189    ) -> Result<Option<&mut Value>, String> {
190        let value = match target_path.prefix {
191            PathPrefix::Event => self.value.get_mut(&target_path.path),
192            PathPrefix::Metadata => self.metadata.get_mut(&target_path.path),
193        };
194        Ok(value)
195    }
196
197    fn target_remove(
198        &mut self,
199        target_path: &OwnedTargetPath,
200        compact: bool,
201    ) -> Result<Option<Value>, String> {
202        let prev_value = match target_path.prefix {
203            PathPrefix::Event => self.value.remove(&target_path.path, compact),
204            PathPrefix::Metadata => self.metadata.remove(&target_path.path, compact),
205        };
206        Ok(prev_value)
207    }
208}
209
210impl SecretTarget for TargetValue {
211    fn get_secret(&self, key: &str) -> Option<&str> {
212        self.secrets.get_secret(key)
213    }
214
215    fn insert_secret(&mut self, key: &str, value: &str) {
216        self.secrets.insert_secret(key, value);
217    }
218
219    fn remove_secret(&mut self, key: &str) {
220        self.secrets.remove_secret(key);
221    }
222}
223
224impl SecretTarget for Secrets {
225    fn get_secret(&self, key: &str) -> Option<&str> {
226        self.get(key).map(AsRef::as_ref)
227    }
228
229    fn insert_secret(&mut self, key: &str, value: &str) {
230        self.insert(key, value);
231    }
232
233    fn remove_secret(&mut self, key: &str) {
234        self.remove(key);
235    }
236}
237
238#[cfg(any(test, feature = "test"))]
239mod value_target_impl {
240    use super::{SecretTarget, Target, Value};
241    use crate::path::{OwnedTargetPath, PathPrefix};
242
243    impl Target for Value {
244        fn target_insert(
245            &mut self,
246            target_path: &OwnedTargetPath,
247            value: Value,
248        ) -> Result<(), String> {
249            match target_path.prefix {
250                PathPrefix::Event => self.insert(&target_path.path, value),
251                PathPrefix::Metadata => panic!("Value has no metadata. Use `TargetValue` instead."),
252            };
253            Ok(())
254        }
255
256        fn target_get(&self, target_path: &OwnedTargetPath) -> Result<Option<&Value>, String> {
257            match target_path.prefix {
258                PathPrefix::Event => Ok(self.get(&target_path.path)),
259                PathPrefix::Metadata => panic!("Value has no metadata. Use `TargetValue` instead."),
260            }
261        }
262
263        fn target_get_mut(
264            &mut self,
265            target_path: &OwnedTargetPath,
266        ) -> Result<Option<&mut Value>, String> {
267            match target_path.prefix {
268                PathPrefix::Event => Ok(self.get_mut(&target_path.path)),
269                PathPrefix::Metadata => panic!("Value has no metadata. Use `TargetValue` instead."),
270            }
271        }
272
273        fn target_remove(
274            &mut self,
275            target_path: &OwnedTargetPath,
276            compact: bool,
277        ) -> Result<Option<Value>, String> {
278            match target_path.prefix {
279                PathPrefix::Event => Ok(self.remove(&target_path.path, compact)),
280                PathPrefix::Metadata => panic!("Value has no metadata. Use `TargetValue` instead."),
281            }
282        }
283    }
284
285    impl SecretTarget for Value {
286        fn get_secret(&self, _key: &str) -> Option<&str> {
287            panic!("Value has no secrets. Use `TargetValue` instead.")
288        }
289
290        fn insert_secret(&mut self, _key: &str, _value: &str) {
291            panic!("Value has no secrets. Use `TargetValue` instead.")
292        }
293
294        fn remove_secret(&mut self, _key: &str) {
295            panic!("Value has no secrets. Use `TargetValue` instead.")
296        }
297    }
298}
299
300#[cfg(test)]
301mod tests {
302    #![allow(clippy::print_stdout)] // tests
303
304    use crate::{
305        compiler::{TypeDef, parser::Ident, state::LocalEnv, type_def::Details},
306        owned_value_path,
307    };
308
309    use super::*;
310    use crate::value;
311
312    #[test]
313    fn get() {
314        let cases = vec![
315            (value!(true), owned_value_path!(), Ok(Some(value!(true)))),
316            (value!(true), owned_value_path!("foo"), Ok(None)),
317            (value!({}), owned_value_path!(), Ok(Some(value!({})))),
318            (
319                value!({foo: "bar"}),
320                owned_value_path!(),
321                Ok(Some(value!({foo: "bar"}))),
322            ),
323            (
324                value!({foo: "bar"}),
325                owned_value_path!("foo"),
326                Ok(Some(value!("bar"))),
327            ),
328            (value!({foo: "bar"}), owned_value_path!("bar"), Ok(None)),
329            (
330                value!([1, 2, 3, 4, 5]),
331                owned_value_path!(1),
332                Ok(Some(value!(2))),
333            ),
334            (
335                value!({foo: [{bar: true}]}),
336                owned_value_path!("foo", 0, "bar"),
337                Ok(Some(value!(true))),
338            ),
339        ];
340
341        for (value, path, expect) in cases {
342            let value: Value = value;
343            let target = TargetValue {
344                value,
345                metadata: value!({}),
346                secrets: Secrets::new(),
347            };
348            let path = OwnedTargetPath::event(path);
349
350            assert_eq!(
351                target.target_get(&path).map(Option::<&Value>::cloned),
352                expect
353            );
354        }
355    }
356
357    #[test]
358    #[allow(clippy::too_many_lines)]
359    fn insert() {
360        let cases = vec![
361            (
362                value!({foo: "bar"}),
363                owned_value_path!(),
364                value!({baz: "qux"}),
365                value!({baz: "qux"}),
366                Ok(()),
367            ),
368            (
369                value!({foo: "bar"}),
370                owned_value_path!("baz"),
371                true.into(),
372                value!({foo: "bar", baz: true}),
373                Ok(()),
374            ),
375            (
376                value!({foo: [{bar: "baz"}]}),
377                owned_value_path!("foo", 0, "baz"),
378                true.into(),
379                value!({foo: [{bar: "baz", baz: true}]}),
380                Ok(()),
381            ),
382            (
383                value!({foo: {bar: "baz"}}),
384                owned_value_path!("bar", "baz"),
385                true.into(),
386                value!({foo: {bar: "baz"}, bar: {baz: true}}),
387                Ok(()),
388            ),
389            (
390                value!({foo: "bar"}),
391                owned_value_path!("foo"),
392                "baz".into(),
393                value!({foo: "baz"}),
394                Ok(()),
395            ),
396            (
397                value!({foo: "bar"}),
398                owned_value_path!("foo", 2, "bar baz", "a", "b"),
399                true.into(),
400                value!({foo: [null, null, {"bar baz": {"a": {"b": true}}}]}),
401                Ok(()),
402            ),
403            (
404                value!({foo: [0, 1, 2]}),
405                owned_value_path!("foo", 5),
406                "baz".into(),
407                value!({foo: [0, 1, 2, null, null, "baz"]}),
408                Ok(()),
409            ),
410            (
411                value!({foo: "bar"}),
412                owned_value_path!("foo", 0),
413                "baz".into(),
414                value!({foo: ["baz"]}),
415                Ok(()),
416            ),
417            (
418                value!({foo: []}),
419                owned_value_path!("foo", 0),
420                "baz".into(),
421                value!({foo: ["baz"]}),
422                Ok(()),
423            ),
424            (
425                value!({foo: [0]}),
426                owned_value_path!("foo", 0),
427                "baz".into(),
428                value!({foo: ["baz"]}),
429                Ok(()),
430            ),
431            (
432                value!({foo: [0, 1]}),
433                owned_value_path!("foo", 0),
434                "baz".into(),
435                value!({foo: ["baz", 1]}),
436                Ok(()),
437            ),
438            (
439                value!({foo: [0, 1]}),
440                owned_value_path!("foo", 1),
441                "baz".into(),
442                value!({foo: [0, "baz"]}),
443                Ok(()),
444            ),
445        ];
446
447        for (target, path, value, expect, result) in cases {
448            let mut target = TargetValue {
449                value: target,
450                metadata: value!({}),
451                secrets: Secrets::new(),
452            };
453            let path = OwnedTargetPath::event(path);
454
455            assert_eq!(
456                Target::target_insert(&mut target, &path, value.clone()),
457                result
458            );
459            assert_eq!(target.value, expect);
460            assert_eq!(
461                Target::target_get(&target, &path).map(Option::<&Value>::cloned),
462                Ok(Some(value))
463            );
464        }
465    }
466
467    #[test]
468    fn remove() {
469        let cases = vec![
470            (
471                value!({foo: "bar"}),
472                owned_value_path!("baz"),
473                false,
474                None,
475                Some(value!({foo: "bar"})),
476            ),
477            (
478                value!({foo: "bar"}),
479                owned_value_path!("foo"),
480                false,
481                Some(value!("bar")),
482                Some(value!({})),
483            ),
484            (
485                value!({foo: "bar", baz: "qux"}),
486                owned_value_path!(),
487                false,
488                Some(value!({foo: "bar", baz: "qux"})),
489                Some(value!({})),
490            ),
491            (
492                value!({foo: "bar", baz: "qux"}),
493                owned_value_path!(),
494                true,
495                Some(value!({foo: "bar", baz: "qux"})),
496                Some(value!({})),
497            ),
498            (
499                value!({foo: [0]}),
500                owned_value_path!("foo", 0),
501                false,
502                Some(value!(0)),
503                Some(value!({foo: []})),
504            ),
505            (
506                value!({foo: [0]}),
507                owned_value_path!("foo", 0),
508                true,
509                Some(value!(0)),
510                Some(value!({})),
511            ),
512            (
513                value!({foo: {"bar baz": [0]}, bar: "baz"}),
514                owned_value_path!("foo", "bar baz", 0),
515                false,
516                Some(value!(0)),
517                Some(value!({foo: {"bar baz": []}, bar: "baz"})),
518            ),
519            (
520                value!({foo: {"bar baz": [0]}, bar: "baz"}),
521                owned_value_path!("foo", "bar baz", 0),
522                true,
523                Some(value!(0)),
524                Some(value!({bar: "baz"})),
525            ),
526        ];
527
528        for (target, path, compact, value, expect) in cases {
529            let path = OwnedTargetPath::event(path);
530
531            let mut target = TargetValue {
532                value: target,
533                metadata: value!({}),
534                secrets: Secrets::new(),
535            };
536            assert_eq!(
537                Target::target_remove(&mut target, &path, compact),
538                Ok(value)
539            );
540            assert_eq!(
541                Target::target_get(&target, &OwnedTargetPath::event_root())
542                    .map(Option::<&Value>::cloned),
543                Ok(expect)
544            );
545        }
546    }
547
548    #[test]
549    fn merge_multiple_local_env() {
550        let mut a = LocalEnv::default();
551        a.insert_variable(
552            Ident("foo".into()),
553            Details {
554                type_def: TypeDef::any(),
555                value: None,
556            },
557        );
558
559        let mut b = LocalEnv::default();
560        b.insert_variable(
561            Ident("bar".into()),
562            Details {
563                type_def: TypeDef::any(),
564                value: None,
565            },
566        );
567
568        let merged = a.merge(b);
569        assert_eq!(merged.bindings.len(), 2);
570    }
571}