native_db_32bit/transaction/query/scan/secondary_scan.rs
1use crate::db_type::{unwrap_item, DatabaseInnerKeyValue, DatabaseInnerKeyValueRange, Input};
2use crate::InnerKeyValue;
3use redb;
4use std::marker::PhantomData;
5use std::ops::RangeBounds;
6
7/// Scan values from the database by secondary key.
8pub struct SecondaryScan<PrimaryTable, SecondaryTable, T: Input>
9where
10 PrimaryTable: redb::ReadableTable<DatabaseInnerKeyValue, &'static [u8]>,
11 SecondaryTable: redb::ReadableTable<DatabaseInnerKeyValue, DatabaseInnerKeyValue>,
12{
13 pub(crate) primary_table: PrimaryTable,
14 pub(crate) secondary_table: SecondaryTable,
15 pub(crate) _marker: PhantomData<T>,
16}
17
18impl<PrimaryTable, SecondaryTable, T: Input> SecondaryScan<PrimaryTable, SecondaryTable, T>
19where
20 PrimaryTable: redb::ReadableTable<DatabaseInnerKeyValue, &'static [u8]>,
21 SecondaryTable: redb::ReadableTable<DatabaseInnerKeyValue, DatabaseInnerKeyValue>,
22{
23 pub(crate) fn new(primary_table: PrimaryTable, secondary_table: SecondaryTable) -> Self {
24 Self {
25 primary_table,
26 secondary_table,
27 _marker: PhantomData::default(),
28 }
29 }
30
31 /// Iterate over all values by secondary key.
32 ///
33 /// If the secondary key is [`optional`](struct.DatabaseBuilder.html#optional) you will
34 /// get all values that have the secondary key set.
35 ///
36 /// Anatomy of a secondary key it is a `enum` with the following structure: `<table_name>Key::<name>`.
37 ///
38 /// # Example
39 /// ```rust
40 /// use native_db::*;
41 /// use native_model::{native_model, Model};
42 /// use serde::{Deserialize, Serialize};
43 ///
44 /// #[derive(Serialize, Deserialize)]
45 /// #[native_model(id=1, version=1)]
46 /// #[native_db]
47 /// struct Data {
48 /// #[primary_key]
49 /// id: u64,
50 /// #[secondary_key(optional)]
51 /// name: Option<String>,
52 /// }
53 ///
54 /// fn main() -> Result<(), db_type::Error> {
55 /// let mut builder = DatabaseBuilder::new();
56 /// builder.define::<Data>()?;
57 /// let db = builder.create_in_memory()?;
58 ///
59 /// // Open a read transaction
60 /// let r = db.r_transaction()?;
61 ///
62 /// // Get only values that have the secondary key set (name is not None)
63 /// let _values: Vec<Data> = r.scan().secondary(DataKey::name)?.all().collect();
64 /// Ok(())
65 /// }
66 /// ```
67 pub fn all(&self) -> SecondaryScanIterator<PrimaryTable, T> {
68 let range = self
69 .secondary_table
70 .range::<DatabaseInnerKeyValue>(..)
71 .unwrap();
72 SecondaryScanIterator {
73 primary_table: &self.primary_table,
74 range,
75 _marker: PhantomData::default(),
76 }
77 }
78
79 /// Iterate over all values by secondary key.
80 ///
81 /// Anatomy of a secondary key it is a `enum` with the following structure: `<table_name>Key::<name>`.
82 ///
83 /// # Example
84 /// ```rust
85 /// use native_db::*;
86 /// use native_model::{native_model, Model};
87 /// use serde::{Deserialize, Serialize};
88 ///
89 /// #[derive(Serialize, Deserialize)]
90 /// #[native_model(id=1, version=1)]
91 /// #[native_db]
92 /// struct Data {
93 /// #[primary_key]
94 /// id: u64,
95 /// #[secondary_key]
96 /// name: String,
97 /// }
98 ///
99 /// fn main() -> Result<(), db_type::Error> {
100 /// let mut builder = DatabaseBuilder::new();
101 /// builder.define::<Data>()?;
102 /// let db = builder.create_in_memory()?;
103 ///
104 /// // Open a read transaction
105 /// let r = db.r_transaction()?;
106 ///
107 /// // Get only values that have the secondary key name from C to the end
108 /// let _values: Vec<Data> = r.scan().secondary(DataKey::name)?.range("C"..).collect();
109 /// Ok(())
110 /// }
111 /// ```
112 pub fn range<TR: InnerKeyValue, R: RangeBounds<TR>>(
113 &self,
114 range: R,
115 ) -> SecondaryScanIterator<PrimaryTable, T> {
116 let database_inner_key_value_range = DatabaseInnerKeyValueRange::new(range);
117 let range = self
118 .secondary_table
119 .range::<DatabaseInnerKeyValue>(database_inner_key_value_range)
120 .unwrap();
121 SecondaryScanIterator {
122 primary_table: &self.primary_table,
123 range,
124 _marker: PhantomData::default(),
125 }
126 }
127
128 /// Iterate over all values by secondary key.
129 ///
130 /// Anatomy of a secondary key it is a `enum` with the following structure: `<table_name>Key::<name>`.
131 ///
132 /// # Example
133 /// ```rust
134 /// use native_db::*;
135 /// use native_model::{native_model, Model};
136 /// use serde::{Deserialize, Serialize};
137 ///
138 /// #[derive(Serialize, Deserialize)]
139 /// #[native_model(id=1, version=1)]
140 /// #[native_db]
141 /// struct Data {
142 /// #[primary_key]
143 /// id: u64,
144 /// #[secondary_key]
145 /// name: String,
146 /// }
147 ///
148 /// fn main() -> Result<(), db_type::Error> {
149 /// let mut builder = DatabaseBuilder::new();
150 /// builder.define::<Data>()?;
151 /// let db = builder.create_in_memory()?;
152 ///
153 /// // Open a read transaction
154 /// let r = db.r_transaction()?;
155 ///
156 /// // Get only values that have the secondary key name starting with "hello"
157 /// let _values: Vec<Data> = r.scan().secondary(DataKey::name)?.start_with("hello").collect();
158 /// Ok(())
159 /// }
160 /// ```
161 pub fn start_with<'a>(
162 &'a self,
163 start_with: impl InnerKeyValue + 'a,
164 ) -> SecondaryScanIteratorStartWith<'a, PrimaryTable, T> {
165 let start_with = start_with.database_inner_key_value();
166 let range = self
167 .secondary_table
168 .range::<DatabaseInnerKeyValue>(start_with.clone()..)
169 .unwrap();
170 SecondaryScanIteratorStartWith {
171 primary_table: &self.primary_table,
172 start_with,
173 range,
174 _marker: PhantomData::default(),
175 }
176 }
177}
178
179pub struct SecondaryScanIterator<'a, PrimaryTable, T: Input>
180where
181 PrimaryTable: redb::ReadableTable<DatabaseInnerKeyValue, &'static [u8]>,
182{
183 pub(crate) primary_table: &'a PrimaryTable,
184 pub(crate) range: redb::Range<'a, DatabaseInnerKeyValue, DatabaseInnerKeyValue>,
185 pub(crate) _marker: PhantomData<T>,
186}
187
188impl<'a, PrimaryTable, T: Input> Iterator for SecondaryScanIterator<'a, PrimaryTable, T>
189where
190 PrimaryTable: redb::ReadableTable<DatabaseInnerKeyValue, &'static [u8]>,
191{
192 type Item = T;
193
194 fn next(&mut self) -> Option<Self::Item> {
195 match self.range.next() {
196 Some(Ok((_, key))) => {
197 if let Ok(value) = self.primary_table.get(key.value()) {
198 unwrap_item(value)
199 } else {
200 None
201 }
202 }
203 _ => None,
204 }
205 }
206}
207
208impl<'a, PrimaryTable, T: Input> DoubleEndedIterator for SecondaryScanIterator<'a, PrimaryTable, T>
209where
210 PrimaryTable: redb::ReadableTable<DatabaseInnerKeyValue, &'static [u8]>,
211{
212 fn next_back(&mut self) -> Option<Self::Item> {
213 match self.range.next_back() {
214 Some(Ok((_, key))) => unwrap_item(self.primary_table.get(key.value()).unwrap()),
215 _ => None,
216 }
217 }
218}
219
220pub struct SecondaryScanIteratorStartWith<'a, PrimaryTable, T>
221where
222 PrimaryTable: redb::ReadableTable<DatabaseInnerKeyValue, &'static [u8]>,
223 T: Input,
224{
225 pub(crate) primary_table: &'a PrimaryTable,
226 pub(crate) start_with: DatabaseInnerKeyValue,
227 pub(crate) range: redb::Range<'a, DatabaseInnerKeyValue, DatabaseInnerKeyValue>,
228 pub(crate) _marker: PhantomData<T>,
229}
230
231impl<'a, PrimaryTable, T> Iterator for SecondaryScanIteratorStartWith<'a, PrimaryTable, T>
232where
233 PrimaryTable: redb::ReadableTable<DatabaseInnerKeyValue, &'static [u8]>,
234 T: Input,
235{
236 type Item = T;
237
238 fn next(&mut self) -> Option<Self::Item> {
239 match self.range.next() {
240 Some(Ok((secondary_key, primary_key))) => {
241 if secondary_key
242 .value()
243 .as_slice()
244 .starts_with(self.start_with.as_slice())
245 {
246 unwrap_item(self.primary_table.get(primary_key.value()).unwrap())
247 } else {
248 None
249 }
250 }
251 _ => None,
252 }
253 }
254}