1use datavalue::OwnedDataValue;
4use serde::{Deserialize, Serialize};
5use std::fmt;
6use std::sync::Arc;
7
8#[derive(Clone, Serialize, Deserialize)]
12#[cfg_attr(feature = "ts", derive(ts_rs::TS))]
13#[non_exhaustive]
14pub struct Change {
15 pub path: Arc<str>,
17 #[serde(deserialize_with = "super::exact")]
19 #[cfg_attr(feature = "ts", ts(type = "JsonValue"))]
20 pub old_value: OwnedDataValue,
21 #[serde(deserialize_with = "super::exact")]
24 #[cfg_attr(feature = "ts", ts(type = "JsonValue"))]
25 pub new_value: OwnedDataValue,
26 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
29 pub removed: bool,
30 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
37 pub replaced: bool,
38 #[serde(skip)]
43 pub(crate) trace_only: bool,
44}
45
46impl PartialEq for Change {
47 fn eq(&self, other: &Self) -> bool {
51 let Self {
52 path,
53 old_value,
54 new_value,
55 removed,
56 replaced,
57 trace_only: _,
58 } = self;
59 *path == other.path
60 && *old_value == other.old_value
61 && *new_value == other.new_value
62 && *removed == other.removed
63 && *replaced == other.replaced
64 }
65}
66
67impl fmt::Debug for Change {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 let Self {
72 path,
73 old_value,
74 new_value,
75 removed,
76 replaced,
77 trace_only: _,
78 } = self;
79 f.debug_struct("Change")
80 .field("path", path)
81 .field("old_value", old_value)
82 .field("new_value", new_value)
83 .field("removed", removed)
84 .field("replaced", replaced)
85 .finish()
86 }
87}
88
89impl Change {
90 pub fn write(
92 path: impl Into<Arc<str>>,
93 old_value: OwnedDataValue,
94 new_value: OwnedDataValue,
95 ) -> Self {
96 Self {
97 path: path.into(),
98 old_value,
99 new_value,
100 removed: false,
101 replaced: false,
102 trace_only: false,
103 }
104 }
105
106 pub(crate) fn assign(
112 path: &crate::expr::Path,
113 old_value: OwnedDataValue,
114 new_value: OwnedDataValue,
115 ) -> Self {
116 Self {
117 replaced: path.is_root(),
118 ..Self::write(Arc::clone(path.dotted()), old_value, new_value)
119 }
120 }
121
122 pub fn removal(path: impl Into<Arc<str>>, old_value: OwnedDataValue) -> Self {
124 Self {
125 path: path.into(),
126 old_value,
127 new_value: OwnedDataValue::Null,
128 removed: true,
129 replaced: false,
130 trace_only: false,
131 }
132 }
133
134 pub(crate) fn for_trace(
136 path: impl Into<Arc<str>>,
137 old_value: OwnedDataValue,
138 new_value: OwnedDataValue,
139 ) -> Self {
140 Self {
141 trace_only: true,
142 ..Self::write(path, old_value, new_value)
143 }
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150 use crate::expr::Path;
151
152 fn path(dotted: &str) -> Path {
153 dotted.parse().unwrap()
154 }
155
156 #[test]
157 fn each_kind_of_record_sets_its_own_flags() {
158 let (old, new) = (OwnedDataValue::Null, OwnedDataValue::from(1));
159 let flags = |c: &Change| (c.removed, c.replaced, c.trace_only);
160 assert_eq!(
163 flags(&Change::assign(&path("data"), old.clone(), new.clone())),
164 (false, true, false)
165 );
166 assert_eq!(
167 flags(&Change::assign(&path("data.a"), old.clone(), new.clone())),
168 (false, false, false)
169 );
170 assert_eq!(
172 flags(&Change::write("data", old.clone(), new.clone())),
173 (false, false, false)
174 );
175 assert_eq!(
176 flags(&Change::removal("data.a", new.clone())),
177 (true, false, false)
178 );
179 assert_eq!(
180 flags(&Change::for_trace("data.a", old, new)),
181 (false, false, true)
182 );
183 }
184}