MeiliSearch/crates/milli/src/fields_ids_map.rs

186 lines
5.3 KiB
Rust
Raw Normal View History

use std::collections::BTreeMap;
2021-06-16 18:33:33 +02:00
use serde::{Deserialize, Serialize};
2020-11-26 17:38:08 +01:00
use crate::FieldId;
2020-10-22 12:50:04 +02:00
mod global;
2024-10-28 14:09:48 +01:00
pub mod metadata;
pub use global::GlobalFieldsIdsMap;
2020-10-22 12:50:04 +02:00
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FieldsIdsMap {
2020-11-26 17:38:08 +01:00
names_ids: BTreeMap<String, FieldId>,
ids_names: BTreeMap<FieldId, String>,
next_id: Option<FieldId>,
2020-10-22 12:50:04 +02:00
}
impl FieldsIdsMap {
pub fn new() -> FieldsIdsMap {
2021-06-16 18:33:33 +02:00
FieldsIdsMap { names_ids: BTreeMap::new(), ids_names: BTreeMap::new(), next_id: Some(0) }
2020-10-22 12:50:04 +02:00
}
/// Returns the number of fields ids in the map.
pub fn len(&self) -> usize {
self.names_ids.len()
}
/// Returns `true` if the map is empty.
pub fn is_empty(&self) -> bool {
self.names_ids.is_empty()
}
/// Returns the field id related to a field name, it will create a new field id if the
/// name is not already known. Returns `None` if the maximum field id as been reached.
2020-11-26 17:38:08 +01:00
pub fn insert(&mut self, name: &str) -> Option<FieldId> {
2020-10-22 12:50:04 +02:00
match self.names_ids.get(name) {
Some(id) => Some(*id),
None => {
let id = self.next_id?;
self.next_id = id.checked_add(1);
self.names_ids.insert(name.to_owned(), id);
self.ids_names.insert(id, name.to_owned());
Some(id)
}
}
}
/// Get the ids of a field and all its nested fields based on its name.
pub fn nested_ids(&self, name: &str) -> Vec<FieldId> {
self.names_ids
.range(name.to_string()..)
.take_while(|(key, _)| key.starts_with(name))
.filter(|(key, _)| crate::is_faceted_by(key, name))
.map(|(_name, id)| *id)
.collect()
}
2020-10-22 12:50:04 +02:00
/// Get the id of a field based on its name.
2020-11-26 17:38:08 +01:00
pub fn id(&self, name: &str) -> Option<FieldId> {
2020-10-22 12:50:04 +02:00
self.names_ids.get(name).copied()
}
/// Get the name of a field based on its id.
2020-11-26 17:38:08 +01:00
pub fn name(&self, id: FieldId) -> Option<&str> {
2020-10-22 12:50:04 +02:00
self.ids_names.get(&id).map(String::as_str)
}
/// Remove a field name and id based on its name.
2020-11-26 17:38:08 +01:00
pub fn remove(&mut self, name: &str) -> Option<FieldId> {
2020-10-22 12:50:04 +02:00
match self.names_ids.remove(name) {
Some(id) => self.ids_names.remove_entry(&id).map(|(id, _)| id),
None => None,
}
}
/// Iterate over the ids and names in the ids order.
2021-06-16 18:33:33 +02:00
pub fn iter(&self) -> impl Iterator<Item = (FieldId, &str)> {
2020-10-22 12:50:04 +02:00
self.ids_names.iter().map(|(id, name)| (*id, name.as_str()))
}
2021-05-04 13:44:55 +02:00
/// Iterate over the ids in the order of the ids.
pub fn ids(&'_ self) -> impl Iterator<Item = FieldId> + '_ {
2021-05-04 13:44:55 +02:00
self.ids_names.keys().copied()
}
/// Iterate over the names in the order of the ids.
2021-06-16 18:33:33 +02:00
pub fn names(&self) -> impl Iterator<Item = &str> {
2021-05-04 13:44:55 +02:00
self.ids_names.values().map(AsRef::as_ref)
}
2020-10-22 12:50:04 +02:00
}
impl Default for FieldsIdsMap {
fn default() -> FieldsIdsMap {
FieldsIdsMap::new()
}
}
2023-11-13 13:37:58 +01:00
impl crate::documents::FieldIdMapper for FieldsIdsMap {
2023-11-09 14:19:16 +01:00
fn id(&self, name: &str) -> Option<FieldId> {
self.id(name)
}
2024-10-03 18:08:09 +02:00
fn name(&self, id: FieldId) -> Option<&str> {
self.name(id)
}
}
pub trait MutFieldIdMapper {
fn insert(&mut self, name: &str) -> Option<FieldId>;
}
impl MutFieldIdMapper for FieldsIdsMap {
fn insert(&mut self, name: &str) -> Option<FieldId> {
self.insert(name)
}
2023-11-09 14:19:16 +01:00
}
2020-10-22 12:50:04 +02:00
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fields_ids_map() {
let mut map = FieldsIdsMap::new();
assert_eq!(map.insert("id"), Some(0));
assert_eq!(map.insert("title"), Some(1));
assert_eq!(map.insert("description"), Some(2));
assert_eq!(map.insert("id"), Some(0));
assert_eq!(map.insert("title"), Some(1));
assert_eq!(map.insert("description"), Some(2));
assert_eq!(map.id("id"), Some(0));
assert_eq!(map.id("title"), Some(1));
assert_eq!(map.id("description"), Some(2));
assert_eq!(map.id("date"), None);
assert_eq!(map.len(), 3);
assert_eq!(map.name(0), Some("id"));
assert_eq!(map.name(1), Some("title"));
assert_eq!(map.name(2), Some("description"));
assert_eq!(map.name(4), None);
assert_eq!(map.remove("title"), Some(1));
assert_eq!(map.id("title"), None);
assert_eq!(map.insert("title"), Some(3));
assert_eq!(map.len(), 3);
let mut iter = map.iter();
assert_eq!(iter.next(), Some((0, "id")));
assert_eq!(iter.next(), Some((2, "description")));
assert_eq!(iter.next(), Some((3, "title")));
assert_eq!(iter.next(), None);
}
#[test]
fn nested_fields() {
let mut map = FieldsIdsMap::new();
assert_eq!(map.insert("id"), Some(0));
assert_eq!(map.insert("doggo"), Some(1));
assert_eq!(map.insert("doggo.name"), Some(2));
assert_eq!(map.insert("doggolution"), Some(3));
assert_eq!(map.insert("doggo.breed.name"), Some(4));
assert_eq!(map.insert("description"), Some(5));
insta::assert_debug_snapshot!(map.nested_ids("doggo"), @r###"
[
1,
4,
2,
]
"###);
insta::assert_debug_snapshot!(map.nested_ids("doggo.breed"), @r###"
[
4,
]
"###);
insta::assert_debug_snapshot!(map.nested_ids("_vector"), @"[]");
}
2020-10-22 12:50:04 +02:00
}