databend_driver_core/value/format/
display.rs

1// Copyright 2021 Datafuse 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
15use crate::_macro_internal::Value;
16use crate::value::base::{DAYS_FROM_CE, TIMESTAMP_FORMAT, TIMESTAMP_TIMEZONE_FORMAT};
17use crate::value::NumberValue;
18use chrono::NaiveDate;
19use ethnum::i256;
20use std::fmt::Write;
21
22impl std::fmt::Display for Value {
23    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24        self.display_value(f, true)
25    }
26}
27
28impl std::fmt::Display for NumberValue {
29    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30        match self {
31            NumberValue::Int8(i) => write!(f, "{i}"),
32            NumberValue::Int16(i) => write!(f, "{i}"),
33            NumberValue::Int32(i) => write!(f, "{i}"),
34            NumberValue::Int64(i) => write!(f, "{i}"),
35            NumberValue::UInt8(i) => write!(f, "{i}"),
36            NumberValue::UInt16(i) => write!(f, "{i}"),
37            NumberValue::UInt32(i) => write!(f, "{i}"),
38            NumberValue::UInt64(i) => write!(f, "{i}"),
39            NumberValue::Float32(i) => display_float(*i, f),
40            NumberValue::Float64(i) => display_float(*i, f),
41            NumberValue::Decimal64(v, s) => {
42                write!(f, "{}", display_decimal_128(*v as i128, s.scale))
43            }
44            NumberValue::Decimal128(v, s) => write!(f, "{}", display_decimal_128(*v, s.scale)),
45            NumberValue::Decimal256(v, s) => write!(f, "{}", display_decimal_256(*v, s.scale)),
46        }
47    }
48}
49
50impl Value {
51    // Used as output of cli
52    // Compatible with Databend, strings inside nested types are quoted.
53    pub fn display_value(&self, f: &mut std::fmt::Formatter<'_>, raw: bool) -> std::fmt::Result {
54        match self {
55            Value::Null => write!(f, "NULL"),
56            Value::EmptyArray => write!(f, "[]"),
57            Value::EmptyMap => write!(f, "{{}}"),
58            Value::Boolean(b) => {
59                if *b {
60                    write!(f, "true")
61                } else {
62                    write!(f, "false")
63                }
64            }
65            Value::Number(n) => write!(f, "{n}"),
66            Value::Binary(s) => write!(f, "{}", hex::encode_upper(s)),
67            Value::String(s) | Value::Bitmap(s) | Value::Interval(s) => {
68                if raw {
69                    write!(f, "{s}")
70                } else {
71                    write!(f, "\"{s}\"")
72                }
73            }
74            Value::Variant(s) => {
75                write!(f, "{s}")
76            }
77            Value::Geometry(s) | Value::Geography(s) => {
78                if raw || s.starts_with('{') {
79                    write!(f, "{s}")
80                } else {
81                    write!(f, "\"{s}\"")
82                }
83            }
84            Value::Timestamp(dt) => {
85                let formatted = dt.strftime(TIMESTAMP_FORMAT);
86                if raw {
87                    write!(f, "{formatted}")
88                } else {
89                    write!(f, "\"{formatted}\"")
90                }
91            }
92            Value::TimestampTz(dt) => {
93                let formatted = dt.strftime(TIMESTAMP_TIMEZONE_FORMAT);
94                if raw {
95                    write!(f, "{formatted}")
96                } else {
97                    write!(f, "\"{formatted}\"")
98                }
99            }
100            Value::Date(i) => {
101                let days = i + DAYS_FROM_CE;
102                let d = NaiveDate::from_num_days_from_ce_opt(days).unwrap_or_default();
103                if raw {
104                    write!(f, "{d}")
105                } else {
106                    write!(f, "\"{d}\"")
107                }
108            }
109            Value::Array(vals) => {
110                write!(f, "[")?;
111                for (i, val) in vals.iter().enumerate() {
112                    if i > 0 {
113                        write!(f, ",")?;
114                    }
115                    val.display_value(f, false)?;
116                }
117                write!(f, "]")?;
118                Ok(())
119            }
120            Value::Map(kvs) => {
121                write!(f, "{{")?;
122                for (i, (key, val)) in kvs.iter().enumerate() {
123                    if i > 0 {
124                        write!(f, ",")?;
125                    }
126                    key.display_value(f, false)?;
127                    write!(f, ":")?;
128                    val.display_value(f, false)?;
129                }
130                write!(f, "}}")?;
131                Ok(())
132            }
133            Value::Tuple(vals) => {
134                write!(f, "(")?;
135                for (i, val) in vals.iter().enumerate() {
136                    if i > 0 {
137                        write!(f, ",")?;
138                    }
139                    val.display_value(f, false)?;
140                }
141                write!(f, ")")?;
142                Ok(())
143            }
144            Value::Vector(vals) => {
145                write!(f, "[")?;
146                let mut buffer = zmij::Buffer::new();
147                for (i, val) in vals.iter().enumerate() {
148                    if i > 0 {
149                        write!(f, ",")?;
150                    }
151                    let s = buffer.format_finite(*val);
152                    write!(f, "{s}")?;
153                }
154                write!(f, "]")?;
155                Ok(())
156            }
157        }
158    }
159}
160
161trait FloatForDisplay: Copy {
162    fn is_nan(self) -> bool;
163    fn is_infinite(self) -> bool;
164    fn is_sign_negative(self) -> bool;
165    fn write_with(self, buf: &mut zmij::Buffer) -> &str;
166}
167
168impl FloatForDisplay for f32 {
169    fn is_nan(self) -> bool {
170        f32::is_nan(self)
171    }
172    fn is_infinite(self) -> bool {
173        f32::is_infinite(self)
174    }
175    fn is_sign_negative(self) -> bool {
176        f32::is_sign_negative(self)
177    }
178    fn write_with(self, buf: &mut zmij::Buffer) -> &str {
179        buf.format_finite(self)
180    }
181}
182
183impl FloatForDisplay for f64 {
184    fn is_nan(self) -> bool {
185        f64::is_nan(self)
186    }
187    fn is_infinite(self) -> bool {
188        f64::is_infinite(self)
189    }
190    fn is_sign_negative(self) -> bool {
191        f64::is_sign_negative(self)
192    }
193    fn write_with(self, buf: &mut zmij::Buffer) -> &str {
194        buf.format_finite(self)
195    }
196}
197
198fn display_float<T: FloatForDisplay>(num: T, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
199    if num.is_nan() {
200        write!(f, "NaN")
201    } else if num.is_infinite() {
202        if num.is_sign_negative() {
203            write!(f, "-inf")
204        } else {
205            write!(f, "inf")
206        }
207    } else {
208        let mut buffer = zmij::Buffer::new();
209        write!(f, "{}", num.write_with(&mut buffer))
210    }
211}
212
213pub fn display_decimal_128(num: i128, scale: u8) -> String {
214    let mut buf = String::new();
215    if scale == 0 {
216        write!(buf, "{num}").unwrap();
217    } else {
218        let pow_scale = 10_i128.pow(scale as u32);
219        if num >= 0 {
220            write!(
221                buf,
222                "{}.{:0>width$}",
223                num / pow_scale,
224                (num % pow_scale).abs(),
225                width = scale as usize
226            )
227            .unwrap();
228        } else {
229            write!(
230                buf,
231                "-{}.{:0>width$}",
232                -num / pow_scale,
233                (num % pow_scale).abs(),
234                width = scale as usize
235            )
236            .unwrap();
237        }
238    }
239    buf
240}
241
242pub fn display_decimal_256(num: i256, scale: u8) -> String {
243    let mut buf = String::new();
244    if scale == 0 {
245        write!(buf, "{}", num).unwrap();
246    } else {
247        let pow_scale = i256::from(10).pow(scale as u32);
248        // -1/10 = 0
249        if !num.is_negative() {
250            write!(
251                buf,
252                "{}.{:0>width$}",
253                num / pow_scale,
254                (num % pow_scale).wrapping_abs(),
255                width = scale as usize
256            )
257        } else {
258            write!(
259                buf,
260                "-{}.{:0>width$}",
261                -num / pow_scale,
262                (num % pow_scale).wrapping_abs(),
263                width = scale as usize
264            )
265        }
266        .expect("display_decimal_256 should not fail");
267    }
268    String::from_utf8_lossy(buf.as_bytes()).to_string()
269}