Skip to main content

nf_rated/data/
query_builder.rs

1use super::ColumnFilter;
2
3const QUERY_HEAD: &str = "SELECT * FROM nf_imdb WHERE";
4const QUERY_TAIL: &str = "last_sync IS NOT NULL ORDER BY imdb_rating DESC;";
5
6pub const GENRE_COLUMN: &str = "genre";
7pub const TITLE_COLUMN: &str = "title";
8pub const CAST_COLUMN: &str = "cast";
9pub const LANGUAGE_COLUMN: &str = "language";
10pub const COUNTRY_COLUMN: &str = "country";
11pub const DIRECTOR_COLUMN: &str = "director";
12pub const PLOT_COLUMN: &str = "plot";
13
14pub enum ItemType {
15    Movie,
16    Series,
17    Both,
18}
19const MOVIE_ITEM_FILTER: &str = "\n  AND type = 'movie'";
20const SHOW_ITEM_FILTER: &str = "\n  AND type = 'series'";
21const BOTH_ITEM_FILTER: &str = "";
22
23fn get_item_filter(item_type: &ItemType) -> String {
24    match item_type {
25        ItemType::Movie => MOVIE_ITEM_FILTER.to_string(),
26        ItemType::Series => SHOW_ITEM_FILTER.to_string(),
27        ItemType::Both => BOTH_ITEM_FILTER.to_string(),
28    }
29}
30
31pub fn build_sorted_query(item_type: &ItemType) -> String {
32    let item_filter = get_item_filter(item_type).replace(" AND ", "");
33    let and = match item_type {
34        ItemType::Movie | ItemType::Series => "AND ",
35        ItemType::Both => "",
36    };
37    format!("{}{}\n {}{}", QUERY_HEAD, item_filter, and, QUERY_TAIL)
38}
39
40pub fn build_sorted_filtered_query(filters: Vec<ColumnFilter>, item_type: &ItemType) -> String {
41    let mut matched_before = false;
42    let resolved_filters: Vec<String> = filters
43        .iter()
44        .flat_map(|filter| {
45            let matches = filter.sql_fragments(matched_before);
46            matched_before = matched_before || matches.len() > 0;
47            matches
48        })
49        .collect();
50
51    let query_filter = resolved_filters.join("");
52    let item_filter = get_item_filter(item_type);
53
54    format!(
55        "{}{}{}\n  AND {}",
56        QUERY_HEAD, query_filter, item_filter, QUERY_TAIL
57    )
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63    #[test]
64    fn query_genre_sci_not_adventure_drama() {
65        assert_eq!(
66            build_sorted_filtered_query(
67                vec![(GENRE_COLUMN, "sci !adventure drama").into()],
68                &ItemType::Both
69            ),
70            "SELECT * FROM nf_imdb WHERE
71  genre LIKE '%sci%'
72  AND NOT genre LIKE '%adventure%'
73  AND genre LIKE '%drama%'
74  AND last_sync IS NOT NULL ORDER BY imdb_rating DESC;"
75        )
76    }
77
78    #[test]
79    fn query_title_ship() {
80        assert_eq!(
81            build_sorted_filtered_query(vec![(TITLE_COLUMN, "ship").into()], &ItemType::Both),
82            "SELECT * FROM nf_imdb WHERE
83  title LIKE '%ship%'
84  AND last_sync IS NOT NULL ORDER BY imdb_rating DESC;"
85        )
86    }
87
88    #[test]
89    fn query_country_not_india() {
90        assert_eq!(
91            build_sorted_filtered_query(vec![(COUNTRY_COLUMN, "!india").into()], &ItemType::Both),
92            "SELECT * FROM nf_imdb WHERE
93  NOT country LIKE '%india%'
94  AND last_sync IS NOT NULL ORDER BY imdb_rating DESC;"
95        )
96    }
97
98    #[test]
99    fn query_title_ship_movies_only() {
100        assert_eq!(
101            build_sorted_filtered_query(vec![(TITLE_COLUMN, "ship").into()], &ItemType::Movie),
102            "SELECT * FROM nf_imdb WHERE
103  title LIKE '%ship%'
104  AND type = 'movie'
105  AND last_sync IS NOT NULL ORDER BY imdb_rating DESC;"
106        )
107    }
108
109    #[test]
110    fn query_title_ship_series_only() {
111        assert_eq!(
112            build_sorted_filtered_query(vec![(TITLE_COLUMN, "ship").into()], &ItemType::Series),
113            "SELECT * FROM nf_imdb WHERE
114  title LIKE '%ship%'
115  AND type = 'series'
116  AND last_sync IS NOT NULL ORDER BY imdb_rating DESC;"
117        )
118    }
119
120    #[test]
121    fn query_title_ship_genre_sci() {
122        assert_eq!(
123            build_sorted_filtered_query(
124                vec![(TITLE_COLUMN, "ship").into(), (GENRE_COLUMN, "sci").into()],
125                &ItemType::Both
126            ),
127            "SELECT * FROM nf_imdb WHERE
128  title LIKE '%ship%'
129  AND genre LIKE '%sci%'
130  AND last_sync IS NOT NULL ORDER BY imdb_rating DESC;"
131        )
132    }
133
134    #[test]
135    fn query_title_ship_genre_sci_cast_not_badactor() {
136        assert_eq!(
137            build_sorted_filtered_query(
138                vec![
139                    (TITLE_COLUMN, "ship").into(),
140                    (GENRE_COLUMN, "sci").into(),
141                    (CAST_COLUMN, "!badactor").into(),
142                ],
143                &ItemType::Both
144            ),
145            "SELECT * FROM nf_imdb WHERE
146  title LIKE '%ship%'
147  AND genre LIKE '%sci%'
148  AND NOT `cast` LIKE '%badactor%'
149  AND last_sync IS NOT NULL ORDER BY imdb_rating DESC;"
150        )
151    }
152}