sqlite_diff_rs/builders/view.rs
1//! Read-only views of operations inside a [`DiffSet`].
2//!
3//! [`DiffSet::iter`] (changeset format) and [`DiffSet::iter`] (patchset
4//! format) yield one of these per stored operation. The fields borrow
5//! from the underlying [`DiffSet`], so consumers can render or inspect
6//! the contents without copying any row data.
7//!
8//! Patchsets do not carry full old-row values, so [`PatchsetOp::Delete`]
9//! and [`PatchsetOp::Update`] expose only the primary-key columns. The
10//! [`PatchsetOp::Update`] `entries` slice is the raw `(F::Old, new)`
11//! storage (with `F::Old = ()` for patchsets); call `.iter().map(|(_, v)| v)`
12//! to drop the unit and walk just the new values.
13//!
14//! [`DiffSet`]: super::DiffSet
15//! [`DiffSet::iter`]: super::DiffSet::iter
16
17use alloc::vec::Vec;
18
19use crate::encoding::Value;
20
21/// `(old, new)` value pair stored per column in a changeset UPDATE.
22/// Either slot may be `None`, which means the column was not part of
23/// the diff.
24pub type ChangesetUpdatePair<S, B> = (Option<Value<S, B>>, Option<Value<S, B>>);
25
26/// Entry stored per column in a patchset UPDATE: a unit (the format
27/// does not carry the old value) plus the new value (or `None` for
28/// unchanged columns).
29pub type PatchsetUpdateEntry<S, B> = ((), Option<Value<S, B>>);
30
31/// View over one operation in a changeset.
32#[derive(Debug)]
33pub enum ChangesetOp<'a, T, S, B> {
34 /// `INSERT`. Carries every column's value in column order.
35 Insert {
36 /// Table this row belongs to.
37 table: &'a T,
38 /// Full row values, one per column.
39 values: &'a [Value<S, B>],
40 /// SQLite session-extension indirect flag.
41 indirect: bool,
42 },
43 /// `UPDATE`. Carries `(old, new)` pairs per column. `None` in either
44 /// slot means "undefined" (the column was not part of the diff).
45 Update {
46 /// Table this row belongs to.
47 table: &'a T,
48 /// `(old, new)` pairs, one per column.
49 values: &'a [ChangesetUpdatePair<S, B>],
50 /// SQLite session-extension indirect flag.
51 indirect: bool,
52 },
53 /// `DELETE`. Carries the full old-row values in column order.
54 Delete {
55 /// Table this row belongs to.
56 table: &'a T,
57 /// Full old-row values, one per column.
58 old_values: &'a [Value<S, B>],
59 /// SQLite session-extension indirect flag.
60 indirect: bool,
61 },
62}
63
64impl<'a, T, S, B> ChangesetOp<'a, T, S, B> {
65 /// Returns the schema of the table this operation applies to.
66 #[must_use]
67 pub fn table(&self) -> &'a T {
68 match self {
69 Self::Insert { table, .. }
70 | Self::Update { table, .. }
71 | Self::Delete { table, .. } => table,
72 }
73 }
74
75 /// Returns the SQLite session-extension indirect flag.
76 #[must_use]
77 pub fn indirect(&self) -> bool {
78 match self {
79 Self::Insert { indirect, .. }
80 | Self::Update { indirect, .. }
81 | Self::Delete { indirect, .. } => *indirect,
82 }
83 }
84}
85
86/// View over one operation in a patchset.
87#[derive(Debug)]
88pub enum PatchsetOp<'a, T, S, B> {
89 /// `INSERT`. Carries every column's value in column order.
90 Insert {
91 /// Table this row belongs to.
92 table: &'a T,
93 /// Full row values, one per column.
94 values: &'a [Value<S, B>],
95 /// SQLite session-extension indirect flag.
96 indirect: bool,
97 },
98 /// `UPDATE`. Carries primary-key values plus a `(unit, new)` entry
99 /// per non-PK column. The unit reflects the patchset format's
100 /// missing old-value storage; consumers can map `|(_, v)| v` to walk
101 /// just the new values.
102 Update {
103 /// Table this row belongs to.
104 table: &'a T,
105 /// Primary-key column values for the row being updated.
106 pk: &'a [Value<S, B>],
107 /// `(unit, new)` entries, one per column.
108 entries: &'a [PatchsetUpdateEntry<S, B>],
109 /// SQLite session-extension indirect flag.
110 indirect: bool,
111 },
112 /// `DELETE`. Carries only the primary-key columns; the rest of the
113 /// old row is not stored in patchset format.
114 Delete {
115 /// Table this row belongs to.
116 table: &'a T,
117 /// Primary-key column values for the row being deleted.
118 pk: &'a [Value<S, B>],
119 /// SQLite session-extension indirect flag.
120 indirect: bool,
121 },
122}
123
124impl<'a, T, S, B> PatchsetOp<'a, T, S, B> {
125 /// Returns the schema of the table this operation applies to.
126 #[must_use]
127 pub fn table(&self) -> &'a T {
128 match self {
129 Self::Insert { table, .. }
130 | Self::Update { table, .. }
131 | Self::Delete { table, .. } => table,
132 }
133 }
134
135 /// Returns the SQLite session-extension indirect flag.
136 #[must_use]
137 pub fn indirect(&self) -> bool {
138 match self {
139 Self::Insert { indirect, .. }
140 | Self::Update { indirect, .. }
141 | Self::Delete { indirect, .. } => *indirect,
142 }
143 }
144
145 /// For an `Update` op, returns the new values per column (with the
146 /// unit dropped). Returns `None` for `Insert` and `Delete`.
147 #[must_use]
148 pub fn update_new_values(&self) -> Option<Vec<&'a Option<Value<S, B>>>> {
149 match self {
150 Self::Update { entries, .. } => Some(entries.iter().map(|((), v)| v).collect()),
151 _ => None,
152 }
153 }
154}