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)]
28pub struct Keyword<S = Root> {
29 path: String,
30 _scope: PhantomData<fn() -> S>,
31}
32
33impl<S> Keyword<S> {
34 pub fn at(path: impl Into<String>) -> Self {
36 Self {
37 path: path.into(),
38 _scope: PhantomData,
39 }
40 }
41
42 pub fn eq(&self, value: impl FlussoValue<kind::Keyword> + serde::Serialize) -> Query<S> {
46 single("term", &self.path, keyword_term(&value))
47 }
48
49 pub fn in_(
51 &self,
52 values: impl IntoIterator<Item = impl FlussoValue<kind::Keyword> + serde::Serialize>,
53 ) -> Query<S> {
54 let array = values.into_iter().map(|v| keyword_term(&v)).collect();
55 single("terms", &self.path, Value::Array(array))
56 }
57
58 pub fn prefix(&self, value: impl Into<String>) -> Query<S> {
60 single("prefix", &self.path, Value::String(value.into()))
61 }
62
63 pub fn wildcard(&self, pattern: impl Into<String>) -> Query<S> {
65 single("wildcard", &self.path, Value::String(pattern.into()))
66 }
67
68 pub fn regexp(&self, pattern: impl Into<String>) -> Query<S> {
70 single("regexp", &self.path, Value::String(pattern.into()))
71 }
72
73 pub fn fuzzy(&self, value: impl Into<String>) -> Query<S> {
75 single("fuzzy", &self.path, Value::String(value.into()))
76 }
77
78 pub fn exists(&self) -> Query<S> {
80 exists_q(&self.path)
81 }
82
83 pub fn asc(&self) -> Sort {
85 Sort::new(&self.path, SortOrder::Asc)
86 }
87
88 pub fn desc(&self) -> Sort {
90 Sort::new(&self.path, SortOrder::Desc)
91 }
92}
93
94#[derive(Debug, Clone)]
98pub struct Text<S = Root> {
99 path: String,
100 _scope: PhantomData<fn() -> S>,
101}
102
103impl<S> Text<S> {
104 pub fn at(path: impl Into<String>) -> Self {
106 Self {
107 path: path.into(),
108 _scope: PhantomData,
109 }
110 }
111
112 pub fn matches(&self, value: impl Into<String>) -> Query<S> {
114 single("match", &self.path, Value::String(value.into()))
115 }
116
117 pub fn match_phrase(&self, value: impl Into<String>) -> Query<S> {
119 single("match_phrase", &self.path, Value::String(value.into()))
120 }
121
122 pub fn match_phrase_prefix(&self, value: impl Into<String>) -> Query<S> {
124 single(
125 "match_phrase_prefix",
126 &self.path,
127 Value::String(value.into()),
128 )
129 }
130
131 pub fn matches_fuzzy(&self, value: impl Into<String>) -> Query<S> {
133 let mut params = Map::new();
134 params.insert("query".to_string(), Value::String(value.into()));
135 params.insert("fuzziness".to_string(), Value::String("AUTO".to_string()));
136 single("match", &self.path, Value::Object(params))
137 }
138
139 pub fn exists(&self) -> Query<S> {
141 exists_q(&self.path)
142 }
143}
144
145pub fn multi_match<S>(
147 query: impl Into<String>,
148 fields: impl IntoIterator<Item = Text<S>>,
149) -> Query<S> {
150 let paths = fields
151 .into_iter()
152 .map(|field| Value::String(field.path))
153 .collect();
154 let mut body = Map::new();
155 body.insert("query".to_string(), Value::String(query.into()));
156 body.insert("fields".to_string(), Value::Array(paths));
157 let mut outer = Map::new();
158 outer.insert("multi_match".to_string(), Value::Object(body));
159 Query::leaf(Value::Object(outer))
160}