1use std::str::FromStr;
2
3use crate::elements::{Document, Element, Field, FieldContent, FieldImpl, Item, Section};
4use crate::queries::{AttributeQuery, AttributeQueryImpl, SectionQuery, SectionQueryImpl};
5use crate::{Error, Printer};
6
7pub struct FieldQuery<'a> {
8 element_option: Option<&'a Field>,
9 key: Option<String>,
10 parent: FieldQueryParent<'a>,
11}
12
13pub trait FieldQueryImpl<'a> {
14 fn element(&self) -> Option<&Field>;
15 #[allow(clippy::new_ret_no_self)]
16 fn new(
17 element_option: Option<&'a Field>,
18 key: Option<String>,
19 parent: FieldQueryParent<'a>,
20 ) -> FieldQuery<'a>;
21}
22
23pub enum FieldQueryParent<'a> {
24 Document(&'a Document),
25 Section(&'a Section),
26 SectionQuery(&'a SectionQuery<'a>),
27}
28
29impl<'a> FieldQuery<'a> {
30 pub fn attribute(&self, key: &str) -> Result<AttributeQuery, Error> {
31 let element_option = match self.element_option {
32 Some(field) => match &field.get_content() {
33 FieldContent::Attributes(attributes) => {
34 let mut attribute_option = None;
35 for attribute in attributes {
36 if attribute.key() == key {
37 match attribute_option {
38 Some(_) => {
39 return Err(Error::new(
40 format!("Multiple attributes with key {} found", key),
41 attribute.line_number,
42 ))
43 }
44 None => {
45 attribute.touch();
46 attribute_option = Some(attribute);
47 }
48 }
49 }
50 }
51 attribute_option
52 }
53 FieldContent::Items(items) => {
54 return Err(Error::new(
55 "Attributes expected, Items found".to_string(),
56 items[0].line_number,
57 ))
58 }
59 FieldContent::Value { .. } => {
60 return Err(Error::new(
61 "Attributes expected, Value found".to_string(),
62 field.line_number,
63 ))
64 }
65 FieldContent::None => None,
66 },
67 None => None,
68 };
69
70 if let Some(element) = element_option {
71 element.touch();
72 }
73
74 Ok(AttributeQuery::new(
75 element_option,
76 Some(key.to_string()),
77 self,
78 ))
79 }
80
81 pub fn attributes(&self) -> Result<Vec<crate::Attribute>, Error> {
82 match self.element_option {
83 Some(field) => match field.get_content() {
84 FieldContent::Attributes(attributes) => Ok(attributes.to_vec()),
85 FieldContent::None => Ok(vec![]),
86 FieldContent::Items(items) => Err(Error::new(
87 "Attributes expected, Items found".to_owned(),
88 items[0].line_number,
89 )),
90 FieldContent::Value { .. } => Err(Error::new(
91 "Attributes expected, Value found".to_owned(),
92 field.line_number,
93 )),
94 },
95 None => Ok(vec![]),
96 }
97 }
98
99 pub fn items(&self) -> Result<&[Item], Error> {
100 match self.element_option {
101 Some(field) => match &field.get_content() {
102 FieldContent::Attributes(attributes) => Err(Error::new(
103 "Items expected, Attributes found".to_string(),
104 attributes[0].line_number,
105 )),
106 FieldContent::Items(items) => {
107 for item in items.iter() {
108 item.touch();
109 }
110 Ok(items.as_slice())
111 }
112 FieldContent::Value { .. } => Err(Error::new(
113 "Items expected, Value found".to_string(),
114 field.line_number,
115 )),
116 FieldContent::None => Ok(&[]),
117 },
118 None => Ok(&[]),
119 }
120 }
121
122 pub fn missing_error(&self) -> Error {
123 match self.parent {
124 FieldQueryParent::Document(_) => Error::new(
125 format!(
126 "Field {} not found",
127 self.key.as_deref().unwrap_or("(can have any key)")
128 ),
129 Document::LINE_NUMBER,
130 ),
131 FieldQueryParent::Section(section) => Error::new(
132 format!(
133 "Field {} not found",
134 self.key.as_deref().unwrap_or("(can have any key)")
135 ),
136 section.line_number,
137 ),
138 FieldQueryParent::SectionQuery(section_query) => match section_query.element() {
139 Some(section) => Error::new(
140 format!(
141 "Field {} not found",
142 self.key.as_deref().unwrap_or("(can have any key)")
143 ),
144 section.line_number,
145 ),
146 None => section_query.missing_error(),
147 },
148 }
149 }
150
151 pub fn optional_value(&self) -> Result<Option<String>, Error> {
152 match &self.element_option {
153 Some(field) => match &field.get_content() {
154 FieldContent::Attributes(attributes) => Err(Error::new(
155 "Value expected, Attributes found".to_string(),
156 attributes[0].line_number,
157 )),
158 FieldContent::Items(items) => Err(Error::new(
159 "Value expected, Items found".to_string(),
160 items[0].line_number,
161 )),
162 FieldContent::Value(range) => {
163 Ok(Some(field.get_document_content()[range.clone()].to_owned()))
164 }
165 FieldContent::None => Ok(None),
166 },
167 None => Ok(None),
168 }
169 }
170
171 pub fn required_value<T: FromStr>(&self) -> Result<T, Error>
172 where
173 <T as FromStr>::Err: std::fmt::Display,
174 {
175 match &self.element_option {
176 Some(field) => match &field.get_content() {
177 FieldContent::Attributes(attributes) => Err(Error::new(
178 "Value expected, Attributes found".to_string(),
179 attributes[0].line_number,
180 )),
181 FieldContent::Items(items) => Err(Error::new(
182 "Value expected, Items found".to_string(),
183 items[0].line_number,
184 )),
185 FieldContent::Value(range) => {
186 let value = field.get_document_content()[range.clone()].to_owned();
187 match value.parse::<T>() {
188 Ok(converted) => Ok(converted),
189 Err(err) => Err(Error::new(format!("{}", err), field.line_number)),
190 }
191 }
192 FieldContent::None => {
193 Err(Error::new("Missing value".to_string(), field.line_number))
194 }
195 },
196 None => Err(self.missing_error()),
197 }
198 }
199
200 pub fn snippet(&self) -> Result<String, Error> {
201 match self.element_option {
202 Some(field) => Ok(field.snippet()),
203 None => Err(self.missing_error()),
204 }
205 }
206
207 pub fn snippet_with_options(
208 &self,
209 printer: &dyn Printer,
210 gutter: bool,
211 ) -> Result<String, Error> {
212 match self.element_option {
213 Some(field) => Ok(field.snippet_with_options(printer, gutter)),
214 None => Err(self.missing_error()),
215 }
216 }
217}
218
219impl<'a> FieldQueryImpl<'a> for FieldQuery<'a> {
220 fn element(&self) -> Option<&Field> {
221 self.element_option
222 }
223
224 fn new(
225 element_option: Option<&'a Field>,
226 key: Option<String>,
227 parent: FieldQueryParent<'a>,
228 ) -> FieldQuery<'a> {
229 FieldQuery {
230 element_option,
231 key,
232 parent,
233 }
234 }
235}