Skip to main content

sqlx_cloudflare_core/
result.rs

1/// What a statement did.
2#[derive(Debug, Default, Clone, PartialEq, Eq)]
3pub struct QueryResult {
4    rows_affected: u64,
5    last_insert_rowid: i64,
6}
7
8impl QueryResult {
9    /// A result reporting `rows_affected` and `last_insert_rowid`, 0 when the
10    /// backend reports none.
11    #[must_use]
12    pub fn new(rows_affected: u64, last_insert_rowid: i64) -> Self {
13        Self {
14            rows_affected,
15            last_insert_rowid,
16        }
17    }
18
19    /// Rows the statement inserted, updated or deleted.
20    #[must_use]
21    pub fn rows_affected(&self) -> u64 {
22        self.rows_affected
23    }
24
25    /// The rowid of the last row inserted, or 0 when the statement inserted
26    /// none.
27    ///
28    /// An `i64` rather than an `Option`, as sqlx-sqlite reports it, so code
29    /// written against `SqliteQueryResult` compiles unchanged. Rowids start
30    /// at 1 unless a row is given 0 explicitly, so 0 is unambiguous in
31    /// practice; `RETURNING` is the way to be certain.
32    #[must_use]
33    pub fn last_insert_rowid(&self) -> i64 {
34        self.last_insert_rowid
35    }
36}
37
38impl Extend<QueryResult> for QueryResult {
39    fn extend<T: IntoIterator<Item = QueryResult>>(&mut self, iter: T) {
40        for result in iter {
41            self.rows_affected += result.rows_affected;
42            // The last statement that reported a rowid, not the last
43            // statement: a trailing SELECT reporting none should not erase
44            // the INSERT before it.
45            if result.last_insert_rowid != 0 {
46                self.last_insert_rowid = result.last_insert_rowid;
47            }
48        }
49    }
50}
51
52/// What one statement of a batch did, and the rows it returned.
53///
54/// Generic over the driver's row type, which only the driver can name;
55/// each driver exposes it as its own alias.
56#[derive(Debug, Clone)]
57pub struct BatchResult<R> {
58    rows: Vec<R>,
59    result: QueryResult,
60}
61
62impl<R> BatchResult<R> {
63    /// A statement's `rows` and what it did.
64    #[must_use]
65    pub fn new(rows: Vec<R>, result: QueryResult) -> Self {
66        Self { rows, result }
67    }
68
69    /// The rows the statement returned: a `SELECT`'s, or an `INSERT ...
70    /// RETURNING`'s. Empty for a statement that returns none.
71    #[must_use]
72    pub fn rows(&self) -> &[R] {
73        &self.rows
74    }
75
76    /// The rows, giving up the result.
77    #[must_use]
78    pub fn into_rows(self) -> Vec<R> {
79        self.rows
80    }
81
82    /// What the statement did.
83    #[must_use]
84    pub fn result(&self) -> &QueryResult {
85        &self.result
86    }
87
88    /// The rows and what the statement did.
89    #[must_use]
90    pub fn into_parts(self) -> (Vec<R>, QueryResult) {
91        (self.rows, self.result)
92    }
93}
94
95#[cfg(test)]
96mod tests {
97    use super::QueryResult;
98
99    #[test]
100    fn extend_sums_changes_and_keeps_the_last_reported_rowid() {
101        let mut result = QueryResult::default();
102
103        result.extend([
104            QueryResult::new(2, 7),
105            QueryResult::new(1, 9),
106            QueryResult::new(0, 0),
107        ]);
108
109        assert_eq!(result.rows_affected(), 3);
110        assert_eq!(result.last_insert_rowid(), 9);
111    }
112}