Skip to main content

reinhardt_urls/proxy/
query.rs

1//! Query filtering for proxies
2
3use crate::proxy::ScalarValue;
4use serde::{Deserialize, Serialize};
5
6/// Filter comparison operators for proxy queries.
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub enum FilterOp {
9	/// Equal comparison.
10	Eq,
11	/// Not equal comparison.
12	Ne,
13	/// Less than comparison.
14	Lt,
15	/// Less than or equal comparison.
16	Le,
17	/// Greater than comparison.
18	Gt,
19	/// Greater than or equal comparison.
20	Ge,
21	/// Membership test (value is contained in the target set).
22	In,
23	/// Negative membership test (value is not in the target set).
24	NotIn,
25	/// Substring containment check.
26	Contains,
27	/// Prefix match check.
28	StartsWith,
29	/// Suffix match check.
30	EndsWith,
31}
32
33/// A single filter condition combining a field, operator, and value.
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct FilterCondition {
36	/// The field name to filter on.
37	pub field: String,
38	/// The comparison operator.
39	pub op: FilterOp,
40	/// The value to compare against (as a string).
41	pub value: String,
42}
43
44impl FilterCondition {
45	/// Create a new filter condition with the given field, operator, and value.
46	pub fn new(field: String, op: FilterOp, value: String) -> Self {
47		Self { field, op, value }
48	}
49
50	/// Check if a `ScalarValue` matches this filter condition.
51	pub fn matches(&self, scalar: &ScalarValue) -> bool {
52		let scalar_str = match scalar {
53			ScalarValue::String(s) => s.clone(),
54			ScalarValue::Integer(i) => i.to_string(),
55			ScalarValue::Float(f) => f.to_string(),
56			ScalarValue::Boolean(b) => b.to_string(),
57			ScalarValue::Null => "null".to_string(),
58		};
59
60		match self.op {
61			FilterOp::Eq => scalar_str == self.value,
62			FilterOp::Ne => scalar_str != self.value,
63			FilterOp::Lt => scalar_str < self.value,
64			FilterOp::Le => scalar_str <= self.value,
65			FilterOp::Gt => scalar_str > self.value,
66			FilterOp::Ge => scalar_str >= self.value,
67			FilterOp::In => self.value.contains(&scalar_str),
68			FilterOp::NotIn => !self.value.contains(&scalar_str),
69			FilterOp::Contains => scalar_str.contains(&self.value),
70			FilterOp::StartsWith => scalar_str.starts_with(&self.value),
71			FilterOp::EndsWith => scalar_str.ends_with(&self.value),
72		}
73	}
74}
75
76/// A collection of filter conditions applied together as a conjunction.
77#[derive(Debug, Clone, Serialize, Deserialize)]
78pub struct QueryFilter {
79	/// The list of filter conditions.
80	pub conditions: Vec<FilterCondition>,
81}
82
83impl QueryFilter {
84	/// Create a new empty query filter.
85	pub fn new() -> Self {
86		Self {
87			conditions: Vec::new(),
88		}
89	}
90
91	/// Add a filter condition to this query filter.
92	pub fn add_condition(&mut self, condition: FilterCondition) {
93		self.conditions.push(condition);
94	}
95}
96
97impl Default for QueryFilter {
98	fn default() -> Self {
99		Self::new()
100	}
101}