1use std::marker::PhantomData;
11
12use serde_json::{Map, Value};
13
14#[derive(Debug, Clone, Copy)]
17pub struct Root;
18
19#[derive(Debug, Clone)]
26pub struct Query<S = Root> {
27 inner: Inner,
28 _scope: PhantomData<fn() -> S>,
29}
30
31#[derive(Debug, Clone)]
33enum Inner {
34 Leaf(Value),
35 Bool(BoolInner),
36}
37
38#[derive(Debug, Clone, Default)]
39pub(crate) struct BoolInner {
40 must: Vec<Inner>,
41 filter: Vec<Inner>,
42 should: Vec<Inner>,
43 must_not: Vec<Inner>,
44}
45
46#[derive(Debug, Clone, Copy)]
47enum Clause {
48 Must,
49 Filter,
50 Should,
51 MustNot,
52}
53
54impl BoolInner {
55 pub(crate) fn is_empty(&self) -> bool {
56 self.must.is_empty()
57 && self.filter.is_empty()
58 && self.should.is_empty()
59 && self.must_not.is_empty()
60 }
61
62 fn push(&mut self, clause: Clause, inner: Inner) {
63 match clause {
64 Clause::Must => self.must.push(inner),
65 Clause::Filter => self.filter.push(inner),
66 Clause::Should => self.should.push(inner),
67 Clause::MustNot => self.must_not.push(inner),
68 }
69 }
70
71 fn is_pure(&self, clause: Clause) -> bool {
74 match clause {
75 Clause::Must => {
76 self.filter.is_empty() && self.should.is_empty() && self.must_not.is_empty()
77 }
78 Clause::Filter => {
79 self.must.is_empty() && self.should.is_empty() && self.must_not.is_empty()
80 }
81 Clause::Should => {
82 self.must.is_empty() && self.filter.is_empty() && self.must_not.is_empty()
83 }
84 Clause::MustNot => {
85 self.must.is_empty() && self.filter.is_empty() && self.should.is_empty()
86 }
87 }
88 }
89
90 pub(crate) fn to_value(&self) -> Value {
91 let mut body = Map::new();
92 insert_clause(&mut body, "must", &self.must);
93 insert_clause(&mut body, "filter", &self.filter);
94 insert_clause(&mut body, "should", &self.should);
95 insert_clause(&mut body, "must_not", &self.must_not);
96 let mut outer = Map::new();
97 outer.insert("bool".to_string(), Value::Object(body));
98 Value::Object(outer)
99 }
100}
101
102fn insert_clause(target: &mut Map<String, Value>, key: &str, clauses: &[Inner]) {
103 if clauses.is_empty() {
104 return;
105 }
106 let array = clauses.iter().map(Inner::to_value).collect();
107 target.insert(key.to_string(), Value::Array(array));
108}
109
110impl Inner {
111 fn to_value(&self) -> Value {
112 match self {
113 Inner::Leaf(value) => value.clone(),
114 Inner::Bool(bool_inner) => bool_inner.to_value(),
115 }
116 }
117}
118
119fn combine(a: Inner, b: Inner, clause: Clause) -> Inner {
122 if let Inner::Bool(mut bool_inner) = a {
123 if bool_inner.is_pure(clause) {
124 bool_inner.push(clause, b);
125 return Inner::Bool(bool_inner);
126 }
127 let mut combined = BoolInner::default();
128 combined.push(clause, Inner::Bool(bool_inner));
129 combined.push(clause, b);
130 return Inner::Bool(combined);
131 }
132 let mut combined = BoolInner::default();
133 combined.push(clause, a);
134 combined.push(clause, b);
135 Inner::Bool(combined)
136}
137
138impl<S> Query<S> {
139 pub(crate) fn leaf(value: Value) -> Self {
141 Query {
142 inner: Inner::Leaf(value),
143 _scope: PhantomData,
144 }
145 }
146
147 fn wrap(inner: Inner) -> Self {
148 Query {
149 inner,
150 _scope: PhantomData,
151 }
152 }
153
154 #[must_use]
156 pub fn and(self, other: impl AsQuery<S>) -> Query<S> {
157 match other.into_query() {
158 Some(other) => Query::wrap(combine(self.inner, other.inner, Clause::Must)),
159 None => self,
160 }
161 }
162
163 #[must_use]
165 pub fn or(self, other: impl AsQuery<S>) -> Query<S> {
166 match other.into_query() {
167 Some(other) => Query::wrap(combine(self.inner, other.inner, Clause::Should)),
168 None => self,
169 }
170 }
171
172 #[must_use]
174 #[allow(clippy::should_implement_trait)]
175 pub fn not(self) -> Query<S> {
176 Query::wrap(Inner::Bool(BoolInner {
177 must_not: vec![self.inner],
178 ..BoolInner::default()
179 }))
180 }
181
182 #[must_use]
184 pub fn to_value(&self) -> Value {
185 self.inner.to_value()
186 }
187
188 pub(crate) fn into_inner(self) -> InnerClause {
190 InnerClause(self.inner)
191 }
192}
193
194pub(crate) struct InnerClause(Inner);
196
197#[derive(Debug, Clone, Default)]
199pub(crate) struct BoolBuilder {
200 bool_inner: BoolInner,
201}
202
203impl BoolBuilder {
204 pub(crate) fn push_must(&mut self, clause: InnerClause) {
205 self.bool_inner.push(Clause::Must, clause.0);
206 }
207 pub(crate) fn push_filter(&mut self, clause: InnerClause) {
208 self.bool_inner.push(Clause::Filter, clause.0);
209 }
210 pub(crate) fn push_should(&mut self, clause: InnerClause) {
211 self.bool_inner.push(Clause::Should, clause.0);
212 }
213 pub(crate) fn push_must_not(&mut self, clause: InnerClause) {
214 self.bool_inner.push(Clause::MustNot, clause.0);
215 }
216 pub(crate) fn is_empty(&self) -> bool {
217 self.bool_inner.is_empty()
218 }
219 pub(crate) fn to_value(&self) -> Value {
220 self.bool_inner.to_value()
221 }
222}
223
224pub trait AsQuery<S> {
228 fn into_query(self) -> Option<Query<S>>;
230}
231
232impl<S> AsQuery<S> for Query<S> {
233 fn into_query(self) -> Option<Query<S>> {
234 Some(self)
235 }
236}
237
238impl<S, T: AsQuery<S>> AsQuery<S> for Option<T> {
239 fn into_query(self) -> Option<Query<S>> {
240 self.and_then(AsQuery::into_query)
241 }
242}