milli_core/
fields_ids_map.rs1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize};
4
5use crate::FieldId;
6
7mod global;
8pub mod metadata;
9pub use global::GlobalFieldsIdsMap;
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct FieldsIdsMap {
13 names_ids: BTreeMap<String, FieldId>,
14 ids_names: BTreeMap<FieldId, String>,
15 next_id: Option<FieldId>,
16}
17
18impl FieldsIdsMap {
19 pub fn new() -> FieldsIdsMap {
20 FieldsIdsMap { names_ids: BTreeMap::new(), ids_names: BTreeMap::new(), next_id: Some(0) }
21 }
22
23 pub fn len(&self) -> usize {
25 self.names_ids.len()
26 }
27
28 pub fn is_empty(&self) -> bool {
30 self.names_ids.is_empty()
31 }
32
33 pub fn insert(&mut self, name: &str) -> Option<FieldId> {
36 match self.names_ids.get(name) {
37 Some(id) => Some(*id),
38 None => {
39 let id = self.next_id?;
40 self.next_id = id.checked_add(1);
41 self.names_ids.insert(name.to_owned(), id);
42 self.ids_names.insert(id, name.to_owned());
43 Some(id)
44 }
45 }
46 }
47
48 pub fn nested_ids(&self, name: &str) -> Vec<FieldId> {
50 self.names_ids
51 .range(name.to_string()..)
52 .take_while(|(key, _)| key.starts_with(name))
53 .filter(|(key, _)| crate::is_faceted_by(key, name))
54 .map(|(_name, id)| *id)
55 .collect()
56 }
57
58 pub fn id(&self, name: &str) -> Option<FieldId> {
60 self.names_ids.get(name).copied()
61 }
62
63 pub fn name(&self, id: FieldId) -> Option<&str> {
65 self.ids_names.get(&id).map(String::as_str)
66 }
67
68 pub fn remove(&mut self, name: &str) -> Option<FieldId> {
70 match self.names_ids.remove(name) {
71 Some(id) => self.ids_names.remove_entry(&id).map(|(id, _)| id),
72 None => None,
73 }
74 }
75
76 pub fn iter(&self) -> impl Iterator<Item = (FieldId, &str)> {
78 self.ids_names.iter().map(|(id, name)| (*id, name.as_str()))
79 }
80
81 pub fn ids(&'_ self) -> impl Iterator<Item = FieldId> + '_ {
83 self.ids_names.keys().copied()
84 }
85
86 pub fn names(&self) -> impl Iterator<Item = &str> {
88 self.ids_names.values().map(AsRef::as_ref)
89 }
90}
91
92impl Default for FieldsIdsMap {
93 fn default() -> FieldsIdsMap {
94 FieldsIdsMap::new()
95 }
96}
97
98impl crate::documents::FieldIdMapper for FieldsIdsMap {
99 fn id(&self, name: &str) -> Option<FieldId> {
100 self.id(name)
101 }
102
103 fn name(&self, id: FieldId) -> Option<&str> {
104 self.name(id)
105 }
106}
107
108pub trait MutFieldIdMapper {
109 fn insert(&mut self, name: &str) -> Option<FieldId>;
110}
111
112impl MutFieldIdMapper for FieldsIdsMap {
113 fn insert(&mut self, name: &str) -> Option<FieldId> {
114 self.insert(name)
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121
122 #[test]
123 fn fields_ids_map() {
124 let mut map = FieldsIdsMap::new();
125
126 assert_eq!(map.insert("id"), Some(0));
127 assert_eq!(map.insert("title"), Some(1));
128 assert_eq!(map.insert("description"), Some(2));
129 assert_eq!(map.insert("id"), Some(0));
130 assert_eq!(map.insert("title"), Some(1));
131 assert_eq!(map.insert("description"), Some(2));
132
133 assert_eq!(map.id("id"), Some(0));
134 assert_eq!(map.id("title"), Some(1));
135 assert_eq!(map.id("description"), Some(2));
136 assert_eq!(map.id("date"), None);
137
138 assert_eq!(map.len(), 3);
139
140 assert_eq!(map.name(0), Some("id"));
141 assert_eq!(map.name(1), Some("title"));
142 assert_eq!(map.name(2), Some("description"));
143 assert_eq!(map.name(4), None);
144
145 assert_eq!(map.remove("title"), Some(1));
146
147 assert_eq!(map.id("title"), None);
148 assert_eq!(map.insert("title"), Some(3));
149 assert_eq!(map.len(), 3);
150
151 let mut iter = map.iter();
152 assert_eq!(iter.next(), Some((0, "id")));
153 assert_eq!(iter.next(), Some((2, "description")));
154 assert_eq!(iter.next(), Some((3, "title")));
155 assert_eq!(iter.next(), None);
156 }
157
158 #[test]
159 fn nested_fields() {
160 let mut map = FieldsIdsMap::new();
161
162 assert_eq!(map.insert("id"), Some(0));
163 assert_eq!(map.insert("doggo"), Some(1));
164 assert_eq!(map.insert("doggo.name"), Some(2));
165 assert_eq!(map.insert("doggolution"), Some(3));
166 assert_eq!(map.insert("doggo.breed.name"), Some(4));
167 assert_eq!(map.insert("description"), Some(5));
168
169 insta::assert_debug_snapshot!(map.nested_ids("doggo"), @r###"
170 [
171 1,
172 4,
173 2,
174 ]
175 "###);
176
177 insta::assert_debug_snapshot!(map.nested_ids("doggo.breed"), @r###"
178 [
179 4,
180 ]
181 "###);
182
183 insta::assert_debug_snapshot!(map.nested_ids("_vector"), @"[]");
184 }
185}