powdb-query 0.11.0

PowQL lexer, parser, planner, and executor — compiled query engine for PowDB
Documentation
#[derive(Debug, Clone, PartialEq)]
pub enum Token {
    // Identifiers and literals
    Ident(String),     // User, name, email
    DotIdent(String),  // .name, .age (field access)
    IntLit(i64),       // 42
    FloatLit(f64),     // 3.14
    StringLit(String), // "hello"
    BoolLit(bool),     // true, false
    Param(String),     // $age, $name (query parameter)

    // Keywords
    Type,         // type
    Filter,       // filter
    Order,        // order
    Limit,        // limit
    Offset,       // offset
    Insert,       // insert
    Update,       // update
    Delete,       // delete
    Upsert,       // upsert
    Returning,    // returning
    Select,       // select (alias for projection)
    Required,     // required
    Default,      // default (column default value)
    Auto,         // auto (auto-incrementing column)
    Multi,        // multi
    Link,         // link
    Index,        // index
    Unique,       // unique
    On,           // on
    Conflict,     // conflict
    Asc,          // asc
    Desc,         // desc
    And,          // and
    Or,           // or
    Not,          // not
    Exists,       // exists
    Let,          // let
    As,           // as
    Match,        // match
    Group,        // group
    Join,         // join
    Inner,        // inner
    LeftKw,       // left  (keyword — avoids clashing with ast::JoinKind::LeftOuter naming)
    RightKw,      // right
    Outer,        // outer
    Cross,        // cross
    Transaction,  // transaction
    Begin,        // begin
    Commit,       // commit
    Rollback,     // rollback
    View,         // view
    Materialized, // materialized
    Refresh,      // refresh
    Union,        // union
    Having,       // having
    Distinct,     // distinct
    In,           // in
    Between,      // between
    Like,         // like
    Count,        // count
    Avg,          // avg
    Sum,          // sum
    Min,          // min
    Max,          // max
    Is,           // is
    Null,         // null

    // String functions
    Upper,     // upper
    Lower,     // lower
    Length,    // length
    Trim,      // trim
    Substring, // substring
    Concat,    // concat

    // Math functions
    Abs,   // abs
    Round, // round
    Ceil,  // ceil
    Floor, // floor
    Sqrt,  // sqrt
    Pow,   // pow

    // Date/time functions
    Now,      // now
    Extract,  // extract
    DateAdd,  // date_add
    DateDiff, // date_diff

    // Type conversion
    Cast, // cast

    // CASE WHEN
    Case, // case
    When, // when
    Then, // then
    Else, // else
    End,  // end

    // Window functions
    Over,      // over
    Partition, // partition
    RowNumber, // row_number
    Rank,      // rank
    DenseRank, // dense_rank

    // DDL
    Alter,    // alter
    Drop,     // drop
    Add,      // add
    Column,   // column
    Explain,  // explain
    Schema,   // schema   (introspection: list types / describe one)
    Describe, // describe (introspection: describe one type)

    // Operators
    Eq,       // =
    Neq,      // !=
    Lt,       // <
    Gt,       // >
    Lte,      // <=
    Gte,      // >=
    Assign,   // :=
    Arrow,    // ->
    Pipe,     // |
    Coalesce, // ??
    Plus,     // +
    Minus,    // -
    Star,     // *
    Slash,    // /

    // Delimiters
    LBrace, // {
    RBrace, // }
    LParen, // (
    RParen, // )
    Comma,  // ,
    Colon,  // :
    Dot,    // .

    // Special
    Eof,
}

