attribute_search_engine/index/
hashmap.rs1use super::{string_to_payload_type, SearchIndex};
2use crate::{Query, Result, SearchEngineError, SupportedQueries, SUPPORTS_EXACT};
3use std::{
4 collections::{HashMap, HashSet},
5 hash::Hash,
6 str::FromStr,
7};
8
9pub struct SearchIndexHashMap<P, V> {
27 index: HashMap<V, HashSet<P>>,
28}
29
30impl<P, V> Default for SearchIndexHashMap<P, V>
31where
32 P: Eq + Hash + Clone + 'static,
33 V: Eq + Hash + FromStr + 'static,
34{
35 fn default() -> Self {
36 Self::new()
37 }
38}
39
40impl<P, V> SearchIndexHashMap<P, V>
41where
42 P: Eq + Hash + Clone + 'static,
43 V: Eq + Hash + FromStr + 'static,
44{
45 pub fn new() -> Self {
54 Self {
55 index: HashMap::new(),
56 }
57 }
58
59 pub fn insert(&mut self, primary_id: P, attribute_value: V) {
75 self.index
76 .entry(attribute_value)
77 .or_default()
78 .insert(primary_id);
79 }
80}
81
82impl<P: Clone, V: Eq + Hash + FromStr> SearchIndex<P> for SearchIndexHashMap<P, V> {
83 fn search(&self, query: &Query) -> Result<HashSet<P>> {
84 match query {
85 Query::Exact(_, value_str) => {
86 let value: V = string_to_payload_type(value_str)?;
87 Ok(self
88 .index
89 .get(&value)
90 .cloned()
91 .unwrap_or(HashSet::<P>::new()))
92 }
93 _ => Err(SearchEngineError::UnsupportedQuery),
94 }
95 }
96
97 fn supported_queries(&self) -> SupportedQueries {
98 SUPPORTS_EXACT
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 #[test]
107 fn search_index_exact_string() {
108 let mut index = SearchIndexHashMap::<usize, String>::new();
109 index.insert(0, "A".into());
110 index.insert(0, "B".into());
111 index.insert(0, "C".into());
112 index.insert(1, "A".into());
113 index.insert(1, "B".into());
114 index.insert(2, "A".into());
115
116 let result = index.search(&Query::Exact("<not used>".into(), "A".into()));
117 assert_eq!(result, Ok(HashSet::from_iter(vec![0, 1, 2])));
118
119 let result = index.search(&Query::Exact("<not used>".into(), "B".into()));
120 assert_eq!(result, Ok(HashSet::from_iter(vec![0, 1])));
121
122 let result = index.search(&Query::Exact("<not used>".into(), "C".into()));
123 assert_eq!(result, Ok(HashSet::from_iter(vec![0])));
124
125 let result = index.search(&Query::Exact("<not used>".into(), "D".into()));
126 assert_eq!(result, Ok(HashSet::from_iter(vec![])));
127 }
128
129 #[test]
130 fn search_index_exact_number() {
131 let mut index = SearchIndexHashMap::<usize, i32>::new();
132 index.insert(0, 0);
133 index.insert(0, 1);
134 index.insert(0, 2);
135 index.insert(1, 0);
136 index.insert(1, 1);
137 index.insert(2, 0);
138
139 let result = index.search(&Query::Exact("<not used>".into(), "0".into()));
140 assert_eq!(result, Ok(HashSet::from_iter(vec![0, 1, 2])));
141
142 let result = index.search(&Query::Exact("<not used>".into(), "1".into()));
143 assert_eq!(result, Ok(HashSet::from_iter(vec![0, 1])));
144
145 let result = index.search(&Query::Exact("<not used>".into(), "2".into()));
146 assert_eq!(result, Ok(HashSet::from_iter(vec![0])));
147
148 let result = index.search(&Query::Exact("<not used>".into(), "4".into()));
149 assert_eq!(result, Ok(HashSet::from_iter(vec![])));
150 }
151
152 #[test]
153 fn search_index_unsupported_queries() {
154 let mut index = SearchIndexHashMap::<usize, i32>::new();
155 index.insert(0, 0);
156
157 assert_eq!(
158 index.search(&Query::Prefix("<not used>".into(), "0".into())),
159 Err(SearchEngineError::UnsupportedQuery)
160 );
161 assert_eq!(
162 index.search(&Query::InRange("<not used>".into(), "0".into(), "1".into())),
163 Err(SearchEngineError::UnsupportedQuery)
164 );
165 assert_eq!(
166 index.search(&Query::OutRange(
167 "<not used>".into(),
168 "0".into(),
169 "1".into()
170 )),
171 Err(SearchEngineError::UnsupportedQuery)
172 );
173 assert_eq!(
174 index.search(&Query::Minimum("<not used>".into(), "0".into())),
175 Err(SearchEngineError::UnsupportedQuery)
176 );
177 assert_eq!(
178 index.search(&Query::Maximum("<not used>".into(), "0".into())),
179 Err(SearchEngineError::UnsupportedQuery)
180 );
181 assert_eq!(
182 index.search(&Query::Or(vec![])),
183 Err(SearchEngineError::UnsupportedQuery)
184 );
185 assert_eq!(
186 index.search(&Query::And(vec![])),
187 Err(SearchEngineError::UnsupportedQuery)
188 );
189 assert_eq!(
190 index.search(&Query::Exclude(
191 Box::new(Query::Exact("<not used>".into(), "0".into())),
192 vec![]
193 )),
194 Err(SearchEngineError::UnsupportedQuery)
195 );
196 }
197}