sqlite_tiny/api/
answer.rs

1//! An SQLite query result
2
3use crate::api::ffiext::{self, PointerMut, PointerMutFlex};
4use crate::api::row::Row;
5use crate::error::Error;
6use crate::{err, ffi, Sqlite};
7
8/// A query result
9#[derive(Debug)]
10pub struct Answer<'db> {
11    /// The database
12    pub(in crate::api) sqlite: &'db Sqlite,
13    /// The statement
14    pub(in crate::api) raw: PointerMut<ffi::sqlite3_stmt>,
15    /// If we already have a fetched row pending
16    pub(in crate::api) has_row: bool,
17}
18impl Answer<'_> {
19    /// Gets the current pending result row or returns an error if there is no row
20    pub fn row(mut self) -> Result<Row<'static>, Error> {
21        // Try to fetch the next row if necessary
22        if !self.has_row {
23            // Do a step to get the next row if any
24            self.step()?;
25        }
26
27        // Check if we have a row now
28        if !self.has_row {
29            // We still don't have a row
30            return Err(err!("No result row available"));
31        }
32
33        // Return an borrowed row
34        let row = Row { raw: PointerMutFlex::Owned(self.raw) };
35        Ok(row)
36    }
37
38    /// Returns the next row like a fallible iterator
39    pub fn next_row(&mut self) -> Result<Option<Row>, Error> {
40        // Try to fetch the next row if necessary
41        if !self.has_row {
42            // Do a step to get the next row if any
43            self.step()?;
44        }
45
46        // Check if we have a row now
47        if !self.has_row {
48            // We still don't have a row
49            return Ok(None);
50        }
51
52        // Return an borrowed row
53        let row = Row { raw: PointerMutFlex::Borrowed(&mut self.raw) };
54        self.has_row = false;
55        Ok(Some(row))
56    }
57
58    /// Advances the underlying statement towards the first or subsequent row
59    pub(in crate::api) fn step(&mut self) -> Result<(), Error> {
60        // Do a step
61        let retval = unsafe { ffi::sqlite3_step(self.raw.as_ptr()) };
62        let true = matches!(retval, ffi::SQLITE_ROW | ffi::SQLITE_DONE) else {
63            // Failed while trying to get the next row
64            return Err(unsafe { ffiext::sqlite3_last_error(retval, self.sqlite.raw.as_ptr()) });
65        };
66
67        // Mark if we have a pending row
68        self.has_row = retval == ffi::SQLITE_ROW;
69        Ok(())
70    }
71}