use crate::error::Result;
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use std::fmt::{Debug, Display, Formatter};
use super::ast::*;
#[async_trait]
pub trait CqlParser: Debug + Send + Sync {
async fn parse(&self, input: &str) -> Result<CqlStatement>;
async fn parse_type(&self, input: &str) -> Result<CqlDataType>;
async fn parse_expression(&self, input: &str) -> Result<CqlExpression>;
async fn parse_identifier(&self, input: &str) -> Result<CqlIdentifier>;
async fn parse_literal(&self, input: &str) -> Result<CqlLiteral>;
async fn parse_column_definitions(&self, input: &str) -> Result<Vec<CqlColumnDef>>;
async fn parse_table_options(&self, input: &str) -> Result<CqlTableOptions>;
fn validate_syntax(&self, input: &str) -> bool;
fn backend_info(&self) -> ParserBackendInfo;
}
pub trait CqlVisitor<T>: Debug {
fn visit_statement(&mut self, statement: &CqlStatement) -> Result<T>;
fn visit_select(&mut self, select: &CqlSelect) -> Result<T>;
fn visit_insert(&mut self, insert: &CqlInsert) -> Result<T>;
fn visit_update(&mut self, update: &CqlUpdate) -> Result<T>;
fn visit_delete(&mut self, delete: &CqlDelete) -> Result<T>;
fn visit_create_table(&mut self, create: &CqlCreateTable) -> Result<T>;
fn visit_drop_table(&mut self, drop: &CqlDropTable) -> Result<T>;
fn visit_create_index(&mut self, create: &CqlCreateIndex) -> Result<T>;
fn visit_alter_table(&mut self, alter: &CqlAlterTable) -> Result<T>;
fn visit_data_type(&mut self, data_type: &CqlDataType) -> Result<T>;
fn visit_expression(&mut self, expression: &CqlExpression) -> Result<T>;
fn visit_identifier(&mut self, identifier: &CqlIdentifier) -> Result<T>;
fn visit_literal(&mut self, literal: &CqlLiteral) -> Result<T>;
}
#[derive(Debug, Clone, PartialEq)]
pub struct ParserBackendInfo {
pub name: String,
pub version: String,
pub features: Vec<ParserFeature>,
pub performance: PerformanceCharacteristics,
}
#[derive(Debug, Clone, PartialEq)]
pub enum ParserFeature {
Incremental,
ErrorRecovery,
SyntaxHighlighting,
CodeCompletion,
AstTransformation,
CustomOperators,
Streaming,
Parallel,
Caching,
}
#[derive(Debug, Clone, PartialEq)]
pub struct PerformanceCharacteristics {
pub statements_per_second: u32,
pub memory_per_statement: u32,
pub startup_time_ms: u32,
pub async_support: bool,
}
#[derive(Debug, Clone)]
pub struct ValidationContext {
pub schemas: std::collections::HashMap<String, crate::schema::TableSchema>,
pub udts: std::collections::HashMap<String, crate::types::UdtTypeDef>,
pub current_keyspace: Option<String>,
pub strictness: ValidationStrictness,
}
#[derive(Debug, Clone, PartialEq)]
pub enum ValidationStrictness {
Strict,
Lenient,
Permissive,
}
impl ValidationContext {
pub fn new() -> Self {
Self {
schemas: std::collections::HashMap::new(),
udts: std::collections::HashMap::new(),
current_keyspace: None,
strictness: ValidationStrictness::Strict,
}
}
}
impl Default for ValidationContext {
fn default() -> Self {
Self::new()
}
}
pub trait CqlParserFactory: Debug + Send + Sync {
fn create_parser(&self) -> Result<Box<dyn CqlParser>>;
fn create_parser_with_config(
&self,
config: super::config::ParserConfig,
) -> Result<Box<dyn CqlParser>>;
fn factory_info(&self) -> FactoryInfo;
}
#[derive(Debug, Clone)]
pub struct FactoryInfo {
pub name: String,
pub supported_backends: Vec<String>,
pub default_backend: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SourcePosition {
pub line: u32,
pub column: u32,
pub offset: u32,
pub length: u32,
}
impl SourcePosition {
pub fn new(line: u32, column: u32, offset: u32, length: u32) -> Self {
Self {
line,
column,
offset,
length,
}
}
pub fn start() -> Self {
Self::new(1, 1, 0, 0)
}
}
impl Display for SourcePosition {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "line {}, column {}", self.line, self.column)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_validation_context_creation() {
let ctx = ValidationContext::new();
assert_eq!(ctx.strictness, ValidationStrictness::Strict);
assert!(ctx.schemas.is_empty());
assert!(ctx.udts.is_empty());
assert!(ctx.current_keyspace.is_none());
}
#[test]
fn test_source_position() {
let pos = SourcePosition::new(10, 5, 100, 20);
assert_eq!(pos.line, 10);
assert_eq!(pos.column, 5);
assert_eq!(pos.offset, 100);
assert_eq!(pos.length, 20);
let start_pos = SourcePosition::start();
assert_eq!(start_pos.line, 1);
assert_eq!(start_pos.column, 1);
assert_eq!(start_pos.offset, 0);
}
#[test]
fn test_parser_backend_info() {
let info = ParserBackendInfo {
name: "test".to_string(),
version: "1.0.0".to_string(),
features: vec![ParserFeature::Incremental, ParserFeature::ErrorRecovery],
performance: PerformanceCharacteristics {
statements_per_second: 1000,
memory_per_statement: 1024,
startup_time_ms: 10,
async_support: true,
},
};
assert_eq!(info.name, "test");
assert_eq!(info.features.len(), 2);
assert!(info.performance.async_support);
}
}