flusso_query/handles/
string.rs1use std::marker::PhantomData;
5
6use serde_json::{Map, Value};
7
8use super::{FlussoValue, Sort, SortOrder, exists_q, kind, single};
9use crate::query::{Query, Root};
10
11fn keyword_term(value: &impl serde::Serialize) -> Value {
17 match serde_json::to_value(value) {
18 Ok(Value::String(string)) => Value::String(string),
19 Ok(other) => Value::String(other.to_string()),
20 Err(_) => Value::String(String::new()),
21 }
22}
23
24#[derive(Debug, Clone)]
26pub struct Keyword<S = Root> {
27 path: String,
28 _scope: PhantomData<fn() -> S>,
29}
30
31impl<S> Keyword<S> {
32 pub fn at(path: impl Into<String>) -> Self {
33 Self {
34 path: path.into(),
35 _scope: PhantomData,
36 }
37 }
38
39 pub fn eq(&self, value: impl FlussoValue<kind::Keyword> + serde::Serialize) -> Query<S> {
43 single("term", &self.path, keyword_term(&value))
44 }
45
46 pub fn in_(
48 &self,
49 values: impl IntoIterator<Item = impl FlussoValue<kind::Keyword> + serde::Serialize>,
50 ) -> Query<S> {
51 let array = values.into_iter().map(|v| keyword_term(&v)).collect();
52 single("terms", &self.path, Value::Array(array))
53 }
54
55 pub fn prefix(&self, value: impl Into<String>) -> Query<S> {
57 single("prefix", &self.path, Value::String(value.into()))
58 }
59
60 pub fn wildcard(&self, pattern: impl Into<String>) -> Query<S> {
62 single("wildcard", &self.path, Value::String(pattern.into()))
63 }
64
65 pub fn regexp(&self, pattern: impl Into<String>) -> Query<S> {
67 single("regexp", &self.path, Value::String(pattern.into()))
68 }
69
70 pub fn fuzzy(&self, value: impl Into<String>) -> Query<S> {
72 single("fuzzy", &self.path, Value::String(value.into()))
73 }
74
75 pub fn exists(&self) -> Query<S> {
77 exists_q(&self.path)
78 }
79
80 pub fn asc(&self) -> Sort {
81 Sort::new(&self.path, SortOrder::Asc)
82 }
83
84 pub fn desc(&self) -> Sort {
85 Sort::new(&self.path, SortOrder::Desc)
86 }
87}
88
89#[derive(Debug, Clone)]
91pub struct Text<S = Root> {
92 path: String,
93 _scope: PhantomData<fn() -> S>,
94}
95
96impl<S> Text<S> {
97 pub fn at(path: impl Into<String>) -> Self {
98 Self {
99 path: path.into(),
100 _scope: PhantomData,
101 }
102 }
103
104 pub fn matches(&self, value: impl Into<String>) -> Query<S> {
106 single("match", &self.path, Value::String(value.into()))
107 }
108
109 pub fn match_phrase(&self, value: impl Into<String>) -> Query<S> {
111 single("match_phrase", &self.path, Value::String(value.into()))
112 }
113
114 pub fn match_phrase_prefix(&self, value: impl Into<String>) -> Query<S> {
116 single(
117 "match_phrase_prefix",
118 &self.path,
119 Value::String(value.into()),
120 )
121 }
122
123 pub fn matches_fuzzy(&self, value: impl Into<String>) -> Query<S> {
125 let mut params = Map::new();
126 params.insert("query".to_string(), Value::String(value.into()));
127 params.insert("fuzziness".to_string(), Value::String("AUTO".to_string()));
128 single("match", &self.path, Value::Object(params))
129 }
130
131 pub fn exists(&self) -> Query<S> {
133 exists_q(&self.path)
134 }
135}
136
137pub fn multi_match<S>(
139 query: impl Into<String>,
140 fields: impl IntoIterator<Item = Text<S>>,
141) -> Query<S> {
142 let paths = fields
143 .into_iter()
144 .map(|field| Value::String(field.path))
145 .collect();
146 let mut body = Map::new();
147 body.insert("query".to_string(), Value::String(query.into()));
148 body.insert("fields".to_string(), Value::Array(paths));
149 let mut outer = Map::new();
150 outer.insert("multi_match".to_string(), Value::Object(body));
151 Query::leaf(Value::Object(outer))
152}