Skip to main content

qail_core/ast/cmd/
mod.rs

1use crate::ast::{
2    Action, Cage, CageKind, Condition, Distance, Expr, GroupByMode, IndexDef, Join, LockMode,
3    LogicalOp, Operator, OverridingKind, SampleMethod, SetOp, TableConstraint, Value,
4};
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8pub struct Qail {
9    pub action: Action,
10    pub table: String,
11    #[serde(default, skip_serializing_if = "Vec::is_empty")]
12    pub columns: Vec<Expr>,
13    #[serde(default, skip_serializing_if = "Vec::is_empty")]
14    pub joins: Vec<Join>,
15    #[serde(default, skip_serializing_if = "Vec::is_empty")]
16    pub cages: Vec<Cage>,
17    #[serde(default, skip_serializing_if = "is_false")]
18    pub distinct: bool,
19    #[serde(default, skip_serializing_if = "Option::is_none")]
20    pub index_def: Option<IndexDef>,
21    #[serde(default, skip_serializing_if = "Vec::is_empty")]
22    pub table_constraints: Vec<TableConstraint>,
23    #[serde(default, skip_serializing_if = "Vec::is_empty")]
24    pub set_ops: Vec<(SetOp, Box<Qail>)>,
25    #[serde(default, skip_serializing_if = "Vec::is_empty")]
26    pub having: Vec<Condition>,
27    #[serde(default, skip_serializing_if = "GroupByMode::is_simple")]
28    pub group_by_mode: GroupByMode,
29    #[serde(default, skip_serializing_if = "Vec::is_empty")]
30    pub ctes: Vec<CTEDef>,
31    #[serde(default, skip_serializing_if = "Vec::is_empty")]
32    pub distinct_on: Vec<Expr>,
33    #[serde(default, skip_serializing_if = "Option::is_none")]
34    pub returning: Option<Vec<Expr>>,
35    #[serde(default, skip_serializing_if = "Option::is_none")]
36    pub on_conflict: Option<OnConflict>,
37    #[serde(default, skip_serializing_if = "Option::is_none")]
38    pub source_query: Option<Box<Qail>>,
39    #[serde(default, skip_serializing_if = "Option::is_none")]
40    pub channel: Option<String>,
41    #[serde(default, skip_serializing_if = "Option::is_none")]
42    pub payload: Option<String>,
43    #[serde(default, skip_serializing_if = "Option::is_none")]
44    pub savepoint_name: Option<String>,
45    #[serde(default, skip_serializing_if = "Vec::is_empty")]
46    pub from_tables: Vec<String>,
47    #[serde(default, skip_serializing_if = "Vec::is_empty")]
48    pub using_tables: Vec<String>,
49    #[serde(default, skip_serializing_if = "Option::is_none")]
50    pub lock_mode: Option<LockMode>,
51    #[serde(default, skip_serializing_if = "Option::is_none")]
52    pub fetch: Option<(u64, bool)>,
53    #[serde(default, skip_serializing_if = "is_false")]
54    pub default_values: bool,
55    #[serde(default, skip_serializing_if = "Option::is_none")]
56    pub overriding: Option<OverridingKind>,
57    #[serde(default, skip_serializing_if = "Option::is_none")]
58    pub sample: Option<(SampleMethod, f64, Option<u64>)>,
59    #[serde(default, skip_serializing_if = "is_false")]
60    pub only_table: bool,
61    // Vector database fields (Qdrant)
62    #[serde(default, skip_serializing_if = "Option::is_none")]
63    pub vector: Option<Vec<f32>>,
64    #[serde(default, skip_serializing_if = "Option::is_none")]
65    pub score_threshold: Option<f32>,
66    #[serde(default, skip_serializing_if = "Option::is_none")]
67    pub vector_name: Option<String>,
68    #[serde(default, skip_serializing_if = "is_false")]
69    pub with_vector: bool,
70    #[serde(default, skip_serializing_if = "Option::is_none")]
71    pub vector_size: Option<u64>,
72    #[serde(default, skip_serializing_if = "Option::is_none")]
73    pub distance: Option<Distance>,
74    #[serde(default, skip_serializing_if = "Option::is_none")]
75    pub on_disk: Option<bool>,
76    // PostgreSQL procedural objects
77    #[serde(default, skip_serializing_if = "Option::is_none")]
78    pub function_def: Option<crate::ast::FunctionDef>,
79    #[serde(default, skip_serializing_if = "Option::is_none")]
80    pub trigger_def: Option<crate::ast::TriggerDef>,
81    // Redis fields
82    #[serde(default, skip_serializing_if = "Option::is_none")]
83    pub raw_value: Option<Vec<u8>>,
84    #[serde(default, skip_serializing_if = "Option::is_none")]
85    pub redis_ttl: Option<i64>,
86    #[serde(default, skip_serializing_if = "Option::is_none")]
87    pub redis_set_condition: Option<String>,
88}
89
90/// Helper for skip_serializing_if on bool fields
91fn is_false(b: &bool) -> bool {
92    !*b
93}
94
95#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
96pub struct CTEDef {
97    pub name: String,
98    pub recursive: bool,
99    pub columns: Vec<String>,
100    pub base_query: Box<Qail>,
101    pub recursive_query: Option<Box<Qail>>,
102    pub source_table: Option<String>,
103}
104
105#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
106pub struct OnConflict {
107    pub columns: Vec<String>,
108    pub action: ConflictAction,
109}
110
111#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
112pub enum ConflictAction {
113    DoNothing,
114    DoUpdate {
115        assignments: Vec<(String, Expr)>,
116    },
117}
118
119impl Default for OnConflict {
120    fn default() -> Self {
121        Self {
122            columns: vec![],
123            action: ConflictAction::DoNothing,
124        }
125    }
126}
127
128impl Default for Qail {
129    fn default() -> Self {
130        Self {
131            action: Action::Get,
132            table: String::new(),
133            columns: vec![],
134            joins: vec![],
135            cages: vec![],
136            distinct: false,
137            index_def: None,
138            table_constraints: vec![],
139            set_ops: vec![],
140            having: vec![],
141            group_by_mode: GroupByMode::Simple,
142            ctes: vec![],
143            distinct_on: vec![],
144            returning: None,
145            on_conflict: None,
146            source_query: None,
147            channel: None,
148            payload: None,
149            savepoint_name: None,
150            from_tables: vec![],
151            using_tables: vec![],
152            lock_mode: None,
153            fetch: None,
154            default_values: false,
155            overriding: None,
156            sample: None,
157            only_table: false,
158            // Vector database fields
159            vector: None,
160            score_threshold: None,
161            vector_name: None,
162            with_vector: false,
163            vector_size: None,
164            distance: None,
165            on_disk: None,
166            // Procedural objects
167            function_def: None,
168            trigger_def: None,
169            // Redis fields
170            raw_value: None,
171            redis_ttl: None,
172            redis_set_condition: None,
173        }
174    }
175}
176
177// Submodules with builder methods
178mod advanced;
179mod constructors;
180mod cte;
181mod query;
182mod rls;
183mod vector;
184
185// Deprecated methods kept in main module for backward compatibility
186impl Qail {
187    #[deprecated(since = "0.11.0", note = "Use .columns([...]) instead")]
188    pub fn hook(mut self, cols: &[&str]) -> Self {
189        self.columns = cols.iter().map(|c| Expr::Named(c.to_string())).collect();
190        self
191    }
192
193    #[deprecated(since = "0.11.0", note = "Use .filter(column, Operator::Eq, value) or .where_eq(column, value) instead")]
194    pub fn cage(mut self, column: &str, value: impl Into<Value>) -> Self {
195        self.cages.push(Cage {
196            kind: CageKind::Filter,
197            conditions: vec![Condition {
198                left: Expr::Named(column.to_string()),
199                op: Operator::Eq,
200                value: value.into(),
201                is_array_unnest: false,
202            }],
203            logical_op: LogicalOp::And,
204        });
205        self
206    }
207}
208
209impl std::fmt::Display for Qail {
210    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
211        // Use the Formatter from the fmt module for canonical output
212        use crate::fmt::Formatter;
213        match Formatter::new().format(self) {
214            Ok(s) => write!(f, "{}", s),
215            Err(_) => write!(f, "{:?}", self), // Fallback to Debug
216        }
217    }
218}