structsy/
queries.rs

1#[allow(deprecated)]
2use crate::{
3    filter::Filter,
4    filter_builder::Reader,
5    internal::{EmbeddedDescription, Projection},
6    Fetch, FilterBuilder, IntoResult, OwnedSytx, Persistent, PersistentEmbedded, Ref, Snapshot, Structsy,
7};
8/// Iterator for query results
9pub struct StructsyIter<'a, T> {
10    iterator: Box<dyn Iterator<Item = T> + 'a>,
11}
12
13impl<'a, T> StructsyIter<'a, T> {
14    pub fn new<I>(iterator: I) -> StructsyIter<'a, T>
15    where
16        I: Iterator<Item = T>,
17        I: 'a,
18    {
19        StructsyIter {
20            iterator: Box::new(iterator),
21        }
22    }
23}
24
25impl<'a, T> Iterator for StructsyIter<'a, T> {
26    type Item = T;
27
28    fn next(&mut self) -> Option<Self::Item> {
29        self.iterator.next()
30    }
31}
32
33/// And/Or/Not Operators
34/// # Example
35/// ```
36/// use structsy::{ Structsy, StructsyTx, StructsyError, Operators};
37/// use structsy_derive::{queries, Persistent};
38/// #[derive(Persistent)]
39/// struct Basic {
40///     name: String,
41/// }
42/// impl Basic {
43///     fn new(name: &str) -> Basic {
44///         Basic { name: name.to_string() }
45///     }
46/// }
47///
48/// #[queries(Basic)]
49/// trait BasicQuery {
50///      fn by_name(self, name: String) -> Self;
51/// }
52///
53///
54/// fn basic_query() -> Result<(), StructsyError> {
55///     let structsy = Structsy::open("file.structsy")?;
56///     structsy.define::<Basic>()?;
57///     let mut tx = structsy.begin()?;
58///     tx.insert(&Basic::new("aaa"))?;
59///     tx.insert(&Basic::new("bbb"))?;
60///     tx.commit()?;
61///     let count = structsy.query::<Basic>().or(|or| {
62///             or.by_name("aaa".to_string()).by_name("bbb".to_string())
63///         }).fetch().count();
64///     assert_eq!(count, 2);
65///     let count = structsy.query::<Basic>().not(|not| {
66///             not.by_name("aaa".to_string())
67///         }).fetch().count();
68///     assert_eq!(count, 1);
69///     let count = structsy.query::<Basic>().and(|and| {
70///             and.by_name("aaa".to_string()).by_name("bbb".to_string())
71///         }).fetch().count();
72///     assert_eq!(count, 0);
73///     Ok(())
74/// }
75/// ```
76pub trait Operators<F> {
77    fn or<FN: Fn(F) -> F>(self, builder: FN) -> Self;
78    fn and<FN: Fn(F) -> F>(self, builder: FN) -> Self;
79    fn not<FN: Fn(F) -> F>(self, builder: FN) -> Self;
80}
81
82pub trait EmbeddedQuery<T: PersistentEmbedded + 'static>: Sized {
83    fn filter_builder(&mut self) -> &mut FilterBuilder<T>;
84    fn add_group(&mut self, filter: Filter<T>);
85}
86
87impl<T: EmbeddedDescription + 'static, Q: EmbeddedQuery<T>> Operators<Filter<T>> for Q {
88    fn or<FN: Fn(Filter<T>) -> Filter<T>>(mut self, builder: FN) -> Self {
89        self.filter_builder().or(builder(Filter::<T>::new()).extract_filter());
90        self
91    }
92    fn and<FN: Fn(Filter<T>) -> Filter<T>>(mut self, builder: FN) -> Self {
93        self.filter_builder().and(builder(Filter::<T>::new()).extract_filter());
94        self
95    }
96    fn not<FN: Fn(Filter<T>) -> Filter<T>>(mut self, builder: FN) -> Self {
97        self.filter_builder().not(builder(Filter::<T>::new()).extract_filter());
98        self
99    }
100}
101
102pub struct ProjectionResult<P, T> {
103    filter: FilterBuilder<T>,
104    phantom: std::marker::PhantomData<P>,
105}
106impl<P, T> ProjectionResult<P, T> {
107    pub(crate) fn new(filter: FilterBuilder<T>) -> Self {
108        Self {
109            filter,
110            phantom: std::marker::PhantomData,
111        }
112    }
113}
114
115impl<P: Projection<T>, T: Persistent + 'static> Fetch<P> for ProjectionResult<P, T> {
116    fn into(self, structsy: &Structsy) -> StructsyIter<P> {
117        self.fetch(structsy)
118    }
119
120    fn into_tx(self, tx: &mut OwnedSytx) -> StructsyIter<P> {
121        self.fetch_tx(tx)
122    }
123
124    fn fetch(self, structsy: &Structsy) -> StructsyIter<P> {
125        let data = self.filter.finish(Reader::Structsy(structsy.clone()));
126        StructsyIter::new(Box::new(data.map(|(_, r)| Projection::projection(&r))))
127    }
128
129    fn fetch_tx(self, tx: &mut OwnedSytx) -> StructsyIter<P> {
130        let data = self.filter.finish(Reader::Tx(tx.reference()));
131        StructsyIter::new(Box::new(data.map(|(_, r)| Projection::projection(&r))))
132    }
133
134    fn fetch_snapshot(self, snapshot: &Snapshot) -> StructsyIter<P> {
135        let data = self.filter.finish(Reader::Snapshot(snapshot.clone()));
136        StructsyIter::new(Box::new(data.map(|(_, r)| Projection::projection(&r))))
137    }
138}
139
140#[allow(deprecated)]
141impl<P: Projection<T>, T: Persistent + 'static> IntoResult<P> for ProjectionResult<P, T> {}
142
143#[allow(deprecated)]
144impl<T: Persistent + 'static> IntoResult<(Ref<T>, T)> for Filter<T> {}
145
146/// Base trait for all the query types
147pub trait Query<T: Persistent + 'static>: Sized {
148    fn filter_builder(&mut self) -> &mut FilterBuilder<T>;
149    fn add_group(&mut self, filter: Filter<T>);
150}
151
152/// A query to be executed on a specific snapshot
153pub struct SnapshotQuery<T> {
154    pub(crate) snapshot: Snapshot,
155    pub(crate) builder: FilterBuilder<T>,
156}
157
158impl<T: Persistent + 'static> IntoIterator for SnapshotQuery<T> {
159    type Item = (Ref<T>, T);
160    type IntoIter = StructsyIter<'static, (Ref<T>, T)>;
161    fn into_iter(self) -> Self::IntoIter {
162        StructsyIter::new(self.builder.finish(Reader::Snapshot(self.snapshot)))
163    }
164}
165
166impl<T: Persistent + 'static> Query<T> for SnapshotQuery<T> {
167    fn filter_builder(&mut self) -> &mut FilterBuilder<T> {
168        &mut self.builder
169    }
170    fn add_group(&mut self, filter: Filter<T>) {
171        let base = self.filter_builder();
172        base.and_filter(filter.extract_filter());
173    }
174}
175impl<T: Persistent + 'static> SnapshotQuery<T> {
176    pub(crate) fn builder(self) -> FilterBuilder<T> {
177        self.builder
178    }
179    pub fn projection<P: Projection<T>>(self) -> ProjectionSnapshotQuery<P, T> {
180        ProjectionSnapshotQuery {
181            builder: self.builder,
182            snapshot: self.snapshot,
183            phantom: std::marker::PhantomData,
184        }
185    }
186
187    pub fn fetch(self) -> StructsyIter<'static, (Ref<T>, T)> {
188        StructsyIter::new(self.builder.finish(Reader::Snapshot(self.snapshot)))
189    }
190}
191
192pub struct ProjectionSnapshotQuery<P, T> {
193    builder: FilterBuilder<T>,
194    snapshot: Snapshot,
195    phantom: std::marker::PhantomData<P>,
196}
197
198impl<P: Projection<T>, T: Persistent + 'static> ProjectionSnapshotQuery<P, T> {
199    pub fn fetch(self) -> StructsyIter<'static, P> {
200        let data = self.builder.finish(Reader::Snapshot(self.snapshot));
201        StructsyIter::new(Box::new(data.map(|(_, r)| Projection::projection(&r))))
202    }
203}
204
205impl<P: Projection<T>, T: Persistent + 'static> IntoIterator for ProjectionSnapshotQuery<P, T> {
206    type Item = P;
207    type IntoIter = StructsyIter<'static, P>;
208    fn into_iter(self) -> Self::IntoIter {
209        let data = self.builder.finish(Reader::Snapshot(self.snapshot));
210        StructsyIter::new(Box::new(data.map(|(_, r)| Projection::projection(&r))))
211    }
212}
213
214/// Query for a persistent struct
215///
216/// # Example
217/// ```
218/// use structsy::{ Structsy, StructsyTx, StructsyError};
219/// use structsy_derive::{queries, Persistent};
220/// #[derive(Persistent)]
221/// struct Basic {
222///     name: String,
223/// }
224/// impl Basic {
225///     fn new(name: &str) -> Basic {
226///         Basic { name: name.to_string() }
227///     }
228/// }
229///
230/// #[queries(Basic)]
231/// trait BasicQuery {
232///      fn by_name(self, name: String) -> Self;
233/// }
234///
235///
236/// fn basic_query() -> Result<(), StructsyError> {
237///     let structsy = Structsy::open("file.structsy")?;
238///     structsy.define::<Basic>()?;
239///     let mut tx = structsy.begin()?;
240///     tx.insert(&Basic::new("aaa"))?;
241///     tx.commit()?;
242///     let count = structsy.query::<Basic>().by_name("aaa".to_string()).fetch().count();
243///     assert_eq!(count, 1);
244///     Ok(())
245/// }
246/// ```
247pub struct StructsyQuery<T: Persistent + 'static> {
248    pub(crate) structsy: Structsy,
249    pub(crate) builder: FilterBuilder<T>,
250}
251
252impl<T: Persistent + 'static> Query<T> for StructsyQuery<T> {
253    fn filter_builder(&mut self) -> &mut FilterBuilder<T> {
254        &mut self.builder
255    }
256    fn add_group(&mut self, filter: Filter<T>) {
257        let base = self.filter_builder();
258        base.and_filter(filter.extract_filter());
259    }
260}
261impl<T: Persistent + 'static> StructsyQuery<T> {
262    pub(crate) fn builder(self) -> FilterBuilder<T> {
263        self.builder
264    }
265    pub fn projection<P: Projection<T>>(self) -> ProjectionQuery<P, T> {
266        ProjectionQuery {
267            builder: self.builder,
268            structsy: self.structsy,
269            phantom: std::marker::PhantomData,
270        }
271    }
272
273    pub fn fetch(self) -> StructsyIter<'static, (Ref<T>, T)> {
274        StructsyIter::new(self.builder.finish(Reader::Structsy(self.structsy.clone())))
275    }
276}
277
278impl<T: Persistent> IntoIterator for StructsyQuery<T> {
279    type Item = (Ref<T>, T);
280    type IntoIter = StructsyIter<'static, (Ref<T>, T)>;
281    fn into_iter(self) -> Self::IntoIter {
282        StructsyIter::new(self.builder.finish(Reader::Structsy(self.structsy.clone())))
283    }
284}
285
286pub struct ProjectionQuery<P: Projection<T>, T> {
287    builder: FilterBuilder<T>,
288    structsy: Structsy,
289    phantom: std::marker::PhantomData<P>,
290}
291
292impl<P: Projection<T>, T: Persistent + 'static> ProjectionQuery<P, T> {
293    pub fn fetch(self) -> StructsyIter<'static, P> {
294        let data = self.builder.finish(Reader::Structsy(self.structsy.clone()));
295        StructsyIter::new(Box::new(data.map(|(_, r)| Projection::projection(&r))))
296    }
297}
298
299impl<P: Projection<T>, T: Persistent + 'static> IntoIterator for ProjectionQuery<P, T> {
300    type Item = P;
301    type IntoIter = StructsyIter<'static, P>;
302    fn into_iter(self) -> Self::IntoIter {
303        let data = self.builder.finish(Reader::Structsy(self.structsy.clone()));
304        StructsyIter::new(Box::new(data.map(|(_, r)| Projection::projection(&r))))
305    }
306}
307
308/// Query for a persistent struct considering in transaction changes.
309///
310/// # Example
311/// ```
312/// use structsy::{ Structsy, StructsyTx, StructsyError};
313/// use structsy_derive::{queries, Persistent};
314/// #[derive(Persistent)]
315/// struct Basic {
316///     name: String,
317/// }
318/// impl Basic {
319///     fn new(name: &str) -> Basic {
320///         Basic { name: name.to_string() }
321///     }
322/// }
323///
324/// #[queries(Basic)]
325/// trait BasicQuery {
326///     fn by_name(self, name: String) -> Self;
327/// }
328///
329///
330/// fn basic_query() -> Result<(), StructsyError> {
331///     let structsy = Structsy::open("file.structsy")?;
332///     structsy.define::<Basic>()?;
333///     let mut tx = structsy.begin()?;
334///     tx.insert(&Basic::new("aaa"))?;
335///     let count = tx.query::<Basic>().by_name("aaa".to_string()).fetch().count();
336///     assert_eq!(count, 1);
337///     tx.commit()?;
338///     Ok(())
339/// }
340/// ```
341///
342pub struct StructsyQueryTx<'a, T: Persistent + 'static> {
343    pub(crate) tx: &'a mut OwnedSytx,
344    pub(crate) builder: FilterBuilder<T>,
345}
346
347impl<'a, T: Persistent + 'static> Query<T> for StructsyQueryTx<'a, T> {
348    fn filter_builder(&mut self) -> &mut FilterBuilder<T> {
349        &mut self.builder
350    }
351    fn add_group(&mut self, filter: Filter<T>) {
352        let base = self.filter_builder();
353        base.and_filter(filter.extract_filter());
354    }
355}
356impl<'a, T: Persistent> StructsyQueryTx<'a, T> {
357    /// Make a projection from filtered structs.
358    ///
359    ///
360    /// # Example
361    /// ```rust
362    /// use structsy::{ Structsy, StructsyTx, StructsyError, Filter};
363    /// use structsy_derive::{queries, Projection, Persistent};
364    ///
365    /// #[derive(Persistent)]
366    /// struct Person {
367    ///     name:String,
368    ///     surname:String,
369    /// }
370    ///
371    /// impl Person {
372    ///     fn new(name:&str, surname:&str) -> Self {
373    ///         Person {
374    ///             name: name.to_string(),
375    ///             surname: surname.to_string(),
376    ///         }
377    ///     }
378    /// }
379    ///
380    /// #[queries(Person)]
381    /// trait PersonQuery {
382    ///     fn by_name(self, name:&str) -> Self;
383    /// }
384    ///
385    /// #[derive(Projection)]
386    /// #[projection = "Person" ]
387    /// struct NameProjection {
388    ///     name:String,
389    /// }
390    ///
391    ///
392    /// fn main() -> Result<(), StructsyError> {
393    ///     let structsy = Structsy::memory()?;
394    ///     structsy.define::<Person>()?;
395    ///     let mut tx = structsy.begin()?;
396    ///     tx.insert(&Person::new("a_name", "a_surname"))?;
397    ///     tx.commit()?;
398    ///     let query = structsy.query::<Person>().by_name("a_name").projection::<NameProjection>();
399    ///     assert_eq!(query.fetch().next().unwrap().name, "a_name");
400    ///     Ok(())
401    /// }
402    /// ```
403    pub fn projection<P: Projection<T>>(self) -> ProjectionQueryTx<'a, P, T> {
404        ProjectionQueryTx {
405            tx: self.tx,
406            builder: self.builder,
407            phantom: std::marker::PhantomData,
408        }
409    }
410
411    pub fn fetch(self) -> StructsyIter<'a, (Ref<T>, T)> {
412        StructsyIter::new(self.builder.finish(Reader::Tx(self.tx.reference())))
413    }
414}
415pub struct ProjectionQueryTx<'a, P, T> {
416    tx: &'a mut OwnedSytx,
417    builder: FilterBuilder<T>,
418    phantom: std::marker::PhantomData<P>,
419}
420
421impl<'a, P: Projection<T>, T: Persistent + 'static> ProjectionQueryTx<'a, P, T> {
422    pub fn fetch(self) -> StructsyIter<'a, P> {
423        let data = self.builder.finish(Reader::Tx(self.tx.reference()));
424        StructsyIter::new(Box::new(data.map(|(_, r)| Projection::projection(&r))))
425    }
426}
427
428impl<'a, P: Projection<T>, T: Persistent + 'static> IntoIterator for ProjectionQueryTx<'a, P, T> {
429    type Item = P;
430    type IntoIter = StructsyIter<'a, P>;
431    fn into_iter(self) -> Self::IntoIter {
432        let data = self.builder.finish(Reader::Tx(self.tx.reference()));
433        StructsyIter::new(Box::new(data.map(|(_, r)| Projection::projection(&r))))
434    }
435}
436
437impl<'a, T: Persistent> IntoIterator for StructsyQueryTx<'a, T> {
438    type Item = (Ref<T>, T);
439    type IntoIter = StructsyIter<'a, (Ref<T>, T)>;
440    fn into_iter(self) -> Self::IntoIter {
441        StructsyIter::new(self.builder.finish(Reader::Tx(self.tx.reference())))
442    }
443}
444
445pub struct StructsyFilter<T: Persistent> {
446    filter: Filter<T>,
447}
448
449impl<T: Persistent + 'static> StructsyFilter<T> {
450    pub fn new() -> StructsyFilter<T> {
451        StructsyFilter {
452            filter: Filter::<T>::new(),
453        }
454    }
455}
456impl<T: Persistent + 'static> Query<T> for StructsyFilter<T> {
457    fn filter_builder(&mut self) -> &mut FilterBuilder<T> {
458        self.filter.filter_builder()
459    }
460    fn add_group(&mut self, filter: Filter<T>) {
461        self.filter.add_group(filter)
462    }
463}
464
465impl<T: Persistent + 'static, Q: Query<T>> Operators<StructsyFilter<T>> for Q {
466    fn or<FN: Fn(StructsyFilter<T>) -> StructsyFilter<T>>(mut self, builder: FN) -> Self {
467        self.filter_builder()
468            .or(builder(StructsyFilter::<T>::new()).filter.extract_filter());
469        self
470    }
471    fn and<FN: Fn(StructsyFilter<T>) -> StructsyFilter<T>>(mut self, builder: FN) -> Self {
472        self.filter_builder()
473            .and(builder(StructsyFilter::<T>::new()).filter.extract_filter());
474        self
475    }
476    fn not<FN: Fn(StructsyFilter<T>) -> StructsyFilter<T>>(mut self, builder: FN) -> Self {
477        self.filter_builder()
478            .not(builder(StructsyFilter::<T>::new()).filter.extract_filter());
479        self
480    }
481}
482
483#[cfg(test)]
484mod tests {
485    use super::Query;
486    use crate::{
487        actions::EqualAction,
488        internal::{Description, Field},
489        Filter, Persistent, Ref, SRes, Sytx,
490    };
491
492    use std::io::{Read, Write};
493    struct ToQuery {
494        first: String,
495        second: Vec<String>,
496    }
497    impl Persistent for ToQuery {
498        fn get_name() -> &'static str {
499            "ToQuery"
500        }
501        fn get_description() -> Description {
502            let fields = [
503                crate::internal::FieldDescription::new::<String>(0u32, "first", None),
504                crate::internal::FieldDescription::new::<Vec<String>>(2u32, "second", None),
505            ];
506            Description::Struct(crate::internal::StructDescription::new("ToQuery", &fields))
507        }
508        fn read(_read: &mut dyn Read) -> SRes<Self>
509        where
510            Self: std::marker::Sized,
511        {
512            unimplemented!()
513        }
514        fn remove_indexes(&self, _tx: &mut dyn Sytx, _id: &Ref<Self>) -> SRes<()>
515        where
516            Self: std::marker::Sized,
517        {
518            unimplemented!()
519        }
520        fn write(&self, _write: &mut dyn Write) -> SRes<()> {
521            unimplemented!()
522        }
523        fn put_indexes(&self, _tx: &mut dyn Sytx, _id: &Ref<Self>) -> SRes<()>
524        where
525            Self: std::marker::Sized,
526        {
527            unimplemented!()
528        }
529        fn declare(_db: &mut dyn Sytx) -> SRes<()> {
530            unimplemented!()
531        }
532    }
533    impl ToQuery {
534        pub fn field_first() -> Field<Self, String> {
535            Field::<ToQuery, String>::new("first", |x| &x.first)
536        }
537        pub fn field_second() -> Field<Self, Vec<String>> {
538            Field::<ToQuery, Vec<String>>::new("second", |x| &x.second)
539        }
540    }
541
542    trait MyQuery {
543        fn by_name(self, first: String) -> Self;
544        fn by_second(self, second: String) -> Self;
545        fn by_first_and_second(self, first: String, second: String) -> Self;
546    }
547
548    impl MyQuery for Filter<ToQuery> {
549        fn by_name(mut self, first: String) -> Self {
550            let builder = self.filter_builder();
551            EqualAction::equal((ToQuery::field_first(), builder), first);
552            self
553        }
554        fn by_second(mut self, second: String) -> Self {
555            let builder = self.filter_builder();
556            EqualAction::equal((ToQuery::field_second(), builder), second);
557            self
558        }
559        fn by_first_and_second(mut self, first: String, second: String) -> Self {
560            EqualAction::equal((ToQuery::field_first(), self.filter_builder()), first);
561            EqualAction::equal((ToQuery::field_second(), self.filter_builder()), second);
562            self
563        }
564    }
565    #[test]
566    fn test_query_build() {
567        let filter = Filter::<ToQuery>::new();
568        filter.by_name("one".to_string()).by_second("second".to_string());
569    }
570}