1use crate::object::PropValue;
2use crate::query::QueryNode;
3use crate::query::QueryNode::*;
4
5pub enum QueryBuilder {
10 #[doc(hidden)]
11 Empty,
12 #[doc(hidden)]
13 Single(QueryNode),
14 #[doc(hidden)]
15 And(Vec<QueryNode>),
16}
17
18pub const Q: QueryBuilder = QueryBuilder::Empty;
21
22impl QueryBuilder {
23 fn add(self, node: QueryNode) -> Self {
24 match self {
25 QueryBuilder::Empty => QueryBuilder::Single(node),
26 QueryBuilder::Single(prev_node) => QueryBuilder::And(vec![prev_node, node]),
27 QueryBuilder::And(mut nodes) => {
28 nodes.push(node);
29 QueryBuilder::And(nodes)
30 }
31 }
32 }
33
34 pub fn id(self, value: impl Into<i64>) -> Self {
36 self.add(PropEqual {
37 name: "object_id".into(),
38 value: value.into().into(),
39 })
40 }
41
42 pub fn equal(self, name: impl Into<String>, value: impl Into<PropValue>) -> Self {
44 self.add(PropEqual {
45 name: name.into(),
46 value: value.into(),
47 })
48 }
49
50 pub fn like(self, name: impl Into<String>, pattern: impl Into<String>) -> Self {
54 self.add(PropLike {
55 name: name.into(),
56 pattern: pattern.into(),
57 })
58 }
59
60 pub fn build(self) -> QueryNode {
62 match self {
63 QueryBuilder::Single(node) => node,
64 QueryBuilder::And(nodes) => And(nodes),
65 QueryBuilder::Empty => Empty,
66 }
67 }
68}
69
70impl Into<QueryNode> for QueryBuilder {
71 fn into(self) -> QueryNode {
72 self.build()
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 macro_rules! builder_test {
81 ($description:expr, $actual:expr, $expected:expr $(,)?) => {
82 ($description, $actual, $expected)
83 };
84 }
85
86 #[test]
87 fn queries_build_correctly() {
88 let tests = [
89 builder_test!("empty query", Q.build(), Empty {}),
90 builder_test!(
91 "string equal",
92 Q.equal("name", "value").build(),
93 PropEqual {
94 name: "name".to_string(),
95 value: "value".into(),
96 },
97 ),
98 builder_test!(
99 "number equal",
100 Q.equal("name", 42).build(),
101 PropEqual {
102 name: "name".to_string(),
103 value: 42.into(),
104 },
105 ),
106 builder_test!(
107 "object_id equal",
108 Q.id(42).build(),
109 PropEqual {
110 name: "object_id".to_string(),
111 value: 42.into(),
112 },
113 ),
114 builder_test!(
115 "simple word like",
116 Q.like("name", "phrase").build(),
117 PropLike {
118 name: "name".to_string(),
119 pattern: "phrase".to_string(),
120 },
121 ),
122 builder_test!(
123 "anded queries",
124 Q.equal("name1", "value1")
125 .equal("name2", "value2")
126 .equal("name3", "value3")
127 .build(),
128 And(vec![
129 PropEqual {
130 name: "name1".to_string(),
131 value: "value1".into(),
132 },
133 PropEqual {
134 name: "name2".to_string(),
135 value: "value2".into(),
136 },
137 PropEqual {
138 name: "name3".to_string(),
139 value: "value3".into(),
140 },
141 ]),
142 ),
143 ];
144
145 for (description, actual_query, expected_query) in &tests {
146 assert_eq!(expected_query, actual_query, "{}", description);
147 }
148 }
149}