heliosdb-nano 3.60.7

PostgreSQL-compatible embedded database with TDE + ZKE encryption, HNSW vector search, Product Quantization, git-like branching, time-travel queries, materialized views, row-level security, and 50+ enterprise features
Documentation
//! Auto-completion for SQL keywords and table names

use rustyline::completion::{Completer, Pair};
use rustyline::Context;
use rustyline::Result as RustyResult;

/// SQL keyword completer
pub struct SqlCompleter {
    keywords: Vec<String>,
    table_names: Vec<String>,
}

impl SqlCompleter {
    /// Create a new SQL completer
    pub fn new() -> Self {
        Self {
            keywords: Self::default_keywords(),
            table_names: Vec::new(),
        }
    }

    /// Update table names for completion
    pub fn set_table_names(&mut self, tables: Vec<String>) {
        self.table_names = tables;
    }

    /// Default SQL keywords
    fn default_keywords() -> Vec<String> {
        vec![
            // DDL
            "CREATE",
            "DROP",
            "ALTER",
            "TRUNCATE",
            "TABLE",
            "INDEX",
            "VIEW",
            "DATABASE",
            "SCHEMA",
            // DML
            "SELECT",
            "INSERT",
            "UPDATE",
            "DELETE",
            "FROM",
            "WHERE",
            "JOIN",
            "ON",
            "USING",
            "GROUP BY",
            "HAVING",
            "ORDER BY",
            "LIMIT",
            "OFFSET",
            "INNER JOIN",
            "LEFT JOIN",
            "RIGHT JOIN",
            "FULL JOIN",
            "CROSS JOIN",
            // Clauses
            "AND",
            "OR",
            "NOT",
            "IN",
            "BETWEEN",
            "LIKE",
            "IS",
            "NULL",
            "TRUE",
            "FALSE",
            "AS",
            "DISTINCT",
            "ALL",
            "ANY",
            "SOME",
            "EXISTS",
            // Functions
            "COUNT",
            "SUM",
            "AVG",
            "MIN",
            "MAX",
            "UPPER",
            "LOWER",
            "LENGTH",
            "SUBSTR",
            "TRIM",
            "NOW",
            "CURRENT_DATE",
            "CURRENT_TIME",
            "CURRENT_TIMESTAMP",
            // Data Types
            "INT",
            "INTEGER",
            "BIGINT",
            "SMALLINT",
            "FLOAT",
            "DOUBLE",
            "NUMERIC",
            "DECIMAL",
            "TEXT",
            "VARCHAR",
            "CHAR",
            "BOOLEAN",
            "BOOL",
            "DATE",
            "TIME",
            "TIMESTAMP",
            "TIMESTAMPTZ",
            "BYTEA",
            "JSONB",
            // Constraints
            "PRIMARY KEY",
            "FOREIGN KEY",
            "UNIQUE",
            "NOT NULL",
            "CHECK",
            "DEFAULT",
            "REFERENCES",
            // Transaction
            "BEGIN",
            "COMMIT",
            "ROLLBACK",
            "SAVEPOINT",
            "START TRANSACTION",
            // Other
            "SET",
            "SHOW",
            "EXPLAIN",
            "ANALYZE",
            "UNION",
            "INTERSECT",
            "EXCEPT",
            "WITH",
            "CASE",
            "WHEN",
            "THEN",
            "ELSE",
            "END",
        ]
        .iter()
        .map(|s| s.to_string())
        .collect()
    }

    /// Find completions for the given word
    fn find_completions(&self, word: &str) -> Vec<String> {
        let word_upper = word.to_uppercase();
        let mut completions = Vec::new();

        // Match SQL keywords
        for keyword in &self.keywords {
            if keyword.starts_with(&word_upper) {
                completions.push(keyword.clone());
            }
        }

        // Match table names (case-insensitive)
        for table in &self.table_names {
            if table.to_uppercase().starts_with(&word_upper) {
                completions.push(table.clone());
            }
        }

        completions.sort();
        completions.dedup();
        completions
    }
}

impl Completer for SqlCompleter {
    type Candidate = Pair;

    fn complete(&self, line: &str, pos: usize, _ctx: &Context<'_>) -> RustyResult<(usize, Vec<Pair>)> {
        // Find the word to complete
        let start = line[..pos]
            .rfind(|c: char| c.is_whitespace() || "(),;".contains(c))
            .map(|i| i + 1)
            .unwrap_or(0);

        let word = &line[start..pos];

        if word.is_empty() {
            return Ok((pos, Vec::new()));
        }

        let completions = self.find_completions(word);

        let pairs = completions
            .into_iter()
            .map(|s| Pair {
                display: s.clone(),
                replacement: s,
            })
            .collect();

        Ok((start, pairs))
    }
}

impl Default for SqlCompleter {
    fn default() -> Self {
        Self::new()
    }
}