circles_types/
query.rs

1use serde::{Deserialize, Serialize};
2
3/// Filter types for query predicates.
4#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
5pub enum FilterType {
6    Equals,
7    NotEquals,
8    GreaterThan,
9    LessThan,
10    GreaterOrEqualThan,
11    LessOrEqualThan,
12    Like,
13}
14
15/// Conjunction types for combining predicates.
16#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
17pub enum ConjunctionType {
18    And,
19    Or,
20}
21
22/// Filter predicate for querying.
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct FilterPredicate {
25    #[serde(rename = "Type")]
26    pub predicate_type: String, // Always "FilterPredicate"
27    #[serde(rename = "FilterType")]
28    pub filter_type: FilterType,
29    #[serde(rename = "Column")]
30    pub column: String,
31    #[serde(rename = "Value")]
32    pub value: serde_json::Value, // Can be string, number, or boolean
33}
34
35impl FilterPredicate {
36    pub fn new(
37        filter_type: FilterType,
38        column: String,
39        value: impl Into<serde_json::Value>,
40    ) -> Self {
41        Self {
42            predicate_type: "FilterPredicate".to_string(),
43            filter_type,
44            column,
45            value: value.into(),
46        }
47    }
48
49    pub fn equals(column: String, value: impl Into<serde_json::Value>) -> Self {
50        Self::new(FilterType::Equals, column, value)
51    }
52
53    pub fn not_equals(column: String, value: impl Into<serde_json::Value>) -> Self {
54        Self::new(FilterType::NotEquals, column, value)
55    }
56
57    pub fn greater_than(column: String, value: impl Into<serde_json::Value>) -> Self {
58        Self::new(FilterType::GreaterThan, column, value)
59    }
60
61    pub fn less_than(column: String, value: impl Into<serde_json::Value>) -> Self {
62        Self::new(FilterType::LessThan, column, value)
63    }
64
65    pub fn like(column: String, pattern: String) -> Self {
66        Self::new(FilterType::Like, column, pattern)
67    }
68}
69
70/// Conjunction for combining multiple predicates.
71#[derive(Debug, Clone, Serialize, Deserialize)]
72pub struct Conjunction {
73    #[serde(rename = "Type")]
74    pub conjunction_type_name: String, // Always "Conjunction"
75    #[serde(rename = "ConjunctionType")]
76    pub conjunction_type: ConjunctionType,
77    #[serde(rename = "Predicates")]
78    pub predicates: Vec<Filter>,
79}
80
81impl Conjunction {
82    pub fn new(conjunction_type: ConjunctionType, predicates: Vec<Filter>) -> Self {
83        Self {
84            conjunction_type_name: "Conjunction".to_string(),
85            conjunction_type,
86            predicates,
87        }
88    }
89
90    pub fn and(predicates: Vec<Filter>) -> Self {
91        Self::new(ConjunctionType::And, predicates)
92    }
93
94    pub fn or(predicates: Vec<Filter>) -> Self {
95        Self::new(ConjunctionType::Or, predicates)
96    }
97}
98
99/// Filter type (either a predicate or conjunction).
100#[derive(Debug, Clone, Serialize, Deserialize)]
101#[serde(untagged)]
102pub enum Filter {
103    Predicate(FilterPredicate),
104    Conjunction(Conjunction),
105}
106
107impl From<FilterPredicate> for Filter {
108    fn from(predicate: FilterPredicate) -> Self {
109        Filter::Predicate(predicate)
110    }
111}
112
113impl From<Conjunction> for Filter {
114    fn from(conjunction: Conjunction) -> Self {
115        Filter::Conjunction(conjunction)
116    }
117}
118
119/// Order direction for query results.
120#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
121pub enum SortOrder {
122    ASC,
123    DESC,
124}
125
126/// Order by clause.
127#[derive(Debug, Clone, Serialize, Deserialize)]
128pub struct OrderBy {
129    #[serde(rename = "Column")]
130    pub column: String,
131    #[serde(rename = "SortOrder")]
132    pub sort_order: SortOrder,
133}
134
135impl OrderBy {
136    pub fn new(column: String, sort_order: SortOrder) -> Self {
137        Self { column, sort_order }
138    }
139
140    pub fn asc(column: String) -> Self {
141        Self::new(column, SortOrder::ASC)
142    }
143
144    pub fn desc(column: String) -> Self {
145        Self::new(column, SortOrder::DESC)
146    }
147}
148
149/// Query parameters for `circles_query`.
150#[derive(Debug, Clone, Serialize, Deserialize)]
151pub struct QueryParams {
152    #[serde(rename = "Namespace")]
153    pub namespace: String,
154    #[serde(rename = "Table")]
155    pub table: String,
156    #[serde(rename = "Columns")]
157    pub columns: Vec<String>,
158    #[serde(rename = "Filter")]
159    pub filter: Vec<Filter>,
160    #[serde(rename = "Order")]
161    pub order: Vec<OrderBy>,
162    #[serde(rename = "Limit", skip_serializing_if = "Option::is_none")]
163    pub limit: Option<u32>,
164}
165
166impl QueryParams {
167    pub fn new(namespace: String, table: String, columns: Vec<String>) -> Self {
168        Self {
169            namespace,
170            table,
171            columns,
172            filter: Vec::new(),
173            order: Vec::new(),
174            limit: None,
175        }
176    }
177
178    pub fn with_filter(mut self, filter: Vec<Filter>) -> Self {
179        self.filter = filter;
180        self
181    }
182
183    pub fn with_order(mut self, order: Vec<OrderBy>) -> Self {
184        self.order = order;
185        self
186    }
187
188    pub fn with_limit(mut self, limit: u32) -> Self {
189        self.limit = Some(limit);
190        self
191    }
192}
193
194/// Column information for table metadata.
195#[derive(Debug, Clone, Serialize, Deserialize)]
196pub struct ColumnInfo {
197    #[serde(rename = "Name")]
198    pub name: String,
199    #[serde(rename = "Type")]
200    pub column_type: String,
201}
202
203/// Table information from circles_tables
204#[derive(Debug, Clone, Serialize, Deserialize)]
205pub struct TableInfo {
206    #[serde(rename = "Namespace")]
207    pub namespace: String,
208    #[serde(rename = "Table")]
209    pub table: String,
210    #[serde(rename = "Columns")]
211    pub columns: Vec<ColumnInfo>,
212}
213
214/// Defines the minimum columns any event row must have for cursor-based pagination.
215/// These values are important for determining cursor position in result sets.
216#[derive(Debug, Clone, Serialize, Deserialize)]
217pub struct EventRow {
218    pub block_number: u64,
219    pub transaction_index: u32,
220    pub log_index: u32,
221    pub batch_index: Option<u32>,
222    pub timestamp: Option<u64>,
223}
224
225/// A cursor is a sortable unique identifier for a specific log entry.
226/// Used to paginate through query results efficiently.
227pub type Cursor = EventRow;
228
229/// Result of a paginated query
230#[derive(Debug, Clone, Serialize, Deserialize)]
231pub struct PagedResult<TRow>
232where
233    TRow: Clone + Serialize,
234{
235    /// The number of results that were requested
236    pub limit: u32,
237    /// The number of results that were returned
238    pub size: u32,
239    /// If the query returned results, this will be the cursor for the first result
240    pub first_cursor: Option<Cursor>,
241    /// If the query returned results, this will be the cursor for the last result
242    pub last_cursor: Option<Cursor>,
243    /// The sort order of the results
244    pub sort_order: SortOrder,
245    /// Whether there are more results available
246    pub has_more: bool,
247    /// The results of the query
248    pub results: Vec<TRow>,
249}
250
251impl<TRow> PagedResult<TRow>
252where
253    TRow: Clone + Serialize,
254{
255    pub fn new(
256        limit: u32,
257        results: Vec<TRow>,
258        sort_order: SortOrder,
259        has_more: bool,
260        first_cursor: Option<Cursor>,
261        last_cursor: Option<Cursor>,
262    ) -> Self {
263        let size = results.len() as u32;
264        Self {
265            limit,
266            size,
267            first_cursor,
268            last_cursor,
269            sort_order,
270            has_more,
271            results,
272        }
273    }
274}
275
276/// Parameters for a paginated query
277#[derive(Debug, Clone, Serialize, Deserialize)]
278pub struct PagedQueryParams {
279    /// The namespace of the table to query
280    pub namespace: String,
281    /// The name of the table to query
282    pub table: String,
283    /// The order to sort the results
284    pub sort_order: SortOrder,
285    /// The columns to return in the results
286    pub columns: Vec<String>,
287    /// The filters to apply to the query
288    #[serde(skip_serializing_if = "Option::is_none")]
289    pub filter: Option<Vec<Filter>>,
290    /// The number of results to return per page
291    pub limit: u32,
292}
293
294impl PagedQueryParams {
295    pub fn new(
296        namespace: String,
297        table: String,
298        sort_order: SortOrder,
299        columns: Vec<String>,
300        limit: u32,
301    ) -> Self {
302        Self {
303            namespace,
304            table,
305            sort_order,
306            columns,
307            filter: None,
308            limit,
309        }
310    }
311
312    pub fn with_filter(mut self, filter: Vec<Filter>) -> Self {
313        self.filter = Some(filter);
314        self
315    }
316}