qubit_metadata/schema/
metadata_schema.rs1use std::collections::BTreeMap;
13
14use qubit_datatype::DataType;
15use qubit_value::Value;
16use serde::{
17 Deserialize,
18 Serialize,
19};
20
21use crate::schema::{
22 MetadataField,
23 MetadataSchemaBuilder,
24 UnknownFieldPolicy,
25};
26use crate::{
27 Metadata,
28 MetadataError,
29 MetadataResult,
30};
31
32#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
38pub struct MetadataSchema {
39 fields: BTreeMap<String, MetadataField>,
41 unknown_field_policy: UnknownFieldPolicy,
43}
44
45impl MetadataSchema {
46 #[inline]
48 #[must_use]
49 pub fn builder() -> MetadataSchemaBuilder {
50 MetadataSchemaBuilder::default()
51 }
52
53 #[inline]
55 pub(crate) fn new(
56 fields: BTreeMap<String, MetadataField>,
57 unknown_field_policy: UnknownFieldPolicy,
58 ) -> Self {
59 Self {
60 fields,
61 unknown_field_policy,
62 }
63 }
64
65 #[inline]
67 #[must_use]
68 pub fn field(&self, key: &str) -> Option<&MetadataField> {
69 self.fields.get(key)
70 }
71
72 #[inline]
74 #[must_use]
75 pub fn field_type(&self, key: &str) -> Option<DataType> {
76 self.field(key).map(MetadataField::data_type)
77 }
78
79 #[inline]
81 #[must_use]
82 pub fn unknown_field_policy(&self) -> UnknownFieldPolicy {
83 self.unknown_field_policy
84 }
85
86 #[inline]
88 pub fn fields(&self) -> impl Iterator<Item = (&str, &MetadataField)> {
89 self.fields.iter().map(|(key, field)| (key.as_str(), field))
90 }
91
92 pub fn validate(&self, meta: &Metadata) -> MetadataResult<()> {
100 for (key, field) in &self.fields {
101 if field.is_required() && !meta.contains_key(key) {
102 return Err(MetadataError::MissingRequiredField {
103 key: key.clone(),
104 expected: field.data_type(),
105 });
106 }
107 }
108
109 for (key, value) in meta.iter() {
110 self.validate_entry(key, value)?;
111 }
112 Ok(())
113 }
114
115 pub(crate) fn validate_entry(&self, key: &str, value: &Value) -> MetadataResult<()> {
117 match self.field(key) {
118 Some(field) if field.data_type() != value.data_type() => Err(
119 MetadataError::type_mismatch(key, field.data_type(), value.data_type()),
120 ),
121 Some(_) => Ok(()),
122 None if matches!(self.unknown_field_policy, UnknownFieldPolicy::Reject) => {
123 Err(MetadataError::UnknownField {
124 key: key.to_string(),
125 })
126 }
127 None => Ok(()),
128 }
129 }
130}
131
132impl Default for MetadataSchema {
133 #[inline]
134 fn default() -> Self {
135 Self {
136 fields: BTreeMap::new(),
137 unknown_field_policy: UnknownFieldPolicy::Reject,
138 }
139 }
140}