package com.cube.sql;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Enhanced SQL Parser with Cubic Index support
*
* Additional syntax:
* - CREATE INDEX idx_name ON table(column)
* - DROP INDEX idx_name
* - SHOW INDEXES ON table
*/
public class CubicIndexSQLParser {
// Patterns for index-related SQL
private static final Pattern CREATE_INDEX_PATTERN = Pattern.compile(
"CREATE\\s+INDEX\\s+(\\w+)\\s+ON\\s+([\\w.]+)\\s*\\(\\s*(\\w+)\\s*\\)",
Pattern.CASE_INSENSITIVE
);
private static final Pattern DROP_INDEX_PATTERN = Pattern.compile(
"DROP\\s+INDEX\\s+(\\w+)",
Pattern.CASE_INSENSITIVE
);
private static final Pattern SHOW_INDEXES_PATTERN = Pattern.compile(
"SHOW\\s+INDEXES\\s+ON\\s+([\\w.]+)",
Pattern.CASE_INSENSITIVE
);
/**
* Parse SQL with index support
*/
public static IndexedParsedSQL parseWithIndex(String sql) {
if (sql == null || sql.trim().isEmpty()) {
throw new IllegalArgumentException("SQL statement is empty");
}
sql = sql.trim();
if (sql.endsWith(";")) {
sql = sql.substring(0, sql.length() - 1).trim();
}
String upperSQL = sql.toUpperCase();
// Check for index-specific commands
if (upperSQL.startsWith("CREATE INDEX")) {
return parseCreateIndex(sql);
} else if (upperSQL.startsWith("DROP INDEX")) {
return parseDropIndex(sql);
} else if (upperSQL.startsWith("SHOW INDEXES")) {
return parseShowIndexes(sql);
}
// Fall back to regular SQL parsing
SQLParser.ParsedSQL parsed = SQLParser.parse(sql);
return convertToIndexed(parsed, sql);
}
/**
* Parse CREATE INDEX statement
*
* Syntax: CREATE INDEX idx_name ON table(column)
* Example: CREATE INDEX idx_email ON users(email)
*/
private static IndexedParsedSQL parseCreateIndex(String sql) {
Matcher matcher = CREATE_INDEX_PATTERN.matcher(sql);
if (!matcher.find()) {
throw new IllegalArgumentException("Invalid CREATE INDEX syntax: " + sql);
}
String indexName = matcher.group(1);
String tableName = matcher.group(2);
String columnName = matcher.group(3);
// Parse table name (might include keyspace)
String keyspace = "default";
String table = tableName;
if (tableName.contains(".")) {
String[] parts = tableName.split("\\.");
keyspace = parts[0];
table = parts[1];
}
return new IndexedParsedSQL.Builder()
.type(SQLParser.SQLType.CREATE_INDEX)
.keyspace(keyspace)
.table(table)
.indexName(indexName)
.indexColumn(columnName)
.indexType(IndexedParsedSQL.IndexType.CUBIC)
.originalSQL(sql)
.build();
}
/**
* Parse DROP INDEX statement
*
* Syntax: DROP INDEX idx_name
* Example: DROP INDEX idx_email
*/
private static IndexedParsedSQL parseDropIndex(String sql) {
Matcher matcher = DROP_INDEX_PATTERN.matcher(sql);
if (!matcher.find()) {
throw new IllegalArgumentException("Invalid DROP INDEX syntax: " + sql);
}
String indexName = matcher.group(1);
return new IndexedParsedSQL.Builder()
.type(SQLParser.SQLType.DROP_INDEX)
.indexName(indexName)
.originalSQL(sql)
.build();
}
/**
* Parse SHOW INDEXES statement
*
* Syntax: SHOW INDEXES ON table
* Example: SHOW INDEXES ON users
*/
private static IndexedParsedSQL parseShowIndexes(String sql) {
Matcher matcher = SHOW_INDEXES_PATTERN.matcher(sql);
if (!matcher.find()) {
throw new IllegalArgumentException("Invalid SHOW INDEXES syntax: " + sql);
}
String tableName = matcher.group(1);
// Parse table name
String keyspace = "default";
String table = tableName;
if (tableName.contains(".")) {
String[] parts = tableName.split("\\.");
keyspace = parts[0];
table = parts[1];
}
return new IndexedParsedSQL.Builder()
.type(SQLParser.SQLType.SHOW_INDEXES)
.keyspace(keyspace)
.table(table)
.originalSQL(sql)
.build();
}
/**
* Convert regular ParsedSQL to IndexedParsedSQL
*/
private static IndexedParsedSQL convertToIndexed(SQLParser.ParsedSQL parsed, String originalSQL) {
// Determine primary key from column definitions
String primaryKey = parsed.getPrimaryKey();
if (primaryKey == null && parsed.getColumnDefinitions() != null) {
primaryKey = parsed.getColumnDefinitions().keySet().iterator().hasNext() ?
parsed.getColumnDefinitions().keySet().iterator().next() : null;
}
return new IndexedParsedSQL.Builder()
.type(parsed.getType())
.keyspace(parsed.getKeyspace())
.table(parsed.getTable())
.columns(parsed.getColumns())
.whereClause(parsed.getWhereClause())
.selectColumns(parsed.getSelectColumns())
.columnDefinitions(parsed.getColumnDefinitions())
.primaryKey(primaryKey)
.indexType(IndexedParsedSQL.IndexType.PRIMARY)
.originalSQL(originalSQL)
.build();
}
/**
* Validate index name
*/
public static boolean isValidIndexName(String indexName) {
return indexName != null && indexName.matches("[a-zA-Z_][a-zA-Z0-9_]*");
}
/**
* Generate index key for storage
*/
public static String generateIndexKey(String keyspace, String table, String column) {
return keyspace + "." + table + "." + column;
}
/**
* Parse index key
*/
public static String[] parseIndexKey(String indexKey) {
if (indexKey == null) {
return null;
}
String[] parts = indexKey.split("\\.");
if (parts.length != 3) {
return null;
}
return parts; // [keyspace, table, column]
}
}