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 MetadataValidationError,
31 MetadataValidationResult,
32};
33
34#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
40pub struct MetadataSchema {
41 fields: BTreeMap<String, MetadataField>,
43 unknown_field_policy: UnknownFieldPolicy,
45}
46
47impl MetadataSchema {
48 #[inline]
50 #[must_use]
51 pub fn builder() -> MetadataSchemaBuilder {
52 MetadataSchemaBuilder::default()
53 }
54
55 #[inline]
57 pub(crate) fn new(fields: BTreeMap<String, MetadataField>, unknown_field_policy: UnknownFieldPolicy) -> Self {
58 Self {
59 fields,
60 unknown_field_policy,
61 }
62 }
63
64 #[inline]
66 #[must_use]
67 pub fn field(&self, key: &str) -> Option<&MetadataField> {
68 self.fields.get(key)
69 }
70
71 #[inline]
73 #[must_use]
74 pub fn field_type(&self, key: &str) -> Option<DataType> {
75 self.field(key).map(MetadataField::data_type)
76 }
77
78 #[inline]
80 #[must_use]
81 pub fn unknown_field_policy(&self) -> UnknownFieldPolicy {
82 self.unknown_field_policy
83 }
84
85 #[inline]
87 pub fn fields(&self) -> impl Iterator<Item = (&str, &MetadataField)> {
88 self.fields.iter().map(|(key, field)| (key.as_str(), field))
89 }
90
91 pub fn validate(&self, meta: &Metadata) -> MetadataValidationResult<()> {
98 let mut issues = Vec::new();
99 for (key, field) in &self.fields {
100 if field.is_required() && !meta.contains_key(key) {
101 issues.push(MetadataError::MissingRequiredField {
102 key: key.clone(),
103 expected: field.data_type(),
104 });
105 }
106 }
107
108 for (key, value) in meta.iter() {
109 if let Err(error) = self.validate_entry(key, value) {
110 issues.push(error);
111 }
112 }
113 if let Some(error) = MetadataValidationError::from_issues(issues) {
114 Err(error)
115 } else {
116 Ok(())
117 }
118 }
119
120 pub(crate) fn validate_entry(&self, key: &str, value: &Value) -> MetadataResult<()> {
122 match self.field(key) {
123 Some(field) if field.data_type() != value.data_type() => {
124 Err(MetadataError::type_mismatch(key, field.data_type(), value.data_type()))
125 }
126 Some(_) => Ok(()),
127 None if matches!(self.unknown_field_policy, UnknownFieldPolicy::Reject) => {
128 Err(MetadataError::UnknownField { key: key.to_string() })
129 }
130 None => Ok(()),
131 }
132 }
133}
134
135impl Default for MetadataSchema {
136 #[inline]
137 fn default() -> Self {
138 Self {
139 fields: BTreeMap::new(),
140 unknown_field_policy: UnknownFieldPolicy::Reject,
141 }
142 }
143}