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