Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,45 +18,45 @@ use std::marker::PhantomData;
use serde::de::{MapAccess, Visitor};
use serde::{Deserialize, Deserializer, de};

/// The point of `StringOrStructForSerialization` is to support
/// The point of `LiteralOrStructForSerialization` is to support
/// the two following formats for various queries.
///
/// `{"field": {"query": "my query", "default_operator": "OR"}}`
///
/// and the shorter.
/// `{"field": "my query"}`
///
/// If a integer is passed, we cast it to string. Floats are not supported.
/// If a number or bool is passed, we cast it to string
///
/// We don't use untagged enum to support this, in order to keep good errors.
///
/// The code below is adapted from solution described here: <https://serde.rs/string-or-struct.html>
#[derive(Deserialize)]
#[serde(transparent)]
pub(crate) struct StringOrStructForSerialization<T>
pub(crate) struct LiteralOrStructForSerialization<T>
where
T: From<String>,
for<'de2> T: Deserialize<'de2>,
{
#[serde(deserialize_with = "string_or_struct")]
#[serde(deserialize_with = "literal_or_struct")]
pub inner: T,
}

struct StringOrStructVisitor<T> {
struct LiteralOrStructVisitor<T> {
phantom_data: PhantomData<T>,
}

fn string_or_struct<'de, D, T>(deserializer: D) -> Result<T, D::Error>
fn literal_or_struct<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
T: From<String> + Deserialize<'de>,
{
deserializer.deserialize_any(StringOrStructVisitor {
deserializer.deserialize_any(LiteralOrStructVisitor {
phantom_data: Default::default(),
})
}

impl<'de, T> Visitor<'de> for StringOrStructVisitor<T>
impl<'de, T> Visitor<'de> for LiteralOrStructVisitor<T>
where
T: From<String>,
T: Deserialize<'de>,
Expand All @@ -68,6 +68,11 @@ where
formatter.write_str(&format!("string or map to deserialize {type_str}."))
}

fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
where E: de::Error {
self.visit_str(&v.to_string())
}

fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
where E: de::Error {
self.visit_str(&v.to_string())
Expand All @@ -78,6 +83,11 @@ where
self.visit_str(&v.to_string())
}

fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
where E: de::Error {
self.visit_str(&v.to_string())
}

fn visit_str<E>(self, query: &str) -> Result<Self::Value, E>
where E: serde::de::Error {
Ok(T::from(query.to_string()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

use serde::Deserialize;

use super::{ElasticQueryDslInner, StringOrStructForSerialization};
use super::{ElasticQueryDslInner, LiteralOrStructForSerialization};
use crate::OneFieldMap;
use crate::elastic_query_dsl::match_query::MatchQueryParams;
use crate::elastic_query_dsl::{ConvertibleToQueryAst, default_max_expansions};
Expand All @@ -23,7 +23,7 @@ use crate::query_ast::{FullTextParams, FullTextQuery, QueryAst};
/// `MatchBoolPrefixQuery` as defined in
/// <https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-bool-prefix-query.html>
#[derive(Deserialize, Clone, Eq, PartialEq, Debug)]
#[serde(from = "OneFieldMap<StringOrStructForSerialization<MatchQueryParams>>")]
#[serde(from = "OneFieldMap<LiteralOrStructForSerialization<MatchQueryParams>>")]
pub(crate) struct MatchBoolPrefixQuery {
pub(crate) field: String,
pub(crate) params: MatchQueryParams,
Expand Down Expand Up @@ -54,9 +54,9 @@ impl From<MatchBoolPrefixQuery> for ElasticQueryDslInner {
}
}

impl From<OneFieldMap<StringOrStructForSerialization<MatchQueryParams>>> for MatchBoolPrefixQuery {
impl From<OneFieldMap<LiteralOrStructForSerialization<MatchQueryParams>>> for MatchBoolPrefixQuery {
fn from(
match_query_params: OneFieldMap<StringOrStructForSerialization<MatchQueryParams>>,
match_query_params: OneFieldMap<LiteralOrStructForSerialization<MatchQueryParams>>,
) -> Self {
let OneFieldMap { field, value } = match_query_params;
MatchBoolPrefixQuery {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@
use serde::Deserialize;

use crate::elastic_query_dsl::{
ConvertibleToQueryAst, ElasticQueryDslInner, StringOrStructForSerialization,
ConvertibleToQueryAst, ElasticQueryDslInner, LiteralOrStructForSerialization,
};
use crate::query_ast::{FullTextMode, FullTextParams, FullTextQuery, QueryAst};
use crate::{MatchAllOrNone, OneFieldMap};

/// `MatchPhraseQuery` as defined in
/// <https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query-phrase.html>
#[derive(Deserialize, Clone, Eq, PartialEq, Debug)]
#[serde(from = "OneFieldMap<StringOrStructForSerialization<MatchPhraseQueryParams>>")]
#[serde(from = "OneFieldMap<LiteralOrStructForSerialization<MatchPhraseQueryParams>>")]
pub(crate) struct MatchPhraseQuery {
pub(crate) field: String,
pub(crate) params: MatchPhraseQueryParams,
Expand Down Expand Up @@ -65,11 +65,11 @@ impl From<MatchPhraseQuery> for ElasticQueryDslInner {
}
}

impl From<OneFieldMap<StringOrStructForSerialization<MatchPhraseQueryParams>>>
impl From<OneFieldMap<LiteralOrStructForSerialization<MatchPhraseQueryParams>>>
for MatchPhraseQuery
{
fn from(
match_query_params: OneFieldMap<StringOrStructForSerialization<MatchPhraseQueryParams>>,
match_query_params: OneFieldMap<LiteralOrStructForSerialization<MatchPhraseQueryParams>>,
) -> Self {
let OneFieldMap { field, value } = match_query_params;
MatchPhraseQuery {
Expand Down
8 changes: 4 additions & 4 deletions quickwit/quickwit-query/src/elastic_query_dsl/match_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ use serde::Deserialize;

use super::LeniencyBool;
use crate::elastic_query_dsl::{
ConvertibleToQueryAst, ElasticQueryDslInner, StringOrStructForSerialization,
ConvertibleToQueryAst, ElasticQueryDslInner, LiteralOrStructForSerialization,
};
use crate::query_ast::{FullTextParams, FullTextQuery, QueryAst};
use crate::{BooleanOperand, MatchAllOrNone, OneFieldMap};

/// `MatchQuery` as defined in
/// <https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html>
#[derive(Deserialize, Clone, Eq, PartialEq, Debug)]
#[serde(from = "OneFieldMap<StringOrStructForSerialization<MatchQueryParams>>")]
#[serde(from = "OneFieldMap<LiteralOrStructForSerialization<MatchQueryParams>>")]
pub struct MatchQuery {
pub(crate) field: String,
pub(crate) params: MatchQueryParams,
Expand Down Expand Up @@ -64,9 +64,9 @@ impl From<MatchQuery> for ElasticQueryDslInner {
}
}

impl From<OneFieldMap<StringOrStructForSerialization<MatchQueryParams>>> for MatchQuery {
impl From<OneFieldMap<LiteralOrStructForSerialization<MatchQueryParams>>> for MatchQuery {
fn from(
match_query_params: OneFieldMap<StringOrStructForSerialization<MatchQueryParams>>,
match_query_params: OneFieldMap<LiteralOrStructForSerialization<MatchQueryParams>>,
) -> Self {
let OneFieldMap { field, value } = match_query_params;
MatchQuery {
Expand Down
4 changes: 2 additions & 2 deletions quickwit/quickwit-query/src/elastic_query_dsl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use serde::{Deserialize, Serialize};

mod bool_query;
mod exists_query;
mod literal_or_struct;
mod match_bool_prefix;
mod match_phrase_query;
mod match_query;
Expand All @@ -26,18 +27,17 @@ mod prefix_query;
mod query_string_query;
mod range_query;
mod regex_query;
mod string_or_struct;
mod term_query;
mod terms_query;
mod wildcard_query;

use bool_query::BoolQuery;
pub(crate) use literal_or_struct::LiteralOrStructForSerialization;
pub use one_field_map::OneFieldMap;
use phrase_prefix_query::MatchPhrasePrefixQuery;
use prefix_query::PrefixQuery;
pub(crate) use query_string_query::QueryStringQuery;
use range_query::RangeQuery;
pub(crate) use string_or_struct::StringOrStructForSerialization;
use term_query::TermQuery;

use crate::elastic_query_dsl::exists_query::ExistsQuery;
Expand Down
8 changes: 4 additions & 4 deletions quickwit/quickwit-query/src/elastic_query_dsl/prefix_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
use serde::Deserialize;

use crate::elastic_query_dsl::one_field_map::OneFieldMap;
use crate::elastic_query_dsl::{ConvertibleToQueryAst, StringOrStructForSerialization};
use crate::elastic_query_dsl::{ConvertibleToQueryAst, LiteralOrStructForSerialization};
use crate::query_ast::{QueryAst, WildcardQuery as AstWildcardQuery};

#[derive(Deserialize, Clone, Eq, PartialEq, Debug)]
#[serde(from = "OneFieldMap<StringOrStructForSerialization<PrefixQueryParams>>")]
#[serde(from = "OneFieldMap<LiteralOrStructForSerialization<PrefixQueryParams>>")]
pub(crate) struct PrefixQuery {
pub(crate) field: String,
pub(crate) params: PrefixQueryParams,
Expand Down Expand Up @@ -53,9 +53,9 @@ impl ConvertibleToQueryAst for PrefixQuery {
}
}

impl From<OneFieldMap<StringOrStructForSerialization<PrefixQueryParams>>> for PrefixQuery {
impl From<OneFieldMap<LiteralOrStructForSerialization<PrefixQueryParams>>> for PrefixQuery {
fn from(
match_query_params: OneFieldMap<StringOrStructForSerialization<PrefixQueryParams>>,
match_query_params: OneFieldMap<LiteralOrStructForSerialization<PrefixQueryParams>>,
) -> Self {
let OneFieldMap { field, value } = match_query_params;
PrefixQuery {
Expand Down
50 changes: 44 additions & 6 deletions quickwit/quickwit-query/src/elastic_query_dsl/term_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,21 @@

use serde::{Deserialize, Deserializer, Serialize};

use super::StringOrStructForSerialization;
use super::LiteralOrStructForSerialization;
use crate::elastic_query_dsl::one_field_map::OneFieldMap;
use crate::elastic_query_dsl::{ConvertibleToQueryAst, ElasticQueryDslInner};
use crate::not_nan_f32::NotNaNf32;
use crate::query_ast::{self, QueryAst};

#[derive(Deserialize, Debug, PartialEq, Eq, Clone)]
#[serde(from = "OneFieldMap<StringOrStructForSerialization<TermQueryParams>>")]
#[serde(from = "OneFieldMap<LiteralOrStructForSerialization<TermQueryParams>>")]
pub struct TermQuery {
pub field: String,
pub value: TermQueryParams,
}

impl From<OneFieldMap<StringOrStructForSerialization<TermQueryParams>>> for TermQuery {
fn from(one_field_map: OneFieldMap<StringOrStructForSerialization<TermQueryParams>>) -> Self {
impl From<OneFieldMap<LiteralOrStructForSerialization<TermQueryParams>>> for TermQuery {
fn from(one_field_map: OneFieldMap<LiteralOrStructForSerialization<TermQueryParams>>) -> Self {
TermQuery {
field: one_field_map.field,
value: one_field_map.value.inner,
Expand All @@ -52,6 +52,8 @@ enum TermValue {
I64(i64),
U64(u64),
Str(String),
Bool(bool),
F64(f64),
}

fn deserialize_term_value<'de, D>(deserializer: D) -> Result<String, D::Error>
Expand All @@ -61,6 +63,8 @@ where D: Deserializer<'de> {
TermValue::I64(i64) => Ok(i64.to_string()),
TermValue::U64(u64) => Ok(u64.to_string()),
TermValue::Str(str) => Ok(str),
TermValue::Bool(b) => Ok(b.to_string()),
TermValue::F64(f) => Ok(f.to_string()),
}
}

Expand Down Expand Up @@ -123,7 +127,7 @@ mod tests {
use super::*;

#[test]
fn test_term_query_simple() {
fn test_term_query_string() {
let term_query_json = r#"{ "product_id": { "value": "61809" } }"#;
let term_query: TermQuery = serde_json::from_str(term_query_json).unwrap();
assert_eq!(
Expand All @@ -133,7 +137,7 @@ mod tests {
}

#[test]
fn test_term_query_deserialization_in_short_format() {
fn test_term_query_string_short_form() {
let term_query: TermQuery = serde_json::from_str(
r#"{
"product_id": "61809"
Expand All @@ -145,4 +149,38 @@ mod tests {
&term_query_from_field_value("product_id", "61809")
);
}

#[test]
fn test_term_query_bool() {
let term_query_json = r#"{ "is_product_pretty": { "value": true } }"#;
let term_query: TermQuery = serde_json::from_str(term_query_json).unwrap();
assert_eq!(
&term_query,
&term_query_from_field_value("is_product_pretty", "true")
);
}

#[test]
fn test_term_query_bool_short_form() {
let term_query_json = r#"{ "is_product_pretty": true }"#;
let term_query: TermQuery = serde_json::from_str(term_query_json).unwrap();
assert_eq!(
&term_query,
&term_query_from_field_value("is_product_pretty", "true")
);
}

#[test]
fn test_term_query_float() {
let term_query_json = r#"{ "price": { "value": 1.1 } }"#;
let term_query: TermQuery = serde_json::from_str(term_query_json).unwrap();
assert_eq!(&term_query, &term_query_from_field_value("price", "1.1"));
}

#[test]
fn test_term_query_float_short_form() {
let term_query_json = r#"{ "price": 1.1 }"#;
let term_query: TermQuery = serde_json::from_str(term_query_json).unwrap();
assert_eq!(&term_query, &term_query_from_field_value("price", "1.1"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ use serde::Deserialize;

use crate::NotNaNf32;
use crate::elastic_query_dsl::one_field_map::OneFieldMap;
use crate::elastic_query_dsl::{ConvertibleToQueryAst, StringOrStructForSerialization};
use crate::elastic_query_dsl::{ConvertibleToQueryAst, LiteralOrStructForSerialization};
use crate::query_ast::{QueryAst, WildcardQuery as AstWildcardQuery};

#[derive(Deserialize, Clone, Eq, PartialEq, Debug)]
#[serde(from = "OneFieldMap<StringOrStructForSerialization<WildcardQueryParams>>")]
#[serde(from = "OneFieldMap<LiteralOrStructForSerialization<WildcardQueryParams>>")]
pub(crate) struct WildcardQuery {
pub(crate) field: String,
pub(crate) params: WildcardQueryParams,
Expand Down Expand Up @@ -49,9 +49,9 @@ impl ConvertibleToQueryAst for WildcardQuery {
}
}

impl From<OneFieldMap<StringOrStructForSerialization<WildcardQueryParams>>> for WildcardQuery {
impl From<OneFieldMap<LiteralOrStructForSerialization<WildcardQueryParams>>> for WildcardQuery {
fn from(
match_query_params: OneFieldMap<StringOrStructForSerialization<WildcardQueryParams>>,
match_query_params: OneFieldMap<LiteralOrStructForSerialization<WildcardQueryParams>>,
) -> Self {
let OneFieldMap { field, value } = match_query_params;
WildcardQuery {
Expand Down
Loading
Loading