Skip to main content

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                let s = s.to_string();
79                if raw || s.starts_with('{') {
80                    write!(f, "{s}")
81                } else {
82                    write!(f, "\"{s}\"")
83                }
84            }
85            Value::Timestamp(dt) => {
86                let formatted = dt.strftime(TIMESTAMP_FORMAT);
87                if raw {
88                    write!(f, "{formatted}")
89                } else {
90                    write!(f, "\"{formatted}\"")
91                }
92            }
93            Value::TimestampTz(dt) => {
94                let formatted = dt.strftime(TIMESTAMP_TIMEZONE_FORMAT);
95                if raw {
96                    write!(f, "{formatted}")
97                } else {
98                    write!(f, "\"{formatted}\"")
99                }
100            }
101            Value::Date(i) => {
102                let days = i + DAYS_FROM_CE;
103                let d = NaiveDate::from_num_days_from_ce_opt(days).unwrap_or_default();
104                if raw {
105                    write!(f, "{d}")
106                } else {
107                    write!(f, "\"{d}\"")
108                }
109            }
110            Value::Array(vals) => {
111                write!(f, "[")?;
112                for (i, val) in vals.iter().enumerate() {
113                    if i > 0 {
114                        write!(f, ",")?;
115                    }
116                    val.display_value(f, false)?;
117                }
118                write!(f, "]")?;
119                Ok(())
120            }
121            Value::Map(kvs) => {
122                write!(f, "{{")?;
123                for (i, (key, val)) in kvs.iter().enumerate() {
124                    if i > 0 {
125                        write!(f, ",")?;
126                    }
127                    key.display_value(f, false)?;
128                    write!(f, ":")?;
129                    val.display_value(f, false)?;
130                }
131                write!(f, "}}")?;
132                Ok(())
133            }
134            Value::Tuple(vals) => {
135                write!(f, "(")?;
136                for (i, val) in vals.iter().enumerate() {
137                    if i > 0 {
138                        write!(f, ",")?;
139                    }
140                    val.display_value(f, false)?;
141                }
142                write!(f, ")")?;
143                Ok(())
144            }
145            Value::Vector(vals) => {
146                write!(f, "[")?;
147                let mut buffer = zmij::Buffer::new();
148                for (i, val) in vals.iter().enumerate() {
149                    if i > 0 {
150                        write!(f, ",")?;
151                    }
152                    let s = buffer.format_finite(*val);
153                    write!(f, "{s}")?;
154                }
155                write!(f, "]")?;
156                Ok(())
157            }
158        }
159    }
160}
161
162trait FloatForDisplay: Copy {
163    fn is_nan(self) -> bool;
164    fn is_infinite(self) -> bool;
165    fn is_sign_negative(self) -> bool;
166    fn write_with(self, buf: &mut zmij::Buffer) -> &str;
167}
168
169impl FloatForDisplay for f32 {
170    fn is_nan(self) -> bool {
171        f32::is_nan(self)
172    }
173    fn is_infinite(self) -> bool {
174        f32::is_infinite(self)
175    }
176    fn is_sign_negative(self) -> bool {
177        f32::is_sign_negative(self)
178    }
179    fn write_with(self, buf: &mut zmij::Buffer) -> &str {
180        buf.format_finite(self)
181    }
182}
183
184impl FloatForDisplay for f64 {
185    fn is_nan(self) -> bool {
186        f64::is_nan(self)
187    }
188    fn is_infinite(self) -> bool {
189        f64::is_infinite(self)
190    }
191    fn is_sign_negative(self) -> bool {
192        f64::is_sign_negative(self)
193    }
194    fn write_with(self, buf: &mut zmij::Buffer) -> &str {
195        buf.format_finite(self)
196    }
197}
198
199fn display_float<T: FloatForDisplay>(num: T, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
200    if num.is_nan() {
201        write!(f, "NaN")
202    } else if num.is_infinite() {
203        if num.is_sign_negative() {
204            write!(f, "-inf")
205        } else {
206            write!(f, "inf")
207        }
208    } else {
209        let mut buffer = zmij::Buffer::new();
210        write!(f, "{}", num.write_with(&mut buffer))
211    }
212}
213
214pub fn display_decimal_128(num: i128, scale: u8) -> String {
215    let mut buf = String::new();
216    if scale == 0 {
217        write!(buf, "{num}").unwrap();
218    } else {
219        let pow_scale = 10_i128.pow(scale as u32);
220        if num >= 0 {
221            write!(
222                buf,
223                "{}.{:0>width$}",
224                num / pow_scale,
225                (num % pow_scale).abs(),
226                width = scale as usize
227            )
228            .unwrap();
229        } else {
230            write!(
231                buf,
232                "-{}.{:0>width$}",
233                -num / pow_scale,
234                (num % pow_scale).abs(),
235                width = scale as usize
236            )
237            .unwrap();
238        }
239    }
240    buf
241}
242
243pub fn display_decimal_256(num: i256, scale: u8) -> String {
244    let mut buf = String::new();
245    if scale == 0 {
246        write!(buf, "{}", num).unwrap();
247    } else {
248        let pow_scale = i256::from(10).pow(scale as u32);
249        // -1/10 = 0
250        if !num.is_negative() {
251            write!(
252                buf,
253                "{}.{:0>width$}",
254                num / pow_scale,
255                (num % pow_scale).wrapping_abs(),
256                width = scale as usize
257            )
258        } else {
259            write!(
260                buf,
261                "-{}.{:0>width$}",
262                -num / pow_scale,
263                (num % pow_scale).wrapping_abs(),
264                width = scale as usize
265            )
266        }
267        .expect("display_decimal_256 should not fail");
268    }
269    String::from_utf8_lossy(buf.as_bytes()).to_string()
270}