1use std::fmt::Display;
16use std::fmt::Formatter;
17
18use derive_visitor::Drive;
19use derive_visitor::DriveMut;
20use ethnum::i256;
21
22use super::quote::QuotedString;
23use crate::ast::quote::QuotedIdent;
24use crate::ast::WithOptions;
25use crate::Span;
26
27#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
29pub struct Identifier {
30 pub span: Span,
31 pub name: String,
32 pub quote: Option<char>,
33 #[drive(skip)]
34 pub ident_type: IdentifierType,
35}
36
37#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
38pub enum IdentifierType {
39 #[default]
40 None,
41 Hole,
42 Variable,
43}
44
45impl Identifier {
46 pub fn is_quoted(&self) -> bool {
47 self.quote.is_some()
48 }
49
50 pub fn is_hole(&self) -> bool {
51 self.ident_type == IdentifierType::Hole
52 }
53
54 pub fn is_variable(&self) -> bool {
55 self.ident_type == IdentifierType::Variable
56 }
57
58 pub fn from_name(span: Span, name: impl Into<String>) -> Self {
59 Self {
60 span,
61 name: name.into(),
62 quote: None,
63 ident_type: IdentifierType::None,
64 }
65 }
66
67 pub fn from_name_with_quoted(span: Span, name: impl Into<String>, quote: Option<char>) -> Self {
68 Self {
69 span,
70 name: name.into(),
71 quote,
72 ident_type: IdentifierType::None,
73 }
74 }
75}
76
77impl Display for Identifier {
78 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
79 if self.is_hole() {
80 write!(f, "IDENTIFIER(:{})", self.name)
81 } else if self.is_variable() {
82 write!(f, "IDENTIFIER(${})", self.name)
83 } else if let Some(quote) = self.quote {
84 write!(f, "{}", QuotedIdent(&self.name, quote))
85 } else {
86 write!(f, "{}", self.name)
87 }
88 }
89}
90
91#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
92pub struct ColumnPosition {
93 pub span: Span,
94 pub pos: usize,
95 pub name: String,
96}
97
98impl ColumnPosition {
99 pub fn create(span: Span, pos: usize) -> ColumnPosition {
100 ColumnPosition {
101 pos,
102 name: format!("${}", pos),
103 span,
104 }
105 }
106 pub fn name(&self) -> String {
107 format!("${}", self.pos)
108 }
109}
110
111impl Display for ColumnPosition {
112 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
113 write!(f, "${}", self.pos)
114 }
115}
116
117#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
118pub enum ColumnID {
119 Name(Identifier),
120 Position(ColumnPosition),
121}
122
123impl ColumnID {
124 pub fn name(&self) -> &str {
125 match self {
126 ColumnID::Name(id) => &id.name,
127 ColumnID::Position(id) => &id.name,
128 }
129 }
130}
131
132impl Display for ColumnID {
133 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
134 match self {
135 ColumnID::Name(id) => write!(f, "{}", id),
136 ColumnID::Position(id) => write!(f, "{}", id),
137 }
138 }
139}
140
141#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
142pub struct DatabaseRef {
143 pub catalog: Option<Identifier>,
144 pub database: Identifier,
145}
146
147impl Display for DatabaseRef {
148 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
149 if let Some(catalog) = &self.catalog {
150 write!(f, "{}.", catalog)?;
151 }
152 write!(f, "{}", self.database)?;
153 Ok(())
154 }
155}
156
157#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
158pub struct TableRef {
159 pub catalog: Option<Identifier>,
160 pub database: Option<Identifier>,
161 pub table: Identifier,
162 pub with_options: Option<WithOptions>,
163}
164
165impl Display for TableRef {
166 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
167 assert!(self.catalog.is_none() || (self.catalog.is_some() && self.database.is_some()));
168 if let Some(catalog) = &self.catalog {
169 write!(f, "{}.", catalog)?;
170 }
171 if let Some(database) = &self.database {
172 write!(f, "{}.", database)?;
173 }
174 write!(f, "{}", self.table)?;
175
176 if let Some(with_options) = &self.with_options {
177 write!(f, " {with_options}")?;
178 }
179 Ok(())
180 }
181}
182
183#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
184pub struct ColumnRef {
185 pub database: Option<Identifier>,
186 pub table: Option<Identifier>,
187 pub column: ColumnID,
188}
189
190impl Display for ColumnRef {
191 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
192 assert!(self.database.is_none() || (self.database.is_some() && self.table.is_some()));
193
194 if f.alternate() {
195 write!(f, "{}", self.column)?;
196 return Ok(());
197 }
198
199 if let Some(database) = &self.database {
200 write!(f, "{}.", database)?;
201 }
202 if let Some(table) = &self.table {
203 write!(f, "{}.", table)?;
204 }
205 write!(f, "{}", self.column)?;
206 Ok(())
207 }
208}
209
210pub(crate) fn write_dot_separated_list(
211 f: &mut Formatter,
212 items: impl IntoIterator<Item = impl Display>,
213) -> std::fmt::Result {
214 for (i, item) in items.into_iter().enumerate() {
215 if i > 0 {
216 write!(f, ".")?;
217 }
218 write!(f, "{}", item)?;
219 }
220 Ok(())
221}
222
223pub(crate) fn write_comma_separated_list(
225 f: &mut Formatter,
226 items: impl IntoIterator<Item = impl Display>,
227) -> std::fmt::Result {
228 for (i, item) in items.into_iter().enumerate() {
229 if i > 0 {
230 write!(f, ", ")?;
231 }
232 write!(f, "{item}")?;
233 }
234 Ok(())
235}
236
237pub(crate) fn write_comma_separated_string_list(
239 f: &mut Formatter,
240 items: impl IntoIterator<Item = impl Display>,
241) -> std::fmt::Result {
242 for (i, item) in items.into_iter().enumerate() {
243 if i > 0 {
244 write!(f, ", ")?;
245 }
246 write!(f, "'{item}'")?;
247 }
248 Ok(())
249}
250
251pub(crate) fn write_comma_separated_map(
253 f: &mut Formatter,
254 items: impl IntoIterator<Item = (impl Display, impl Display)>,
255) -> std::fmt::Result {
256 for (i, (k, v)) in items.into_iter().enumerate() {
257 if i > 0 {
258 write!(f, ", ")?;
259 }
260 write!(f, "{k} = {v}")?;
261 }
262 Ok(())
263}
264
265pub(crate) fn write_comma_separated_string_map(
267 f: &mut Formatter,
268 items: impl IntoIterator<Item = (impl Display, impl Display)>,
269) -> std::fmt::Result {
270 for (i, (k, v)) in items.into_iter().enumerate() {
271 if i > 0 {
272 write!(f, ", ")?;
273 }
274 write!(f, "{k} = {}", QuotedString(v.to_string(), '\''))?;
275 }
276 Ok(())
277}
278
279pub(crate) fn write_space_separated_string_map(
281 f: &mut Formatter,
282 items: impl IntoIterator<Item = (impl Display, impl Display)>,
283) -> std::fmt::Result {
284 for (i, (k, v)) in items.into_iter().enumerate() {
285 if i > 0 {
286 write!(f, " ")?;
287 }
288 write!(f, "{k} = {}", QuotedString(v.to_string(), '\''))?;
289 }
290 Ok(())
291}
292
293pub(crate) fn display_decimal_256(num: i256, scale: u8) -> impl Display {
294 struct Decimal256 {
295 num: i256,
296 scale: u8,
297 }
298
299 impl Display for Decimal256 {
300 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
301 if self.scale == 0 {
302 write!(f, "{}", self.num)
303 } else {
304 let pow_scale = i256::from(10).pow(self.scale as u32);
305 if self.num >= 0 {
307 write!(
308 f,
309 "{}.{:0>width$}",
310 self.num / pow_scale,
311 (self.num % pow_scale).abs(),
312 width = self.scale as usize
313 )
314 } else {
315 write!(
316 f,
317 "-{}.{:0>width$}",
318 -self.num / pow_scale,
319 (self.num % pow_scale).abs(),
320 width = self.scale as usize
321 )
322 }
323 }
324 }
325 }
326
327 Decimal256 { num, scale }
328}