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#[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#[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#[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#[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#[derive(Debug, Clone, Domain, Serialize, Deserialize)]
103#[domain_commands(value)]
104pub struct Creator(String);
105
106#[derive(Debug, Clone, Domain, Serialize, Deserialize)]
108#[domain_commands(value)]
109pub struct Owner(String);
110
111#[derive(Debug, Clone, Domain, Serialize, Deserialize)]
113#[domain_commands(value)]
114pub struct EntityId(String);
115#[derive(Debug)]
116pub struct EntityIdIr(pub EntityId);
117#[derive(Debug, Clone, Domain, Serialize, Deserialize)]
119#[domain_commands(value)]
120pub struct Updater(String);
121#[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#[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#[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#[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#[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}
376impl 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}
409impl From<&UtcDateTime> for Value {
413 fn from(x: &UtcDateTime) -> Self {
414 let naive = x.0.naive_utc();
415 Value::from(naive)
416 }
417}
418
419impl 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}