Skip to main content

powdb_query/
token.rs

1#[derive(Debug, Clone, PartialEq)]
2pub enum Token {
3    // Identifiers and literals
4    Ident(String),     // User, name, email
5    DotIdent(String),  // .name, .age (field access)
6    IntLit(i64),       // 42
7    FloatLit(f64),     // 3.14
8    StringLit(String), // "hello"
9    BoolLit(bool),     // true, false
10    Param(String),     // $age, $name (query parameter)
11
12    // Keywords
13    Type,         // type
14    Filter,       // filter
15    Order,        // order
16    Limit,        // limit
17    Offset,       // offset
18    Insert,       // insert
19    Update,       // update
20    Delete,       // delete
21    Upsert,       // upsert
22    Returning,    // returning
23    Select,       // select (alias for projection)
24    Required,     // required
25    Default,      // default (column default value)
26    Auto,         // auto (auto-incrementing column)
27    Multi,        // multi
28    Link,         // link
29    Index,        // index
30    Unique,       // unique
31    On,           // on
32    Conflict,     // conflict
33    Asc,          // asc
34    Desc,         // desc
35    And,          // and
36    Or,           // or
37    Not,          // not
38    Exists,       // exists
39    Let,          // let
40    As,           // as
41    Match,        // match
42    Group,        // group
43    Join,         // join
44    Inner,        // inner
45    LeftKw,       // left  (keyword — avoids clashing with ast::JoinKind::LeftOuter naming)
46    RightKw,      // right
47    Outer,        // outer
48    Cross,        // cross
49    Transaction,  // transaction
50    Begin,        // begin
51    Commit,       // commit
52    Rollback,     // rollback
53    View,         // view
54    Materialized, // materialized
55    Refresh,      // refresh
56    Union,        // union
57    Having,       // having
58    Distinct,     // distinct
59    In,           // in
60    Between,      // between
61    Like,         // like
62    Count,        // count
63    Avg,          // avg
64    Sum,          // sum
65    Min,          // min
66    Max,          // max
67    Raw,          // raw (aggregate bag semantics)
68    Is,           // is
69    Null,         // null
70
71    // String functions
72    Upper,     // upper
73    Lower,     // lower
74    Length,    // length
75    Trim,      // trim
76    Substring, // substring
77    Concat,    // concat
78
79    // Math functions
80    Abs,   // abs
81    Round, // round
82    Ceil,  // ceil
83    Floor, // floor
84    Sqrt,  // sqrt
85    Pow,   // pow
86
87    // Date/time functions
88    Now,      // now
89    Extract,  // extract
90    DateAdd,  // date_add
91    DateDiff, // date_diff
92
93    // JSON functions
94    JsonType, // json_type
95    JsonText, // json_text
96
97    // Type conversion
98    Cast, // cast
99
100    // CASE WHEN
101    Case, // case
102    When, // when
103    Then, // then
104    Else, // else
105    End,  // end
106
107    // Window functions
108    Over,      // over
109    Partition, // partition
110    RowNumber, // row_number
111    Rank,      // rank
112    DenseRank, // dense_rank
113
114    // DDL
115    Alter,    // alter
116    Drop,     // drop
117    Add,      // add
118    Column,   // column
119    Explain,  // explain
120    Schema,   // schema   (introspection: list types / describe one)
121    Describe, // describe (introspection: describe one type)
122
123    // Operators
124    Eq,       // =
125    Neq,      // !=
126    Lt,       // <
127    Gt,       // >
128    Lte,      // <=
129    Gte,      // >=
130    Assign,   // :=
131    Arrow,    // ->
132    Pipe,     // |
133    Coalesce, // ??
134    Plus,     // +
135    Minus,    // -
136    Star,     // *
137    Slash,    // /
138
139    // Delimiters
140    LBrace, // {
141    RBrace, // }
142    LParen, // (
143    RParen, // )
144    Comma,  // ,
145    Colon,  // :
146    Dot,    // .
147
148    // Special
149    Eof,
150}
151
152impl Token {
153    /// Human-readable name for error messages. Avoids exposing raw Rust Debug
154    /// format like `IntLit(42)` to end users.
155    pub fn display_name(&self) -> String {
156        match self {
157            // Literals
158            Token::Ident(s) => format!("identifier '{s}'"),
159            Token::DotIdent(s) => format!("field '.{s}'"),
160            Token::IntLit(v) => format!("number {v}"),
161            Token::FloatLit(v) => format!("decimal number {v}"),
162            Token::StringLit(s) => {
163                let preview = if s.len() > 20 {
164                    let end = s.floor_char_boundary(20);
165                    format!("{}...", &s[..end])
166                } else {
167                    s.clone()
168                };
169                format!("string \"{preview}\"")
170            }
171            Token::BoolLit(v) => format!("{v}"),
172            Token::Param(s) => format!("parameter '${s}'"),
173
174            // Keywords
175            Token::Type => "'type'".into(),
176            Token::Filter => "'filter'".into(),
177            Token::Order => "'order'".into(),
178            Token::Limit => "'limit'".into(),
179            Token::Offset => "'offset'".into(),
180            Token::Insert => "'insert'".into(),
181            Token::Update => "'update'".into(),
182            Token::Delete => "'delete'".into(),
183            Token::Upsert => "'upsert'".into(),
184            Token::Returning => "'returning'".into(),
185            Token::Select => "'select'".into(),
186            Token::Required => "'required'".into(),
187            Token::Default => "'default'".into(),
188            Token::Auto => "'auto'".into(),
189            Token::Multi => "'multi'".into(),
190            Token::Link => "'link'".into(),
191            Token::Index => "'index'".into(),
192            Token::Unique => "'unique'".into(),
193            Token::On => "'on'".into(),
194            Token::Conflict => "'conflict'".into(),
195            Token::Asc => "'asc'".into(),
196            Token::Desc => "'desc'".into(),
197            Token::And => "'and'".into(),
198            Token::Or => "'or'".into(),
199            Token::Not => "'not'".into(),
200            Token::Exists => "'exists'".into(),
201            Token::Let => "'let'".into(),
202            Token::As => "'as'".into(),
203            Token::Match => "'match'".into(),
204            Token::Group => "'group'".into(),
205            Token::Join => "'join'".into(),
206            Token::Inner => "'inner'".into(),
207            Token::LeftKw => "'left'".into(),
208            Token::RightKw => "'right'".into(),
209            Token::Outer => "'outer'".into(),
210            Token::Cross => "'cross'".into(),
211            Token::Transaction => "'transaction'".into(),
212            Token::Begin => "'begin'".into(),
213            Token::Commit => "'commit'".into(),
214            Token::Rollback => "'rollback'".into(),
215            Token::View => "'view'".into(),
216            Token::Materialized => "'materialized'".into(),
217            Token::Refresh => "'refresh'".into(),
218            Token::Union => "'union'".into(),
219            Token::Having => "'having'".into(),
220            Token::Distinct => "'distinct'".into(),
221            Token::In => "'in'".into(),
222            Token::Between => "'between'".into(),
223            Token::Like => "'like'".into(),
224            Token::Count => "'count'".into(),
225            Token::Avg => "'avg'".into(),
226            Token::Sum => "'sum'".into(),
227            Token::Min => "'min'".into(),
228            Token::Max => "'max'".into(),
229            Token::Raw => "'raw'".into(),
230            Token::Is => "'is'".into(),
231            Token::Null => "'null'".into(),
232
233            // Functions
234            Token::Upper => "'upper'".into(),
235            Token::Lower => "'lower'".into(),
236            Token::Length => "'length'".into(),
237            Token::Trim => "'trim'".into(),
238            Token::Substring => "'substring'".into(),
239            Token::Concat => "'concat'".into(),
240            Token::Abs => "'abs'".into(),
241            Token::Round => "'round'".into(),
242            Token::Ceil => "'ceil'".into(),
243            Token::Floor => "'floor'".into(),
244            Token::Sqrt => "'sqrt'".into(),
245            Token::Pow => "'pow'".into(),
246            Token::Now => "'now'".into(),
247            Token::Extract => "'extract'".into(),
248            Token::DateAdd => "'date_add'".into(),
249            Token::DateDiff => "'date_diff'".into(),
250            Token::JsonType => "'json_type'".into(),
251            Token::JsonText => "'json_text'".into(),
252            Token::Cast => "'cast'".into(),
253            Token::Case => "'case'".into(),
254            Token::When => "'when'".into(),
255            Token::Then => "'then'".into(),
256            Token::Else => "'else'".into(),
257            Token::End => "'end'".into(),
258
259            // Window
260            Token::Over => "'over'".into(),
261            Token::Partition => "'partition'".into(),
262            Token::RowNumber => "'row_number'".into(),
263            Token::Rank => "'rank'".into(),
264            Token::DenseRank => "'dense_rank'".into(),
265
266            // DDL
267            Token::Alter => "'alter'".into(),
268            Token::Drop => "'drop'".into(),
269            Token::Add => "'add'".into(),
270            Token::Column => "'column'".into(),
271            Token::Explain => "'explain'".into(),
272            Token::Schema => "'schema'".into(),
273            Token::Describe => "'describe'".into(),
274
275            // Operators
276            Token::Eq => "'='".into(),
277            Token::Neq => "'!='".into(),
278            Token::Lt => "'<'".into(),
279            Token::Gt => "'>'".into(),
280            Token::Lte => "'<='".into(),
281            Token::Gte => "'>='".into(),
282            Token::Assign => "':='".into(),
283            Token::Arrow => "'->'".into(),
284            Token::Pipe => "'|'".into(),
285            Token::Coalesce => "'??'".into(),
286            Token::Plus => "'+'".into(),
287            Token::Minus => "'-'".into(),
288            Token::Star => "'*'".into(),
289            Token::Slash => "'/'".into(),
290
291            // Delimiters
292            Token::LBrace => "'{'".into(),
293            Token::RBrace => "'}'".into(),
294            Token::LParen => "'('".into(),
295            Token::RParen => "')'".into(),
296            Token::Comma => "','".into(),
297            Token::Colon => "':'".into(),
298            Token::Dot => "'.'".into(),
299
300            Token::Eof => "end of input".into(),
301        }
302    }
303
304    /// The lowercase source spelling of this token when it is a reserved
305    /// keyword (or built-in literal word), or `None` for identifiers,
306    /// literals, operators, and delimiters. Inverts the lexer's word→token
307    /// table so the parser can tell a caller *which* reserved word collided
308    /// with an identifier position and how to quote it (`` `type` ``).
309    pub fn keyword_str(&self) -> Option<&'static str> {
310        Some(match self {
311            Token::Type => "type",
312            Token::Filter => "filter",
313            Token::Order => "order",
314            Token::Limit => "limit",
315            Token::Offset => "offset",
316            Token::Insert => "insert",
317            Token::Update => "update",
318            Token::Delete => "delete",
319            Token::Upsert => "upsert",
320            Token::Returning => "returning",
321            Token::Select => "select",
322            Token::Required => "required",
323            Token::Default => "default",
324            Token::Auto => "auto",
325            Token::Multi => "multi",
326            Token::Link => "link",
327            Token::Index => "index",
328            Token::Unique => "unique",
329            Token::On => "on",
330            Token::Conflict => "conflict",
331            Token::Asc => "asc",
332            Token::Desc => "desc",
333            Token::And => "and",
334            Token::Or => "or",
335            Token::Not => "not",
336            Token::Exists => "exists",
337            Token::Let => "let",
338            Token::As => "as",
339            Token::Match => "match",
340            Token::Group => "group",
341            Token::Join => "join",
342            Token::Inner => "inner",
343            Token::LeftKw => "left",
344            Token::RightKw => "right",
345            Token::Outer => "outer",
346            Token::Cross => "cross",
347            Token::Transaction => "transaction",
348            Token::Begin => "begin",
349            Token::Commit => "commit",
350            Token::Rollback => "rollback",
351            Token::View => "view",
352            Token::Materialized => "materialized",
353            Token::Refresh => "refresh",
354            Token::Union => "union",
355            Token::Having => "having",
356            Token::Distinct => "distinct",
357            Token::In => "in",
358            Token::Between => "between",
359            Token::Like => "like",
360            Token::Count => "count",
361            Token::Avg => "avg",
362            Token::Sum => "sum",
363            Token::Min => "min",
364            Token::Max => "max",
365            Token::Raw => "raw",
366            Token::Is => "is",
367            Token::Null => "null",
368            Token::Upper => "upper",
369            Token::Lower => "lower",
370            Token::Length => "length",
371            Token::Trim => "trim",
372            Token::Substring => "substring",
373            Token::Concat => "concat",
374            Token::Abs => "abs",
375            Token::Round => "round",
376            Token::Ceil => "ceil",
377            Token::Floor => "floor",
378            Token::Sqrt => "sqrt",
379            Token::Pow => "pow",
380            Token::Now => "now",
381            Token::Extract => "extract",
382            Token::DateAdd => "date_add",
383            Token::DateDiff => "date_diff",
384            Token::JsonType => "json_type",
385            Token::JsonText => "json_text",
386            Token::Cast => "cast",
387            Token::Case => "case",
388            Token::When => "when",
389            Token::Then => "then",
390            Token::Else => "else",
391            Token::End => "end",
392            Token::Over => "over",
393            Token::Partition => "partition",
394            Token::RowNumber => "row_number",
395            Token::Rank => "rank",
396            Token::DenseRank => "dense_rank",
397            Token::Alter => "alter",
398            Token::Drop => "drop",
399            Token::Add => "add",
400            Token::Column => "column",
401            Token::Explain => "explain",
402            Token::Schema => "schema",
403            Token::Describe => "describe",
404            _ => return None,
405        })
406    }
407}