sql_fun_sqlast/sem/scalar_expr/
boolean.rs1use sql_fun_core::IVec;
2
3use crate::{
4 sem::{
5 AnalysisError, FromClause, ParseContext, PgBuiltInType, SemScalarExpr, TypeReference,
6 WithClause, analyze_scaler_expr,
7 },
8 syn::{BoolExprType, ListOpt, Opt, ScanToken},
9};
10
11use super::{AnalyzeScalarExpr, SemScalarExprNode};
12
13#[derive(Debug, Clone, Eq, Hash, PartialEq, serde::Serialize, serde::Deserialize)]
14pub enum BooleanExprBody {
15 And(Vec<SemScalarExpr>),
16 Or(Vec<SemScalarExpr>),
17 Not(Box<SemScalarExpr>),
18}
19
20impl BooleanExprBody {
21 pub fn and(items: &[SemScalarExpr]) -> Self {
22 Self::And(items.to_vec())
23 }
24
25 pub fn or(items: &[SemScalarExpr]) -> Self {
26 Self::Or(items.to_vec())
27 }
28
29 pub fn not(expr: &SemScalarExpr) -> Self {
30 Self::Not(Box::new(expr.clone()))
31 }
32}
33
34#[derive(Debug, Clone, Eq, Hash, PartialEq, serde::Serialize, serde::Deserialize)]
36pub struct BooleanExpr {
37 body: BooleanExprBody,
38}
39
40impl BooleanExpr {
41 fn analyze_args<TParseContext>(
42 mut context: TParseContext,
43 with_clause: &WithClause,
44 from_clause: &FromClause,
45 nodes: Vec<crate::syn::Node>,
46 tokens: &IVec<ScanToken>,
47 ) -> Result<(Vec<SemScalarExpr>, TParseContext), AnalysisError>
48 where
49 TParseContext: ParseContext,
50 {
51 let mut results = Vec::new();
52 for node in nodes {
53 let (arg_expr, new_context) =
54 analyze_scaler_expr(context, with_clause, from_clause, node, tokens)?;
55 context = new_context;
56 results.push(arg_expr);
57 }
58 Ok((results, context))
59 }
60}
61
62impl SemScalarExprNode for BooleanExpr {
63 fn get_type(&self) -> Option<TypeReference> {
64 Some(PgBuiltInType::bool())
65 }
66
67 fn is_not_null(&self) -> Option<bool> {
68 match &self.body {
69 BooleanExprBody::And(items) => {
70 for item in items {
71 let is_not_null = item.is_not_null()?;
72 if !is_not_null {
73 return Some(false);
74 }
75 }
76 Some(true)
77 }
78 BooleanExprBody::Or(items) => {
79 for item in items {
80 let is_not_null = item.is_not_null()?;
81 if !is_not_null {
82 return Some(false);
83 }
84 }
85 Some(true)
86 }
87 BooleanExprBody::Not(expr) => expr.is_not_null(),
88 }
89 }
90}
91
92impl<TParseContext> AnalyzeScalarExpr<TParseContext, crate::syn::BoolExpr> for BooleanExpr
93where
94 TParseContext: ParseContext,
95{
96 fn analyze_scalar_expr(
97 mut context: TParseContext,
98 with_clause: &WithClause,
99 from_clause: &FromClause,
100 syn: crate::syn::BoolExpr,
101 tokens: &IVec<ScanToken>,
102 ) -> Result<(SemScalarExpr, TParseContext), AnalysisError> {
103 let Some(boolop) = syn.get_boolop().as_inner() else {
104 AnalysisError::raise_unexpected_none("boolexpr.boolop")?
105 };
106 let Some(args) = syn.get_args().as_inner() else {
107 AnalysisError::raise_unexpected_none("boolexpr.args")?
108 };
109 let (args, new_context) =
110 Self::analyze_args(context, with_clause, from_clause, args, tokens)?;
111 context = new_context;
112
113 let body = match boolop {
114 BoolExprType::AndExpr => BooleanExprBody::and(&args),
115 BoolExprType::OrExpr => BooleanExprBody::or(&args),
116 BoolExprType::NotExpr => {
117 if args.len() != 1 {
118 AnalysisError::raise_unexpected_input("boolexpr.args len")?;
119 }
120 BooleanExprBody::not(&args[0])
121 }
122 _ => AnalysisError::raise_unexpected_input("boolexpr.boolop unexpected value")?,
123 };
124 let expr = Self { body };
125 Ok((SemScalarExpr::Boolean(expr), context))
126 }
127}
128
129#[derive(Debug, Clone, Eq, Hash, PartialEq, serde::Serialize, serde::Deserialize)]
131pub struct NullTestExpr {
132 null_test_type: NullTestType,
133 arg_expr: Box<SemScalarExpr>,
134}
135
136#[derive(Debug, Clone, Eq, Hash, PartialEq, serde::Serialize, serde::Deserialize)]
137pub enum NullTestType {
138 IsNull,
139 IsNotNull,
140}
141
142impl TryFrom<crate::syn::NullTestType> for NullTestType {
143 type Error = AnalysisError;
144
145 fn try_from(value: crate::syn::NullTestType) -> Result<Self, Self::Error> {
146 match value {
147 crate::syn::NullTestType::OptionNone | crate::syn::NullTestType::Undefined => {
148 AnalysisError::raise_unexpected_input("nulltesttype")?
149 }
150 crate::syn::NullTestType::IsNull => Ok(Self::IsNull),
151 crate::syn::NullTestType::IsNotNull => Ok(Self::IsNotNull),
152 }
153 }
154}
155
156impl SemScalarExprNode for NullTestExpr {
157 fn get_type(&self) -> Option<TypeReference> {
158 Some(PgBuiltInType::bool())
159 }
160
161 fn is_not_null(&self) -> Option<bool> {
162 Some(true)
163 }
164}
165
166impl<TParseContext> AnalyzeScalarExpr<TParseContext, crate::syn::NullTest> for NullTestExpr
167where
168 TParseContext: ParseContext,
169{
170 fn analyze_scalar_expr(
171 mut context: TParseContext,
172 with_clause: &WithClause,
173 from_clause: &FromClause,
174 syn: crate::syn::NullTest,
175 tokens: &IVec<ScanToken>,
176 ) -> Result<(SemScalarExpr, TParseContext), AnalysisError> {
177 let Some(null_test_type) = syn.get_nulltesttype().as_inner() else {
178 AnalysisError::raise_unexpected_none("NullTest.nulltesttype")?
179 };
180 let Some(arg) = syn.get_arg().as_inner() else {
181 AnalysisError::raise_unexpected_none("NullTest.arg")?
182 };
183 let (arg_expr, new_context) =
184 analyze_scaler_expr(context, with_clause, from_clause, arg, tokens)?;
185 context = new_context;
186 Ok((
187 SemScalarExpr::NullTest(Self {
188 null_test_type: NullTestType::try_from(null_test_type)?,
189 arg_expr: Box::new(arg_expr),
190 }),
191 context,
192 ))
193 }
194}