couchbase_lite/
query.rs

1use crate::{
2    error::{c4error_init, Error, Result},
3    ffi::{
4        c4query_new2, c4query_release, c4query_run, c4query_setParameters, c4queryenum_next,
5        c4queryenum_release, C4Query, C4QueryEnumerator, C4String, FLArrayIterator_GetCount,
6        FLArrayIterator_GetValueAt, FLStringResult, FLValue,
7    },
8    value::{FromValueRef, ValueRef},
9    Database, QueryLanguage,
10};
11use fallible_streaming_iterator::FallibleStreamingIterator;
12use serde::Serialize;
13use serde_fleece::NonNullConst;
14use std::ptr::{self, NonNull};
15
16pub struct Query<'db> {
17    _db: &'db Database,
18    inner: NonNull<C4Query>,
19}
20
21impl Drop for Query<'_> {
22    fn drop(&mut self) {
23        unsafe { c4query_release(self.inner.as_ptr()) };
24    }
25}
26
27impl Query<'_> {
28    pub(crate) fn new<'a>(
29        db: &'a Database,
30        query_lang: QueryLanguage,
31        query: &str,
32    ) -> Result<Query<'a>> {
33        let mut c4err = c4error_init();
34        let mut out_error_pos = -1;
35        let query = unsafe {
36            c4query_new2(
37                db.inner.0.as_ptr(),
38                query_lang,
39                query.into(),
40                &mut out_error_pos,
41                &mut c4err,
42            )
43        };
44
45        NonNull::new(query)
46            .map(|inner| Query { _db: db, inner })
47            .ok_or_else(|| c4err.into())
48    }
49
50    /// convinient function to call with macros `serde_fleece::fleece`
51    /// as parameter
52    pub fn set_parameters_fleece(
53        &self,
54        parameters: std::result::Result<FLStringResult, serde_fleece::Error>,
55    ) -> Result<()> {
56        let params = parameters?;
57        unsafe {
58            c4query_setParameters(self.inner.as_ptr(), params.as_fl_slice());
59        }
60        Ok(())
61    }
62
63    pub fn set_parameters<T>(&self, parameters: &T) -> Result<()>
64    where
65        T: Serialize,
66    {
67        let param_string = serde_fleece::to_fl_slice_result(parameters)?;
68        unsafe {
69            c4query_setParameters(self.inner.as_ptr(), param_string.as_fl_slice());
70        }
71        Ok(())
72    }
73
74    pub fn run<'a>(&'a self) -> Result<Enumerator<'a>> {
75        let mut c4err = c4error_init();
76        let it = unsafe {
77            c4query_run(
78                self.inner.as_ptr(),
79                ptr::null(),
80                C4String::default(),
81                &mut c4err,
82            )
83        };
84
85        NonNull::new(it)
86            .map(|inner| Enumerator {
87                _query: self,
88                reach_end: false,
89                inner,
90            })
91            .ok_or_else(|| c4err.into())
92    }
93}
94
95pub struct Enumerator<'query> {
96    _query: &'query Query<'query>,
97    reach_end: bool,
98    inner: NonNull<C4QueryEnumerator>,
99}
100
101impl Drop for Enumerator<'_> {
102    #[inline]
103    fn drop(&mut self) {
104        unsafe { c4queryenum_release(self.inner.as_ptr()) };
105    }
106}
107
108impl<'en> FallibleStreamingIterator for Enumerator<'en> {
109    type Error = crate::error::Error;
110    type Item = Enumerator<'en>;
111
112    fn advance(&mut self) -> Result<()> {
113        if self.reach_end {
114            return Ok(());
115        }
116        let mut c4err = c4error_init();
117        if unsafe { c4queryenum_next(self.inner.as_ptr(), &mut c4err) } {
118            Ok(())
119        } else if c4err.code == 0 {
120            self.reach_end = true;
121            Ok(())
122        } else {
123            Err(c4err.into())
124        }
125    }
126
127    #[inline]
128    fn get(&self) -> Option<&Enumerator<'en>> {
129        if !self.reach_end {
130            Some(self)
131        } else {
132            None
133        }
134    }
135}
136
137impl<'a> Enumerator<'a> {
138    fn do_get_raw_checked(&self, i: u32) -> Result<FLValue> {
139        let n = unsafe { FLArrayIterator_GetCount(&self.inner.as_ref().columns) };
140        if i >= n {
141            return Err(Error::LogicError(
142                format!("Enumerator::get_raw_checked: Index out of bounds {i} / {n}").into(),
143            ));
144        }
145
146        Ok(unsafe { FLArrayIterator_GetValueAt(&self.inner.as_ref().columns, i) })
147    }
148
149    #[inline]
150    pub fn get_raw_checked(&self, i: u32) -> Result<ValueRef<'a>> {
151        let value = self.do_get_raw_checked(i)?;
152
153        let val = unsafe { ValueRef::new(value) };
154        Ok(val)
155    }
156
157    #[inline]
158    pub fn get_checked<T>(&self, i: u32) -> Result<T>
159    where
160        T: FromValueRef<'a>,
161    {
162        let value_ref = self.get_raw_checked(i)?;
163        FromValueRef::column_result(value_ref)
164    }
165
166    #[inline]
167    pub fn get_checked_serde<'de, T: serde::de::Deserialize<'de>>(&'de self, i: u32) -> Result<T> {
168        let value = self.do_get_raw_checked(i)?;
169        let value = NonNullConst::new(value).ok_or_else(|| {
170            Error::LogicError(format!("Query parameter {i} is null, can not deserialize").into())
171        })?;
172        serde_fleece::from_fl_value(value).map_err(Error::from)
173    }
174}