impl Token {
    /// Human-readable name for error messages. Avoids exposing raw Rust Debug
    /// format like `IntLit(42)` to end users.
    pub fn display_name(&self) -> String {
        match self {
            // Literals
            Token::Ident(s) => format!("identifier '{s}'"),
            Token::DotIdent(s) => format!("field '.{s}'"),
            Token::IntLit(v) => format!("number {v}"),
            Token::FloatLit(v) => format!("decimal number {v}"),
            Token::StringLit(s) => {
                let preview = if s.len() > 20 {
                    let end = s.floor_char_boundary(20);
                    format!("{}...", &s[..end])
                } else {
                    s.clone()
                };
                format!("string \"{preview}\"")
            }
            Token::BoolLit(v) => format!("{v}"),
            Token::Param(s) => format!("parameter '${s}'"),

            // Keywords
            Token::Type => "'type'".into(),
            Token::Filter => "'filter'".into(),
            Token::Order => "'order'".into(),
            Token::Limit => "'limit'".into(),
            Token::Offset => "'offset'".into(),
            Token::Insert => "'insert'".into(),
            Token::Update => "'update'".into(),
            Token::Delete => "'delete'".into(),
            Token::Upsert => "'upsert'".into(),
            Token::Returning => "'returning'".into(),
            Token::Select => "'select'".into(),
            Token::Required => "'required'".into(),
            Token::Default => "'default'".into(),
            Token::Auto => "'auto'".into(),
            Token::Multi => "'multi'".into(),
            Token::Link => "'link'".into(),
            Token::Index => "'index'".into(),
            Token::Unique => "'unique'".into(),
            Token::On => "'on'".into(),
            Token::Conflict => "'conflict'".into(),
            Token::Asc => "'asc'".into(),
            Token::Desc => "'desc'".into(),
            Token::And => "'and'".into(),
            Token::Or => "'or'".into(),
            Token::Not => "'not'".into(),
            Token::Exists => "'exists'".into(),
            Token::Let => "'let'".into(),
            Token::As => "'as'".into(),
            Token::Match => "'match'".into(),
            Token::Group => "'group'".into(),
            Token::Join => "'join'".into(),
            Token::Inner => "'inner'".into(),
            Token::LeftKw => "'left'".into(),
            Token::RightKw => "'right'".into(),
            Token::Outer => "'outer'".into(),
            Token::Cross => "'cross'".into(),
            Token::Transaction => "'transaction'".into(),
            Token::Begin => "'begin'".into(),
            Token::Commit => "'commit'".into(),
            Token::Rollback => "'rollback'".into(),
            Token::View => "'view'".into(),
            Token::Materialized => "'materialized'".into(),
            Token::Refresh => "'refresh'".into(),
            Token::Union => "'union'".into(),
            Token::Having => "'having'".into(),
            Token::Distinct => "'distinct'".into(),
            Token::In => "'in'".into(),
            Token::Between => "'between'".into(),
            Token::Like => "'like'".into(),
            Token::Count => "'count'".into(),
            Token::Avg => "'avg'".into(),
            Token::Sum => "'sum'".into(),
            Token::Min => "'min'".into(),
            Token::Max => "'max'".into(),
            Token::Is => "'is'".into(),
            Token::Null => "'null'".into(),

            // Functions
            Token::Upper => "'upper'".into(),
            Token::Lower => "'lower'".into(),
            Token::Length => "'length'".into(),
            Token::Trim => "'trim'".into(),
            Token::Substring => "'substring'".into(),
            Token::Concat => "'concat'".into(),
            Token::Abs => "'abs'".into(),
            Token::Round => "'round'".into(),
            Token::Ceil => "'ceil'".into(),
            Token::Floor => "'floor'".into(),
            Token::Sqrt => "'sqrt'".into(),
            Token::Pow => "'pow'".into(),
            Token::Now => "'now'".into(),
            Token::Extract => "'extract'".into(),
            Token::DateAdd => "'date_add'".into(),
            Token::DateDiff => "'date_diff'".into(),
            Token::Cast => "'cast'".into(),
            Token::Case => "'case'".into(),
            Token::When => "'when'".into(),
            Token::Then => "'then'".into(),
            Token::Else => "'else'".into(),
            Token::End => "'end'".into(),

            // Window
            Token::Over => "'over'".into(),
            Token::Partition => "'partition'".into(),
            Token::RowNumber => "'row_number'".into(),
            Token::Rank => "'rank'".into(),
            Token::DenseRank => "'dense_rank'".into(),

            // DDL
            Token::Alter => "'alter'".into(),
            Token::Drop => "'drop'".into(),
            Token::Add => "'add'".into(),
            Token::Column => "'column'".into(),
            Token::Explain => "'explain'".into(),
            Token::Schema => "'schema'".into(),
            Token::Describe => "'describe'".into(),

            // Operators
            Token::Eq => "'='".into(),
            Token::Neq => "'!='".into(),
            Token::Lt => "'<'".into(),
            Token::Gt => "'>'".into(),
            Token::Lte => "'<='".into(),
            Token::Gte => "'>='".into(),
            Token::Assign => "':='".into(),
            Token::Arrow => "'->'".into(),
            Token::Pipe => "'|'".into(),
            Token::Coalesce => "'??'".into(),
            Token::Plus => "'+'".into(),
            Token::Minus => "'-'".into(),
            Token::Star => "'*'".into(),
            Token::Slash => "'/'".into(),

            // Delimiters
            Token::LBrace => "'{'".into(),
            Token::RBrace => "'}'".into(),
            Token::LParen => "'('".into(),
            Token::RParen => "')'".into(),
            Token::Comma => "','".into(),
            Token::Colon => "':'".into(),
            Token::Dot => "'.'".into(),

            Token::Eof => "end of input".into(),
        }
    }

