crcnt_ddd/
value.rs

1use {chrono::{DateTime,
2              Duration,
3              NaiveDateTime,
4              Utc},
5     crcnt_ddd_macros::Domain,
6     mysql_common::value::{convert::{ConvIr,
7                                     FromValue,
8                                     FromValueError},
9                           Value},
10     serde::{Deserialize,
11             Serialize},
12     std::{cmp::Ordering,
13           ops},
14     ulid::Ulid};
15
16//<editor-fold desc="CreateAt Def">
17/// CreateAt is a timestamp in milliseconds like it in Java
18#[derive(Debug, Clone, Domain, Serialize, Deserialize)]
19#[domain_commands(value)]
20pub struct CreateAt(UtcDateTime);
21
22impl CreateAt {
23  pub fn now() -> Self { Self(UtcDateTime::now()) }
24
25  pub fn from_utd_date_time(v: UtcDateTime) -> Self { Self(v) }
26
27  pub fn timestamp(&self) -> i64 { *&self.0.0.timestamp() }
28
29  pub fn timestamp_millis(&self) -> i64 { *&self.0.0.timestamp_millis() }
30
31  pub fn naive_date_time(&self) -> NaiveDateTime { self.0.0.naive_utc() }
32}
33//</editor-fold>
34
35//<editor-fold desc="UpdateAt Def">
36/// UpdateAt is a timestamp in milliseconds like it in Java
37#[derive(Debug, Clone, Domain, Serialize, Deserialize)]
38#[domain_commands(value)]
39pub struct UpdateAt(UtcDateTime);
40
41impl UpdateAt {
42  pub fn now() -> Self { Self(UtcDateTime::now()) }
43
44  pub fn from_utd_date_time(v: UtcDateTime) -> Self { Self(v) }
45
46  pub fn timestamp(&self) -> i64 { *&self.0.0.timestamp() }
47
48  pub fn timestamp_millis(&self) -> i64 { *&self.0.0.timestamp_millis() }
49
50  pub fn naive_date_time(&self) -> NaiveDateTime { self.0.0.naive_utc() }
51}
52//</editor-fold>
53
54//<editor-fold desc="AvailableSince Def">
55#[derive(Debug, Clone, Domain, Serialize, Deserialize)]
56#[domain_commands(value)]
57pub struct AvailableSince(UtcDateTime);
58
59impl AvailableSince {
60  pub fn now() -> Self { Self(UtcDateTime::now()) }
61
62  pub fn timestamp(&self) -> i64 { *&self.0.0.timestamp() }
63
64  pub fn timestamp_millis(&self) -> i64 { *&self.0.0.timestamp_millis() }
65
66  pub fn from_rfc3399<S: AsRef<str>>(s: S) -> Result<Self, String> { Ok(AvailableSince(UtcDateTime::from_rfc3339(s)?)) }
67
68  pub fn is_available_now(&self) -> bool {
69    let now = Utc::now();
70    &self.0.0 <= &now
71  }
72
73  pub fn naive_date_time(&self) -> NaiveDateTime { self.0.0.naive_utc() }
74}
75//</editor-fold>
76
77//<editor-fold desc="ExpiredSince Def">
78#[derive(Debug, Clone, Domain, Serialize, Deserialize)]
79#[domain_commands(value)]
80pub struct ExpiredSince(UtcDateTime);
81
82impl ExpiredSince {
83  pub fn now() -> Self { Self(UtcDateTime::now()) }
84
85  pub fn timestamp(&self) -> i64 { *&self.0.0.timestamp() }
86
87  pub fn timestamp_millis(&self) -> i64 { *&self.0.0.timestamp_millis() }
88
89  pub fn from_rfc3399<S: AsRef<str>>(s: S) -> Result<Self, String> { Ok(ExpiredSince(UtcDateTime::from_rfc3339(s)?)) }
90
91  pub fn is_expired_now(&self) -> bool {
92    let now = Utc::now();
93    &self.inner().0 <= &now
94  }
95
96  pub fn naive_date_time(&self) -> NaiveDateTime { self.0.0.naive_utc() }
97}
98//</editor-fold>
99
100//<editor-fold desc="Basic String Value">
101/// Creator
102#[derive(Debug, Clone, Domain, Serialize, Deserialize)]
103#[domain_commands(value)]
104pub struct Creator(String);
105
106/// Owner
107#[derive(Debug, Clone, Domain, Serialize, Deserialize)]
108#[domain_commands(value)]
109pub struct Owner(String);
110
111/// Owner
112#[derive(Debug, Clone, Domain, Serialize, Deserialize)]
113#[domain_commands(value)]
114pub struct EntityId(String);
115#[derive(Debug)]
116pub struct EntityIdIr(pub EntityId);
117/// Updater
118#[derive(Debug, Clone, Domain, Serialize, Deserialize)]
119#[domain_commands(value)]
120pub struct Updater(String);
121//</editor-fold>
122
123//<editor-fold desc="UtcDateTime Def">
124#[derive(Debug, Clone, Serialize, Deserialize)]
125pub struct UtcDateTime(DateTime<Utc>);
126
127impl UtcDateTime {
128  pub fn now() -> Self { UtcDateTime(Utc::now()) }
129
130  pub fn from_date_time(v: DateTime<Utc>) -> Self { Self(v) }
131
132  pub fn from_rfc3339<S: AsRef<str>>(s: S) -> Result<Self, String> {
133    let date_time = DateTime::parse_from_rfc3339(s.as_ref()).map_err(|e| format!("AvailableSince parse error: {}", e.to_string()))?;
134    let date_time = date_time.with_timezone(&Utc);
135    Ok(Self(date_time))
136  }
137
138  pub fn from_timestamp(timestamp: i64) -> Option<Self> {
139    let naive = NaiveDateTime::from_timestamp_opt(timestamp, 0);
140    if let Some(naive) = naive {
141      let date_time = DateTime::<Utc>::from_utc(naive, Utc);
142      Some(Self(date_time))
143    } else {
144      None
145    }
146  }
147
148  pub fn from_timestamp_millis(timestamp: i64) -> Option<Self> {
149    let naive = NaiveDateTime::from_timestamp_millis(timestamp);
150    if let Some(naive) = naive {
151      let date_time = DateTime::<Utc>::from_utc(naive, Utc);
152      Some(Self(date_time))
153    } else {
154      None
155    }
156  }
157
158  pub fn timestamp(&self) -> i64 { *&self.0.timestamp() }
159
160  pub fn timestamp_millis(&self) -> i64 { *&self.0.timestamp_millis() }
161
162  pub fn naive_date_time(&self) -> NaiveDateTime { self.0.naive_utc() }
163}
164//</editor-fold>
165
166#[derive(Debug, Clone, Serialize, Deserialize)]
167pub struct Amount(f64);
168impl PartialEq for Amount {
169  fn eq(&self, other: &Self) -> bool { (self.0 * 100.00) as u64 == (other.0 * 100.00) as u64 }
170}
171impl Ord for Amount {
172  fn cmp(&self, other: &Self) -> Ordering {
173    let a = (self.0 * 100.00) as u64;
174    let b = (other.0 * 100.00) as u64;
175    a.cmp(&b)
176  }
177}
178impl PartialOrd for Amount {
179  fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
180    let a = (self.0 * 100.00) as u64;
181    let b = (other.0 * 100.00) as u64;
182    a.partial_cmp(&b)
183  }
184}
185impl Eq for Amount {}
186impl From<f64> for Amount {
187  fn from(value: f64) -> Self { Amount((value * 100.00).round() / 100.00) }
188}
189impl Amount {
190  pub fn new<T: Into<f64>>(v: T) -> Self {
191    let x: f64 = v.into();
192    From::from(x)
193  }
194
195  pub fn inner(&self) -> &f64 { &self.0 }
196
197  pub fn into_inner(self) -> f64 { self.0 }
198}
199impl From<Amount> for Value {
200  fn from(value: Amount) -> Self { Value::from(value.0) }
201}
202#[derive(Debug)]
203pub struct F64Ir {
204  v: f64,
205}
206impl ConvIr<Amount> for F64Ir {
207  fn new(v: Value) -> Result<Self, FromValueError> {
208    let v = f64::from_value_opt(v)?;
209    Ok(Self { v })
210  }
211
212  fn commit(self) -> Amount { Amount(self.v) }
213
214  fn rollback(self) -> Value { Value::from(self.v) }
215}
216impl FromValue for Amount {
217  type Intermediate = F64Ir;
218}
219
220//<editor-fold desc="ConvIr<T> for TimestampIr">
221#[derive(Debug)]
222pub struct TimestampIr {
223  ndt: NaiveDateTime,
224}
225impl ConvIr<UtcDateTime> for TimestampIr {
226  fn new(v: Value) -> Result<Self, FromValueError> {
227    let ndt = NaiveDateTime::from_value_opt(v)?;
228    Ok(Self { ndt })
229  }
230
231  fn commit(self) -> UtcDateTime {
232    let dt = DateTime::from_utc(self.ndt, Utc);
233    UtcDateTime(dt)
234  }
235
236  fn rollback(self) -> Value { Value::from(self.ndt) }
237}
238
239impl ConvIr<CreateAt> for TimestampIr {
240  fn new(v: Value) -> Result<Self, FromValueError> {
241    let ndt = NaiveDateTime::from_value_opt(v)?;
242    Ok(Self { ndt })
243  }
244
245  fn commit(self) -> CreateAt {
246    let dt = DateTime::from_utc(self.ndt, Utc);
247    CreateAt(UtcDateTime(dt))
248  }
249
250  fn rollback(self) -> Value { Value::from(self.ndt) }
251}
252
253impl ConvIr<UpdateAt> for TimestampIr {
254  fn new(v: Value) -> Result<Self, FromValueError> {
255    let ndt = NaiveDateTime::from_value_opt(v)?;
256    Ok(Self { ndt })
257  }
258
259  fn commit(self) -> UpdateAt {
260    let dt = DateTime::from_utc(self.ndt, Utc);
261    UpdateAt(UtcDateTime(dt))
262  }
263
264  fn rollback(self) -> Value { Value::from(self.ndt) }
265}
266
267impl ConvIr<AvailableSince> for TimestampIr {
268  fn new(v: Value) -> Result<Self, FromValueError> {
269    let ndt = NaiveDateTime::from_value_opt(v)?;
270    Ok(Self { ndt })
271  }
272
273  fn commit(self) -> AvailableSince {
274    let dt = DateTime::from_utc(self.ndt, Utc);
275    AvailableSince(UtcDateTime(dt))
276  }
277
278  fn rollback(self) -> Value { Value::from(self.ndt) }
279}
280
281impl ConvIr<ExpiredSince> for TimestampIr {
282  fn new(v: Value) -> Result<Self, FromValueError> {
283    let ndt = NaiveDateTime::from_value_opt(v)?;
284    Ok(Self { ndt })
285  }
286
287  fn commit(self) -> ExpiredSince {
288    let dt = DateTime::from_utc(self.ndt, Utc);
289    ExpiredSince(UtcDateTime(dt))
290  }
291
292  fn rollback(self) -> Value { Value::from(self.ndt) }
293}
294//</editor-fold>
295
296//<editor-fold desc="Deleted and ConvIr">
297/// Deleted is a logic deletion flag
298#[derive(Debug, Clone, Domain, Serialize, Deserialize)]
299#[domain_commands(value)]
300pub struct Deleted(bool);
301
302#[derive(Debug)]
303pub struct DeletedIr {
304  b: bool,
305}
306
307impl ConvIr<Deleted> for DeletedIr {
308  fn new(v: Value) -> Result<Self, FromValueError> {
309    let b = bool::from_value_opt(v)?;
310    Ok(Self { b })
311  }
312
313  fn commit(self) -> Deleted { Deleted(self.b) }
314
315  fn rollback(self) -> Value { Value::from(self.b) }
316}
317//</editor-fold>
318
319//<editor-fold desc="ConvIr<T> for StrIr">
320#[derive(Debug)]
321pub struct StrIr {
322  pub bytes: Vec<u8>,
323}
324impl ConvIr<Creator> for StrIr {
325  fn new(v: Value) -> Result<Self, FromValueError> {
326    let bytes = Vec::<u8>::from_value_opt(v)?;
327    Ok(StrIr { bytes })
328  }
329
330  fn commit(self) -> Creator {
331    let creator = String::from_utf8_lossy(&self.bytes).to_string();
332    Creator(creator)
333  }
334
335  fn rollback(self) -> Value { Value::from(self.bytes) }
336}
337impl ConvIr<Updater> for StrIr {
338  fn new(v: Value) -> Result<Self, FromValueError> {
339    let bytes = Vec::<u8>::from_value_opt(v)?;
340    Ok(StrIr { bytes })
341  }
342
343  fn commit(self) -> Updater {
344    let updater = String::from_utf8_lossy(&self.bytes).to_string();
345    Updater(updater)
346  }
347
348  fn rollback(self) -> Value { Value::from(self.bytes) }
349}
350impl ConvIr<Owner> for StrIr {
351  fn new(v: Value) -> Result<Self, FromValueError> {
352    let bytes = Vec::<u8>::from_value_opt(v)?;
353    Ok(StrIr { bytes })
354  }
355
356  fn commit(self) -> Owner {
357    let owner = String::from_utf8_lossy(&self.bytes).to_string();
358    Owner(owner)
359  }
360
361  fn rollback(self) -> Value { Value::from(self.bytes) }
362}
363impl ConvIr<EntityId> for StrIr {
364  fn new(v: Value) -> Result<Self, FromValueError> {
365    let bytes = Vec::<u8>::from_value_opt(v)?;
366    Ok(StrIr { bytes })
367  }
368
369  fn commit(self) -> EntityId {
370    let id = String::from_utf8_lossy(&self.bytes).to_string();
371    EntityId(id)
372  }
373
374  fn rollback(self) -> Value { Value::from(self.bytes) }
375}
376//</editor-fold>
377
378//<editor-fold desc="impl FromValue">
379impl FromValue for CreateAt {
380  type Intermediate = TimestampIr;
381}
382impl FromValue for UpdateAt {
383  type Intermediate = TimestampIr;
384}
385impl FromValue for AvailableSince {
386  type Intermediate = TimestampIr;
387}
388impl FromValue for ExpiredSince {
389  type Intermediate = TimestampIr;
390}
391impl FromValue for UtcDateTime {
392  type Intermediate = TimestampIr;
393}
394impl FromValue for Deleted {
395  type Intermediate = DeletedIr;
396}
397impl FromValue for Creator {
398  type Intermediate = StrIr;
399}
400impl FromValue for Updater {
401  type Intermediate = StrIr;
402}
403impl FromValue for Owner {
404  type Intermediate = StrIr;
405}
406impl FromValue for EntityId {
407  type Intermediate = StrIr;
408}
409//</editor-fold>
410
411//<editor-fold desc="From<&T> for Value">
412impl From<&UtcDateTime> for Value {
413  fn from(x: &UtcDateTime) -> Self {
414    let naive = x.0.naive_utc();
415    Value::from(naive)
416  }
417}
418
419//</editor-fold>
420
421impl EntityId {
422  pub fn new_with_prefix<T: AsRef<str>>(prefix: T) -> Self {
423    let id = format!("{}{}", prefix.as_ref(), Ulid::new().to_string());
424    EntityId::new(id)
425  }
426}
427
428impl ops::Add<Duration> for UtcDateTime {
429  type Output = UtcDateTime;
430
431  fn add(self, rhs: Duration) -> Self::Output {
432    let dt = self.0 + rhs;
433    UtcDateTime(dt)
434  }
435}
436
437impl ops::Sub for UtcDateTime {
438  type Output = Duration;
439
440  fn sub(self, rhs: Self) -> Self::Output { self.0 - rhs.0 }
441}
442
443impl PartialEq for UtcDateTime {
444  fn eq(&self, other: &Self) -> bool { (&self.0).eq(&other.0) }
445}
446impl PartialOrd for UtcDateTime {
447  fn partial_cmp(&self, other: &Self) -> Option<Ordering> { (&self.0).partial_cmp(&other.0) }
448}
449
450#[cfg(test)]
451mod test {
452  use crate::value::Amount;
453
454  #[test]
455  fn test_amount() {
456    let amt = Amount::new(0.64523);
457    let amt2 = Amount::new(0.6463);
458    let amt3 = Amount::new(0.6563);
459    println!("amt = {:?}", amt);
460    println!("{}", amt == amt2);
461    println!("{}", amt < amt3);
462  }
463}