1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use std::{
any::Any,
ops::{Deref, DerefMut},
};
use crate::{
IntoExpr, Table, TableRow, Transaction, scoped_transaction::MutTemp,
transaction::try_update_private,
};
/// [Mutable] access to columns of a single table row.
///
/// The whole row is retrieved and can be inspected/updated from Rust code.
///
/// Only rows that are not used in a `#[unique]` constraint can be updated directly by dereferencing [Mutable].
/// To update columns with a unique constraint, you have to use [Mutable::unique].
pub struct Mutable<'transaction, T: Table> {
pub(crate) temp: &'transaction mut MutTemp<T>,
}
impl<'transaction, T: Table> Mutable<'transaction, T> {
pub(crate) fn new(temp: &'transaction mut dyn Any) -> Self {
Self {
temp: temp.downcast_mut().unwrap(),
}
}
/// Turn the [Mutable] into a [TableRow].
///
/// This will end the lifetime of the [Mutable], which is useful since
/// [Mutable] does not have a non lexical lifetime, because of the [Drop] impl.
///
/// If you do not need the [TableRow], then it is also possible to just call [drop].
pub fn table_row(&self) -> TableRow<T> {
self.temp.row_id
}
/// Update unique constraint columns.
///
/// When the update succeeds, this function returns [Ok], when it fails it returns [Err] with one of
/// three conflict types:
/// - 0 unique constraints => [std::convert::Infallible]
/// - 1 unique constraint => [TableRow] reference to the conflicting table row.
/// - 2+ unique constraints => [crate::Conflict]
///
/// If any of the changes made inside the closure conflict with an existing row, then all changes
/// made inside the closure are reverted.
///
/// If the closure panics, then all changes made inside the closure are also reverted.
/// Applying those changes is not possible, as conflicts can not be reported if there is a panic.
pub fn unique<O>(
&mut self,
f: impl FnOnce(&mut <T::Mutable as Deref>::Target) -> O,
) -> Result<O, T::Conflict> {
// taking the data puts it in a guaranteed valid state
if let Some(update) = self.temp.inner.take() {
try_update_private(self.temp.row_id, update)
.expect("flushing non unique update should always work");
}
let data = Transaction::new_ref().query_one(T::into_select(self.temp.row_id.into_expr()));
let mut data = T::select_mutable(data);
// no need to catch panics here because we already guaranteed a valid state.
let out = f(T::mutable_as_unique(&mut data));
// only apply the update if there was no panic
try_update_private(self.temp.row_id, data)?;
Ok(out)
}
}
impl<'transaction, T: Table> Deref for Mutable<'transaction, T> {
type Target = T::Mutable;
fn deref(&self) -> &Self::Target {
self.temp.inner.get_or_init(|| {
let data =
Transaction::new_ref().query_one(T::into_select(self.temp.row_id.into_expr()));
T::select_mutable(data)
})
}
}
impl<'transaction, T: Table> DerefMut for Mutable<'transaction, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
let _ = Deref::deref(self);
self.temp.inner.get_mut().unwrap()
}
}