c3p0_common/json/
model.rs

1use serde::{Deserialize, Serialize};
2
3use crate::{DataType, IdType};
4
5use super::types::{EpochMillisType, VersionType};
6
7/// A model for a database table.
8/// This is used to retrieve and update an entry in a database table.
9#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
10pub struct Model<Id, Data> {
11    /// The unique identifier of the model.
12    pub id: Id,
13    /// The version of the model used for optimistic locking.
14    pub version: VersionType,
15    /// The epoch millis when the model was created.
16    #[serde(default)]
17    pub create_epoch_millis: EpochMillisType,
18    /// The epoch millis when the model was last updated.
19    #[serde(default)]
20    pub update_epoch_millis: EpochMillisType,
21    /// The data of the model.
22    pub data: Data,
23}
24
25impl<Id: IdType, Data: DataType> Model<Id, Data> {
26    /// Converts the current `Model` instance into a `NewModel` instance,
27    /// resetting the version to the initial state while retaining the data.
28    pub fn into_new(self) -> NewModel<Data> {
29        NewModel::new(self.data)
30    }
31
32    /// Creates a new `Model` instance from a `NewModel` instance.
33    ///
34    /// - `id`: The unique identifier of the model.
35    /// - `create_epoch_millis`: The epoch millis when the model was created.
36    /// - `model`: The `NewModel` instance to create the `Model` instance from.
37    ///
38    /// Returns a `Model` instance with the version set to the initial state,
39    /// the create and update epoch millis set to the given `create_epoch_millis`,
40    /// and the data set to the data of the `model` parameter.
41    pub fn from_new(
42        id: Id,
43        create_epoch_millis: EpochMillisType,
44        model: NewModel<Data>,
45    ) -> Model<Id, Data> {
46        Model {
47            id,
48            version: model.version,
49            create_epoch_millis,
50            update_epoch_millis: create_epoch_millis,
51            data: model.data,
52        }
53    }
54
55    /// Creates a new `Model` instance from the current `Model` instance,
56    /// incrementing the version by one and updating the update epoch millis
57    /// to the given `update_epoch_millis`.
58    ///
59    /// - `update_epoch_millis`: The epoch millis when the model was last updated.
60    ///
61    /// Returns a `Model` instance with the version incremented by one,
62    /// the create epoch millis unchanged, the update epoch millis set to
63    /// the given `update_epoch_millis`, and the data unchanged.
64    pub fn into_new_version(self, update_epoch_millis: EpochMillisType) -> Model<Id, Data> {
65        Model {
66            id: self.id,
67            version: self.version + 1,
68            create_epoch_millis: self.create_epoch_millis,
69            update_epoch_millis,
70            data: self.data,
71        }
72    }
73}
74
75/// A new model for a database table.
76/// This is used to create a new entry in a database table.
77#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
78pub struct NewModel<Data> {
79    pub version: VersionType,
80    pub data: Data,
81}
82
83impl<Data: DataType> NewModel<Data> {
84    /// Creates a new `NewModel` instance from a `Data` value.
85    /// Sets the version to 0.
86    pub fn new(data: Data) -> Self {
87        NewModel { version: 0, data }
88    }
89}
90
91impl<Data: DataType + Default> Default for NewModel<Data> {
92    fn default() -> Self {
93        NewModel::new(Data::default())
94    }
95}
96
97impl<Data> From<Data> for NewModel<Data>
98where
99    Data: DataType,
100{
101    fn from(data: Data) -> Self {
102        NewModel::new(data)
103    }
104}
105
106#[cfg(test)]
107mod test {
108
109    use super::*;
110    use serde::{Deserialize, Serialize};
111    use serde_json;
112
113    #[test]
114    fn model_should_be_serializable() -> Result<(), Box<dyn std::error::Error>> {
115        let model = Model {
116            id: 1,
117            version: 1,
118            data: SimpleData {
119                name: "test".to_owned(),
120            },
121            create_epoch_millis: 0,
122            update_epoch_millis: 0,
123        };
124
125        let serialize = serde_json::to_string(&model)?;
126        let deserialize: Model<i64, SimpleData> = serde_json::from_str(&serialize)?;
127
128        assert_eq!(model.id, deserialize.id);
129        assert_eq!(model.version, deserialize.version);
130        assert_eq!(model.data, deserialize.data);
131
132        Ok(())
133    }
134
135    #[test]
136    fn new_model_should_be_serializable() -> Result<(), Box<dyn std::error::Error>> {
137        let model = NewModel::new(SimpleData {
138            name: "test".to_owned(),
139        });
140
141        let serialize = serde_json::to_string(&model)?;
142        let deserialize: NewModel<SimpleData> = serde_json::from_str(&serialize)?;
143
144        assert_eq!(model.version, deserialize.version);
145        assert_eq!(model.data, deserialize.data);
146        Ok(())
147    }
148
149    #[test]
150    fn model_should_impl_debug_if_data_is_debug() {
151        let model = Model {
152            id: 1,
153            version: 1,
154            data: SimpleData {
155                name: "test".to_owned(),
156            },
157            create_epoch_millis: 0,
158            update_epoch_millis: 0,
159        };
160
161        println!("Debug model: {:?}", model);
162    }
163
164    #[test]
165    fn new_model_should_impl_debug_if_data_is_debug() {
166        let model = NewModel::new(SimpleData {
167            name: "test".to_owned(),
168        });
169
170        println!("Debug model: {:?}", model);
171    }
172
173    #[test]
174    fn new_model_from_model_should_have_new_version() {
175        let model = Model {
176            id: 10,
177            version: 10,
178            data: SimpleData {
179                name: "test".to_owned(),
180            },
181            create_epoch_millis: 0,
182            update_epoch_millis: 0,
183        };
184
185        let new_model = model.clone().into_new();
186
187        assert_eq!(model.data, new_model.data);
188        assert_eq!(new_model.version, 0);
189    }
190
191    #[test]
192    fn should_build_new_model_version() {
193        let model = Model {
194            id: 10,
195            version: 10,
196            data: SimpleData {
197                name: "test".to_owned(),
198            },
199            create_epoch_millis: 0,
200            update_epoch_millis: 0,
201        };
202
203        let new_update_epoch_millis = 111;
204
205        let new_model_version = model.clone().into_new_version(new_update_epoch_millis);
206
207        assert_eq!(model.data, new_model_version.data);
208        assert_eq!(model.id, new_model_version.id);
209        assert_eq!(
210            model.create_epoch_millis,
211            new_model_version.create_epoch_millis
212        );
213        assert_eq!(
214            new_update_epoch_millis,
215            new_model_version.update_epoch_millis
216        );
217        assert_eq!(model.version + 1, new_model_version.version);
218    }
219
220    #[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
221    struct SimpleData {
222        name: String,
223    }
224}