1use std::marker::PhantomData;
2use std::ops::Not;
3
4use crate::id::Id;
5use crate::inner::Inner;
6use crate::persistence::{N, Persistence, S};
7use crate::timestamp::Timestamp;
8
9#[derive(Debug, Clone)]
15pub struct Record<T, R = (), S: Persistence = N, K = i64>
16where
17 T: Inner,
18 R: Inner,
19 K: Clone,
20{
21 id: Option<Id<K>>,
23
24 pub inner: T,
25
26 pub relations: R,
27
28 created_at: Option<Timestamp>,
29
30 updated_at: Option<Timestamp>,
31
32 _dirty: bool,
33 _state: PhantomData<S>,
34}
35
36impl<T, R, S, K> Record<T, R, S, K>
38where
39 T: Inner,
40 R: Inner,
41 S: Persistence,
42 K: Clone,
43{
44 pub fn is_dirty(&self) -> bool {
45 self._dirty
46 }
47
48 pub fn mark_dirty(&mut self) {
49 self._dirty = true;
50 }
51}
52
53impl<T, K> Record<T, (), N, K>
55where
56 T: Inner,
57 K: Inner,
58{
59 pub fn new(inner: T) -> Self {
60 Self {
61 id: None,
62 inner,
63 relations: (),
64 created_at: None,
65 updated_at: None,
66 _dirty: true,
67 _state: PhantomData,
68 }
69 }
70
71 pub fn with_relations<R>(inner: T, relations: R) -> Record<T, R, N>
72 where
73 R: Inner,
74 {
75 Record {
76 id: None,
77 inner,
78 relations,
79 created_at: None,
80 updated_at: None,
81 _dirty: true,
82 _state: PhantomData,
83 }
84 }
85}
86
87impl<T, K, R> Record<T, R, N, K>
89where
90 T: Inner,
91 R: Inner,
92 K: Clone,
93{
94 pub fn store(self, id: K, created_at: Timestamp) -> Record<T, R, S, K> {
95 Record {
96 id: Some(Id::new(id)),
97 inner: self.inner,
98 relations: self.relations,
99 created_at: Some(created_at),
100 updated_at: Some(created_at),
101 _dirty: false,
102 _state: PhantomData,
103 }
104 }
105}
106
107impl<T, K, R> Record<T, R, S, K>
109where
110 T: Inner,
111 R: Inner,
112 K: Clone,
113{
114 pub fn id(&self) -> &K {
115 self.id
116 .as_ref()
117 .and_then(|id| id.get())
118 .expect("stored record must have an id")
119 }
120
121 pub fn created_at(&self) -> &Timestamp {
122 self.created_at
123 .as_ref()
124 .expect("stored record must have a created_at timestamp")
125 }
126
127 pub fn updated_at(&self) -> &Timestamp {
128 self.updated_at
129 .as_ref()
130 .expect("stored record must have an updated_at timestamp")
131 }
132
133 pub fn store(self, id: K, created_at: Timestamp) -> Record<T, R, S, K> {
134 if self._dirty.not() {
135 return self;
136 }
137
138 Record {
139 id: Some(Id::new(id)),
140 inner: self.inner,
141 relations: self.relations,
142 created_at: Some(created_at),
143 updated_at: Some(created_at),
144 _dirty: false,
145 _state: PhantomData,
146 }
147 }
148}