Skip to content

Commit fce0233

Browse files
committed
chore: impl Display for LicenseInfo and JWTClaims<T>
1 parent 4db95ee commit fce0233

File tree

6 files changed

+290
-24
lines changed

6 files changed

+290
-24
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
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+
15+
use std::fmt;
16+
17+
/// Implement `Display` for `&[T]` if T is `Display`.
18+
///
19+
/// It outputs at most `MAX` elements, excluding those from the 5th to the second-to-last one:
20+
/// - `DisplaySlice(&[1,2,3,4,5,6])` outputs: `"[1,2,3,4,...,6]"`.
21+
pub struct DisplaySlice<'a, T: fmt::Display, const MAX: usize = 5>(pub &'a [T]);
22+
23+
impl<'a, T: fmt::Display, const MAX: usize> fmt::Display for DisplaySlice<'a, T, MAX> {
24+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25+
let slice = self.0;
26+
let len = slice.len();
27+
28+
write!(f, "[")?;
29+
30+
if len > MAX {
31+
for (i, t) in slice[..(MAX - 1)].iter().enumerate() {
32+
if i > 0 {
33+
write!(f, ",")?;
34+
}
35+
36+
write!(f, "{}", t)?;
37+
}
38+
39+
write!(f, ",..,")?;
40+
write!(f, "{}", slice.last().unwrap())?;
41+
} else {
42+
for (i, t) in slice.iter().enumerate() {
43+
if i > 0 {
44+
write!(f, ",")?;
45+
}
46+
47+
write!(f, "{}", t)?;
48+
}
49+
}
50+
51+
write!(f, "]")
52+
}
53+
}
54+
55+
pub trait DisplaySliceExt<'a, T: fmt::Display> {
56+
fn display(&'a self) -> DisplaySlice<'a, T>;
57+
58+
/// Display at most `MAX` elements.
59+
fn display_n<const MAX: usize>(&'a self) -> DisplaySlice<'a, T, MAX>;
60+
}
61+
62+
impl<T> DisplaySliceExt<'_, T> for [T]
63+
where T: fmt::Display
64+
{
65+
fn display(&self) -> DisplaySlice<T> {
66+
DisplaySlice(self)
67+
}
68+
69+
fn display_n<const MAX: usize>(&'_ self) -> DisplaySlice<'_, T, MAX> {
70+
DisplaySlice(self)
71+
}
72+
}
73+
74+
#[cfg(test)]
75+
mod tests {
76+
use super::DisplaySlice;
77+
78+
#[test]
79+
fn test_display_slice() {
80+
let a = vec![1, 2, 3, 4];
81+
assert_eq!("[1,2,3,4]", DisplaySlice::<_>(&a).to_string());
82+
83+
let a = vec![1, 2, 3, 4, 5];
84+
assert_eq!("[1,2,3,4,5]", DisplaySlice::<_>(&a).to_string());
85+
86+
let a = vec![1, 2, 3, 4, 5, 6];
87+
assert_eq!("[1,2,3,4,..,6]", DisplaySlice::<_>(&a).to_string());
88+
89+
let a = vec![1, 2, 3, 4, 5, 6, 7];
90+
assert_eq!("[1,2,3,4,..,7]", DisplaySlice::<_>(&a).to_string());
91+
92+
let a = vec![1, 2, 3, 4, 5, 6, 7];
93+
assert_eq!("[1,..,7]", DisplaySlice::<_, 2>(&a).to_string());
94+
}
95+
}

src/common/base/src/display/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@
1313
// limitations under the License.
1414

1515
pub mod display_option;
16+
pub mod display_slice;
1617
pub mod display_unix_epoch;
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
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+
15+
use std::fmt;
16+
use std::time::Duration;
17+
18+
use databend_common_base::display::display_option::DisplayOptionExt;
19+
use databend_common_base::display::display_unix_epoch::DisplayUnixTimeStamp;
20+
use databend_common_base::display::display_unix_epoch::DisplayUnixTimeStampExt;
21+
use jwt_simple::claims::JWTClaims;
22+
use jwt_simple::prelude::coarsetime;
23+
24+
/// A helper struct to Display JWT claims.
25+
pub struct DisplayJWTClaims<'a, T> {
26+
claims: &'a JWTClaims<T>,
27+
}
28+
29+
impl<'a, T> fmt::Display for DisplayJWTClaims<'a, T>
30+
where T: fmt::Display
31+
{
32+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33+
fn to_ts(v: Option<coarsetime::UnixTimeStamp>) -> Option<DisplayUnixTimeStamp> {
34+
v.map(|x| {
35+
let duration = Duration::from_micros(x.as_micros());
36+
duration.display_unix_timestamp()
37+
})
38+
}
39+
40+
write!(f, "JWTClaims{{")?;
41+
write!(f, "issuer: {}, ", self.claims.issuer.display())?;
42+
write!(f, "issued_at: {}, ", to_ts(self.claims.issued_at).display())?;
43+
write!(
44+
f,
45+
"expires_at: {}, ",
46+
to_ts(self.claims.expires_at).display()
47+
)?;
48+
write!(f, "custom: {}", self.claims.custom)?;
49+
write!(f, "}}")
50+
}
51+
}
52+
53+
/// Add `display_jwt_claims` method to `JWTClaims<T>` if `T` is Display.
54+
pub trait DisplayJWTClaimsExt<T> {
55+
fn display_jwt_claims(&self) -> DisplayJWTClaims<T>;
56+
}
57+
58+
impl<T> DisplayJWTClaimsExt<T> for JWTClaims<T>
59+
where T: fmt::Display
60+
{
61+
fn display_jwt_claims(&self) -> DisplayJWTClaims<T> {
62+
DisplayJWTClaims { claims: self }
63+
}
64+
}
65+
66+
#[cfg(test)]
67+
mod tests {
68+
use jwt_simple::prelude::coarsetime;
69+
70+
use crate::display_jwt_claims::DisplayJWTClaimsExt;
71+
72+
#[test]
73+
fn test_display_jwt_claims() {
74+
use jwt_simple::claims::JWTClaims;
75+
76+
let claims = JWTClaims {
77+
issuer: Some("issuer".to_string()),
78+
subject: None,
79+
audiences: None,
80+
jwt_id: None,
81+
issued_at: Some(coarsetime::UnixTimeStamp::from_millis(1723102819023)),
82+
expires_at: Some(coarsetime::UnixTimeStamp::from_millis(1723102819023)),
83+
custom: "custom".to_string(),
84+
invalid_before: None,
85+
nonce: None,
86+
};
87+
88+
let display = claims.display_jwt_claims();
89+
assert_eq!(
90+
format!("{}", display),
91+
"JWTClaims{issuer: issuer, issued_at: 2024-08-08T07:40:19.022460Z+0000, expires_at: 2024-08-08T07:40:19.022460Z+0000, custom: custom}"
92+
);
93+
}
94+
}

