vector_config/schema/parser/
component.rs1use std::borrow::Cow;
2
3use serde_json::Value;
4use snafu::Snafu;
5use vector_config_common::{
6 attributes::CustomAttribute,
7 constants::{self, ComponentType},
8 schema::SchemaObject,
9};
10
11use super::query::{OneOrMany, QueryError, QueryableSchema, SchemaType, SimpleSchema};
12
13#[derive(Debug, Snafu)]
14pub enum SchemaError {
15 #[snafu(display("invalid component schema: {pointer}: {reason}"))]
16 InvalidComponentSchema {
17 pointer: &'static str,
18 reason: Cow<'static, str>,
19 },
20}
21
22impl SchemaError {
23 pub fn invalid_component_schema<S: Into<Cow<'static, str>>>(
24 pointer: &'static str,
25 reason: S,
26 ) -> Self {
27 Self::InvalidComponentSchema {
28 pointer,
29 reason: reason.into(),
30 }
31 }
32}
33
34pub struct ComponentSchema<'a> {
41 schema: &'a SchemaObject,
42 component_name: String,
43 component_type: ComponentType,
44}
45
46impl ComponentSchema<'_> {
47 pub fn component_type(&self) -> ComponentType {
49 self.component_type
50 }
51
52 pub fn component_name(&self) -> &str {
59 &self.component_name
60 }
61}
62
63impl QueryableSchema for ComponentSchema<'_> {
64 fn schema_type(&self) -> SchemaType {
65 self.schema.schema_type()
66 }
67
68 fn description(&self) -> Option<&str> {
69 self.schema.description()
70 }
71
72 fn title(&self) -> Option<&str> {
73 self.schema.title()
74 }
75
76 fn get_attributes(&self, key: &str) -> Option<OneOrMany<CustomAttribute>> {
77 self.schema.get_attributes(key)
78 }
79
80 fn get_attribute(&self, key: &str) -> Result<Option<CustomAttribute>, QueryError> {
81 self.schema.get_attribute(key)
82 }
83
84 fn has_flag_attribute(&self, key: &str) -> Result<bool, QueryError> {
85 self.schema.has_flag_attribute(key)
86 }
87}
88
89impl<'a> TryFrom<SimpleSchema<'a>> for ComponentSchema<'a> {
90 type Error = SchemaError;
91
92 fn try_from(value: SimpleSchema<'a>) -> Result<Self, Self::Error> {
93 let component_type =
95 get_component_metadata_kv_str(&value, constants::DOCS_META_COMPONENT_TYPE).and_then(
96 |s| {
97 ComponentType::try_from(s.as_str()).map_err(|_| {
98 SchemaError::invalid_component_schema(
99 constants::DOCS_META_COMPONENT_TYPE,
100 "value was not a valid component type",
101 )
102 })
103 },
104 )?;
105
106 let component_name =
107 get_component_metadata_kv_str(&value, constants::DOCS_META_COMPONENT_NAME)?;
108
109 Ok(Self {
110 schema: value.into_inner(),
111 component_name,
112 component_type,
113 })
114 }
115}
116
117fn get_component_metadata_kv_str<'a>(
118 schema: &'a SimpleSchema<'a>,
119 key: &'static str,
120) -> Result<String, SchemaError> {
121 schema
122 .get_attribute(key)
123 .map_err(|e| SchemaError::invalid_component_schema(key, e.to_string()))?
124 .ok_or_else(|| SchemaError::invalid_component_schema(key, "attribute must be present"))
125 .and_then(|attr| match attr {
126 CustomAttribute::Flag(_) => Err(SchemaError::invalid_component_schema(
127 key,
128 "expected key/value attribute, got flag instead",
129 )),
130 CustomAttribute::KeyValue { value, .. } => Ok(value),
131 })
132 .and_then(|v| match v {
133 Value::String(name) => Ok(name),
134 _ => Err(SchemaError::invalid_component_schema(
135 key,
136 format!("`{key}` must be a string"),
137 )),
138 })
139}