Skip to main content

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}