Skip to main content

cqlite_core/cql/
mod.rs

1//! # CQL Text Parsing Module
2//!
3//! Parses CQL (Cassandra Query Language) query strings into Abstract Syntax Trees.
4//!
5//! This is one of four parsing subsystems in cqlite-core:
6//!
7//! | Module | Purpose |
8//! |--------|---------|
9//! | **`cql/`** | Full CQL text → AST parsing (this module) |
10//! | `parser/` | SSTable binary format parsing |
11//! | `schema/cql_parser.rs` | CREATE TABLE → TableSchema |
12//! | `query/parser.rs` | Lightweight DML → ParsedQuery |
13//!
14//! See `docs/architecture/parser-overview.md` for the complete architecture overview.
15//!
16//! ## Available Backends
17//!
18//! - **Nom**: High-performance parser combinator implementation (recommended)
19//! - **ANTLR**: Grammar-based parsing (placeholder for future development)
20//!
21//! ## Usage
22//!
23//! ```rust,ignore
24//! use cqlite_core::cql::{create_default_parser, CqlStatement};
25//!
26//! let parser = create_default_parser()?;
27//! let statement = parser.parse("SELECT * FROM users").await?;
28//! ```
29
30pub mod ast;
31pub mod config;
32pub mod error;
33pub mod traits;
34pub mod visitor;
35
36pub mod antlr_backend;
37pub mod nom_backend;
38
39#[cfg(feature = "write-support")]
40pub mod mutation_parser;
41
42pub mod factory;
43pub mod schema_integration;
44
45pub use ast::{
46    CqlAssignment, CqlAssignmentOperator, CqlBinaryOperator, CqlColumnDef, CqlCreateTable,
47    CqlDataType, CqlDelete, CqlDropTable, CqlExpression, CqlIdentifier, CqlInsert, CqlInsertValues,
48    CqlLiteral, CqlOrderBy, CqlPrimaryKey, CqlSelect, CqlSelectItem, CqlSortDirection,
49    CqlStatement, CqlTable, CqlTableOptions, CqlUnaryOperator, CqlUpdate, CqlUsing,
50};
51pub use config::{
52    MemorySettings, ParserBackend, ParserConfig, ParserFeature as ConfigFeature,
53    PerformanceSettings, SecuritySettings,
54};
55pub use error::{ErrorCategory as ParserErrorCategory, ErrorSeverity, ParserError, ParserWarning};
56pub use factory::{register_global_factory, ParserFactory, ParserRegistry, UseCase};
57pub use schema_integration::{
58    extract_table_name_enhanced, parse_cql_schema_enhanced, parse_cql_schema_fast,
59    parse_cql_schema_simple, parse_cql_schema_strict, parse_cql_schemas_batch,
60    table_name_matches_enhanced, validate_cql_schema_syntax, SchemaParserConfig,
61};
62pub use traits::{
63    CqlParser, CqlParserFactory, CqlVisitor, FactoryInfo, ParserBackendInfo, ParserFeature,
64    PerformanceCharacteristics, SourcePosition,
65};
66pub use visitor::{
67    DefaultVisitor, IdentifierCollector, SchemaBuilderVisitor, SemanticValidator,
68    TypeCollectorVisitor, ValidationVisitor,
69};
70
71#[allow(deprecated)]
72pub use schema_integration::parse_cql_schema_compat;
73
74pub use antlr_backend::AntlrParser;
75pub use nom_backend::NomParser;
76
77pub use crate::error::Result as CqlResult;
78
79use crate::error::Result;
80use std::sync::Arc;
81
82/// Convenience function to create a default parser.
83pub fn create_default_parser() -> Result<Arc<dyn CqlParser + Send + Sync>> {
84    ParserFactory::create_default()
85}
86
87/// Detect whether a CQL statement is a Data Manipulation Language (DML) statement.
88///
89/// Returns `true` for statements that write data — `INSERT`, `UPDATE`, `DELETE`, or
90/// `BEGIN` (which begins a `BATCH` block). Detection is done by case-insensitive
91/// prefix matching on the trimmed input, so it is suitable for routing read vs.
92/// write paths *before* full parsing.
93///
94/// # Examples
95///
96/// ```
97/// use cqlite_core::cql::is_dml_statement;
98///
99/// assert!(is_dml_statement("INSERT INTO t (id) VALUES (1)"));
100/// assert!(is_dml_statement("insert into t (id) values (1)"));
101/// assert!(is_dml_statement("UPDATE t SET x = 1 WHERE id = 1"));
102/// assert!(is_dml_statement("DELETE FROM t WHERE id = 1"));
103/// assert!(is_dml_statement("BEGIN BATCH INSERT INTO t (id) VALUES (1) APPLY BATCH"));
104/// assert!(!is_dml_statement("SELECT * FROM t"));
105/// assert!(!is_dml_statement("  CREATE TABLE t (id int PRIMARY KEY)"));
106/// ```
107pub fn is_dml_statement(s: &str) -> bool {
108    let upper = s.trim().to_uppercase();
109    upper.starts_with("INSERT")
110        || upper.starts_with("UPDATE")
111        || upper.starts_with("DELETE")
112        || upper.starts_with("BEGIN")
113}