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