Skip to main content

reifydb_rql/expression/
json.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4use 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	// Helper functions to create test expressions
821	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		// Build: (age > 18 AND status = 'active') OR (role = 'admin')
1513		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		// Verify pretty print works
1540		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}