1#![doc = include_str!("../docs/queries.md")]
2
3use std::{collections::HashSet, ops::{BitAnd, BitOr}};
4use crate::{error::PakResult, pointer::PakTypedPointer};
5use super::{value::PakValue, Pak};
6
7pub trait PakQueryExpression {
12 fn execute(&self, pak : &Pak) -> PakResult<HashSet<PakTypedPointer>>;
13}
14
15pub struct PakQueryUnion(Box<dyn PakQueryExpression>, Box<dyn PakQueryExpression>);
16
17impl PakQueryExpression for PakQueryUnion {
18 fn execute(&self, pak : &Pak) -> PakResult<HashSet<PakTypedPointer>> {
19 let results_a = self.0.execute(pak)?;
20 let results_b = self.1.execute(pak)?;
21 let results = results_a.into_iter().chain(results_b.into_iter()).collect::<HashSet<_>>();
22 Ok(results)
23 }
24}
25
26impl<B> BitOr<B> for PakQueryUnion where B : PakQueryExpression + 'static {
27 type Output = Self;
28
29 fn bitor(self, other: B) -> Self::Output {
30 PakQueryUnion(Box::new(self), Box::new(other))
31 }
32}
33
34impl <B> BitOr<B> for PakQueryIntersection where B : PakQueryExpression + 'static {
35 type Output = PakQueryUnion;
36
37 fn bitor(self, other: B) -> Self::Output {
38 PakQueryUnion(Box::new(self), Box::new(other))
39 }
40}
41
42impl <B> BitOr<B> for PakQuery where B : PakQueryExpression + 'static {
43 type Output = PakQueryUnion;
44
45 fn bitor(self, other: B) -> Self::Output {
46 PakQueryUnion(Box::new(self), Box::new(other))
47 }
48}
49
50pub struct PakQueryIntersection(Box::<dyn PakQueryExpression>, Box::<dyn PakQueryExpression>);
55
56impl PakQueryExpression for PakQueryIntersection {
57 fn execute(&self, pak : &Pak) -> PakResult<HashSet<PakTypedPointer>> {
58 let results_a = self.0.execute(pak)?;
59 let results_b = self.1.execute(pak)?;
60 Ok(results_a.into_iter().filter(|e| results_b.contains(e)).collect())
61 }
62}
63
64impl <B> BitAnd<B> for PakQuery where B : PakQueryExpression + 'static {
65 type Output = PakQueryIntersection;
66
67 fn bitand(self, rhs: B) -> Self::Output {
68 PakQueryIntersection(Box::new(self), Box::new(rhs))
69 }
70}
71
72impl <B> BitAnd<B> for PakQueryUnion where B : PakQueryExpression + 'static {
73 type Output = PakQueryIntersection;
74
75 fn bitand(self, rhs: B) -> Self::Output {
76 PakQueryIntersection(Box::new(self), Box::new(rhs))
77 }
78}
79
80impl <B> BitAnd<B> for PakQueryIntersection where B : PakQueryExpression + 'static {
81 type Output = PakQueryIntersection;
82
83 fn bitand(self, rhs: B) -> Self::Output {
84 PakQueryIntersection(Box::new(self), Box::new(rhs))
85 }
86}
87
88
89pub enum PakQuery {
94 Equal(String, PakValue),
95 GreaterThan(String, PakValue),
96 LessThan(String, PakValue),
97 GreaterThanEqual(String, PakValue),
98 LessThanEqual(String, PakValue),
99 Contains(String, PakValue)
100}
101
102impl PakQuery {
103 pub fn equals(key : &str, value : impl Into<PakValue>) -> Self {
104 PakQuery::Equal(key.to_string(), value.into())
105 }
106
107 pub fn greater_than(key : &str, value : impl Into<PakValue>) -> Self {
108 PakQuery::GreaterThan(key.to_string(), value.into())
109 }
110
111 pub fn less_than(key : &str, value : impl Into<PakValue>) -> Self {
112 PakQuery::LessThan(key.to_string(), value.into())
113 }
114
115 pub fn greater_than_or_equal(key : &str, value : impl Into<PakValue>) -> Self {
116 PakQuery::GreaterThanEqual(key.to_string(), value.into())
117 }
118
119 pub fn less_than_or_equal(key : &str, value : impl Into<PakValue>) -> Self {
120 PakQuery::LessThanEqual(key.to_string(), value.into())
121 }
122
123 pub fn contains(key : &str, value : impl Into<PakValue>) -> Self {
124 PakQuery::Contains(key.to_string(), value.into())
125 }
126}
127
128pub fn equals(key : &str, value : impl Into<PakValue>) -> PakQuery {
129 PakQuery::Equal(key.to_string(), value.into())
130}
131
132pub fn greater_than(key : &str, value : impl Into<PakValue>) -> PakQuery {
133 PakQuery::GreaterThan(key.to_string(), value.into())
134}
135
136pub fn less_than(key : &str, value : impl Into<PakValue>) -> PakQuery {
137 PakQuery::LessThan(key.to_string(), value.into())
138}
139
140pub fn greater_than_equal(key : &str, value : impl Into<PakValue>) -> PakQuery {
141 PakQuery::GreaterThanEqual(key.to_string(), value.into())
142}
143
144pub fn less_than_equal(key : &str, value : impl Into<PakValue>) -> PakQuery {
145 PakQuery::LessThanEqual(key.to_string(), value.into())
146}
147
148impl PakQueryExpression for PakQuery {
149 fn execute(&self, pak : &Pak) -> PakResult<HashSet<PakTypedPointer>> {
150 match self {
151 PakQuery::Equal(key, pak_value) => {
152 let tree = pak.get_tree(key)?;
153 tree.get(pak_value)
154 },
155 PakQuery::GreaterThan(key, pak_value) => {
156 let tree = pak.get_tree(key)?;
157 tree.get_greater(pak_value)
158 },
159 PakQuery::LessThan(key, pak_value) => {
160 let tree = pak.get_tree(key)?;
161 tree.get_less(pak_value)
162 },
163 PakQuery::GreaterThanEqual(key, pak_value) => {
164 let tree = pak.get_tree(key)?;
165 tree.get_greater_eq(pak_value)
166 },
167 PakQuery::LessThanEqual(key, pak_value) => {
168 let tree = pak.get_tree(key)?;
169 tree.get_less_eq(pak_value)
170 },
171 PakQuery::Contains(key, pak_value) => {
172 let tree = pak.get_tree(key)?;
173 tree.get_contains(pak_value)
174 }
175 }
176 }
177}