1use std::mem;
5
6use arrow_array::RecordBatch;
7use reifydb_value::{
8 Result,
9 value::{datetime::DateTime, diff_type::DiffType},
10};
11use serde::{Deserialize, Serialize};
12use smallvec::SmallVec;
13
14use crate::{
15 common::ChangeVersion,
16 interface::{
17 catalog::{flow::OperatorId, object::ObjectId},
18 consolidate::coalesce_diffs,
19 },
20};
21
22pub type Diffs = SmallVec<[Diff; 4]>;
23
24pub type StagedBatch = (DiffType, RecordBatch);
25
26#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
27pub enum ChangeOrigin {
28 Object(ObjectId),
29 Flow(OperatorId),
30}
31
32#[derive(Debug, Clone, PartialEq)]
33pub enum Diff {
34 Insert {
35 post: RecordBatch,
36 origin: Option<ChangeOrigin>,
37 },
38 Update {
39 pre: RecordBatch,
40 post: RecordBatch,
41 origin: Option<ChangeOrigin>,
42 },
43 Remove {
44 pre: RecordBatch,
45 origin: Option<ChangeOrigin>,
46 },
47}
48
49impl Diff {
50 pub fn insert(post: RecordBatch) -> Self {
51 Self::Insert {
52 post,
53 origin: None,
54 }
55 }
56
57 pub fn update(pre: RecordBatch, post: RecordBatch) -> Self {
58 Self::update_with_origin(pre, post, None)
59 }
60
61 pub fn update_with_origin(pre: RecordBatch, post: RecordBatch, origin: Option<ChangeOrigin>) -> Self {
62 assert!(
63 pre.num_rows() == post.num_rows(),
64 "an update change needs as many pre rows as post rows, got {} pre and {} post",
65 pre.num_rows(),
66 post.num_rows()
67 );
68 Self::Update {
69 pre,
70 post,
71 origin,
72 }
73 }
74
75 pub fn remove(pre: RecordBatch) -> Self {
76 Self::Remove {
77 pre,
78 origin: None,
79 }
80 }
81
82 pub fn pre(&self) -> Option<&RecordBatch> {
83 match self {
84 Diff::Insert {
85 ..
86 } => None,
87 Diff::Update {
88 pre,
89 ..
90 } => Some(pre),
91 Diff::Remove {
92 pre,
93 ..
94 } => Some(pre),
95 }
96 }
97
98 pub fn post(&self) -> Option<&RecordBatch> {
99 match self {
100 Diff::Insert {
101 post,
102 ..
103 } => Some(post),
104 Diff::Update {
105 post,
106 ..
107 } => Some(post),
108 Diff::Remove {
109 ..
110 } => None,
111 }
112 }
113
114 pub fn batches_mut(&mut self) -> impl Iterator<Item = &mut RecordBatch> {
115 let pair: [Option<&mut RecordBatch>; 2] = match self {
116 Diff::Insert {
117 post,
118 ..
119 } => [Some(post), None],
120 Diff::Update {
121 pre,
122 post,
123 ..
124 } => [Some(pre), Some(post)],
125 Diff::Remove {
126 pre,
127 ..
128 } => [Some(pre), None],
129 };
130 pair.into_iter().flatten()
131 }
132
133 pub fn kind(&self) -> DiffType {
134 match self {
135 Diff::Insert {
136 ..
137 } => DiffType::Insert,
138 Diff::Update {
139 ..
140 } => DiffType::Update,
141 Diff::Remove {
142 ..
143 } => DiffType::Remove,
144 }
145 }
146
147 pub fn row_count(&self) -> usize {
148 match self {
149 Diff::Insert {
150 post,
151 ..
152 } => post.num_rows(),
153 Diff::Update {
154 post,
155 ..
156 } => post.num_rows(),
157 Diff::Remove {
158 pre,
159 ..
160 } => pre.num_rows(),
161 }
162 }
163
164 pub fn origin(&self) -> Option<&ChangeOrigin> {
165 match self {
166 Diff::Insert {
167 origin,
168 ..
169 } => origin.as_ref(),
170 Diff::Update {
171 origin,
172 ..
173 } => origin.as_ref(),
174 Diff::Remove {
175 origin,
176 ..
177 } => origin.as_ref(),
178 }
179 }
180
181 pub fn set_origin(&mut self, new_origin: Option<ChangeOrigin>) {
182 match self {
183 Diff::Insert {
184 origin,
185 ..
186 } => *origin = new_origin,
187 Diff::Update {
188 origin,
189 ..
190 } => *origin = new_origin,
191 Diff::Remove {
192 origin,
193 ..
194 } => *origin = new_origin,
195 }
196 }
197}
198
199#[derive(Debug, Clone)]
200pub struct Change {
201 pub origin: ChangeOrigin,
202
203 pub diffs: Diffs,
204
205 pub version: ChangeVersion,
206
207 pub changed_at: DateTime,
208}
209
210impl Change {
211 pub fn from_object(
212 object: ObjectId,
213 version: ChangeVersion,
214 diffs: impl Into<Diffs>,
215 changed_at: DateTime,
216 ) -> Self {
217 Self {
218 origin: ChangeOrigin::Object(object),
219 diffs: diffs.into(),
220 version,
221 changed_at,
222 }
223 }
224
225 pub fn from_flow(
226 from: OperatorId,
227 version: ChangeVersion,
228 diffs: impl Into<Diffs>,
229 changed_at: DateTime,
230 ) -> Self {
231 Self {
232 origin: ChangeOrigin::Flow(from),
233 diffs: diffs.into(),
234 version,
235 changed_at,
236 }
237 }
238
239 pub fn from_operator(
240 operator: OperatorId,
241 version: ChangeVersion,
242 changed_at: DateTime,
243 result: Change,
244 ) -> Self {
245 Self::from_flow(operator, version, result.diffs, changed_at.max(result.changed_at))
246 }
247
248 pub fn row_count(&self) -> usize {
249 self.diffs.iter().map(Diff::row_count).sum()
250 }
251
252 pub fn merge(changes: Vec<Change>) -> Result<Change> {
253 let mut iter = changes.into_iter();
254 let mut merged = iter.next().expect("Change::merge requires at least one Change");
255 for mut ch in iter {
256 if ch.changed_at > merged.changed_at {
257 merged.changed_at = ch.changed_at;
258 }
259 if ch.version.commit > merged.version.commit {
260 merged.version.commit = ch.version.commit;
261 }
262 if ch.version.source > merged.version.source {
263 merged.version.source = ch.version.source;
264 }
265 if ch.origin != merged.origin {
266 for diff in ch.diffs.iter_mut() {
267 if diff.origin().is_none() {
268 diff.set_origin(Some(ch.origin.clone()));
269 }
270 }
271 }
272 merged.diffs.extend(ch.diffs);
273 }
274 merged.coalesce()?;
275 Ok(merged)
276 }
277
278 pub fn coalesce(&mut self) -> Result<()> {
279 if self.diffs.len() <= 1 {
280 return Ok(());
281 }
282 let original = mem::take(&mut self.diffs);
283 self.diffs = SmallVec::from_vec(coalesce_diffs(original.into_vec())?);
284 Ok(())
285 }
286}