1use std::sync::Arc;
5
6use reifydb_core::{
7 interface::identifier::{ColumnIdentifier, ColumnShape},
8 internal,
9};
10use reifydb_type::{
11 Result,
12 error::{Error, TypeError},
13 fragment::Fragment,
14 value::r#type::Type,
15};
16use serde::{Deserialize, Serialize};
17use serde_json::{from_str, to_string, to_string_pretty};
18
19use super::{
20 AccessShapeExpression, AddExpression, AliasExpression, AndExpression, BetweenExpression, CallExpression,
21 CastExpression, ColumnExpression, ConstantExpression, ContainsExpression, DivExpression, ElseIfExpression,
22 EqExpression, Expression, ExtendExpression, FieldAccessExpression, GreaterThanEqExpression,
23 GreaterThanExpression, IdentExpression, IfExpression, InExpression, LessThanEqExpression, LessThanExpression,
24 ListExpression, MapExpression, MulExpression, NotEqExpression, OrExpression, ParameterExpression,
25 PrefixExpression, PrefixOperator, RemExpression, SubExpression, TupleExpression, TypeExpression,
26 VariableExpression, XorExpression,
27};
28
29#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
30#[serde(tag = "type", rename_all = "snake_case")]
31pub enum JsonExpression {
32 None,
33 Bool {
34 value: String,
35 },
36 Number {
37 value: String,
38 },
39 Text {
40 value: String,
41 },
42 Temporal {
43 value: String,
44 },
45
46 Column {
47 namespace: String,
48 shape: String,
49 name: String,
50 },
51 AccessSource {
52 namespace: String,
53 shape: String,
54 name: String,
55 },
56 Variable {
57 name: String,
58 },
59 #[serde(rename = "parameter_positional")]
60 ParameterPositional {
61 position: String,
62 },
63 #[serde(rename = "parameter_named")]
64 ParameterNamed {
65 name: String,
66 },
67
68 GreaterThan {
69 left: Box<JsonExpression>,
70 right: Box<JsonExpression>,
71 },
72 GreaterThanEqual {
73 left: Box<JsonExpression>,
74 right: Box<JsonExpression>,
75 },
76 LessThan {
77 left: Box<JsonExpression>,
78 right: Box<JsonExpression>,
79 },
80 LessThanEqual {
81 left: Box<JsonExpression>,
82 right: Box<JsonExpression>,
83 },
84 Equal {
85 left: Box<JsonExpression>,
86 right: Box<JsonExpression>,
87 },
88 NotEqual {
89 left: Box<JsonExpression>,
90 right: Box<JsonExpression>,
91 },
92
93 And {
94 left: Box<JsonExpression>,
95 right: Box<JsonExpression>,
96 },
97 Or {
98 left: Box<JsonExpression>,
99 right: Box<JsonExpression>,
100 },
101 Xor {
102 left: Box<JsonExpression>,
103 right: Box<JsonExpression>,
104 },
105
106 Add {
107 left: Box<JsonExpression>,
108 right: Box<JsonExpression>,
109 },
110 Sub {
111 left: Box<JsonExpression>,
112 right: Box<JsonExpression>,
113 },
114 Mul {
115 left: Box<JsonExpression>,
116 right: Box<JsonExpression>,
117 },
118 Div {
119 left: Box<JsonExpression>,
120 right: Box<JsonExpression>,
121 },
122 Rem {
123 left: Box<JsonExpression>,
124 right: Box<JsonExpression>,
125 },
126
127 Alias {
128 alias: String,
129 expression: Box<JsonExpression>,
130 },
131 Cast {
132 expression: Box<JsonExpression>,
133 to: String,
134 },
135 Call {
136 function: String,
137 args: Vec<JsonExpression>,
138 },
139 Tuple {
140 expressions: Vec<JsonExpression>,
141 },
142 List {
143 expressions: Vec<JsonExpression>,
144 },
145 Prefix {
146 operator: String,
147 expression: Box<JsonExpression>,
148 },
149 Between {
150 value: Box<JsonExpression>,
151 lower: Box<JsonExpression>,
152 upper: Box<JsonExpression>,
153 },
154 In {
155 value: Box<JsonExpression>,
156 list: Box<JsonExpression>,
157 negated: bool,
158 },
159 Contains {
160 value: Box<JsonExpression>,
161 list: Box<JsonExpression>,
162 },
163 If {
164 condition: Box<JsonExpression>,
165 then: Box<JsonExpression>,
166 else_ifs: Vec<JsonElseIf>,
167 #[serde(skip_serializing_if = "Option::is_none")]
168 else_expr: Option<Box<JsonExpression>>,
169 },
170 Map {
171 expressions: Vec<JsonExpression>,
172 },
173 Extend {
174 expressions: Vec<JsonExpression>,
175 },
176 Type {
177 ty: String,
178 },
179 FieldAccess {
180 object: Box<JsonExpression>,
181 field: String,
182 },
183}
184
185#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
186pub struct JsonElseIf {
187 pub condition: Box<JsonExpression>,
188 pub then: Box<JsonExpression>,
189}
190
191fn extract_shape(cp: &ColumnShape) -> (String, String) {
192 match cp {
193 ColumnShape::Qualified {
194 namespace,
195 name,
196 } => (namespace.text().to_string(), name.text().to_string()),
197 ColumnShape::Alias(alias) => ("_alias".to_string(), alias.text().to_string()),
198 }
199}
200
201fn internal_fragment(text: &str) -> Fragment {
202 Fragment::Internal {
203 text: Arc::from(text),
204 }
205}
206
207impl From<&Expression> for JsonExpression {
208 fn from(expr: &Expression) -> Self {
209 match expr {
210 Expression::Constant(constant) => match constant {
211 ConstantExpression::None {
212 ..
213 } => JsonExpression::None,
214 ConstantExpression::Bool {
215 fragment,
216 } => JsonExpression::Bool {
217 value: fragment.text().to_string(),
218 },
219 ConstantExpression::Number {
220 fragment,
221 } => JsonExpression::Number {
222 value: fragment.text().to_string(),
223 },
224 ConstantExpression::Text {
225 fragment,
226 } => JsonExpression::Text {
227 value: fragment.text().to_string(),
228 },
229 ConstantExpression::Temporal {
230 fragment,
231 } => JsonExpression::Temporal {
232 value: fragment.text().to_string(),
233 },
234 },
235
236 Expression::Column(ColumnExpression(col)) => {
237 let (namespace, shape) = extract_shape(&col.shape);
238 JsonExpression::Column {
239 namespace,
240 shape,
241 name: col.name.text().to_string(),
242 }
243 }
244 Expression::AccessSource(AccessShapeExpression {
245 column,
246 }) => {
247 let (namespace, shape) = extract_shape(&column.shape);
248 JsonExpression::AccessSource {
249 namespace,
250 shape,
251 name: column.name.text().to_string(),
252 }
253 }
254 Expression::Variable(var) => JsonExpression::Variable {
255 name: var.name().to_string(),
256 },
257 Expression::Parameter(param) => match param {
258 ParameterExpression::Positional {
259 fragment,
260 } => JsonExpression::ParameterPositional {
261 position: fragment.text()[1..].to_string(),
262 },
263 ParameterExpression::Named {
264 fragment,
265 } => JsonExpression::ParameterNamed {
266 name: fragment.text()[1..].to_string(),
267 },
268 },
269
270 Expression::GreaterThan(e) => JsonExpression::GreaterThan {
271 left: Box::new((&*e.left).into()),
272 right: Box::new((&*e.right).into()),
273 },
274 Expression::GreaterThanEqual(e) => JsonExpression::GreaterThanEqual {
275 left: Box::new((&*e.left).into()),
276 right: Box::new((&*e.right).into()),
277 },
278 Expression::LessThan(e) => JsonExpression::LessThan {
279 left: Box::new((&*e.left).into()),
280 right: Box::new((&*e.right).into()),
281 },
282 Expression::LessThanEqual(e) => JsonExpression::LessThanEqual {
283 left: Box::new((&*e.left).into()),
284 right: Box::new((&*e.right).into()),
285 },
286 Expression::Equal(e) => JsonExpression::Equal {
287 left: Box::new((&*e.left).into()),
288 right: Box::new((&*e.right).into()),
289 },
290 Expression::NotEqual(e) => JsonExpression::NotEqual {
291 left: Box::new((&*e.left).into()),
292 right: Box::new((&*e.right).into()),
293 },
294
295 Expression::And(e) => JsonExpression::And {
296 left: Box::new((&*e.left).into()),
297 right: Box::new((&*e.right).into()),
298 },
299 Expression::Or(e) => JsonExpression::Or {
300 left: Box::new((&*e.left).into()),
301 right: Box::new((&*e.right).into()),
302 },
303 Expression::Xor(e) => JsonExpression::Xor {
304 left: Box::new((&*e.left).into()),
305 right: Box::new((&*e.right).into()),
306 },
307
308 Expression::Add(e) => JsonExpression::Add {
309 left: Box::new((&*e.left).into()),
310 right: Box::new((&*e.right).into()),
311 },
312 Expression::Sub(e) => JsonExpression::Sub {
313 left: Box::new((&*e.left).into()),
314 right: Box::new((&*e.right).into()),
315 },
316 Expression::Mul(e) => JsonExpression::Mul {
317 left: Box::new((&*e.left).into()),
318 right: Box::new((&*e.right).into()),
319 },
320 Expression::Div(e) => JsonExpression::Div {
321 left: Box::new((&*e.left).into()),
322 right: Box::new((&*e.right).into()),
323 },
324 Expression::Rem(e) => JsonExpression::Rem {
325 left: Box::new((&*e.left).into()),
326 right: Box::new((&*e.right).into()),
327 },
328
329 Expression::Alias(e) => JsonExpression::Alias {
330 alias: e.alias.name().to_string(),
331 expression: Box::new((&*e.expression).into()),
332 },
333 Expression::Cast(e) => JsonExpression::Cast {
334 expression: Box::new((&*e.expression).into()),
335 to: format!("{:?}", e.to.ty),
336 },
337 Expression::Call(e) => JsonExpression::Call {
338 function: e.func.name().to_string(),
339 args: e.args.iter().map(|a| a.into()).collect(),
340 },
341 Expression::Tuple(e) => JsonExpression::Tuple {
342 expressions: e.expressions.iter().map(|a| a.into()).collect(),
343 },
344 Expression::List(e) => JsonExpression::List {
345 expressions: e.expressions.iter().map(|a| a.into()).collect(),
346 },
347 Expression::Prefix(e) => {
348 let operator = match &e.operator {
349 PrefixOperator::Minus(_) => "-",
350 PrefixOperator::Plus(_) => "+",
351 PrefixOperator::Not(_) => "not",
352 };
353 JsonExpression::Prefix {
354 operator: operator.to_string(),
355 expression: Box::new((&*e.expression).into()),
356 }
357 }
358 Expression::Between(e) => JsonExpression::Between {
359 value: Box::new((&*e.value).into()),
360 lower: Box::new((&*e.lower).into()),
361 upper: Box::new((&*e.upper).into()),
362 },
363 Expression::In(e) => JsonExpression::In {
364 value: Box::new((&*e.value).into()),
365 list: Box::new((&*e.list).into()),
366 negated: e.negated,
367 },
368 Expression::Contains(e) => JsonExpression::Contains {
369 value: Box::new((&*e.value).into()),
370 list: Box::new((&*e.list).into()),
371 },
372 Expression::If(e) => JsonExpression::If {
373 condition: Box::new((&*e.condition).into()),
374 then: Box::new((&*e.then_expr).into()),
375 else_ifs: e
376 .else_ifs
377 .iter()
378 .map(|ei| JsonElseIf {
379 condition: Box::new((&*ei.condition).into()),
380 then: Box::new((&*ei.then_expr).into()),
381 })
382 .collect(),
383 else_expr: e.else_expr.as_ref().map(|ee| Box::new((&**ee).into())),
384 },
385 Expression::Map(e) => JsonExpression::Map {
386 expressions: e.expressions.iter().map(|a| a.into()).collect(),
387 },
388 Expression::Extend(e) => JsonExpression::Extend {
389 expressions: e.expressions.iter().map(|a| a.into()).collect(),
390 },
391 Expression::Type(e) => JsonExpression::Type {
392 ty: format!("{:?}", e.ty),
393 },
394 Expression::SumTypeConstructor(_) => JsonExpression::Type {
395 ty: "SumTypeConstructor".to_string(),
396 },
397 Expression::IsVariant(_) => JsonExpression::Type {
398 ty: "IsVariant".to_string(),
399 },
400 Expression::FieldAccess(e) => JsonExpression::FieldAccess {
401 object: Box::new((&*e.object).into()),
402 field: e.field.text().to_string(),
403 },
404 }
405 }
406}
407
408impl TryFrom<JsonExpression> for Expression {
409 type Error = Error;
410
411 fn try_from(json: JsonExpression) -> Result<Self> {
412 Ok(match json {
413 JsonExpression::None => Expression::Constant(ConstantExpression::None {
414 fragment: Fragment::None,
415 }),
416 JsonExpression::Bool {
417 value,
418 } => Expression::Constant(ConstantExpression::Bool {
419 fragment: internal_fragment(&value),
420 }),
421 JsonExpression::Number {
422 value,
423 } => Expression::Constant(ConstantExpression::Number {
424 fragment: internal_fragment(&value),
425 }),
426 JsonExpression::Text {
427 value,
428 } => Expression::Constant(ConstantExpression::Text {
429 fragment: internal_fragment(&value),
430 }),
431 JsonExpression::Temporal {
432 value,
433 } => Expression::Constant(ConstantExpression::Temporal {
434 fragment: internal_fragment(&value),
435 }),
436
437 JsonExpression::Column {
438 namespace,
439 shape,
440 name,
441 } => Expression::Column(ColumnExpression(ColumnIdentifier {
442 shape: ColumnShape::Qualified {
443 namespace: internal_fragment(&namespace),
444 name: internal_fragment(&shape),
445 },
446 name: internal_fragment(&name),
447 })),
448 JsonExpression::AccessSource {
449 namespace,
450 shape,
451 name,
452 } => Expression::AccessSource(AccessShapeExpression {
453 column: ColumnIdentifier {
454 shape: ColumnShape::Qualified {
455 namespace: internal_fragment(&namespace),
456 name: internal_fragment(&shape),
457 },
458 name: internal_fragment(&name),
459 },
460 }),
461 JsonExpression::Variable {
462 name,
463 } => Expression::Variable(VariableExpression {
464 fragment: internal_fragment(&format!("${}", name)),
465 }),
466 JsonExpression::ParameterPositional {
467 position,
468 } => Expression::Parameter(ParameterExpression::Positional {
469 fragment: internal_fragment(&format!("${}", position)),
470 }),
471 JsonExpression::ParameterNamed {
472 name,
473 } => Expression::Parameter(ParameterExpression::Named {
474 fragment: internal_fragment(&format!("${}", name)),
475 }),
476
477 JsonExpression::GreaterThan {
478 left,
479 right,
480 } => Expression::GreaterThan(GreaterThanExpression {
481 left: Box::new((*left).try_into()?),
482 right: Box::new((*right).try_into()?),
483 fragment: Fragment::None,
484 }),
485 JsonExpression::GreaterThanEqual {
486 left,
487 right,
488 } => Expression::GreaterThanEqual(GreaterThanEqExpression {
489 left: Box::new((*left).try_into()?),
490 right: Box::new((*right).try_into()?),
491 fragment: Fragment::None,
492 }),
493 JsonExpression::LessThan {
494 left,
495 right,
496 } => Expression::LessThan(LessThanExpression {
497 left: Box::new((*left).try_into()?),
498 right: Box::new((*right).try_into()?),
499 fragment: Fragment::None,
500 }),
501 JsonExpression::LessThanEqual {
502 left,
503 right,
504 } => Expression::LessThanEqual(LessThanEqExpression {
505 left: Box::new((*left).try_into()?),
506 right: Box::new((*right).try_into()?),
507 fragment: Fragment::None,
508 }),
509 JsonExpression::Equal {
510 left,
511 right,
512 } => Expression::Equal(EqExpression {
513 left: Box::new((*left).try_into()?),
514 right: Box::new((*right).try_into()?),
515 fragment: Fragment::None,
516 }),
517 JsonExpression::NotEqual {
518 left,
519 right,
520 } => Expression::NotEqual(NotEqExpression {
521 left: Box::new((*left).try_into()?),
522 right: Box::new((*right).try_into()?),
523 fragment: Fragment::None,
524 }),
525
526 JsonExpression::And {
527 left,
528 right,
529 } => Expression::And(AndExpression {
530 left: Box::new((*left).try_into()?),
531 right: Box::new((*right).try_into()?),
532 fragment: Fragment::None,
533 }),
534 JsonExpression::Or {
535 left,
536 right,
537 } => Expression::Or(OrExpression {
538 left: Box::new((*left).try_into()?),
539 right: Box::new((*right).try_into()?),
540 fragment: Fragment::None,
541 }),
542 JsonExpression::Xor {
543 left,
544 right,
545 } => Expression::Xor(XorExpression {
546 left: Box::new((*left).try_into()?),
547 right: Box::new((*right).try_into()?),
548 fragment: Fragment::None,
549 }),
550
551 JsonExpression::Add {
552 left,
553 right,
554 } => Expression::Add(AddExpression {
555 left: Box::new((*left).try_into()?),
556 right: Box::new((*right).try_into()?),
557 fragment: Fragment::None,
558 }),
559 JsonExpression::Sub {
560 left,
561 right,
562 } => Expression::Sub(SubExpression {
563 left: Box::new((*left).try_into()?),
564 right: Box::new((*right).try_into()?),
565 fragment: Fragment::None,
566 }),
567 JsonExpression::Mul {
568 left,
569 right,
570 } => Expression::Mul(MulExpression {
571 left: Box::new((*left).try_into()?),
572 right: Box::new((*right).try_into()?),
573 fragment: Fragment::None,
574 }),
575 JsonExpression::Div {
576 left,
577 right,
578 } => Expression::Div(DivExpression {
579 left: Box::new((*left).try_into()?),
580 right: Box::new((*right).try_into()?),
581 fragment: Fragment::None,
582 }),
583 JsonExpression::Rem {
584 left,
585 right,
586 } => Expression::Rem(RemExpression {
587 left: Box::new((*left).try_into()?),
588 right: Box::new((*right).try_into()?),
589 fragment: Fragment::None,
590 }),
591
592 JsonExpression::Alias {
593 alias,
594 expression,
595 } => Expression::Alias(AliasExpression {
596 alias: IdentExpression(internal_fragment(&alias)),
597 expression: Box::new((*expression).try_into()?),
598 fragment: Fragment::None,
599 }),
600 JsonExpression::Cast {
601 expression,
602 to,
603 } => {
604 let ty = parse_type(&to)?;
605 Expression::Cast(CastExpression {
606 expression: Box::new((*expression).try_into()?),
607 to: TypeExpression {
608 ty,
609 fragment: internal_fragment(&to),
610 },
611 fragment: Fragment::None,
612 })
613 }
614 JsonExpression::Call {
615 function,
616 args,
617 } => Expression::Call(CallExpression {
618 func: IdentExpression(internal_fragment(&function)),
619 args: args.into_iter().map(|a| a.try_into()).collect::<Result<Vec<_>>>()?,
620 fragment: Fragment::None,
621 }),
622 JsonExpression::Tuple {
623 expressions,
624 } => Expression::Tuple(TupleExpression {
625 expressions: expressions
626 .into_iter()
627 .map(|a| a.try_into())
628 .collect::<Result<Vec<_>>>()?,
629 fragment: Fragment::None,
630 }),
631 JsonExpression::List {
632 expressions,
633 } => Expression::List(ListExpression {
634 expressions: expressions
635 .into_iter()
636 .map(|a| a.try_into())
637 .collect::<Result<Vec<_>>>()?,
638 fragment: Fragment::None,
639 }),
640 JsonExpression::Prefix {
641 operator,
642 expression,
643 } => {
644 let op = match operator.as_str() {
645 "-" => PrefixOperator::Minus(Fragment::None),
646 "+" => PrefixOperator::Plus(Fragment::None),
647 "not" => PrefixOperator::Not(Fragment::None),
648 _ => {
649 return Err(Error(Box::new(internal!(
650 "Unknown prefix operator: {}",
651 operator
652 ))));
653 }
654 };
655 Expression::Prefix(PrefixExpression {
656 operator: op,
657 expression: Box::new((*expression).try_into()?),
658 fragment: Fragment::None,
659 })
660 }
661 JsonExpression::Between {
662 value,
663 lower,
664 upper,
665 } => Expression::Between(BetweenExpression {
666 value: Box::new((*value).try_into()?),
667 lower: Box::new((*lower).try_into()?),
668 upper: Box::new((*upper).try_into()?),
669 fragment: Fragment::None,
670 }),
671 JsonExpression::In {
672 value,
673 list,
674 negated,
675 } => Expression::In(InExpression {
676 value: Box::new((*value).try_into()?),
677 list: Box::new((*list).try_into()?),
678 negated,
679 fragment: Fragment::None,
680 }),
681 JsonExpression::Contains {
682 value,
683 list,
684 } => Expression::Contains(ContainsExpression {
685 value: Box::new((*value).try_into()?),
686 list: Box::new((*list).try_into()?),
687 fragment: Fragment::None,
688 }),
689 JsonExpression::If {
690 condition,
691 then,
692 else_ifs,
693 else_expr,
694 } => {
695 let converted_else: Option<Box<Expression>> = match else_expr {
696 Some(ee) => Some(Box::new((*ee).try_into()?)),
697 None => None,
698 };
699 Expression::If(IfExpression {
700 condition: Box::new((*condition).try_into()?),
701 then_expr: Box::new((*then).try_into()?),
702 else_ifs: else_ifs
703 .into_iter()
704 .map(|ei| {
705 Ok(ElseIfExpression {
706 condition: Box::new((*ei.condition).try_into()?),
707 then_expr: Box::new((*ei.then).try_into()?),
708 fragment: Fragment::None,
709 })
710 })
711 .collect::<Result<Vec<_>>>()?,
712 else_expr: converted_else,
713 fragment: Fragment::None,
714 })
715 }
716 JsonExpression::Map {
717 expressions,
718 } => Expression::Map(MapExpression {
719 expressions: expressions
720 .into_iter()
721 .map(|a| a.try_into())
722 .collect::<Result<Vec<_>>>()?,
723 fragment: Fragment::None,
724 }),
725 JsonExpression::Extend {
726 expressions,
727 } => Expression::Extend(ExtendExpression {
728 expressions: expressions
729 .into_iter()
730 .map(|a| a.try_into())
731 .collect::<Result<Vec<_>>>()?,
732 fragment: Fragment::None,
733 }),
734 JsonExpression::Type {
735 ty,
736 } => {
737 let parsed_ty = parse_type(&ty)?;
738 Expression::Type(TypeExpression {
739 ty: parsed_ty,
740 fragment: internal_fragment(&ty),
741 })
742 }
743 JsonExpression::FieldAccess {
744 object,
745 field,
746 } => Expression::FieldAccess(FieldAccessExpression {
747 object: Box::new((*object).try_into()?),
748 field: internal_fragment(&field),
749 fragment: Fragment::None,
750 }),
751 })
752 }
753}
754
755fn parse_type(s: &str) -> Result<Type> {
756 let ty = match s.to_lowercase().as_str() {
757 "boolean" => Type::Boolean,
758 "bool" => Type::Boolean,
759 "int1" => Type::Int1,
760 "int2" => Type::Int2,
761 "int4" => Type::Int4,
762 "int8" => Type::Int8,
763 "int16" => Type::Int16,
764 "int32" => Type::Int4,
765 "int64" => Type::Int8,
766 "uint1" => Type::Uint1,
767 "uint2" => Type::Uint2,
768 "uint4" => Type::Uint4,
769 "uint8" => Type::Uint8,
770 "uint16" => Type::Uint16,
771 "float4" => Type::Float4,
772 "float8" => Type::Float8,
773 "float32" => Type::Float4,
774 "float64" => Type::Float8,
775 "utf8" => Type::Utf8,
776 "string" => Type::Utf8,
777 "text" => Type::Utf8,
778 "blob" => Type::Blob,
779 "uuid4" => Type::Uuid4,
780 "uuid7" => Type::Uuid7,
781 "date" => Type::Date,
782 "time" => Type::Time,
783 "datetime" => Type::DateTime,
784 "duration" => Type::Duration,
785 "identityid" => Type::IdentityId,
786 "int" => Type::Int,
787 "uint" => Type::Uint,
788 "decimal" => Type::Decimal,
789 _ => {
790 return Err(Error(Box::new(internal!("Unknown type: {}", s))));
791 }
792 };
793
794 Ok(ty)
795}
796
797pub fn to_json(expr: &Expression) -> String {
798 let json_expr: JsonExpression = expr.into();
799 to_string(&json_expr).expect("JsonExpression should always serialize")
800}
801
802pub fn to_json_pretty(expr: &Expression) -> String {
803 let json_expr: JsonExpression = expr.into();
804 to_string_pretty(&json_expr).expect("JsonExpression should always serialize")
805}
806
807pub fn from_json(json: &str) -> Result<Expression> {
808 let json_expr: JsonExpression = from_str(json).map_err(|e| {
809 Error::from(TypeError::SerdeDeserialize {
810 message: e.to_string(),
811 })
812 })?;
813 json_expr.try_into()
814}
815
816#[cfg(test)]
817pub mod tests {
818 use super::*;
819
820 fn column_expr(name: &str) -> Expression {
822 Expression::Column(ColumnExpression(ColumnIdentifier {
823 shape: ColumnShape::Qualified {
824 namespace: internal_fragment("_context"),
825 name: internal_fragment("_context"),
826 },
827 name: internal_fragment(name),
828 }))
829 }
830
831 fn constant_number(val: &str) -> Expression {
832 Expression::Constant(ConstantExpression::Number {
833 fragment: internal_fragment(val),
834 })
835 }
836
837 fn constant_text(val: &str) -> Expression {
838 Expression::Constant(ConstantExpression::Text {
839 fragment: internal_fragment(val),
840 })
841 }
842
843 fn constant_bool(val: &str) -> Expression {
844 Expression::Constant(ConstantExpression::Bool {
845 fragment: internal_fragment(val),
846 })
847 }
848
849 #[test]
850 fn test_undefined() {
851 let expr = Expression::Constant(ConstantExpression::None {
852 fragment: Fragment::None,
853 });
854
855 let json = to_json(&expr);
856 assert_eq!(json, r#"{"type":"none"}"#);
857
858 let recovered = from_json(&json).unwrap();
859 assert_eq!(to_json(&recovered), json);
860 }
861
862 #[test]
863 fn test_bool() {
864 let expr = constant_bool("true");
865
866 let json = to_json(&expr);
867 assert_eq!(json, r#"{"type":"bool","value":"true"}"#);
868
869 let recovered = from_json(&json).unwrap();
870 assert_eq!(to_json(&recovered), json);
871 }
872
873 #[test]
874 fn test_number() {
875 let expr = constant_number("42");
876
877 let json = to_json(&expr);
878 assert_eq!(json, r#"{"type":"number","value":"42"}"#);
879
880 let recovered = from_json(&json).unwrap();
881 assert_eq!(to_json(&recovered), json);
882 }
883
884 #[test]
885 fn test_text() {
886 let expr = constant_text("hello world");
887
888 let json = to_json(&expr);
889 assert_eq!(json, r#"{"type":"text","value":"hello world"}"#);
890
891 let recovered = from_json(&json).unwrap();
892 assert_eq!(to_json(&recovered), json);
893 }
894
895 #[test]
896 fn test_temporal() {
897 let expr = Expression::Constant(ConstantExpression::Temporal {
898 fragment: internal_fragment("2024-01-15T10:30:00"),
899 });
900
901 let json = to_json(&expr);
902 assert_eq!(json, r#"{"type":"temporal","value":"2024-01-15T10:30:00"}"#);
903
904 let recovered = from_json(&json).unwrap();
905 assert_eq!(to_json(&recovered), json);
906 }
907
908 #[test]
909 fn test_column() {
910 let expr = column_expr("age");
911
912 let json = to_json(&expr);
913 assert_eq!(json, r#"{"type":"column","namespace":"_context","shape":"_context","name":"age"}"#);
914
915 let recovered = from_json(&json).unwrap();
916 assert_eq!(to_json(&recovered), json);
917 }
918
919 #[test]
920 fn test_variable() {
921 let expr = Expression::Variable(VariableExpression {
922 fragment: internal_fragment("$my_var"),
923 });
924
925 let json = to_json(&expr);
926 assert_eq!(json, r#"{"type":"variable","name":"my_var"}"#);
927
928 let recovered = from_json(&json).unwrap();
929 assert_eq!(to_json(&recovered), json);
930 }
931
932 #[test]
933 fn test_parameter_positional() {
934 let expr = Expression::Parameter(ParameterExpression::Positional {
935 fragment: internal_fragment("$1"),
936 });
937
938 let json = to_json(&expr);
939 assert_eq!(json, r#"{"type":"parameter_positional","position":"1"}"#);
940
941 let recovered = from_json(&json).unwrap();
942 assert_eq!(to_json(&recovered), json);
943 }
944
945 #[test]
946 fn test_parameter_named() {
947 let expr = Expression::Parameter(ParameterExpression::Named {
948 fragment: internal_fragment("$name"),
949 });
950
951 let json = to_json(&expr);
952 assert_eq!(json, r#"{"type":"parameter_named","name":"name"}"#);
953
954 let recovered = from_json(&json).unwrap();
955 assert_eq!(to_json(&recovered), json);
956 }
957
958 #[test]
959 fn test_greater_than() {
960 let expr = Expression::GreaterThan(GreaterThanExpression {
961 left: Box::new(column_expr("age")),
962 right: Box::new(constant_number("18")),
963 fragment: Fragment::None,
964 });
965
966 let json = to_json(&expr);
967 assert_eq!(
968 json,
969 r#"{"type":"greater_than","left":{"type":"column","namespace":"_context","shape":"_context","name":"age"},"right":{"type":"number","value":"18"}}"#
970 );
971
972 let recovered = from_json(&json).unwrap();
973 assert_eq!(to_json(&recovered), json);
974 }
975
976 #[test]
977 fn test_greater_than_equal() {
978 let expr = Expression::GreaterThanEqual(GreaterThanEqExpression {
979 left: Box::new(column_expr("price")),
980 right: Box::new(constant_number("100")),
981 fragment: Fragment::None,
982 });
983
984 let json = to_json(&expr);
985 assert_eq!(
986 json,
987 r#"{"type":"greater_than_equal","left":{"type":"column","namespace":"_context","shape":"_context","name":"price"},"right":{"type":"number","value":"100"}}"#
988 );
989
990 let recovered = from_json(&json).unwrap();
991 assert_eq!(to_json(&recovered), json);
992 }
993
994 #[test]
995 fn test_less_than() {
996 let expr = Expression::LessThan(LessThanExpression {
997 left: Box::new(column_expr("count")),
998 right: Box::new(constant_number("10")),
999 fragment: Fragment::None,
1000 });
1001
1002 let json = to_json(&expr);
1003 assert_eq!(
1004 json,
1005 r#"{"type":"less_than","left":{"type":"column","namespace":"_context","shape":"_context","name":"count"},"right":{"type":"number","value":"10"}}"#
1006 );
1007
1008 let recovered = from_json(&json).unwrap();
1009 assert_eq!(to_json(&recovered), json);
1010 }
1011
1012 #[test]
1013 fn test_less_than_equal() {
1014 let expr = Expression::LessThanEqual(LessThanEqExpression {
1015 left: Box::new(column_expr("quantity")),
1016 right: Box::new(constant_number("5")),
1017 fragment: Fragment::None,
1018 });
1019
1020 let json = to_json(&expr);
1021 assert_eq!(
1022 json,
1023 r#"{"type":"less_than_equal","left":{"type":"column","namespace":"_context","shape":"_context","name":"quantity"},"right":{"type":"number","value":"5"}}"#
1024 );
1025
1026 let recovered = from_json(&json).unwrap();
1027 assert_eq!(to_json(&recovered), json);
1028 }
1029
1030 #[test]
1031 fn test_equal() {
1032 let expr = Expression::Equal(EqExpression {
1033 left: Box::new(column_expr("status")),
1034 right: Box::new(constant_text("active")),
1035 fragment: Fragment::None,
1036 });
1037
1038 let json = to_json(&expr);
1039 assert_eq!(
1040 json,
1041 r#"{"type":"equal","left":{"type":"column","namespace":"_context","shape":"_context","name":"status"},"right":{"type":"text","value":"active"}}"#
1042 );
1043
1044 let recovered = from_json(&json).unwrap();
1045 assert_eq!(to_json(&recovered), json);
1046 }
1047
1048 #[test]
1049 fn test_not_equal() {
1050 let expr = Expression::NotEqual(NotEqExpression {
1051 left: Box::new(column_expr("type")),
1052 right: Box::new(constant_text("deleted")),
1053 fragment: Fragment::None,
1054 });
1055
1056 let json = to_json(&expr);
1057 assert_eq!(
1058 json,
1059 r#"{"type":"not_equal","left":{"type":"column","namespace":"_context","shape":"_context","name":"type"},"right":{"type":"text","value":"deleted"}}"#
1060 );
1061
1062 let recovered = from_json(&json).unwrap();
1063 assert_eq!(to_json(&recovered), json);
1064 }
1065
1066 #[test]
1067 fn test_and() {
1068 let expr = Expression::And(AndExpression {
1069 left: Box::new(Expression::GreaterThan(GreaterThanExpression {
1070 left: Box::new(column_expr("age")),
1071 right: Box::new(constant_number("18")),
1072 fragment: Fragment::None,
1073 })),
1074 right: Box::new(Expression::Equal(EqExpression {
1075 left: Box::new(column_expr("active")),
1076 right: Box::new(constant_bool("true")),
1077 fragment: Fragment::None,
1078 })),
1079 fragment: Fragment::None,
1080 });
1081
1082 let json = to_json(&expr);
1083 assert_eq!(
1084 json,
1085 r#"{"type":"and","left":{"type":"greater_than","left":{"type":"column","namespace":"_context","shape":"_context","name":"age"},"right":{"type":"number","value":"18"}},"right":{"type":"equal","left":{"type":"column","namespace":"_context","shape":"_context","name":"active"},"right":{"type":"bool","value":"true"}}}"#
1086 );
1087
1088 let recovered = from_json(&json).unwrap();
1089 assert_eq!(to_json(&recovered), json);
1090 }
1091
1092 #[test]
1093 fn test_or() {
1094 let expr = Expression::Or(OrExpression {
1095 left: Box::new(column_expr("a")),
1096 right: Box::new(column_expr("b")),
1097 fragment: Fragment::None,
1098 });
1099
1100 let json = to_json(&expr);
1101 assert_eq!(
1102 json,
1103 r#"{"type":"or","left":{"type":"column","namespace":"_context","shape":"_context","name":"a"},"right":{"type":"column","namespace":"_context","shape":"_context","name":"b"}}"#
1104 );
1105
1106 let recovered = from_json(&json).unwrap();
1107 assert_eq!(to_json(&recovered), json);
1108 }
1109
1110 #[test]
1111 fn test_xor() {
1112 let expr = Expression::Xor(XorExpression {
1113 left: Box::new(column_expr("x")),
1114 right: Box::new(column_expr("y")),
1115 fragment: Fragment::None,
1116 });
1117
1118 let json = to_json(&expr);
1119 assert_eq!(
1120 json,
1121 r#"{"type":"xor","left":{"type":"column","namespace":"_context","shape":"_context","name":"x"},"right":{"type":"column","namespace":"_context","shape":"_context","name":"y"}}"#
1122 );
1123
1124 let recovered = from_json(&json).unwrap();
1125 assert_eq!(to_json(&recovered), json);
1126 }
1127
1128 #[test]
1129 fn test_add() {
1130 let expr = Expression::Add(AddExpression {
1131 left: Box::new(column_expr("price")),
1132 right: Box::new(constant_number("10")),
1133 fragment: Fragment::None,
1134 });
1135
1136 let json = to_json(&expr);
1137 assert_eq!(
1138 json,
1139 r#"{"type":"add","left":{"type":"column","namespace":"_context","shape":"_context","name":"price"},"right":{"type":"number","value":"10"}}"#
1140 );
1141
1142 let recovered = from_json(&json).unwrap();
1143 assert_eq!(to_json(&recovered), json);
1144 }
1145
1146 #[test]
1147 fn test_sub() {
1148 let expr = Expression::Sub(SubExpression {
1149 left: Box::new(column_expr("total")),
1150 right: Box::new(constant_number("5")),
1151 fragment: Fragment::None,
1152 });
1153
1154 let json = to_json(&expr);
1155 assert_eq!(
1156 json,
1157 r#"{"type":"sub","left":{"type":"column","namespace":"_context","shape":"_context","name":"total"},"right":{"type":"number","value":"5"}}"#
1158 );
1159
1160 let recovered = from_json(&json).unwrap();
1161 assert_eq!(to_json(&recovered), json);
1162 }
1163
1164 #[test]
1165 fn test_mul() {
1166 let expr = Expression::Mul(MulExpression {
1167 left: Box::new(column_expr("qty")),
1168 right: Box::new(constant_number("2")),
1169 fragment: Fragment::None,
1170 });
1171
1172 let json = to_json(&expr);
1173 assert_eq!(
1174 json,
1175 r#"{"type":"mul","left":{"type":"column","namespace":"_context","shape":"_context","name":"qty"},"right":{"type":"number","value":"2"}}"#
1176 );
1177
1178 let recovered = from_json(&json).unwrap();
1179 assert_eq!(to_json(&recovered), json);
1180 }
1181
1182 #[test]
1183 fn test_div() {
1184 let expr = Expression::Div(DivExpression {
1185 left: Box::new(column_expr("amount")),
1186 right: Box::new(constant_number("4")),
1187 fragment: Fragment::None,
1188 });
1189
1190 let json = to_json(&expr);
1191 assert_eq!(
1192 json,
1193 r#"{"type":"div","left":{"type":"column","namespace":"_context","shape":"_context","name":"amount"},"right":{"type":"number","value":"4"}}"#
1194 );
1195
1196 let recovered = from_json(&json).unwrap();
1197 assert_eq!(to_json(&recovered), json);
1198 }
1199
1200 #[test]
1201 fn test_rem() {
1202 let expr = Expression::Rem(RemExpression {
1203 left: Box::new(column_expr("num")),
1204 right: Box::new(constant_number("3")),
1205 fragment: Fragment::None,
1206 });
1207
1208 let json = to_json(&expr);
1209 assert_eq!(
1210 json,
1211 r#"{"type":"rem","left":{"type":"column","namespace":"_context","shape":"_context","name":"num"},"right":{"type":"number","value":"3"}}"#
1212 );
1213
1214 let recovered = from_json(&json).unwrap();
1215 assert_eq!(to_json(&recovered), json);
1216 }
1217
1218 #[test]
1219 fn test_alias() {
1220 let expr = Expression::Alias(AliasExpression {
1221 alias: IdentExpression(internal_fragment("user_name")),
1222 expression: Box::new(column_expr("name")),
1223 fragment: Fragment::None,
1224 });
1225
1226 let json = to_json(&expr);
1227 assert_eq!(
1228 json,
1229 r#"{"type":"alias","alias":"user_name","expression":{"type":"column","namespace":"_context","shape":"_context","name":"name"}}"#
1230 );
1231
1232 let recovered = from_json(&json).unwrap();
1233 assert_eq!(to_json(&recovered), json);
1234 }
1235
1236 #[test]
1237 fn test_cast() {
1238 let expr = Expression::Cast(CastExpression {
1239 expression: Box::new(column_expr("value")),
1240 to: TypeExpression {
1241 ty: Type::Int4,
1242 fragment: internal_fragment("Int4"),
1243 },
1244 fragment: Fragment::None,
1245 });
1246
1247 let json = to_json(&expr);
1248 assert_eq!(
1249 json,
1250 r#"{"type":"cast","expression":{"type":"column","namespace":"_context","shape":"_context","name":"value"},"to":"Int4"}"#
1251 );
1252
1253 let recovered = from_json(&json).unwrap();
1254 assert_eq!(to_json(&recovered), json);
1255 }
1256
1257 #[test]
1258 fn test_call() {
1259 let expr = Expression::Call(CallExpression {
1260 func: IdentExpression(internal_fragment("math::avg")),
1261 args: vec![column_expr("price")],
1262 fragment: Fragment::None,
1263 });
1264
1265 let json = to_json(&expr);
1266 assert_eq!(
1267 json,
1268 r#"{"type":"call","function":"math::avg","args":[{"type":"column","namespace":"_context","shape":"_context","name":"price"}]}"#
1269 );
1270
1271 let recovered = from_json(&json).unwrap();
1272 assert_eq!(to_json(&recovered), json);
1273 }
1274
1275 #[test]
1276 fn test_tuple() {
1277 let expr = Expression::Tuple(TupleExpression {
1278 expressions: vec![constant_number("1"), constant_number("2"), constant_number("3")],
1279 fragment: Fragment::None,
1280 });
1281
1282 let json = to_json(&expr);
1283 assert_eq!(
1284 json,
1285 r#"{"type":"tuple","expressions":[{"type":"number","value":"1"},{"type":"number","value":"2"},{"type":"number","value":"3"}]}"#
1286 );
1287
1288 let recovered = from_json(&json).unwrap();
1289 assert_eq!(to_json(&recovered), json);
1290 }
1291
1292 #[test]
1293 fn test_prefix_minus() {
1294 let expr = Expression::Prefix(PrefixExpression {
1295 operator: PrefixOperator::Minus(Fragment::None),
1296 expression: Box::new(column_expr("value")),
1297 fragment: Fragment::None,
1298 });
1299
1300 let json = to_json(&expr);
1301 assert_eq!(
1302 json,
1303 r#"{"type":"prefix","operator":"-","expression":{"type":"column","namespace":"_context","shape":"_context","name":"value"}}"#
1304 );
1305
1306 let recovered = from_json(&json).unwrap();
1307 assert_eq!(to_json(&recovered), json);
1308 }
1309
1310 #[test]
1311 fn test_prefix_not() {
1312 let expr = Expression::Prefix(PrefixExpression {
1313 operator: PrefixOperator::Not(Fragment::None),
1314 expression: Box::new(column_expr("flag")),
1315 fragment: Fragment::None,
1316 });
1317
1318 let json = to_json(&expr);
1319 assert_eq!(
1320 json,
1321 r#"{"type":"prefix","operator":"not","expression":{"type":"column","namespace":"_context","shape":"_context","name":"flag"}}"#
1322 );
1323
1324 let recovered = from_json(&json).unwrap();
1325 assert_eq!(to_json(&recovered), json);
1326 }
1327
1328 #[test]
1329 fn test_between() {
1330 let expr = Expression::Between(BetweenExpression {
1331 value: Box::new(column_expr("age")),
1332 lower: Box::new(constant_number("18")),
1333 upper: Box::new(constant_number("65")),
1334 fragment: Fragment::None,
1335 });
1336
1337 let json = to_json(&expr);
1338 assert_eq!(
1339 json,
1340 r#"{"type":"between","value":{"type":"column","namespace":"_context","shape":"_context","name":"age"},"lower":{"type":"number","value":"18"},"upper":{"type":"number","value":"65"}}"#
1341 );
1342
1343 let recovered = from_json(&json).unwrap();
1344 assert_eq!(to_json(&recovered), json);
1345 }
1346
1347 #[test]
1348 fn test_in() {
1349 let expr = Expression::In(InExpression {
1350 value: Box::new(column_expr("status")),
1351 list: Box::new(Expression::Tuple(TupleExpression {
1352 expressions: vec![constant_text("active"), constant_text("pending")],
1353 fragment: Fragment::None,
1354 })),
1355 negated: false,
1356 fragment: Fragment::None,
1357 });
1358
1359 let json = to_json(&expr);
1360 assert_eq!(
1361 json,
1362 r#"{"type":"in","value":{"type":"column","namespace":"_context","shape":"_context","name":"status"},"list":{"type":"tuple","expressions":[{"type":"text","value":"active"},{"type":"text","value":"pending"}]},"negated":false}"#
1363 );
1364
1365 let recovered = from_json(&json).unwrap();
1366 assert_eq!(to_json(&recovered), json);
1367 }
1368
1369 #[test]
1370 fn test_not_in() {
1371 let expr = Expression::In(InExpression {
1372 value: Box::new(column_expr("type")),
1373 list: Box::new(Expression::Tuple(TupleExpression {
1374 expressions: vec![constant_text("deleted"), constant_text("archived")],
1375 fragment: Fragment::None,
1376 })),
1377 negated: true,
1378 fragment: Fragment::None,
1379 });
1380
1381 let json = to_json(&expr);
1382 assert_eq!(
1383 json,
1384 r#"{"type":"in","value":{"type":"column","namespace":"_context","shape":"_context","name":"type"},"list":{"type":"tuple","expressions":[{"type":"text","value":"deleted"},{"type":"text","value":"archived"}]},"negated":true}"#
1385 );
1386
1387 let recovered = from_json(&json).unwrap();
1388 assert_eq!(to_json(&recovered), json);
1389 }
1390
1391 #[test]
1392 fn test_if_simple() {
1393 let expr = Expression::If(IfExpression {
1394 condition: Box::new(Expression::GreaterThan(GreaterThanExpression {
1395 left: Box::new(column_expr("age")),
1396 right: Box::new(constant_number("18")),
1397 fragment: Fragment::None,
1398 })),
1399 then_expr: Box::new(constant_text("adult")),
1400 else_ifs: vec![],
1401 else_expr: Some(Box::new(constant_text("minor"))),
1402 fragment: Fragment::None,
1403 });
1404
1405 let json = to_json(&expr);
1406 assert_eq!(
1407 json,
1408 r#"{"type":"if","condition":{"type":"greater_than","left":{"type":"column","namespace":"_context","shape":"_context","name":"age"},"right":{"type":"number","value":"18"}},"then":{"type":"text","value":"adult"},"else_ifs":[],"else_expr":{"type":"text","value":"minor"}}"#
1409 );
1410
1411 let recovered = from_json(&json).unwrap();
1412 assert_eq!(to_json(&recovered), json);
1413 }
1414
1415 #[test]
1416 fn test_if_with_else_if() {
1417 let expr = Expression::If(IfExpression {
1418 condition: Box::new(Expression::GreaterThan(GreaterThanExpression {
1419 left: Box::new(column_expr("score")),
1420 right: Box::new(constant_number("90")),
1421 fragment: Fragment::None,
1422 })),
1423 then_expr: Box::new(constant_text("A")),
1424 else_ifs: vec![ElseIfExpression {
1425 condition: Box::new(Expression::GreaterThan(GreaterThanExpression {
1426 left: Box::new(column_expr("score")),
1427 right: Box::new(constant_number("80")),
1428 fragment: Fragment::None,
1429 })),
1430 then_expr: Box::new(constant_text("B")),
1431 fragment: Fragment::None,
1432 }],
1433 else_expr: Some(Box::new(constant_text("C"))),
1434 fragment: Fragment::None,
1435 });
1436
1437 let json = to_json(&expr);
1438 assert_eq!(
1439 json,
1440 r#"{"type":"if","condition":{"type":"greater_than","left":{"type":"column","namespace":"_context","shape":"_context","name":"score"},"right":{"type":"number","value":"90"}},"then":{"type":"text","value":"A"},"else_ifs":[{"condition":{"type":"greater_than","left":{"type":"column","namespace":"_context","shape":"_context","name":"score"},"right":{"type":"number","value":"80"}},"then":{"type":"text","value":"B"}}],"else_expr":{"type":"text","value":"C"}}"#
1441 );
1442
1443 let recovered = from_json(&json).unwrap();
1444 assert_eq!(to_json(&recovered), json);
1445 }
1446
1447 #[test]
1448 fn test_map() {
1449 let expr = Expression::Map(MapExpression {
1450 expressions: vec![
1451 Expression::Alias(AliasExpression {
1452 alias: IdentExpression(internal_fragment("user_name")),
1453 expression: Box::new(column_expr("name")),
1454 fragment: Fragment::None,
1455 }),
1456 column_expr("id"),
1457 ],
1458 fragment: Fragment::None,
1459 });
1460
1461 let json = to_json(&expr);
1462 assert_eq!(
1463 json,
1464 r#"{"type":"map","expressions":[{"type":"alias","alias":"user_name","expression":{"type":"column","namespace":"_context","shape":"_context","name":"name"}},{"type":"column","namespace":"_context","shape":"_context","name":"id"}]}"#
1465 );
1466
1467 let recovered = from_json(&json).unwrap();
1468 assert_eq!(to_json(&recovered), json);
1469 }
1470
1471 #[test]
1472 fn test_extend() {
1473 let expr = Expression::Extend(ExtendExpression {
1474 expressions: vec![Expression::Alias(AliasExpression {
1475 alias: IdentExpression(internal_fragment("full_name")),
1476 expression: Box::new(Expression::Add(AddExpression {
1477 left: Box::new(column_expr("first")),
1478 right: Box::new(column_expr("last")),
1479 fragment: Fragment::None,
1480 })),
1481 fragment: Fragment::None,
1482 })],
1483 fragment: Fragment::None,
1484 });
1485
1486 let json = to_json(&expr);
1487 assert_eq!(
1488 json,
1489 r#"{"type":"extend","expressions":[{"type":"alias","alias":"full_name","expression":{"type":"add","left":{"type":"column","namespace":"_context","shape":"_context","name":"first"},"right":{"type":"column","namespace":"_context","shape":"_context","name":"last"}}}]}"#
1490 );
1491
1492 let recovered = from_json(&json).unwrap();
1493 assert_eq!(to_json(&recovered), json);
1494 }
1495
1496 #[test]
1497 fn test_type_expression() {
1498 let expr = Expression::Type(TypeExpression {
1499 ty: Type::Utf8,
1500 fragment: internal_fragment("Utf8"),
1501 });
1502
1503 let json = to_json(&expr);
1504 assert_eq!(json, r#"{"type":"type","ty":"Utf8"}"#);
1505
1506 let recovered = from_json(&json).unwrap();
1507 assert_eq!(to_json(&recovered), json);
1508 }
1509
1510 #[test]
1511 fn test_complex_nested_expression() {
1512 let expr = Expression::Or(OrExpression {
1514 left: Box::new(Expression::And(AndExpression {
1515 left: Box::new(Expression::GreaterThan(GreaterThanExpression {
1516 left: Box::new(column_expr("age")),
1517 right: Box::new(constant_number("18")),
1518 fragment: Fragment::None,
1519 })),
1520 right: Box::new(Expression::Equal(EqExpression {
1521 left: Box::new(column_expr("status")),
1522 right: Box::new(constant_text("active")),
1523 fragment: Fragment::None,
1524 })),
1525 fragment: Fragment::None,
1526 })),
1527 right: Box::new(Expression::Equal(EqExpression {
1528 left: Box::new(column_expr("role")),
1529 right: Box::new(constant_text("admin")),
1530 fragment: Fragment::None,
1531 })),
1532 fragment: Fragment::None,
1533 });
1534
1535 let json = to_json(&expr);
1536 let recovered = from_json(&json).unwrap();
1537 assert_eq!(to_json(&recovered), json);
1538
1539 let pretty = to_json_pretty(&expr);
1541 assert!(pretty.contains('\n'));
1542 assert!(pretty.contains("greater_than"));
1543 }
1544
1545 #[test]
1546 fn test_access_source() {
1547 let expr = Expression::AccessSource(AccessShapeExpression {
1548 column: ColumnIdentifier {
1549 shape: ColumnShape::Qualified {
1550 namespace: internal_fragment("public"),
1551 name: internal_fragment("users"),
1552 },
1553 name: internal_fragment("email"),
1554 },
1555 });
1556
1557 let json = to_json(&expr);
1558 assert_eq!(json, r#"{"type":"access_source","namespace":"public","shape":"users","name":"email"}"#);
1559
1560 let recovered = from_json(&json).unwrap();
1561 assert_eq!(to_json(&recovered), json);
1562 }
1563}