src/common/license/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
pub mod display_jwt_claims;
1516
pub mod license;
1617
pub mod license_manager;

src/common/license/src/license.rs

Lines changed: 95 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
use std::fmt::Display;
16-
use std::fmt::Formatter;
15+
use std::fmt;
1716

17+
use databend_common_base::display::display_option::DisplayOptionExt;
18+
use databend_common_base::display::display_slice::DisplaySliceExt;
1819
use serde::Deserialize;
1920
use serde::Serialize;
2021

@@ -75,8 +76,8 @@ pub enum Feature {
7576
Unknown,
7677
}
7778

78-
impl Display for Feature {
79-
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
79+
impl fmt::Display for Feature {
80+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
8081
match self {
8182
Feature::LicenseInfo => write!(f, "license_info"),
8283
Feature::Vacuum => write!(f, "vacuum"),
@@ -93,23 +94,28 @@ impl Display for Feature {
9394
Feature::ComputeQuota(v) => {
9495
write!(f, "compute_quota(")?;
9596

97+
write!(f, "threads_num: ")?;
9698
match &v.threads_num {
97-
None => write!(f, "threads_num: unlimited,")?,
98-
Some(threads_num) => write!(f, "threads_num: {}", *threads_num)?,
99+
None => write!(f, "unlimited,")?,
100+
Some(threads_num) => write!(f, "{}", *threads_num)?,
99101
};
100102

103+
write!(f, ", memory_usage: ")?;
101104
match v.memory_usage {
102-
None => write!(f, "memory_usage: unlimited,"),
103-
Some(memory_usage) => write!(f, "memory_usage: {}", memory_usage),
105+
None => write!(f, "unlimited,")?,
106+
Some(memory_usage) => write!(f, "{}", memory_usage)?,
104107
}
108+
write!(f, ")")
105109
}
106110
Feature::StorageQuota(v) => {
107111
write!(f, "storage_quota(")?;
108112

113+
write!(f, "storage_usage: ")?;
109114
match v.storage_usage {
110-
None => write!(f, "storage_usage: unlimited,"),
111-
Some(storage_usage) => write!(f, "storage_usage: {}", storage_usage),
115+
None => write!(f, "unlimited,")?,
116+
Some(storage_usage) => write!(f, "{}", storage_usage)?,
112117
}
118+
write!(f, ")")
113119
}
114120
Feature::AmendTable => write!(f, "amend_table"),
115121
Feature::Unknown => write!(f, "unknown"),
@@ -170,23 +176,53 @@ pub struct LicenseInfo {
170176
pub features: Option<Vec<Feature>>,
171177
}
172178

179+
impl fmt::Display for LicenseInfo {
180+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181+
write!(
182+
f,
183+
"LicenseInfo{{ type: {}, org: {}, tenants: {}, features: [{}] }}",
184+
self.r#type.display(),
185+
self.org.display(),
186+
self.tenants
187+
.as_ref()
188+
.map(|x| x.as_slice().display())
189+
.display(),
190+
self.display_features()
191+
)
192+
}
193+
}
194+
173195
impl LicenseInfo {
174-
pub fn display_features(&self) -> String {
175-
// sort all features in alphabet order and ignore test feature
176-
let mut features = self.features.clone().unwrap_or_default();
196+
pub fn display_features(&self) -> impl fmt::Display + '_ {
197+
/// sort all features in alphabet order and ignore test feature
198+
struct DisplayFeatures<'a>(&'a LicenseInfo);
177199

178-
if features.is_empty() {
179-
return String::from("Unlimited");
180-
}
200+
impl<'a> fmt::Display for DisplayFeatures<'a> {
201+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
202+
let Some(features) = self.0.features.clone() else {
203+
return write!(f, "Unlimited");
204+
};
181205

182-
features.sort();
206+
let mut features = features
207+
.into_iter()
208+
.filter(|f| f != &Feature::Test)
209+
.map(|x| x.to_string())
210+
.collect::<Vec<_>>();
183211

184-
features
185-
.iter()
186-
.filter(|f| **f != Feature::Test)
187-
.map(|f| f.to_string())
188-
.collect::<Vec<_>>()
189-
.join(",")
212+
features.sort();
213+
214+
for (i, feat) in features.into_iter().enumerate() {
215+
if i > 0 {
216+
write!(f, ",")?;
217+
}
218+
219+
write!(f, "{}", feat)?;
220+
}
221+
Ok(())
222+
}
223+
}
224+
225+
DisplayFeatures(self)
190226
}
191227

192228
/// Get Storage Quota from given license info.
@@ -298,4 +334,40 @@ mod tests {
298334
serde_json::from_str::<Feature>("\"ssss\"").unwrap()
299335
);
300336
}
337+
338+
#[test]
339+
fn test_display_license_info() {
340+
let license_info = LicenseInfo {
341+
r#type: Some("enterprise".to_string()),
342+
org: Some("databend".to_string()),
343+
tenants: Some(vec!["databend_tenant".to_string(), "foo".to_string()]),
344+
features: Some(vec![
345+
Feature::LicenseInfo,
346+
Feature::Vacuum,
347+
Feature::Test,
348+
Feature::VirtualColumn,
349+
Feature::BackgroundService,
350+
Feature::DataMask,
351+
Feature::AggregateIndex,
352+
Feature::InvertedIndex,
353+
Feature::ComputedColumn,
354+
Feature::StorageEncryption,
355+
Feature::Stream,
356+
Feature::AttacheTable,
357+
Feature::ComputeQuota(ComputeQuota {
358+
threads_num: Some(1),
359+
memory_usage: Some(1),
360+
}),
361+
Feature::StorageQuota(StorageQuota {
362+
storage_usage: Some(1),
363+
}),
364+
Feature::AmendTable,
365+
]),
366+
};
367+
368+
assert_eq!(
369+
"LicenseInfo{ type: enterprise, org: databend, tenants: [databend_tenant,foo], features: [aggregate_index,amend_table,attach_table,background_service,compute_quota(threads_num: 1, memory_usage: 1),computed_column,data_mask,inverted_index,license_info,storage_encryption,storage_quota(storage_usage: 1),stream,vacuum,virtual_column] }",
370+
license_info.to_string()
371+
);
372+
}
301373
}

src/query/service/src/table_functions/others/license_info.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,10 @@ impl LicenseInfoSource {
191191
DataType::String,
192192
Value::Scalar(Scalar::String(human_readable_available_time)),
193193
),
194-
BlockEntry::new(DataType::String, Value::Scalar(Scalar::String(feature_str))),
194+
BlockEntry::new(
195+
DataType::String,
196+
Value::Scalar(Scalar::String(feature_str.to_string())),
197+
),
195198
],
196199
1,
197200
))

0 commit comments

Comments
 (0)