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