    /// The lowercase source spelling of this token when it is a reserved
    /// keyword (or built-in literal word), or `None` for identifiers,
    /// literals, operators, and delimiters. Inverts the lexer's word→token
    /// table so the parser can tell a caller *which* reserved word collided
    /// with an identifier position and how to quote it (`` `type` ``).
    pub fn keyword_str(&self) -> Option<&'static str> {
        Some(match self {
            Token::Type => "type",
            Token::Filter => "filter",
            Token::Order => "order",
            Token::Limit => "limit",
            Token::Offset => "offset",
            Token::Insert => "insert",
            Token::Update => "update",
            Token::Delete => "delete",
            Token::Upsert => "upsert",
            Token::Returning => "returning",
            Token::Select => "select",
            Token::Required => "required",
            Token::Default => "default",
            Token::Auto => "auto",
            Token::Multi => "multi",
            Token::Link => "link",
            Token::Index => "index",
            Token::Unique => "unique",
            Token::On => "on",
            Token::Conflict => "conflict",
            Token::Asc => "asc",
            Token::Desc => "desc",
            Token::And => "and",
            Token::Or => "or",
            Token::Not => "not",
            Token::Exists => "exists",
            Token::Let => "let",
            Token::As => "as",
            Token::Match => "match",
            Token::Group => "group",
            Token::Join => "join",
            Token::Inner => "inner",
            Token::LeftKw => "left",
            Token::RightKw => "right",
            Token::Outer => "outer",
            Token::Cross => "cross",
            Token::Transaction => "transaction",
            Token::Begin => "begin",
            Token::Commit => "commit",
            Token::Rollback => "rollback",
            Token::View => "view",
            Token::Materialized => "materialized",
            Token::Refresh => "refresh",
            Token::Union => "union",
            Token::Having => "having",
            Token::Distinct => "distinct",
            Token::In => "in",
            Token::Between => "between",
            Token::Like => "like",
            Token::Count => "count",
            Token::Avg => "avg",
            Token::Sum => "sum",
            Token::Min => "min",
            Token::Max => "max",
            Token::Is => "is",
            Token::Null => "null",
            Token::Upper => "upper",
            Token::Lower => "lower",
            Token::Length => "length",
            Token::Trim => "trim",
            Token::Substring => "substring",
            Token::Concat => "concat",
            Token::Abs => "abs",
            Token::Round => "round",
            Token::Ceil => "ceil",
            Token::Floor => "floor",
            Token::Sqrt => "sqrt",
            Token::Pow => "pow",
            Token::Now => "now",
            Token::Extract => "extract",
            Token::DateAdd => "date_add",
            Token::DateDiff => "date_diff",
            Token::Cast => "cast",
            Token::Case => "case",
            Token::When => "when",
            Token::Then => "then",
            Token::Else => "else",
            Token::End => "end",
            Token::Over => "over",
            Token::Partition => "partition",
            Token::RowNumber => "row_number",
            Token::Rank => "rank",
            Token::DenseRank => "dense_rank",
            Token::Alter => "alter",
            Token::Drop => "drop",
            Token::Add => "add",
            Token::Column => "column",
            Token::Explain => "explain",
            Token::Schema => "schema",
            Token::Describe => "describe",
            _ => return None,
        })
    }
}