1use std::{
2 collections::HashMap,
3 fmt::{self, Display, Formatter},
4};
5
6use serde::{Deserialize, Serialize};
7
8pub mod entities;
9pub mod input;
10pub mod storage;
11pub mod utils;
12
13#[derive(Clone, Copy, Hash, Eq, PartialEq, PartialOrd, Debug, Default, Serialize, Deserialize)]
15pub enum Direction {
16 OUT,
17 IN,
18 #[default]
19 BOTH,
20}
21
22#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize)]
23pub enum PropType {
24 #[default]
25 Empty,
26 Str,
27 U8,
28 U16,
29 I32,
30 I64,
31 U32,
32 U64,
33 F32,
34 F64,
35 Bool,
36 List(Box<PropType>),
37 Map(HashMap<String, PropType>),
38 NDTime,
39 DTime,
40 Array(Box<PropType>),
41 Decimal {
42 scale: i64,
43 },
44}
45
46impl Display for PropType {
47 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
48 let type_str = match self {
49 PropType::Empty => "Empty",
50 PropType::Str => "Str",
51 PropType::U8 => "U8",
52 PropType::U16 => "U16",
53 PropType::I32 => "I32",
54 PropType::I64 => "I64",
55 PropType::U32 => "U32",
56 PropType::U64 => "U64",
57 PropType::F32 => "F32",
58 PropType::F64 => "F64",
59 PropType::Bool => "Bool",
60 PropType::List(p_type) => return write!(f, "List<{}>", p_type),
61 PropType::Map(p_type) => {
62 let mut types = p_type
63 .iter()
64 .map(|(k, v)| format!("{}: {}", k, v))
65 .collect::<Vec<String>>();
66 types.sort();
67 return write!(f, "Map{{ {} }}", types.join(", "));
68 }
69 PropType::NDTime => "NDTime",
70 PropType::DTime => "DTime",
71 PropType::Array(p_type) => return write!(f, "Array<{}>", p_type),
72 PropType::Decimal { scale } => return write!(f, "Decimal({})", scale),
73 };
74
75 write!(f, "{}", type_str)
76 }
77}
78
79impl PropType {
80 pub fn map(fields: impl IntoIterator<Item = (impl AsRef<str>, PropType)>) -> Self {
81 PropType::Map(
82 fields
83 .into_iter()
84 .map(|(k, v)| (k.as_ref().to_owned(), v))
85 .collect(),
86 )
87 }
88 pub fn is_numeric(&self) -> bool {
89 matches!(
90 self,
91 PropType::U8
92 | PropType::U16
93 | PropType::U32
94 | PropType::U64
95 | PropType::I32
96 | PropType::I64
97 | PropType::F32
98 | PropType::F64
99 | PropType::Decimal { .. }
100 )
101 }
102
103 pub fn is_str(&self) -> bool {
104 matches!(self, PropType::Str)
105 }
106
107 pub fn is_bool(&self) -> bool {
108 matches!(self, PropType::Bool)
109 }
110
111 pub fn is_date(&self) -> bool {
112 matches!(self, PropType::DTime | PropType::NDTime)
113 }
114
115 pub fn has_add(&self) -> bool {
116 self.is_numeric() || self.is_str()
117 }
118
119 pub fn has_divide(&self) -> bool {
120 self.is_numeric()
121 }
122
123 pub fn has_cmp(&self) -> bool {
124 self.is_bool() || self.is_numeric() || self.is_str() || self.is_date()
125 }
126}
127
128use crate::core::entities::properties::PropError;
129#[cfg(feature = "storage")]
130use polars_arrow::datatypes::ArrowDataType as DataType;
131
132#[cfg(feature = "storage")]
133impl From<&DataType> for PropType {
134 fn from(value: &DataType) -> Self {
135 match value {
136 DataType::Utf8 => PropType::Str,
137 DataType::LargeUtf8 => PropType::Str,
138 DataType::UInt8 => PropType::U8,
139 DataType::UInt16 => PropType::U16,
140 DataType::Int32 => PropType::I32,
141 DataType::Int64 => PropType::I64,
142 DataType::UInt32 => PropType::U32,
143 DataType::UInt64 => PropType::U64,
144 DataType::Float32 => PropType::F32,
145 DataType::Float64 => PropType::F64,
146 DataType::Boolean => PropType::Bool,
147
148 _ => PropType::Empty,
149 }
150 }
151}
152
153pub fn unify_types(l: &PropType, r: &PropType, unified: &mut bool) -> Result<PropType, PropError> {
157 match (l, r) {
158 (PropType::Empty, r) => {
159 *unified = true;
160 Ok(r.clone())
161 }
162 (l, PropType::Empty) => {
163 *unified = true;
164 Ok(l.clone())
165 }
166 (PropType::Str, PropType::Str) => Ok(PropType::Str),
167 (PropType::U8, PropType::U8) => Ok(PropType::U8),
168 (PropType::U16, PropType::U16) => Ok(PropType::U16),
169 (PropType::I32, PropType::I32) => Ok(PropType::I32),
170 (PropType::I64, PropType::I64) => Ok(PropType::I64),
171 (PropType::U32, PropType::U32) => Ok(PropType::U32),
172 (PropType::U64, PropType::U64) => Ok(PropType::U64),
173 (PropType::F32, PropType::F32) => Ok(PropType::F32),
174 (PropType::F64, PropType::F64) => Ok(PropType::F64),
175 (PropType::Bool, PropType::Bool) => Ok(PropType::Bool),
176 (PropType::NDTime, PropType::NDTime) => Ok(PropType::NDTime),
177 (PropType::DTime, PropType::DTime) => Ok(PropType::DTime),
178 (PropType::List(l_type), PropType::List(r_type)) => {
179 unify_types(l_type, r_type, unified).map(|t| PropType::List(Box::new(t)))
180 }
181 (PropType::Array(l_type), PropType::Array(r_type)) => {
182 unify_types(l_type, r_type, unified).map(|t| PropType::Array(Box::new(t)))
183 }
184 (PropType::Map(l_map), PropType::Map(r_map)) => {
185 let mut merged = HashMap::new();
188 for (k, v) in l_map.iter() {
189 if let Some(r_v) = r_map.get(k) {
190 let merged_prop = unify_types(v, r_v, unified)?;
191 merged.insert(k.clone(), merged_prop);
192 } else {
193 merged.insert(k.clone(), v.clone());
194 *unified = true;
195 }
196 }
197 for (k, v) in r_map.iter() {
198 if !merged.contains_key(k) {
199 merged.insert(k.clone(), v.clone());
200 *unified = true;
201 }
202 }
203 Ok(PropType::Map(merged))
204 }
205 (PropType::Decimal { scale: l_scale }, PropType::Decimal { scale: r_scale })
206 if l_scale == r_scale =>
207 {
208 Ok(PropType::Decimal { scale: *l_scale })
209 }
210 (_, _) => Err(PropError::PropertyTypeError {
211 name: "unknown".to_string(),
212 expected: l.clone(),
213 actual: r.clone(),
214 }),
215 }
216}
217
218#[cfg(test)]
219mod test {
220 use super::*;
221
222 #[test]
223 fn test_unify_types_ne() {
224 let l = PropType::List(Box::new(PropType::U8));
225 let r = PropType::List(Box::new(PropType::U16));
226 assert!(unify_types(&l, &r, &mut false).is_err());
227
228 let l = PropType::map([("a".to_string(), PropType::U8)]);
229 let r = PropType::map([("a".to_string(), PropType::U16)]);
230 assert!(unify_types(&l, &r, &mut false).is_err());
231
232 let l = PropType::List(Box::new(PropType::U8));
233 let r = PropType::List(Box::new(PropType::U16));
234 assert!(unify_types(&l, &r, &mut false).is_err());
235 }
236
237 #[test]
238 fn test_unify_types_eq() {
239 let l = PropType::List(Box::new(PropType::U8));
240 let r = PropType::List(Box::new(PropType::U8));
241 assert_eq!(
242 unify_types(&l, &r, &mut false),
243 Ok(PropType::List(Box::new(PropType::U8)))
244 );
245
246 let l = PropType::map([("a".to_string(), PropType::U8)]);
247 let r = PropType::map([("a".to_string(), PropType::U8)]);
248 assert_eq!(
249 unify_types(&l, &r, &mut false),
250 Ok(PropType::map([("a".to_string(), PropType::U8)]))
251 );
252 }
253
254 #[test]
255 fn test_unify_maps() {
256 let l = PropType::map([("a".to_string(), PropType::U8)]);
257 let r = PropType::map([("a".to_string(), PropType::U16)]);
258 assert!(unify_types(&l, &r, &mut false).is_err());
259
260 let l = PropType::map([("a".to_string(), PropType::U8)]);
261 let r = PropType::map([("b".to_string(), PropType::U16)]);
262 let mut unify = false;
263 assert_eq!(
264 unify_types(&l, &r, &mut unify),
265 Ok(PropType::map([
266 ("a".to_string(), PropType::U8),
267 ("b".to_string(), PropType::U16)
268 ]))
269 );
270 assert!(unify);
271
272 let l = PropType::map([("a".to_string(), PropType::U8)]);
273 let r = PropType::map([
274 ("a".to_string(), PropType::U8),
275 ("b".to_string(), PropType::U16),
276 ]);
277 let mut unify = false;
278 assert_eq!(
279 unify_types(&l, &r, &mut unify),
280 Ok(PropType::map([
281 ("a".to_string(), PropType::U8),
282 ("b".to_string(), PropType::U16)
283 ]))
284 );
285 assert!(unify);
286
287 let l = PropType::map([
288 ("a".to_string(), PropType::U8),
289 ("b".to_string(), PropType::U16),
290 ]);
291 let r = PropType::map([("a".to_string(), PropType::U8)]);
292 let mut unify = false;
293 assert_eq!(
294 unify_types(&l, &r, &mut unify),
295 Ok(PropType::map([
296 ("a".to_string(), PropType::U8),
297 ("b".to_string(), PropType::U16)
298 ]))
299 );
300 assert!(unify);
301 }
302
303 #[test]
304 fn test_unify() {
305 let l = PropType::Empty;
306 let r = PropType::U8;
307 let mut unify = false;
308 assert_eq!(unify_types(&l, &r, &mut unify), Ok(PropType::U8));
309 assert!(unify);
310
311 let l = PropType::Str;
312 let r = PropType::Empty;
313 let mut unify = false;
314 assert_eq!(unify_types(&l, &r, &mut unify), Ok(PropType::Str));
315 assert!(unify);
316
317 let l = PropType::List(Box::new(PropType::List(Box::new(PropType::U8))));
318 let r = PropType::List(Box::new(PropType::Empty));
319 let mut unify = false;
320 assert_eq!(
321 unify_types(&l, &r, &mut unify),
322 Ok(PropType::List(Box::new(PropType::List(Box::new(
323 PropType::U8
324 )))))
325 );
326 assert!(unify);
327
328 let l = PropType::Array(Box::new(PropType::map([("a".to_string(), PropType::U8)])));
329 let r = PropType::Array(Box::new(PropType::map([
330 ("a".to_string(), PropType::Empty),
331 ("b".to_string(), PropType::Str),
332 ])));
333 let mut unify = false;
334 assert_eq!(
335 unify_types(&l, &r, &mut unify),
336 Ok(PropType::Array(Box::new(PropType::map([
337 ("a".to_string(), PropType::U8),
338 ("b".to_string(), PropType::Str)
339 ]))))
340 );
341 assert!(unify);
342 }
343}