1use std::ops::{Deref, DerefMut};
8
9use crate::fields_set::FieldsSet;
10use crate::validate::{DumpOptions, DumpResult, apply_serialization_aliases};
11use crate::{FieldInfo, Model};
12
13#[derive(Clone, Debug)]
15pub struct TrackedModel<T> {
16 inner: T,
17 fields_set: FieldsSet,
18}
19
20impl<T> TrackedModel<T> {
21 #[must_use]
23 pub const fn new(inner: T, fields_set: FieldsSet) -> Self {
24 Self { inner, fields_set }
25 }
26
27 #[must_use]
29 pub const fn inner(&self) -> &T {
30 &self.inner
31 }
32
33 #[must_use]
35 pub fn inner_mut(&mut self) -> &mut T {
36 &mut self.inner
37 }
38
39 #[must_use]
41 pub fn into_inner(self) -> T {
42 self.inner
43 }
44
45 #[must_use]
47 pub const fn fields_set(&self) -> &FieldsSet {
48 &self.fields_set
49 }
50}
51
52impl<T: Model> TrackedModel<T> {
53 #[must_use]
55 pub fn all_fields_set(inner: T) -> Self {
56 let fields_set = FieldsSet::all(T::fields().len());
57 Self { inner, fields_set }
58 }
59
60 #[must_use]
64 pub fn from_explicit_field_names(inner: T, names: &[&str]) -> Self {
65 let mut fields_set = FieldsSet::empty(T::fields().len());
66 for (idx, field) in T::fields().iter().enumerate() {
67 if names.contains(&field.name) {
68 fields_set.set(idx);
69 }
70 }
71 Self { inner, fields_set }
72 }
73
74 fn apply_field_exclusions(
75 map: &mut serde_json::Map<String, serde_json::Value>,
76 fields: &[FieldInfo],
77 fields_set: &FieldsSet,
78 exclude_unset: bool,
79 exclude_computed_fields: bool,
80 exclude_defaults: bool,
81 ) {
82 for field in fields {
84 if field.exclude {
85 map.remove(field.name);
86 }
87 }
88
89 if exclude_unset {
90 for (idx, field) in fields.iter().enumerate() {
91 if !fields_set.is_set(idx) {
92 map.remove(field.name);
93 }
94 }
95 }
96
97 if exclude_computed_fields {
98 for field in fields {
99 if field.computed {
100 map.remove(field.name);
101 }
102 }
103 }
104
105 if exclude_defaults {
106 for field in fields {
107 if let Some(default_json) = field.default_json
108 && let Some(current_value) = map.get(field.name)
109 && let Ok(default_value) =
110 serde_json::from_str::<serde_json::Value>(default_json)
111 && current_value == &default_value
112 {
113 map.remove(field.name);
114 }
115 }
116 }
117 }
118}
119
120impl<T: Model + serde::Serialize> TrackedModel<T> {
121 pub fn sql_model_dump(&self, options: DumpOptions) -> DumpResult {
126 let DumpOptions {
127 include,
128 exclude,
129 by_alias,
130 exclude_unset,
131 exclude_defaults,
132 exclude_none,
133 exclude_computed_fields,
134 mode: _,
135 round_trip: _,
136 indent: _,
137 } = options;
138
139 let mut value = serde_json::to_value(&self.inner)?;
140
141 if let serde_json::Value::Object(ref mut map) = value {
142 Self::apply_field_exclusions(
143 map,
144 T::fields(),
145 &self.fields_set,
146 exclude_unset,
147 exclude_computed_fields,
148 exclude_defaults,
149 );
150 }
151
152 if by_alias {
153 apply_serialization_aliases(&mut value, T::fields());
154 }
155
156 if let serde_json::Value::Object(ref mut map) = value {
157 if let Some(ref include_set) = include {
158 map.retain(|k, _| include_set.contains(k));
159 }
160 if let Some(ref exclude_set) = exclude {
161 map.retain(|k, _| !exclude_set.contains(k));
162 }
163 if exclude_none {
164 map.retain(|_, v| !v.is_null());
165 }
166 }
167
168 Ok(value)
169 }
170
171 pub fn sql_model_dump_json(&self) -> std::result::Result<String, serde_json::Error> {
172 let value = self.sql_model_dump(DumpOptions::default())?;
173 serde_json::to_string(&value)
174 }
175
176 pub fn sql_model_dump_json_pretty(&self) -> std::result::Result<String, serde_json::Error> {
177 let value = self.sql_model_dump(DumpOptions::default())?;
178 serde_json::to_string_pretty(&value)
179 }
180
181 pub fn sql_model_dump_json_with_options(
182 &self,
183 options: DumpOptions,
184 ) -> std::result::Result<String, serde_json::Error> {
185 let DumpOptions { indent, .. } = options.clone();
186 let value = self.sql_model_dump(DumpOptions {
187 indent: None,
188 ..options
189 })?;
190
191 match indent {
192 Some(spaces) => {
193 let indent_bytes = " ".repeat(spaces).into_bytes();
194 let formatter = serde_json::ser::PrettyFormatter::with_indent(&indent_bytes);
195 let mut writer = Vec::new();
196 let mut ser = serde_json::Serializer::with_formatter(&mut writer, formatter);
197 serde::Serialize::serialize(&value, &mut ser)?;
198 String::from_utf8(writer).map_err(|e| {
199 serde_json::Error::io(std::io::Error::new(
200 std::io::ErrorKind::InvalidData,
201 format!("UTF-8 encoding error: {e}"),
202 ))
203 })
204 }
205 None => serde_json::to_string(&value),
206 }
207 }
208}
209
210impl<T> Deref for TrackedModel<T> {
211 type Target = T;
212 fn deref(&self) -> &Self::Target {
213 &self.inner
214 }
215}
216
217impl<T> DerefMut for TrackedModel<T> {
218 fn deref_mut(&mut self) -> &mut Self::Target {
219 &mut self.inner
220 }
221}