sqlite_tiny/api/
answer.rs

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