sql-ddl-to-json-schema 0.2.1

Parse MySQL and MariaDB DDL into a compact table model and JSON Schema draft-07 documents
Documentation
//! Keyword table for the lexer.
//!
//! The order matters. Longer keywords come first so the longest match wins in
//! the merged lexer. Each entry pairs the uppercase keyword name with its
//! characters, used for case-insensitive matching with word boundaries.

use std::sync::OnceLock;

/// Every keyword, longest first, matching the source dictionary order.
const KEYWORD_NAMES: &[&str] = &[
    "STATS_SAMPLE_PAGES",
    "GEOMETRYCOLLECTION",
    "STATS_AUTO_RECALC",
    "ENCRYPTION_KEY_ID",
    "CURRENT_TIMESTAMP",
    "STATS_PERSISTENT",
    "UNIQUEIDENTIFIER",
    "DELAY_KEY_WRITE",
    "MULTILINESTRING",
    "LOCALTIMESTAMP",
    "AUTO_INCREMENT",
    "AVG_ROW_LENGTH",
    "UNIX_TIMESTAMP",
    "LAST_INSERT_ID",
    "KEY_BLOCK_SIZE",
    "COLUMN_FORMAT",
    "CONNECTION_ID",
    "PAGE_CHECKSUM",
    "TRANSACTIONAL",
    "UTC_TIMESTAMP",
    "INSERT_METHOD",
    "SESSION_USER",
    "MULTIPOLYGON",
    "CURRENT_DATE",
    "CURRENT_TIME",
    "CURRENT_USER",
    "COMPRESSION",
    "IETF_QUOTES",
    "SYSTEM_TIME",
    "SYSTEM_USER",
    "VERSIONING",
    "MULTIPOINT",
    "LINESTRING",
    "CONNECTION",
    "MEDIUMBLOB",
    "COMPRESSED",
    "ENCRYPTION",
    "VALIDATION",
    "CONSTRAINT",
    "ROW_FORMAT",
    "UUID_SHORT",
    "FOUND_ROWS",
    "TABLESPACE",
    "REFERENCES",
    "MEDIUMTEXT",
    "VARBINARY",
    "TEMPORARY",
    "REDUNDANT",
    "EXCLUSIVE",
    "ROW_COUNT",
    "LOCALTIME",
    "MEDIUMINT",
    "TIMESTAMP",
    "DIRECTORY",
    "INVISIBLE",
    "PACK_KEYS",
    "ALGORITHM",
    "CHARACTER",
    "TINYBLOB",
    "UTC_TIME",
    "NATIONAL",
    "FULLTEXT",
    "GEOMETRY",
    "MAX_ROWS",
    "DATABASE",
    "LONGBLOB",
    "UNSIGNED",
    "TINYTEXT",
    "DATETIME",
    "MIN_ROWS",
    "ZEROFILL",
    "UTC_DATE",
    "PASSWORD",
    "CHECKSUM",
    "RESTRICT",
    "LONGTEXT",
    "SMALLINT",
    "NVARCHAR",
    "CONVERT",
    "SPATIAL",
    "INPLACE",
    "STORAGE",
    "SYSDATE",
    "FOREIGN",
    "TINYINT",
    "DYNAMIC",
    "DISCARD",
    "DISABLE",
    "DEFAULT",
    "DECIMAL",
    "CURTIME",
    "CURDATE",
    "INTEGER",
    "COMPACT",
    "COMMENT",
    "COLLATE",
    "REPLACE",
    "CHARSET",
    "CASCADE",
    "BOOLEAN",
    "NUMERIC",
    "OFFLINE",
    "PRIMARY",
    "POLYGON",
    "VARCHAR",
    "VERSION",
    "WITHOUT",
    "PARTIAL",
    "ENABLE",
    "MEMORY",
    "CREATE",
    "MODIFY",
    "DELETE",
    "ENGINE",
    "UPDATE",
    "BIGINT",
    "SYSTEM",
    "SIMPLE",
    "EXISTS",
    "RENAME",
    "BINARY",
    "NOWAIT",
    "IGNORE",
    "SHARED",
    "IMPORT",
    "ACTION",
    "ONLINE",
    "SCHEMA",
    "PERIOD",
    "UNIQUE",
    "DOUBLE",
    "CHANGE",
    "PARSER",
    "COLUMN",
    "INDEX",
    "FLOAT",
    "POINT",
    "ALTER",
    "ROUND",
    "NCHAR",
    "MATCH",
    "RTREE",
    "BTREE",
    "AFTER",
    "USING",
    "FORCE",
    "TABLE",
    "ORDER",
    "FIXED",
    "FIRST",
    "FALSE",
    "UNION",
    "UUID",
    "LOCK",
    "LIKE",
    "LAST",
    "KEYS",
    "CHAR",
    "JSON",
    "COPY",
    "WAIT",
    "NONE",
    "HASH",
    "FULL",
    "BLOB",
    "YEAR",
    "USER",
    "PAGE",
    "TEXT",
    "TIME",
    "RAND",
    "NULL",
    "BOOL",
    "ENUM",
    "DATA",
    "DROP",
    "TRUE",
    "WITH",
    "DISK",
    "DESC",
    "DATE",
    "ZLIB",
    "BIT",
    "YES",
    "INT",
    "KEY",
    "NOW",
    "SET",
    "ADD",
    "LZ4",
    "NOT",
    "FOR",
    "ASC",
    "USE",
    "AS",
    "NO",
    "BY",
    "ON",
    "OR",
    "IF",
    "PI",
    "TO",
];

/// A keyword name paired with its characters for matching.
pub struct Keyword {
    /// Uppercase keyword name, also the token kind payload.
    pub name: &'static str,
    /// The keyword characters, used for case-insensitive comparison.
    pub letters: Vec<char>,
}

/// Lazily built keyword table in declaration order.
pub struct Keywords(Vec<Keyword>);

impl Keywords {
    /// Iterate over the keywords in declaration order.
    pub fn iter(&self) -> impl Iterator<Item = (&&'static str, &[char])> {
        self.0.iter().map(|k| (&k.name, k.letters.as_slice()))
    }
}

/// The shared keyword table.
pub static KEYWORDS: KeywordTable = KeywordTable;

/// Zero-sized handle that derefs to the built table.
pub struct KeywordTable;

impl std::ops::Deref for KeywordTable {
    type Target = Keywords;

    fn deref(&self) -> &Self::Target {
        static TABLE: OnceLock<Keywords> = OnceLock::new();
        TABLE.get_or_init(|| {
            Keywords(
                KEYWORD_NAMES
                    .iter()
                    .map(|name| Keyword {
                        name,
                        letters: name.chars().collect(),
                    })
                    .collect(),
            )
        })
    }
}