1use std::collections::HashMap;
2
3use chrono::{DateTime, Utc};
4use getset2::Getset2;
5use serde::{Deserialize, Serialize};
6
7use crate::{MaybeString, utils::OrderedHashMap};
8
9#[cfg_attr(feature = "salvo", derive(salvo::prelude::ToSchema))]
11#[derive(Debug, Serialize, Deserialize)]
12#[serde(rename_all = "camelCase")]
13#[non_exhaustive]
14pub struct DefaultMeta {
15 #[serde(skip_serializing_if = "Option::is_none")]
16 pub request_id: Option<String>,
17 #[serde(skip_serializing_if = "Option::is_none")]
18 pub user: Option<UserMeta>,
19 #[serde(skip_serializing_if = "Option::is_none")]
20 pub pagination: Option<Pagination>,
21 #[serde(skip_serializing_if = "Option::is_none")]
22 pub rate_limit: Option<RateLimit>,
23 #[serde(skip_serializing_if = "Option::is_none")]
24 pub cost: Option<Cost>,
25 #[serde(skip_serializing_if = "Option::is_none")]
26 pub api_version: Option<String>,
27 #[serde(skip_serializing_if = "HashMap::is_empty", default)]
28 custom: OrderedHashMap<String, String>,
29}
30
31#[cfg_attr(feature = "salvo", derive(salvo::prelude::ToSchema))]
33#[derive(Default, Getset2, Debug, Serialize, Deserialize)]
34#[serde(rename_all = "camelCase")]
35#[getset2(get_ref, set_with)]
36#[non_exhaustive]
37pub struct UserMeta {
38 pub id: String,
39 pub roles: Vec<String>,
40}
41
42#[cfg_attr(feature = "salvo", derive(salvo::prelude::ToSchema))]
44#[derive(Default, Getset2, Debug, Serialize, Deserialize)]
45#[serde(rename_all = "camelCase")]
46#[getset2(get_ref(pub), set_with(pub))]
47#[non_exhaustive]
48pub struct Pagination {
49 pub current_page: u32,
50 pub page_size: u32,
51 pub total_pages: u32,
52 pub total_records: u32,
53 pub next_page: Option<u32>,
54 pub prev_page: Option<u32>,
55}
56
57#[cfg_attr(feature = "salvo", derive(salvo::prelude::ToSchema))]
59#[derive(Default, Getset2, Debug, Serialize, Deserialize)]
60#[serde(rename_all = "camelCase")]
61#[getset2(set_with)]
62#[non_exhaustive]
63pub struct RateLimit {
64 pub limit: i32,
65 pub remaining: i32,
66 pub restore_rate: i32,
67 pub reset_at: Option<DateTime<Utc>>,
68}
69
70#[cfg_attr(feature = "salvo", derive(salvo::prelude::ToSchema))]
72#[derive(Default, Getset2, Debug, Serialize, Deserialize)]
73#[serde(rename_all = "camelCase")]
74#[getset2(set_with)]
75#[non_exhaustive]
76pub struct Cost {
77 pub actual_cost: u32,
78 pub requested_query_cost: u32,
79 pub execution_time: Option<DateTime<Utc>>,
80}
81
82impl Default for DefaultMeta {
83 fn default() -> Self {
84 Self::new()
85 }
86}
87
88impl DefaultMeta {
89 #[inline(always)]
90 pub fn new() -> Self {
91 Self {
92 request_id: None,
93 user: None,
94 pagination: None,
95 rate_limit: None,
96 cost: None,
97 api_version: None,
98 custom: OrderedHashMap::default(),
99 }
100 }
101 #[inline(always)]
102 pub fn with_request_id(mut self, request_id: impl Into<MaybeString>) -> Self {
103 self.request_id = request_id.into().option_string();
104 self
105 }
106 #[inline(always)]
107 pub fn with_user(mut self, user: Option<UserMeta>) -> Self {
108 self.user = user;
109 self
110 }
111 #[inline(always)]
112 pub const fn with_pagination(mut self, pagination: Option<Pagination>) -> Self {
113 self.pagination = pagination;
114 self
115 }
116 #[inline(always)]
117 pub const fn with_rate_limit(mut self, rate_limit: Option<RateLimit>) -> Self {
118 self.rate_limit = rate_limit;
119 self
120 }
121 #[inline(always)]
122 pub const fn with_cost(mut self, cost: Option<Cost>) -> Self {
123 self.cost = cost;
124 self
125 }
126 #[inline(always)]
127 pub fn with_api_version(mut self, api_version: impl Into<MaybeString>) -> Self {
128 self.api_version = api_version.into().option_string();
129 self
130 }
131 #[inline(always)]
132 pub fn insert_custom(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
133 self.custom.insert(key.into(), value.into());
134 self
135 }
136 #[inline]
137 pub const fn request_id(&self) -> Option<&String> {
138 self.request_id.as_ref()
139 }
140 pub const fn user(&self) -> Option<&UserMeta> {
141 self.user.as_ref()
142 }
143 pub const fn pagination(&self) -> Option<&Pagination> {
144 self.pagination.as_ref()
145 }
146 pub const fn rate_limit(&self) -> Option<&RateLimit> {
147 self.rate_limit.as_ref()
148 }
149 pub const fn cost(&self) -> Option<&Cost> {
150 self.cost.as_ref()
151 }
152 pub const fn api_version(&self) -> Option<&String> {
153 self.api_version.as_ref()
154 }
155 pub fn custom(&self) -> &HashMap<String, String> {
156 &self.custom
157 }
158 pub fn custom_kv(&self, key: impl AsRef<str>) -> Option<&String> {
159 self.custom.get(key.as_ref())
160 }
161}