1use std::collections::{BTreeMap, HashMap};
2
3use chrono::{SecondsFormat, Utc};
4use serde::{Deserialize, Serialize};
5
6use crate::expr::Expr;
7pub type ParamValue = PropertyValue;
9
10pub type ParamObject = BTreeMap<String, PropertyValue>;
12#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14#[serde(rename_all = "snake_case")]
15pub enum PropertyValue {
16 Null,
18 Bool(bool),
20 I64(i64),
22 DateTime(i64),
24 F64(f64),
26 F32(f32),
28 String(String),
30 Bytes(Vec<u8>),
32 I64Array(Vec<i64>),
34 F64Array(Vec<f64>),
36 F32Array(Vec<f32>),
38 StringArray(Vec<String>),
40 Array(Vec<PropertyValue>),
42 Object(BTreeMap<String, PropertyValue>),
44}
45
46impl PropertyValue {
47 pub fn array<V>(values: impl IntoIterator<Item = V>) -> Self
49 where
50 V: Into<PropertyValue>,
51 {
52 Self::Array(values.into_iter().map(Into::into).collect())
53 }
54
55 pub fn object<K, V>(values: impl IntoIterator<Item = (K, V)>) -> Self
57 where
58 K: Into<String>,
59 V: Into<PropertyValue>,
60 {
61 Self::Object(
62 values
63 .into_iter()
64 .map(|(key, value)| (key.into(), value.into()))
65 .collect(),
66 )
67 }
68
69 pub fn as_str(&self) -> Option<&str> {
71 match self {
72 Self::String(value) => Some(value),
73 _ => None,
74 }
75 }
76
77 pub fn as_i64(&self) -> Option<i64> {
79 match self {
80 Self::I64(value) => Some(*value),
81 _ => None,
82 }
83 }
84
85 pub fn datetime_millis(millis: i64) -> Self {
87 Self::DateTime(millis)
88 }
89
90 pub fn as_datetime_millis(&self) -> Option<i64> {
92 match self {
93 Self::DateTime(value) => Some(*value),
94 _ => None,
95 }
96 }
97
98 pub fn as_f64(&self) -> Option<f64> {
100 match self {
101 Self::F64(value) => Some(*value),
102 Self::F32(value) => Some(*value as f64),
103 _ => None,
104 }
105 }
106
107 pub fn as_bool(&self) -> Option<bool> {
109 match self {
110 Self::Bool(value) => Some(*value),
111 _ => None,
112 }
113 }
114
115 pub fn as_array(&self) -> Option<&[PropertyValue]> {
117 match self {
118 Self::Array(values) => Some(values),
119 _ => None,
120 }
121 }
122
123 pub fn as_object(&self) -> Option<&BTreeMap<String, PropertyValue>> {
125 match self {
126 Self::Object(values) => Some(values),
127 _ => None,
128 }
129 }
130}
131
132impl From<&str> for PropertyValue {
133 fn from(value: &str) -> Self {
134 Self::String(value.to_string())
135 }
136}
137
138impl From<String> for PropertyValue {
139 fn from(value: String) -> Self {
140 Self::String(value)
141 }
142}
143
144impl From<i64> for PropertyValue {
145 fn from(value: i64) -> Self {
146 Self::I64(value)
147 }
148}
149
150impl From<i32> for PropertyValue {
151 fn from(value: i32) -> Self {
152 Self::I64(value as i64)
153 }
154}
155
156impl From<f64> for PropertyValue {
157 fn from(value: f64) -> Self {
158 Self::F64(value)
159 }
160}
161
162impl From<f32> for PropertyValue {
163 fn from(value: f32) -> Self {
164 Self::F32(value)
165 }
166}
167
168impl From<bool> for PropertyValue {
169 fn from(value: bool) -> Self {
170 Self::Bool(value)
171 }
172}
173
174impl From<Vec<u8>> for PropertyValue {
175 fn from(value: Vec<u8>) -> Self {
176 Self::Bytes(value)
177 }
178}
179
180impl From<Vec<i64>> for PropertyValue {
181 fn from(value: Vec<i64>) -> Self {
182 Self::I64Array(value)
183 }
184}
185
186impl From<Vec<f64>> for PropertyValue {
187 fn from(value: Vec<f64>) -> Self {
188 Self::F64Array(value)
189 }
190}
191
192impl From<Vec<f32>> for PropertyValue {
193 fn from(value: Vec<f32>) -> Self {
194 Self::F32Array(value)
195 }
196}
197
198impl From<Vec<String>> for PropertyValue {
199 fn from(value: Vec<String>) -> Self {
200 Self::StringArray(value)
201 }
202}
203
204impl From<Vec<PropertyValue>> for PropertyValue {
205 fn from(value: Vec<PropertyValue>) -> Self {
206 Self::Array(value)
207 }
208}
209
210impl From<BTreeMap<String, PropertyValue>> for PropertyValue {
211 fn from(value: BTreeMap<String, PropertyValue>) -> Self {
212 Self::Object(value)
213 }
214}
215
216impl From<HashMap<String, PropertyValue>> for PropertyValue {
217 fn from(value: HashMap<String, PropertyValue>) -> Self {
218 Self::Object(value.into_iter().collect())
219 }
220}
221
222#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
224pub struct DateTime(i64);
225
226impl DateTime {
227 pub fn from_millis(millis: i64) -> Self {
229 Self(millis)
230 }
231
232 pub fn parse_rfc3339(input: &str) -> Result<Self, chrono::ParseError> {
234 Ok(Self(
235 chrono::DateTime::parse_from_rfc3339(input)?
236 .with_timezone(&Utc)
237 .timestamp_millis(),
238 ))
239 }
240
241 pub fn millis(self) -> i64 {
243 self.0
244 }
245
246 pub fn to_rfc3339(self) -> Option<String> {
248 chrono::DateTime::<Utc>::from_timestamp_millis(self.0)
249 .map(|dt| dt.to_rfc3339_opts(SecondsFormat::Millis, true))
250 }
251}
252
253impl From<DateTime> for PropertyValue {
254 fn from(value: DateTime) -> Self {
255 Self::DateTime(value.millis())
256 }
257}
258#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
260#[serde(rename_all = "snake_case")]
261pub enum PropertyInput {
262 Value(PropertyValue),
264 Expr(Expr),
266}
267
268impl PropertyInput {
269 pub fn param(name: impl Into<String>) -> Self {
271 Self::Expr(Expr::param(name))
272 }
273
274 pub fn into_expr(self) -> Expr {
276 match self {
277 Self::Value(value) => Expr::Constant(value),
278 Self::Expr(expr) => expr,
279 }
280 }
281}
282
283impl<T> From<T> for PropertyInput
284where
285 PropertyValue: From<T>,
286{
287 fn from(value: T) -> Self {
288 Self::Value(value.into())
289 }
290}
291
292impl From<Expr> for PropertyInput {
293 fn from(value: Expr) -> Self {
294 Self::Expr(value)
295 }
296}
297pub type PropertyMap = HashMap<String, PropertyValue>;