risingwave_frontend/utils/pretty_serde.rs
1// Copyright 2025 RisingWave Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! @kwannoel:
16//! This module implements Serde for the Pretty struct. Why not implement it directly on our plan nodes?
17//! That's because Pretty already summarizes the fields that are important to us.
18//! You can see that when `explain()` is called, we directly return the `Pretty` struct.
19//! The _proper way_ to do this would be to create a new data structure that plan nodes get converted into,
20//! and then implement `Serialize` and `Deserialize` on that data structure (including to `Pretty`).
21//! But that's a lot of refactoring work.
22//! So we just wrap `Pretty` in a newtype and implement `Serialize` on that,
23//! since it's a good enough intermediate representation.
24
25use std::collections::BTreeMap;
26
27use pretty_xmlish::Pretty;
28use serde::ser::{SerializeSeq, SerializeStruct};
29use serde::{Serialize, Serializer};
30
31// Second anymous field is include_children.
32// If true the children information will be serialized.
33pub struct PrettySerde<'a>(pub Pretty<'a>, pub bool);
34
35impl Serialize for PrettySerde<'_> {
36 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
37 where
38 S: Serializer,
39 {
40 match &self.0 {
41 Pretty::Text(text) => serializer.serialize_str(text.as_ref()),
42
43 Pretty::Record(node) => {
44 let mut state = serializer.serialize_struct("XmlNode", 3)?;
45 state.serialize_field("name", node.name.as_ref())?;
46 state.serialize_field(
47 "fields",
48 &node
49 .fields
50 .iter()
51 .map(|(k, v)| (k.as_ref(), PrettySerde(v.clone(), self.1)))
52 .collect::<BTreeMap<_, _>>(),
53 )?;
54 if self.1 {
55 state.serialize_field(
56 "children",
57 &node
58 .children
59 .iter()
60 .map(|c| PrettySerde(c.clone(), self.1))
61 .collect::<Vec<_>>(),
62 )?;
63 }
64 state.end()
65 }
66
67 Pretty::Array(elements) => {
68 let mut seq = serializer.serialize_seq(Some(elements.len()))?;
69 for element in elements {
70 seq.serialize_element(&PrettySerde((*element).clone(), self.1))?;
71 }
72 seq.end()
73 }
74
75 Pretty::Linearized(inner, size) => {
76 let mut state = serializer.serialize_struct("Linearized", 2)?;
77 state.serialize_field("inner", &PrettySerde((**inner).clone(), self.1))?;
78 state.serialize_field("size", size)?;
79 state.end()
80 }
81 }
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use std::fmt::Debug;
88
89 use expect_test::{Expect, expect};
90
91 use super::*;
92
93 fn check(actual: impl Debug, expect: Expect) {
94 let actual = format!("{:#?}", actual);
95 expect.assert_eq(&actual);
96 }
97
98 #[test]
99 fn test_pretty_serde() {
100 let pretty = Pretty::childless_record("root", vec![("a", Pretty::Text("1".into()))]);
101 let pretty_serde = PrettySerde(pretty, true);
102 let serialized = serde_json::to_string(&pretty_serde).unwrap();
103 check(
104 serialized,
105 expect![[r#""{\"name\":\"root\",\"fields\":{\"a\":\"1\"},\"children\":[]}""#]],
106 );
107 }
108}