diff --git a/meilisearch-core/src/query_builder.rs b/meilisearch-core/src/query_builder.rs index 014198fb1..22b8ca4d9 100644 --- a/meilisearch-core/src/query_builder.rs +++ b/meilisearch-core/src/query_builder.rs @@ -269,7 +269,7 @@ mod tests { let mut postings_lists = HashMap::new(); let mut fields_counts = HashMap::<_, u16>::new(); - let mut schema = Schema::default(); + let mut schema = Schema::with_identifier("id"); for (word, indexes) in iter { let mut final_indexes = Vec::new(); diff --git a/meilisearch-core/src/serde/serializer.rs b/meilisearch-core/src/serde/serializer.rs index 40525b8e6..2c1d124ca 100644 --- a/meilisearch-core/src/serde/serializer.rs +++ b/meilisearch-core/src/serde/serializer.rs @@ -305,7 +305,7 @@ pub fn serialize_value<'a, T: ?Sized>( where T: ser::Serialize, { - let field_id = schema.get_or_create_empty(attribute.clone())?; + let field_id = schema.get_or_create(attribute.clone())?; serialize_value_with_id( txn, @@ -316,7 +316,7 @@ where documents_fields_counts, indexer, ranked_map, - value + value, ) } diff --git a/meilisearch-core/src/settings.rs b/meilisearch-core/src/settings.rs index 0759524f5..30d9cd361 100644 --- a/meilisearch-core/src/settings.rs +++ b/meilisearch-core/src/settings.rs @@ -21,6 +21,7 @@ pub struct Settings { pub attributes_displayed: Option>, pub stop_words: Option>, pub synonyms: Option>>, + pub index_new_fields: Option, } impl Settings { @@ -40,6 +41,7 @@ impl Settings { attributes_displayed: UpdateState::convert_with_default(settings.attributes_displayed, UpdateState::Clear), stop_words: UpdateState::convert_with_default(settings.stop_words, UpdateState::Clear), synonyms: UpdateState::convert_with_default(settings.synonyms, UpdateState::Clear), + index_new_fields: UpdateState::convert_with_default(settings.index_new_fields, UpdateState::Clear), } } } @@ -61,6 +63,7 @@ impl Into for Settings { attributes_displayed: settings.attributes_displayed.into(), stop_words: settings.stop_words.into(), synonyms: settings.synonyms.into(), + index_new_fields: settings.index_new_fields.into(), } } } @@ -184,6 +187,7 @@ pub struct SettingsUpdate { pub attributes_displayed: UpdateState>, pub stop_words: UpdateState>, pub synonyms: UpdateState>>, + pub index_new_fields: UpdateState, } impl Default for SettingsUpdate { @@ -196,6 +200,7 @@ impl Default for SettingsUpdate { attributes_displayed: UpdateState::Nothing, stop_words: UpdateState::Nothing, synonyms: UpdateState::Nothing, + index_new_fields: UpdateState::Nothing, } } } diff --git a/meilisearch-core/src/update/settings_update.rs b/meilisearch-core/src/update/settings_update.rs index cefdd6339..2c57ae02b 100644 --- a/meilisearch-core/src/update/settings_update.rs +++ b/meilisearch-core/src/update/settings_update.rs @@ -57,6 +57,7 @@ pub fn apply_settings_update( }, _ => (), } + match settings.ranking_distinct { UpdateState::Update(v) => { index.main.put_ranking_distinct(writer, v)?; @@ -67,6 +68,16 @@ pub fn apply_settings_update( _ => (), } + match settings.index_new_fields { + UpdateState::Update(v) => { + schema.set_must_index_new_fields(v); + }, + UpdateState::Clear => { + schema.set_must_index_new_fields(true); + }, + _ => (), + } + match settings.attributes_searchable.clone() { UpdateState::Update(v) => { schema.update_indexed(v)?; @@ -109,6 +120,7 @@ pub fn apply_settings_update( } } }; + match settings.attribute_identifier.clone() { UpdateState::Update(v) => { schema.set_identifier(v)?; diff --git a/meilisearch-http/src/routes/setting.rs b/meilisearch-http/src/routes/setting.rs index 0d43bfd8f..64fea1b97 100644 --- a/meilisearch-http/src/routes/setting.rs +++ b/meilisearch-http/src/routes/setting.rs @@ -57,6 +57,7 @@ pub async fn get_all(ctx: Request) -> SResult { let attribute_identifier = schema.clone().map(|s| s.identifier()); let attributes_searchable = schema.clone().map(|s| s.get_indexed_name()); let attributes_displayed = schema.clone().map(|s| s.get_displayed_name()); + let index_new_fields = schema.map(|s| s.must_index_new_fields()); let settings = Settings { ranking_rules, @@ -66,6 +67,7 @@ pub async fn get_all(ctx: Request) -> SResult { attributes_displayed, stop_words, synonyms, + index_new_fields, }; Ok(tide::Response::new(200).body_json(&settings).unwrap()) @@ -99,6 +101,7 @@ pub async fn delete_all(ctx: Request) -> SResult { attributes_displayed: UpdateState::Clear, stop_words: UpdateState::Clear, synonyms: UpdateState::Clear, + index_new_fields: UpdateState::Clear, }; let update_id = index.settings_update(&mut writer, settings)?; diff --git a/meilisearch-http/tests/common.rs b/meilisearch-http/tests/common.rs index 2770cc605..35e575e16 100644 --- a/meilisearch-http/tests/common.rs +++ b/meilisearch-http/tests/common.rs @@ -1,8 +1,11 @@ #![allow(dead_code)] +use serde_json::Value; use std::error::Error; use std::time::Duration; use async_std::task::{block_on, sleep}; +use async_std::io::prelude::*; +use assert_json_diff::assert_json_eq; use http_service::Body; use http_service_mock::{make_server, TestBackend}; use meilisearch_http::data::Data; @@ -41,9 +44,7 @@ pub fn enrich_server_with_movies_index( let req = http::Request::post("/indexes") .body(Body::from(body)) .unwrap(); - let res = server.simulate(req).unwrap(); - - println!("enrich_server_with_movies_index: {:?}", res.status()); + let _res = server.simulate(req).unwrap(); Ok(()) } @@ -96,9 +97,7 @@ pub fn enrich_server_with_movies_settings( let req = http::Request::post("/indexes/movies/settings") .body(Body::from(body)) .unwrap(); - let res = server.simulate(req).unwrap(); - - println!("enrich_server_with_movies_settings: {:?}", res.status()); + let _res = server.simulate(req).unwrap(); block_on(sleep(Duration::from_secs(5))); @@ -113,9 +112,7 @@ pub fn enrich_server_with_movies_documents( let req = http::Request::post("/indexes/movies/documents") .body(Body::from(body)) .unwrap(); - let res = server.simulate(req).unwrap(); - - println!("enrich_server_with_movies_documents: {:?}", res.status()); + let _res = server.simulate(req).unwrap(); block_on(sleep(Duration::from_secs(5))); @@ -132,17 +129,17 @@ pub fn search(server: &mut TestBackend>, query: &str, expect: Valu block_on(res.into_body().read_to_end(&mut buf)).unwrap(); let response: Value = serde_json::from_slice(&buf).unwrap(); - assert_json_eq!(expect, response, ordered: false) + assert_json_eq!(expect, response["hits"].clone(), ordered: false) } pub fn update_config(server: &mut TestBackend>, config: Value) { let body = config.to_string().into_bytes(); - let req = http::Request::post("/indexes") + let req = http::Request::post("/indexes/movies/settings") .body(Body::from(body)) .unwrap(); let res = server.simulate(req).unwrap(); - assert_eq!(res.status(), 201); + assert_eq!(res.status(), 202); block_on(sleep(Duration::from_secs(5))); } diff --git a/meilisearch-http/tests/search.rs b/meilisearch-http/tests/search.rs index 592f128c1..241f69d16 100644 --- a/meilisearch-http/tests/search.rs +++ b/meilisearch-http/tests/search.rs @@ -1,15 +1,6 @@ use std::convert::Into; -use std::time::Duration; -use assert_json_diff::assert_json_eq; -use async_std::io::prelude::*; -use async_std::task::{block_on, sleep}; -use http_service::Body; -use http_service_mock::TestBackend; -use meilisearch_http::data::Data; use serde_json::json; -use serde_json::Value; -use tide::server::Service; mod common; @@ -628,15 +619,11 @@ fn basic_search() { } #[test] -fn search_with_settings_change() { +fn search_with_settings_basic() { let mut server = common::setup_server().unwrap(); - common::enrich_server_with_movies_index(&mut server).unwrap(); - common::enrich_server_with_movies_settings(&mut server).unwrap(); common::enrich_server_with_movies_documents(&mut server).unwrap(); - // Basic - let config = json!({ "rankingRules": [ "_typo", @@ -735,9 +722,12 @@ fn search_with_settings_change() { ]); common::search(&mut server, query, response); +} - //////////////////////////////////////////////////////////////////////////////////////////////// - // Set with stop words +#[test] +fn search_with_settings_stop_words() { + let mut server = common::setup_server().unwrap(); + common::enrich_server_with_movies_index(&mut server).unwrap(); let config = json!({ "rankingRules": [ @@ -780,6 +770,7 @@ fn search_with_settings_change() { }); common::update_config(&mut server, config); + common::enrich_server_with_movies_documents(&mut server).unwrap(); let query = "q=the%20avangers&limit=3"; let response = json!([ @@ -837,9 +828,12 @@ fn search_with_settings_change() { ]); common::search(&mut server, query, response); +} - //////////////////////////////////////////////////////////////////////////////////////////////// - // Set with synonyms +#[test] +fn search_with_settings_synonyms() { + let mut server = common::setup_server().unwrap(); + common::enrich_server_with_movies_index(&mut server).unwrap(); let config = json!({ "rankingRules": [ @@ -887,6 +881,7 @@ fn search_with_settings_change() { }); common::update_config(&mut server, config); + common::enrich_server_with_movies_documents(&mut server).unwrap(); let query = "q=avangers&limit=3"; let response = json!([ @@ -944,9 +939,12 @@ fn search_with_settings_change() { ]); common::search(&mut server, query, response); +} - //////////////////////////////////////////////////////////////////////////////////////////////// - // Set asc(vote_average) in ranking rules +#[test] +fn search_with_settings_ranking_rules() { + let mut server = common::setup_server().unwrap(); + common::enrich_server_with_movies_index(&mut server).unwrap(); let config = json!({ "rankingRules": [ @@ -989,6 +987,7 @@ fn search_with_settings_change() { }); common::update_config(&mut server, config); + common::enrich_server_with_movies_documents(&mut server).unwrap(); let query = "q=avangers&limit=3"; let response = json!([ @@ -1046,9 +1045,12 @@ fn search_with_settings_change() { ]); common::search(&mut server, query, response); +} - //////////////////////////////////////////////////////////////////////////////////////////////// - // Remove Title from attributesSearchable +#[test] +fn search_with_settings_attributes_searchable() { + let mut server = common::setup_server().unwrap(); + common::enrich_server_with_movies_index(&mut server).unwrap(); let config = json!({ "rankingRules": [ @@ -1090,6 +1092,7 @@ fn search_with_settings_change() { }); common::update_config(&mut server, config); + common::enrich_server_with_movies_documents(&mut server).unwrap(); let query = "q=avangers&limit=3"; let response = json!([ @@ -1147,9 +1150,12 @@ fn search_with_settings_change() { ]); common::search(&mut server, query, response); +} - //////////////////////////////////////////////////////////////////////////////////////////////// - // Remove Attributes displayed +#[test] +fn search_with_settings_attributes_displayed() { + let mut server = common::setup_server().unwrap(); + common::enrich_server_with_movies_index(&mut server).unwrap(); let config = json!({ "rankingRules": [ @@ -1186,6 +1192,7 @@ fn search_with_settings_change() { }); common::update_config(&mut server, config); + common::enrich_server_with_movies_documents(&mut server).unwrap(); let query = "q=avangers&limit=3"; let response = json!([ @@ -1213,9 +1220,12 @@ fn search_with_settings_change() { ]); common::search(&mut server, query, response); +} - //////////////////////////////////////////////////////////////////////////////////////////////// - // Reoder attributesSearchable +#[test] +fn search_with_settings_attributes_searchable_2() { + let mut server = common::setup_server().unwrap(); + common::enrich_server_with_movies_index(&mut server).unwrap(); let config = json!({ "rankingRules": [ @@ -1252,6 +1262,7 @@ fn search_with_settings_change() { }); common::update_config(&mut server, config); + common::enrich_server_with_movies_documents(&mut server).unwrap(); let query = "q=avangers&limit=3"; let response = json!([ diff --git a/meilisearch-http/tests/settings.rs b/meilisearch-http/tests/settings.rs index 8e76aae3d..37e17f5b9 100644 --- a/meilisearch-http/tests/settings.rs +++ b/meilisearch-http/tests/settings.rs @@ -132,6 +132,7 @@ fn write_all_and_delete() { "attributesDisplayed": null, "stopWords": null, "synonyms": null, + "indexNewFields": true, }); assert_json_eq!(json, res_value, ordered: false); @@ -312,7 +313,8 @@ fn write_all_and_update() { "synonyms": { "wolverine": ["xmen", "logan"], "logan": ["wolverine", "xmen"], - } + }, + "indexNewFields": true }); assert_json_eq!(res_expected, res_value, ordered: false); diff --git a/meilisearch-schema/src/lib.rs b/meilisearch-schema/src/lib.rs index 8090221f1..2b77b4336 100644 --- a/meilisearch-schema/src/lib.rs +++ b/meilisearch-schema/src/lib.rs @@ -81,602 +81,3 @@ impl Into for FieldId { self.0 } } - - - - - -// use std::collections::{BTreeMap, HashMap}; -// use std::ops::BitOr; -// use std::sync::Arc; -// use std::{fmt, u16}; - -// use indexmap::IndexMap; -// use serde::{Deserialize, Serialize}; - -// pub const DISPLAYED: SchemaProps = SchemaProps { -// displayed: true, -// indexed: false, -// ranked: false, -// }; -// pub const INDEXED: SchemaProps = SchemaProps { -// displayed: false, -// indexed: true, -// ranked: false, -// }; -// pub const RANKED: SchemaProps = SchemaProps { -// displayed: false, -// indexed: false, -// ranked: true, -// }; - -// #[derive(Default, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] -// pub struct SchemaProps { -// #[serde(default)] -// pub displayed: bool, - -// #[serde(default)] -// pub indexed: bool, - -// #[serde(default)] -// pub ranked: bool, -// } - -// impl SchemaProps { -// pub fn is_displayed(self) -> bool { -// self.displayed -// } - -// pub fn is_indexed(self) -> bool { -// self.indexed -// } - -// pub fn is_ranked(self) -> bool { -// self.ranked -// } -// } - -// impl BitOr for SchemaProps { -// type Output = Self; - -// fn bitor(self, other: Self) -> Self::Output { -// SchemaProps { -// displayed: self.displayed | other.displayed, -// indexed: self.indexed | other.indexed, -// ranked: self.ranked | other.ranked, -// } -// } -// } - -// impl fmt::Debug for SchemaProps { -// #[allow(non_camel_case_types)] -// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -// #[derive(Debug)] -// struct DISPLAYED; - -// #[derive(Debug)] -// struct INDEXED; - -// #[derive(Debug)] -// struct RANKED; - -// let mut debug_set = f.debug_set(); - -// if self.displayed { -// debug_set.entry(&DISPLAYED); -// } - -// if self.indexed { -// debug_set.entry(&INDEXED); -// } - -// if self.ranked { -// debug_set.entry(&RANKED); -// } - -// debug_set.finish() -// } -// } - -// #[derive(Serialize, Deserialize)] -// pub struct SchemaBuilder { -// identifier: String, -// attributes: IndexMap, -// } - -// impl SchemaBuilder { - -// pub fn with_identifier>(name: S) -> SchemaBuilder { -// SchemaBuilder { -// identifier: name.into(), -// attributes: IndexMap::new(), -// } -// } - -// pub fn new_attribute>(&mut self, name: S, props: SchemaProps) -> SchemaAttr { -// let len = self.attributes.len(); -// if self.attributes.insert(name.into(), props).is_some() { -// panic!("Field already inserted.") -// } -// SchemaAttr(len as u16) -// } - -// pub fn build(self) -> Schema { -// let mut attrs = HashMap::new(); -// let mut props = Vec::new(); - -// for (i, (name, prop)) in self.attributes.into_iter().enumerate() { -// attrs.insert(name.clone(), SchemaAttr(i as u16)); -// props.push((name, prop)); -// } - -// let identifier = self.identifier; -// Schema { -// inner: Arc::new(InnerSchema { -// identifier, -// attrs, -// props, -// }), -// } -// } -// } - -// #[derive(Clone, PartialEq, Eq)] -// pub struct Schema { -// inner: Arc, -// } - -// #[derive(Clone, PartialEq, Eq)] -// struct InnerSchema { -// identifier: (String, u16), -// attrs: HashMap, -// props: Vec<(String, SchemaProps)>, -// } - -// impl Schema { -// pub fn to_builder(&self) -> SchemaBuilder { -// let identifier = self.inner.identifier.clone(); -// let attributes = self.attributes_ordered(); -// SchemaBuilder { -// identifier, -// attributes, -// } -// } - -// fn attributes_ordered(&self) -> IndexMap { -// let mut ordered = BTreeMap::new(); -// for (name, attr) in &self.inner.attrs { -// let (_, props) = self.inner.props[attr.0 as usize]; -// ordered.insert(attr.0, (name, props)); -// } - -// let mut attributes = IndexMap::with_capacity(ordered.len()); -// for (_, (name, props)) in ordered { -// attributes.insert(name.clone(), props); -// } - -// attributes -// } - -// pub fn number_of_attributes(&self) -> usize { -// self.inner.attrs.len() -// } - -// pub fn props(&self, attr: SchemaAttr) -> SchemaProps { -// let (_, props) = self.inner.props[attr.0 as usize]; -// props -// } - -// pub fn identifier_name(&self) -> &str { -// &self.inner.identifier -// } - -// pub fn attribute>(&self, name: S) -> Option { -// self.inner.attrs.get(name.as_ref()).cloned() -// } - -// pub fn attribute_name(&self, attr: SchemaAttr) -> &str { -// let (name, _) = &self.inner.props[attr.0 as usize]; -// name -// } - -// pub fn into_iter<'a>(&'a self) -> impl Iterator + 'a { -// self.inner.props.clone().into_iter() -// } - -// pub fn iter<'a>(&'a self) -> impl Iterator + 'a { -// self.inner.props.iter().map(move |(name, prop)| { -// let attr = self.inner.attrs.get(name).unwrap(); -// (name.as_str(), *attr, *prop) -// }) -// } -// } - -// impl Serialize for Schema { -// fn serialize(&self, serializer: S) -> Result -// where -// S: serde::ser::Serializer, -// { -// self.to_builder().serialize(serializer) -// } -// } - -// impl<'de> Deserialize<'de> for Schema { -// fn deserialize(deserializer: D) -> Result -// where -// D: serde::de::Deserializer<'de>, -// { -// let builder = SchemaBuilder::deserialize(deserializer)?; -// Ok(builder.build()) -// } -// } - -// impl fmt::Debug for Schema { -// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -// let builder = self.to_builder(); -// f.debug_struct("Schema") -// .field("identifier", &builder.identifier) -// .field("attributes", &builder.attributes) -// .finish() -// } -// } - -// #[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] -// pub struct SchemaAttr(pub u16); - -// impl SchemaAttr { -// pub const fn new(value: u16) -> SchemaAttr { -// SchemaAttr(value) -// } - -// pub const fn min() -> SchemaAttr { -// SchemaAttr(u16::min_value()) -// } - -// pub const fn max() -> SchemaAttr { -// SchemaAttr(u16::max_value()) -// } - -// pub fn next(self) -> Option { -// self.0.checked_add(1).map(SchemaAttr) -// } - -// pub fn prev(self) -> Option { -// self.0.checked_sub(1).map(SchemaAttr) -// } -// } - -// impl fmt::Display for SchemaAttr { -// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { -// self.0.fmt(f) -// } -// } - -// #[derive(Debug, Clone, PartialEq, Eq)] -// pub enum Diff { -// IdentChange { -// old: String, -// new: String, -// }, -// AttrMove { -// name: String, -// old: usize, -// new: usize, -// }, -// AttrPropsChange { -// name: String, -// old: SchemaProps, -// new: SchemaProps, -// }, -// NewAttr { -// name: String, -// pos: usize, -// props: SchemaProps, -// }, -// RemovedAttr { -// name: String, -// }, -// } - -// pub fn diff(old: &Schema, new: &Schema) -> Vec { -// use Diff::{AttrMove, AttrPropsChange, IdentChange, NewAttr, RemovedAttr}; - -// let mut differences = Vec::new(); -// let old = old.to_builder(); -// let new = new.to_builder(); - -// // check if the old identifier differs from the new one -// if old.identifier != new.identifier { -// let old = old.identifier; -// let new = new.identifier; -// differences.push(IdentChange { old, new }); -// } - -// // compare all old attributes positions -// // and properties with the new ones -// for (pos, (name, props)) in old.attributes.iter().enumerate() { -// match new.attributes.get_full(name) { -// Some((npos, _, nprops)) => { -// if pos != npos { -// let name = name.clone(); -// differences.push(AttrMove { -// name, -// old: pos, -// new: npos, -// }); -// } -// if props != nprops { -// let name = name.clone(); -// differences.push(AttrPropsChange { -// name, -// old: *props, -// new: *nprops, -// }); -// } -// } -// None => differences.push(RemovedAttr { name: name.clone() }), -// } -// } - -// // retrieve all attributes that -// // were not present in the old schema -// for (pos, (name, props)) in new.attributes.iter().enumerate() { -// if !old.attributes.contains_key(name) { -// let name = name.clone(); -// differences.push(NewAttr { -// name, -// pos, -// props: *props, -// }); -// } -// } - -// differences -// } - - -// // The diff_transposition return the transpotion matrix to apply during the documents rewrite process. -// // e.g. -// // old_schema: ["id", "title", "description", "tags", "date"] -// // new_schema: ["title", "tags", "id", "new", "position","description"] -// // diff_transposition: [Some(2), Some(0), Some(5), Some(1), None] -// // -// // - attribute 0 (id) become attribute 2 -// // - attribute 1 (title) become attribute 0 -// // - attribute 2 (description) become attribute 5 -// // - attribute 3 (tags) become attribute 1 -// // - attribute 4 (date) is deleted -// pub fn diff_transposition(old: &Schema, new: &Schema) -> Vec> { -// let old = old.to_builder(); -// let new = new.to_builder(); - -// let old_attributes: Vec<&str> = old.attributes.iter().map(|(key, _)| key.as_str()).collect(); -// let new_attributes: Vec<&str> = new.attributes.iter().map(|(key, _)| key.as_str()).collect(); - -// let mut transpotition = Vec::new(); - -// for (_pos, attr) in old_attributes.iter().enumerate() { -// if let Some(npos) = new_attributes[..].iter().position(|x| x == attr) { -// transpotition.push(Some(npos as u16)); -// } else { -// transpotition.push(None); -// } -// } - -// transpotition -// } - -// pub fn generate_schema(identifier: String, indexed: Vec, displayed: Vec, ranked: Vec) -> Schema { -// let mut map = IndexMap::new(); - -// for item in indexed.iter() { -// map.entry(item).or_insert(SchemaProps::default()).indexed = true; -// } -// for item in ranked.iter() { -// map.entry(item).or_insert(SchemaProps::default()).ranked = true; -// } -// for item in displayed.iter() { -// map.entry(item).or_insert(SchemaProps::default()).displayed = true; -// } -// let id = identifier.clone(); -// map.entry(&id).or_insert(SchemaProps::default()); - -// let mut builder = SchemaBuilder::with_identifier(identifier); - -// for (key, value) in map { -// builder.new_attribute(key, value); -// } - -// builder.build() -// } - -// #[cfg(test)] -// mod tests { -// use super::*; -// use std::error::Error; - -// #[test] -// fn difference() { -// use Diff::{AttrMove, AttrPropsChange, IdentChange, NewAttr, RemovedAttr}; - -// let mut builder = SchemaBuilder::with_identifier("id"); -// builder.new_attribute("alpha", DISPLAYED); -// builder.new_attribute("beta", DISPLAYED | INDEXED); -// builder.new_attribute("gamma", INDEXED); -// builder.new_attribute("omega", INDEXED); -// let old = builder.build(); - -// let mut builder = SchemaBuilder::with_identifier("kiki"); -// builder.new_attribute("beta", DISPLAYED | INDEXED); -// builder.new_attribute("alpha", DISPLAYED | INDEXED); -// builder.new_attribute("delta", RANKED); -// builder.new_attribute("gamma", DISPLAYED); -// let new = builder.build(); - -// let differences = diff(&old, &new); -// let expected = &[ -// IdentChange { -// old: format!("id"), -// new: format!("kiki"), -// }, -// AttrMove { -// name: format!("alpha"), -// old: 0, -// new: 1, -// }, -// AttrPropsChange { -// name: format!("alpha"), -// old: DISPLAYED, -// new: DISPLAYED | INDEXED, -// }, -// AttrMove { -// name: format!("beta"), -// old: 1, -// new: 0, -// }, -// AttrMove { -// name: format!("gamma"), -// old: 2, -// new: 3, -// }, -// AttrPropsChange { -// name: format!("gamma"), -// old: INDEXED, -// new: DISPLAYED, -// }, -// RemovedAttr { -// name: format!("omega"), -// }, -// NewAttr { -// name: format!("delta"), -// pos: 2, -// props: RANKED, -// }, -// ]; - -// assert_eq!(&differences, expected) -// } - -// #[test] -// fn serialize_deserialize() -> bincode::Result<()> { -// let mut builder = SchemaBuilder::with_identifier("id"); -// builder.new_attribute("alpha", DISPLAYED); -// builder.new_attribute("beta", DISPLAYED | INDEXED); -// builder.new_attribute("gamma", INDEXED); -// let schema = builder.build(); - -// let mut buffer = Vec::new(); -// bincode::serialize_into(&mut buffer, &schema)?; -// let schema2 = bincode::deserialize_from(buffer.as_slice())?; - -// assert_eq!(schema, schema2); - -// Ok(()) -// } - -// #[test] -// fn serialize_deserialize_toml() -> Result<(), Box> { -// let mut builder = SchemaBuilder::with_identifier("id"); -// builder.new_attribute("alpha", DISPLAYED); -// builder.new_attribute("beta", DISPLAYED | INDEXED); -// builder.new_attribute("gamma", INDEXED); -// let schema = builder.build(); - -// let buffer = toml::to_vec(&schema)?; -// let schema2 = toml::from_slice(buffer.as_slice())?; - -// assert_eq!(schema, schema2); - -// let data = r#" -// identifier = "id" - -// [attributes."alpha"] -// displayed = true - -// [attributes."beta"] -// displayed = true -// indexed = true - -// [attributes."gamma"] -// indexed = true -// "#; -// let schema2 = toml::from_str(data)?; -// assert_eq!(schema, schema2); - -// Ok(()) -// } - -// #[test] -// fn serialize_deserialize_json() -> Result<(), Box> { -// let mut builder = SchemaBuilder::with_identifier("id"); -// builder.new_attribute("alpha", DISPLAYED); -// builder.new_attribute("beta", DISPLAYED | INDEXED); -// builder.new_attribute("gamma", INDEXED); -// let schema = builder.build(); - -// let buffer = serde_json::to_vec(&schema)?; -// let schema2 = serde_json::from_slice(buffer.as_slice())?; - -// assert_eq!(schema, schema2); - -// let data = r#" -// { -// "identifier": "id", -// "attributes": { -// "alpha": { -// "displayed": true -// }, -// "beta": { -// "displayed": true, -// "indexed": true -// }, -// "gamma": { -// "indexed": true -// } -// } -// }"#; -// let schema2 = serde_json::from_str(data)?; -// assert_eq!(schema, schema2); - -// Ok(()) -// } - -// #[test] -// fn debug_output() { -// use std::fmt::Write as _; - -// let mut builder = SchemaBuilder::with_identifier("id"); -// builder.new_attribute("alpha", DISPLAYED); -// builder.new_attribute("beta", DISPLAYED | INDEXED); -// builder.new_attribute("gamma", INDEXED); -// let schema = builder.build(); - -// let mut output = String::new(); -// let _ = write!(&mut output, "{:#?}", schema); - -// let expected = r#"Schema { -// identifier: "id", -// attributes: { -// "alpha": { -// DISPLAYED, -// }, -// "beta": { -// DISPLAYED, -// INDEXED, -// }, -// "gamma": { -// INDEXED, -// }, -// }, -// }"#; - -// assert_eq!(output, expected); - -// let mut output = String::new(); -// let _ = write!(&mut output, "{:?}", schema); - -// let expected = r#"Schema { identifier: "id", attributes: {"alpha": {DISPLAYED}, "beta": {DISPLAYED, INDEXED}, "gamma": {INDEXED}} }"#; - -// assert_eq!(output, expected); -// } -// } diff --git a/meilisearch-schema/src/schema.rs b/meilisearch-schema/src/schema.rs index c39d145c4..8fe3e2b23 100644 --- a/meilisearch-schema/src/schema.rs +++ b/meilisearch-schema/src/schema.rs @@ -4,7 +4,7 @@ use serde::{Serialize, Deserialize}; use crate::{FieldsMap, FieldId, SResult, Error, IndexedPos}; -#[derive(Clone, Debug, Default, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct Schema { fields_map: FieldsMap, @@ -14,16 +14,25 @@ pub struct Schema { indexed: Vec, indexed_map: HashMap, + + must_index_new_fields: bool, } impl Schema { pub fn with_identifier>(name: S) -> Schema { - let mut schema = Schema::default(); - let field_id = schema.fields_map.insert(name.into()).unwrap(); - schema.identifier = field_id; + let mut fields_map = FieldsMap::default(); + let field_id = fields_map.insert(name.into()).unwrap(); - schema + Schema { + fields_map, + identifier: field_id, + ranked: HashSet::new(), + displayed: HashSet::new(), + indexed: Vec::new(), + indexed_map: HashMap::new(), + must_index_new_fields: true, + } } pub fn identifier(&self) -> String { @@ -62,8 +71,12 @@ impl Schema { Ok(id) } None => { - self.set_indexed(name.clone())?; - self.set_displayed(name) + if self.must_index_new_fields { + self.set_indexed(name.clone())?; + self.set_displayed(name) + } else { + self.fields_map.insert(name.clone()) + } } } } @@ -200,4 +213,12 @@ impl Schema { } Ok(()) } + + pub fn must_index_new_fields(&self) -> bool { + self.must_index_new_fields + } + + pub fn set_must_index_new_fields(&mut self, value: bool) { + self.must_index_new_fields = value; + } }