1use std::collections::{BTreeMap, BTreeSet};
2use std::str::FromStr;
3use bigdecimal::{BigDecimal, FromPrimitive};
4use bson::oid::ObjectId;
5use chrono::{DateTime, NaiveDate, Utc};
6use indexmap::IndexMap;
7use key_path::KeyPath;
8use maplit::btreemap;
9use teo_parser::ast::schema::Schema;
10use teo_parser::r#type::synthesized_enum::SynthesizedEnum;
11use teo_parser::r#type::synthesized_enum_reference::SynthesizedEnumReference;
12use teo_parser::r#type::synthesized_interface_enum::SynthesizedInterfaceEnum;
13use teo_parser::r#type::synthesized_interface_enum_reference::SynthesizedInterfaceEnumReference;
14use teo_parser::r#type::synthesized_shape::SynthesizedShape;
15use teo_parser::r#type::synthesized_shape_reference::SynthesizedShapeReference;
16use teo_parser::r#type::Type;
17use teo_parser::traits::resolved::Resolve;
18use crate::value::Value;
19use crate::value::file::File;
20use crate::interface::Interface;
21use crate::namespace::Namespace;
22use teo_result::Error;
23use crate::namespace;
24use crate::utils::ContainsStr;
25
26
27pub fn fetch_synthesized_interface_enum<'a>(reference: &SynthesizedInterfaceEnumReference, schema: &'a Schema) -> &'a SynthesizedInterfaceEnum {
28 let model = schema.find_top_by_path(reference.owner.as_model_object().unwrap().path()).unwrap().as_model().unwrap();
29 model.resolved().interface_enums.get(&reference.kind).unwrap()
30}
31
32pub fn fetch_synthesized_enum<'a>(reference: &SynthesizedEnumReference, main_namespace: &'a namespace::Builder) -> SynthesizedEnum {
33 let model = main_namespace.model_at_path(&reference.owner.as_model_object().unwrap().string_path()).unwrap();
34 model.cache().shape.enums.get(&reference.kind).unwrap().clone()
35}
36
37pub fn fetch_synthesized_enum_from_namespace<'a>(reference: &SynthesizedEnumReference, main_namespace: &'a Namespace) -> &'a SynthesizedEnum {
38 let model = main_namespace.model_at_path(&reference.owner.as_model_object().unwrap().string_path()).unwrap();
39 model.cache().shape.enums.get(&reference.kind).unwrap()
40}
41
42pub fn fetch_input<'a>(reference: &SynthesizedShapeReference, main_namespace: &'a Namespace) -> &'a Type {
43 let model = main_namespace.model_at_path(&reference.owner.as_model_object().unwrap().string_path()).unwrap();
44 if reference.kind.requires_without() {
45 model.cache().shape.get_without(reference.kind, reference.without.as_ref().unwrap()).unwrap()
46 } else {
47 model.cache().shape.get(reference.kind).unwrap()
48 }
49}
50
51pub fn json_to_teon_with_type(json: &serde_json::Value, path: &KeyPath, t: &Type, main_namespace: &Namespace) -> teo_result::Result<Value> {
52 match t {
53 Type::Undetermined => Ok(Value::from(json)),
54 Type::Ignored => Ok(Value::from(json)),
55 Type::Any => Ok(Value::from(json)),
56 Type::Null => if json.is_null() { Ok(Value::Null) } else { Err(Error::invalid_request_pathed(path.clone(), "expect null")) },
57 Type::Bool => if json.is_boolean() { Ok(Value::from(json)) } else { Err(Error::invalid_request_pathed(path.clone(), "expect bool")) },
58 Type::Int => if json.is_i64() { Ok(Value::Int(json.as_i64().unwrap() as i32)) } else { Err(Error::invalid_request_pathed(path.clone(), "expect int")) },
59 Type::Int64 => if json.is_i64() { Ok(Value::Int64(json.as_i64().unwrap())) } else { Err(Error::invalid_request_pathed(path.clone(), "expect int 64")) },
60 Type::Float32 => if json.is_f64() { Ok(Value::Float32(json.as_f64().unwrap() as f32)) } else if json.is_i64() { Ok(Value::Float32(json.as_i64().unwrap() as f32)) } else { Err(Error::invalid_request_pathed(path.clone(), "expect float 32")) },
61 Type::Float => if json.is_f64() { Ok(Value::Float(json.as_f64().unwrap())) } else if json.is_i64() { Ok(Value::Float(json.as_i64().unwrap() as f64)) } else { Err(Error::invalid_request_pathed(path.clone(), "expect float")) },
62 Type::Decimal => if json.is_string() {
63 Ok(Value::Decimal(match BigDecimal::from_str(json.as_str().unwrap()) {
64 Ok(s) => s,
65 Err(_) => Err(Error::invalid_request_pathed(path.clone(), "string is not valid decimal"))?,
66 }))
67 } else if json.is_number() {
68 if let Some(f) = json.as_f64() {
69 Ok(Value::Decimal(match BigDecimal::from_f64(f) {
70 Some(s) => s,
71 None => Err(Error::invalid_request_pathed(path.clone(), "number is not valid decimal"))?,
72 }))
73 } else if let Some(i) = json.as_i64() {
74 Ok(Value::Decimal(match BigDecimal::from_i64(i) {
75 Some(s) => s,
76 None => Err(Error::invalid_request_pathed(path.clone(), "number is not valid decimal"))?,
77 }))
78 } else {
79 unreachable!()
80 }
81 } else if let Some(object) = json.as_object() {
82 if object.keys().len() > 1 {
83 Err(Error::invalid_request_pathed(path.clone(), "wrong decimal object format"))?
84 }
85 if let Some(decimal) = object.get("$decimal") {
86 if decimal.is_string() {
87 Ok(Value::Decimal(match BigDecimal::from_str(decimal.as_str().unwrap()) {
88 Ok(s) => s,
89 Err(_) => Err(Error::invalid_request_pathed(path.clone(), "string is not valid decimal"))?,
90 }))
91 } else {
92 Err(Error::invalid_request_pathed(path.clone(), "wrong decimal object format"))?
93 }
94 } else {
95 Err(Error::invalid_request_pathed(path.clone(), "wrong decimal object format"))?
96 }
97 } else {
98 Err(Error::invalid_request_pathed(path.clone(), "expect string or number which represents decimal"))
99 }
100 Type::String => if json.is_string() { Ok(Value::String(json.as_str().unwrap().to_owned())) } else { Err(Error::invalid_request_pathed(path.clone(), "expect string")) },
101 Type::ObjectId => if json.is_string() {
102 Ok(Value::ObjectId(match ObjectId::parse_str(json.as_str().unwrap()) {
103 Ok(s) => s,
104 Err(_) => Err(Error::invalid_request_pathed(path.clone(), "string is not valid object id"))?,
105 }))
106 } else {
107 Err(Error::invalid_request_pathed(path.clone(), "expect string represents object id"))
108 }
109 Type::Date => if json.is_string() {
110 Ok(Value::Date(match NaiveDate::parse_from_str(json.as_str().unwrap(), "%Y-%m-%d") {
111 Ok(s) => s,
112 Err(_) => Err(Error::invalid_request_pathed(path.clone(), "string is not valid date"))?,
113 }))
114 } else if let Some(object) = json.as_object() {
115 if object.keys().len() > 1 {
116 Err(Error::invalid_request_pathed(path.clone(), "wrong date object format"))?
117 }
118 if let Some(date) = object.get("$date") {
119 if date.is_string() {
120 Ok(Value::Date(match NaiveDate::parse_from_str(date.as_str().unwrap(), "%Y-%m-%d") {
121 Ok(s) => s,
122 Err(_) => Err(Error::invalid_request_pathed(path.clone(), "string is not valid date"))?,
123 }))
124 } else {
125 Err(Error::invalid_request_pathed(path.clone(), "wrong date object format"))?
126 }
127 } else {
128 Err(Error::invalid_request_pathed(path.clone(), "wrong date object format"))?
129 }
130 } else {
131 Err(Error::invalid_request_pathed(path.clone(), "expect string represents date"))
132 }
133 Type::DateTime => if json.is_string() {
134 Ok(Value::DateTime(match DateTime::parse_from_rfc3339(json.as_str().unwrap()) {
135 Ok(d) => d.with_timezone(&Utc),
136 Err(_) => Err(Error::invalid_request_pathed(path.clone(), "string is not valid datetime"))?,
137 }))
138 } else if let Some(object) = json.as_object() {
139 if object.keys().len() > 1 {
140 Err(Error::invalid_request_pathed(path.clone(), "wrong datetime object format"))?
141 }
142 if let Some(datetime) = object.get("$datetime") {
143 if datetime.is_string() {
144 Ok(Value::DateTime(match DateTime::parse_from_rfc3339(datetime.as_str().unwrap()) {
145 Ok(d) => d.with_timezone(&Utc),
146 Err(_) => Err(Error::invalid_request_pathed(path.clone(), "string is not valid datetime"))?,
147 }))
148 } else {
149 Err(Error::invalid_request_pathed(path.clone(), "wrong datetime object format"))?
150 }
151 } else {
152 Err(Error::invalid_request_pathed(path.clone(), "wrong datetime object format"))?
153 }
154 } else {
155 Err(Error::invalid_request_pathed(path.clone(), "expect string or object represents datetime"))
156 }
157 Type::File => {
158 Ok(Value::File(match File::try_from(json) {
159 Ok(f) => f,
160 Err(err) => Err(Error::invalid_request_pathed(path.clone(), err.message()))?,
161 }))
162 },
163 Type::Enumerable(inner) => {
164 if let Some(json_array) = json.as_array() {
165 let values: Vec<Value> = json_array.iter().enumerate().map(|(i, j)| Ok(json_to_teon_with_type(j, &(path + i), inner.as_ref(), main_namespace)?)).collect::<teo_result::Result<Vec<Value>>>()?;
166 Ok(Value::Array(values))
167 } else {
168 Ok(Value::Array(vec![json_to_teon_with_type(json, path, inner.as_ref(), main_namespace)?]))
169 }
170 }
171 Type::Array(inner) => {
172 if let Some(json_array) = json.as_array() {
173 let values: Vec<Value> = json_array.iter().enumerate().map(|(i, j)| json_to_teon_with_type(j, &(path + i), inner.as_ref(), main_namespace)).collect::<teo_result::Result<Vec<Value>>>()?;
174 Ok(Value::Array(values))
175 } else {
176 Err(Error::invalid_request_pathed(path.clone(), "expect array"))
177 }
178 }
179 Type::Dictionary(inner) => {
180 if let Some(json_object) = json.as_object() {
181 let values: IndexMap<String, Value> = json_object.iter().map(|(k, j)| Ok((k.clone(), json_to_teon_with_type(j, &(path + k), inner.as_ref(), main_namespace)?))).collect::<teo_result::Result<IndexMap<String, Value>>>()?;
182 Ok(Value::Dictionary(values))
183 } else {
184 Err(Error::invalid_request_pathed(path.clone(), "expect dictionary"))
185 }
186 }
187 Type::Tuple(_) => Err(Error::invalid_request_pathed(path.clone(), "unexpected type"))?,
188 Type::Range(_) => Err(Error::invalid_request_pathed(path.clone(), "unexpected type"))?,
189 Type::Union(inners) => {
190 for inner in inners {
191 if let Ok(result) = json_to_teon_with_type(json, path, inner, main_namespace) {
192 return Ok(result);
193 }
194 }
195 Err(Error::invalid_request_pathed(path.clone(), "unexpected value"))
196 }
197 Type::EnumVariant(reference) => if json.is_string() {
198 let e = main_namespace.enum_at_path(reference.string_path()).unwrap();
199 if e.member_names().contains_str(json.as_str().unwrap()) {
200 Ok(Value::String(json.as_str().unwrap().to_owned()))
201 } else {
202 Err(Error::invalid_request_pathed(path.clone(), "expect enum member"))
203 }
204 } else {
205 Err(Error::invalid_request_pathed(path.clone(), "expect string represents enum member"))
206 }
207 Type::InterfaceObject(reference, gens) => {
208 let i = main_namespace.interface_at_path(&reference.string_path()).unwrap();
209 let shape = collect_interface_shape(i, gens);
210 json_to_teon_with_shape(json, path, &shape, main_namespace)
211 }
212 Type::Optional(inner) => {
213 if json.is_null() {
214 Ok(Value::Null)
215 } else {
216 json_to_teon_with_type(json, path, inner.as_ref(), main_namespace)
217 }
218 },
219 Type::SynthesizedShapeReference(shape_reference) => {
220 let input = fetch_input(shape_reference, main_namespace);
221 json_to_teon(json, path, input, main_namespace)
222 },
223 Type::SynthesizedEnumReference(enum_reference) => {
224 let synthesized_enum = fetch_synthesized_enum_from_namespace(enum_reference, main_namespace);
225 json_to_teon_with_synthesized_enum(json, path, synthesized_enum)
226 },
227 Type::SynthesizedEnum(synthesized_enum) => json_to_teon_with_synthesized_enum(json, path, synthesized_enum),
228 Type::SynthesizedShape(synthesized_shape) => json_to_teon_with_shape(json, path, synthesized_shape, main_namespace),
229 Type::DeclaredSynthesizedShape(synthesized_shape_reference, model_type) => {
230 if let Some(model_reference) = model_type.as_model_object() {
231 let m = main_namespace.model_at_path(model_reference.string_path()).unwrap();
232 if let Some(shape) = m.cache().shape.get_declared(synthesized_shape_reference.string_path()) {
233 json_to_teon_with_shape(json, path, shape, main_namespace)
234 } else {
235 Err(Error::invalid_request_pathed(path.clone(), "unexpected type"))?
236 }
237 } else {
238 Err(Error::invalid_request_pathed(path.clone(), "unexpected type"))?
239 }
240 },
241 _ => Err(Error::invalid_request_pathed(path.clone(), "unexpected type"))?,
242 }
243}
244
245fn json_to_teon_with_synthesized_enum(json: &serde_json::Value, path: &KeyPath, synthesized_enum: &SynthesizedEnum) -> teo_result::Result<Value> {
246 if json.is_string() {
247 let name = json.as_str().unwrap();
248 if synthesized_enum.keys.contains_str(name) {
249 return Ok(Value::String(name.to_owned()));
250 }
251 }
252 Err(Error::invalid_request_pathed(path.clone(), "expect string enum variant"))
253}
254
255pub fn json_to_teon_with_shape(json: &serde_json::Value, path: &KeyPath, shape: &SynthesizedShape, main_namespace: &Namespace) -> teo_result::Result<Value> {
256 if let Some(object) = json.as_object() {
257 let required_keys: BTreeSet<&str> = shape.iter().filter_map(|(k, v)| if !v.is_optional() {
258 Some(k.as_str())
259 } else {
260 None
261 }).collect();
262 let all_keys: BTreeSet<&str> = shape.keys().map(AsRef::as_ref).collect();
263 let passed_in_keys: BTreeSet<&str> = object.keys().map(AsRef::as_ref).collect();
264 let unallowed_keys: Vec<&str> = passed_in_keys.difference(&all_keys).map(|s| *s).collect();
265 if let Some(unallowed) = unallowed_keys.first() {
266 return Err(Error::invalid_request_pathed(path + *unallowed, "unexpected key"));
267 }
268 let not_provided_keys: Vec<&str> = required_keys.difference(&passed_in_keys).map(|s| *s).collect();
269 if let Some(not_provided) = not_provided_keys.first() {
270 return Err(Error::invalid_request_pathed(path + *not_provided, "expect value"));
271 }
272 let map: IndexMap<String, Value> = object.iter().map(|(k, v)| Ok((k.to_owned(), json_to_teon(v, &(path + k), shape.get(k).unwrap(), main_namespace)?))).collect::<teo_result::Result<IndexMap<String, Value>>>()?;
273 Ok(Value::Dictionary(map))
274 } else {
275 Err(Error::invalid_request_pathed(path.clone(), "unexpected value"))
276 }
277
278}
279
280pub fn json_to_teon(json: &serde_json::Value, path: &KeyPath, input: &Type, main_namespace: &Namespace) -> teo_result::Result<Value> {
281 json_to_teon_with_type(json, path, input, main_namespace)
282}
283
284fn collect_interface_shape(interface: &Interface, gens: &Vec<Type>) -> SynthesizedShape {
285 interface.shape_from_generics(gens)
286}