From bb804ec2b0cf3472a1c5641ab81e28f29fe210af Mon Sep 17 00:00:00 2001 From: Tony Solomonik Date: Sat, 1 Jun 2024 17:32:35 +0300 Subject: [PATCH] Add boolean fields --- src/commands/index.rs | 30 +++++++++++++++++++++++++++++- src/config/boolean.rs | 35 +++++++++++++++++++++++++++++++++++ src/config/mod.rs | 4 ++++ 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 src/config/boolean.rs diff --git a/src/commands/index.rs b/src/commands/index.rs index cde12d6..f52917f 100644 --- a/src/commands/index.rs +++ b/src/commands/index.rs @@ -1,4 +1,4 @@ -use color_eyre::Result; +use color_eyre::{eyre::eyre, Result}; use sqlx::PgPool; use tantivy::{ directory::MmapDirectory, @@ -74,6 +74,34 @@ pub async fn run_index(args: IndexArgs, pool: PgPool) -> Result<()> { }), )); } + FieldType::Boolean(options) => { + let parse_string = options.parse_string; + let field = schema_builder.add_bool_field(&name, options); + field_parsers.push(( + name, + field, + Box::new(move |value| { + if !parse_string { + return common_parse(value); + } + + if let Ok(value_str) = serde_json::from_value::(value.clone()) { + let trimmed = value_str.trim(); + if trimmed.len() < 4 || trimmed.len() > 5 { + return Err(eyre!("cannot parse '{}' as boolean", trimmed)); + } + let value_str = trimmed.to_lowercase(); + match value_str.as_str() { + "true" => Ok(true.into()), + "false" => Ok(false.into()), + _ => Err(eyre!("cannot parse '{}' as boolean", trimmed)), + } + } else { + common_parse(value) + } + }), + )); + } FieldType::Datetime(options) => { let field = schema_builder.add_date_field(&name, options.clone()); field_parsers.push(( diff --git a/src/config/boolean.rs b/src/config/boolean.rs new file mode 100644 index 0000000..01ff899 --- /dev/null +++ b/src/config/boolean.rs @@ -0,0 +1,35 @@ +use serde::{Deserialize, Serialize}; +use tantivy::schema::NumericOptions; + +use super::default_true; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BooleanFieldConfig { + #[serde(default = "default_true")] + pub stored: bool, + + #[serde(default)] + pub fast: bool, + + #[serde(default = "default_true")] + pub indexed: bool, + + #[serde(default = "default_true")] + pub parse_string: bool, +} + +impl From for NumericOptions { + fn from(config: BooleanFieldConfig) -> Self { + let mut options = NumericOptions::default(); + if config.stored { + options = options.set_stored(); + } + if config.indexed { + options = options.set_indexed(); + } + if config.fast { + options = options.set_fast(); + } + options + } +} diff --git a/src/config/mod.rs b/src/config/mod.rs index 3deea95..0383e6b 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,3 +1,4 @@ +pub mod boolean; pub mod datetime; pub mod number; pub mod text; @@ -9,6 +10,7 @@ use serde::{Deserialize, Serialize}; use tokio::fs::read_to_string; use self::{ + boolean::BooleanFieldConfig, datetime::DateTimeFieldConfig, number::NumberFieldConfig, text::{IndexedTextFieldType, TextFieldConfig}, @@ -29,6 +31,7 @@ fn default_true() -> bool { pub enum FieldType { Text(TextFieldConfig), Number(NumberFieldConfig), + Boolean(BooleanFieldConfig), Datetime(DateTimeFieldConfig), } @@ -44,6 +47,7 @@ impl MappingConfig { match &self.type_ { Text(config) => !matches!(config.indexed, IndexedTextFieldType::False), Number(config) => config.indexed, + Boolean(config) => config.indexed, Datetime(config) => config.indexed, } }