aboutsummaryrefslogtreecommitdiff
path: root/database/src/filter/mod.rs
blob: c40e4c03242252f534e5d7e1a3d5c3c523766479 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/*
    This file is part of jellything (https://codeberg.org/metamuffin/jellything)
    which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
    Copyright (C) 2026 metamuffin <metamuffin.org>
*/
pub mod binning;

use crate::{
    filter::binning::{Binning, BinningComponent},
    query::Filter,
};

impl Filter {
    pub fn get_bins(&self) -> Vec<Binning> {
        fn recurse(f: &Filter) -> Vec<Vec<BinningComponent>> {
            match f {
                Filter::True => vec![vec![]],
                Filter::All(filters) => {
                    let mut o = vec![vec![]];
                    for filter in filters {
                        let mut new_o = Vec::new();
                        for par in recurse(filter) {
                            for mut prev in o.clone() {
                                prev.extend(par.clone());
                                new_o.push(prev);
                            }
                        }
                        o = new_o;
                    }
                    o
                }
                Filter::Any(filters) => filters.iter().flat_map(|f| recurse(f)).collect(),
                Filter::Match(path, _) => vec![vec![BinningComponent::Match(path.to_owned())]],
                Filter::Has(path) => vec![vec![BinningComponent::Has(path.to_owned())]],
            }
        }
        recurse(self).into_iter().map(Binning::new).collect()
    }
}

#[cfg(test)]
mod test {
    use crate::{
        filter::binning::{Binning, BinningComponent},
        query::Filter,
    };
    use jellyobject::{Path, Tag};

    #[test]
    fn all() {
        let f = Filter::All(vec![
            Filter::Has(Path(vec![Tag(0)])),
            Filter::Has(Path(vec![Tag(1)])),
        ]);
        let bins = vec![Binning::new(vec![
            BinningComponent::Has(Path(vec![Tag(0)])),
            BinningComponent::Has(Path(vec![Tag(1)])),
        ])];
        assert_eq!(f.get_bins(), bins)
    }

    #[test]
    fn any() {
        let f = Filter::Any(vec![
            Filter::Has(Path(vec![Tag(0)])),
            Filter::Has(Path(vec![Tag(1)])),
        ]);
        let bins = vec![
            Binning::new(vec![BinningComponent::Has(Path(vec![Tag(0)]))]),
            Binning::new(vec![BinningComponent::Has(Path(vec![Tag(1)]))]),
        ];
        assert_eq!(f.get_bins(), bins)
    }

    #[test]
    fn nested() {
        let f = Filter::All(vec![
            Filter::Any(vec![
                Filter::Has(Path(vec![Tag(0)])),
                Filter::Has(Path(vec![Tag(1)])),
            ]),
            Filter::Any(vec![
                Filter::Has(Path(vec![Tag(2)])),
                Filter::Has(Path(vec![Tag(3)])),
            ]),
        ]);
        let bins = vec![
            Binning::new(vec![
                BinningComponent::Has(Path(vec![Tag(0)])),
                BinningComponent::Has(Path(vec![Tag(2)])),
            ]),
            Binning::new(vec![
                BinningComponent::Has(Path(vec![Tag(1)])),
                BinningComponent::Has(Path(vec![Tag(2)])),
            ]),
            Binning::new(vec![
                BinningComponent::Has(Path(vec![Tag(0)])),
                BinningComponent::Has(Path(vec![Tag(3)])),
            ]),
            Binning::new(vec![
                BinningComponent::Has(Path(vec![Tag(1)])),
                BinningComponent::Has(Path(vec![Tag(3)])),
            ]),
        ];
        assert_eq!(f.get_bins(), bins)
    }
}