Skip to main content

pick/selector/
types.rs

1/// Index operation within array brackets.
2#[derive(Debug, Clone, PartialEq)]
3pub enum Index {
4    /// Specific index: `[0]`, `[-1]`
5    Number(i64),
6    /// Wildcard: `[*]`
7    Wildcard,
8    /// Slice: `[2:5]`, `[2:]`, `[:5]`, `[:]`
9    Slice { start: Option<i64>, end: Option<i64> },
10}
11
12/// Built-in functions that transform values.
13#[derive(Debug, Clone, PartialEq)]
14pub enum Builtin {
15    Keys,
16    Values,
17    Length,
18}
19
20/// A single path segment between dots.
21#[derive(Debug, Clone, PartialEq)]
22pub struct Segment {
23    pub key: Option<String>,
24    pub indices: Vec<Index>,
25    pub recursive: bool,
26    pub builtin: Option<Builtin>,
27}
28
29/// A dot-separated path expression.
30#[derive(Debug, Clone, PartialEq)]
31pub struct Selector {
32    pub segments: Vec<Segment>,
33}
34
35/// Comparison operators for filter expressions.
36#[derive(Debug, Clone, PartialEq)]
37pub enum CompareOp {
38    Eq,
39    Ne,
40    Gt,
41    Lt,
42    Gte,
43    Lte,
44    Match,
45}
46
47/// Logical operators for combining conditions.
48#[derive(Debug, Clone, PartialEq)]
49pub enum LogicOp {
50    And,
51    Or,
52}
53
54/// A literal value in a filter expression.
55#[derive(Debug, Clone, PartialEq)]
56pub enum LiteralValue {
57    String(String),
58    Number(f64),
59    Bool(bool),
60    Null,
61}
62
63impl LiteralValue {
64    pub fn to_json_value(&self) -> serde_json::Value {
65        match self {
66            LiteralValue::String(s) => serde_json::Value::String(s.clone()),
67            LiteralValue::Number(n) => {
68                // Prefer integer representation when the value is a whole number
69                if n.fract() == 0.0 && *n >= i64::MIN as f64 && *n <= i64::MAX as f64 {
70                    serde_json::Value::Number((*n as i64).into())
71                } else {
72                    serde_json::Number::from_f64(*n)
73                        .map(serde_json::Value::Number)
74                        .unwrap_or(serde_json::Value::Null)
75                }
76            }
77            LiteralValue::Bool(b) => serde_json::Value::Bool(*b),
78            LiteralValue::Null => serde_json::Value::Null,
79        }
80    }
81}
82
83/// A single comparison condition.
84#[derive(Debug, Clone, PartialEq)]
85pub struct Condition {
86    pub path: Selector,
87    pub op: CompareOp,
88    pub value: LiteralValue,
89}
90
91/// A filter expression, possibly compound with logic operators.
92#[derive(Debug, Clone, PartialEq)]
93pub enum FilterExpr {
94    Condition(Condition),
95    Truthy(Selector),
96    And(Box<FilterExpr>, Box<FilterExpr>),
97    Or(Box<FilterExpr>, Box<FilterExpr>),
98    Not(Box<FilterExpr>),
99}
100
101/// A single stage in a pipeline.
102#[derive(Debug, Clone, PartialEq)]
103pub enum PipeStage {
104    Path(Selector),
105    Builtin(Builtin),
106    Select(FilterExpr),
107    Set { path: Selector, value: LiteralValue },
108    Del(Selector),
109}
110
111/// A pipeline of stages separated by `|`.
112#[derive(Debug, Clone, PartialEq)]
113pub struct Pipeline {
114    pub stages: Vec<PipeStage>,
115}
116
117/// Top-level expression: comma-separated pipelines (union semantics).
118#[derive(Debug, Clone, PartialEq)]
119pub struct Expression {
120    pub pipelines: Vec<Pipeline>,
121}