use std::collections::HashMap;
use vibesql_storage::Database;
use vibesql_types::SqlValue;
use crate::evaluator::ExpressionEvaluator;
pub fn maintain_expression_indexes_for_insert(
db: &mut Database,
table_name: &str,
row: &vibesql_storage::Row,
row_index: usize,
) {
if !db.has_expression_indexes(table_name) {
return;
}
let table_schema = match db.catalog.get_table(table_name) {
Some(schema) => schema.clone(),
None => return,
};
let expression_indexes = db.get_expression_indexes_for_table(table_name);
if expression_indexes.is_empty() {
return;
}
let evaluator = ExpressionEvaluator::new(&table_schema);
let mut expression_keys: HashMap<String, Vec<SqlValue>> = HashMap::new();
for (index_name, metadata) in expression_indexes {
let mut key_values = Vec::new();
for col in &metadata.columns {
let value = if let Some(expr) = col.get_expression() {
match evaluator.eval(expr, row) {
Ok(v) => v,
Err(e) => {
log::warn!(
"Failed to evaluate expression for index '{}' during insert: {:?}",
index_name,
e
);
SqlValue::Null
}
}
} else if let Some(col_name) = col.column_name() {
if let Some(col_idx) = table_schema.get_column_index(col_name) {
row.values[col_idx].clone()
} else {
SqlValue::Null
}
} else {
SqlValue::Null
};
key_values.push(value);
}
expression_keys.insert(index_name, key_values);
}
db.add_to_expression_indexes_for_insert(table_name, row_index, &expression_keys);
}
pub fn maintain_expression_indexes_for_update(
db: &mut Database,
table_name: &str,
old_row: &vibesql_storage::Row,
new_row: &vibesql_storage::Row,
row_index: usize,
) {
if !db.has_expression_indexes(table_name) {
return;
}
let table_schema = match db.catalog.get_table(table_name) {
Some(schema) => schema.clone(),
None => return,
};
let expression_indexes = db.get_expression_indexes_for_table(table_name);
if expression_indexes.is_empty() {
return;
}
let evaluator = ExpressionEvaluator::new(&table_schema);
let mut old_expression_keys: HashMap<String, Vec<SqlValue>> = HashMap::new();
let mut new_expression_keys: HashMap<String, Vec<SqlValue>> = HashMap::new();
for (index_name, metadata) in expression_indexes {
let mut old_key_values = Vec::new();
let mut new_key_values = Vec::new();
for col in &metadata.columns {
let (old_value, new_value) = if let Some(expr) = col.get_expression() {
let old_val = match evaluator.eval(expr, old_row) {
Ok(v) => v,
Err(e) => {
log::warn!(
"Failed to evaluate expression for index '{}' (old row) during update: {:?}",
index_name,
e
);
SqlValue::Null
}
};
let new_val = match evaluator.eval(expr, new_row) {
Ok(v) => v,
Err(e) => {
log::warn!(
"Failed to evaluate expression for index '{}' (new row) during update: {:?}",
index_name,
e
);
SqlValue::Null
}
};
(old_val, new_val)
} else if let Some(col_name) = col.column_name() {
if let Some(col_idx) = table_schema.get_column_index(col_name) {
(old_row.values[col_idx].clone(), new_row.values[col_idx].clone())
} else {
(SqlValue::Null, SqlValue::Null)
}
} else {
(SqlValue::Null, SqlValue::Null)
};
old_key_values.push(old_value);
new_key_values.push(new_value);
}
old_expression_keys.insert(index_name.clone(), old_key_values);
new_expression_keys.insert(index_name, new_key_values);
}
db.update_expression_indexes_for_update(
table_name,
row_index,
&old_expression_keys,
&new_expression_keys,
);
}
pub fn maintain_expression_indexes_for_delete(
db: &mut Database,
table_name: &str,
row: &vibesql_storage::Row,
row_index: usize,
) {
if !db.has_expression_indexes(table_name) {
return;
}
let table_schema = match db.catalog.get_table(table_name) {
Some(schema) => schema.clone(),
None => return,
};
let expression_indexes = db.get_expression_indexes_for_table(table_name);
if expression_indexes.is_empty() {
return;
}
let evaluator = ExpressionEvaluator::new(&table_schema);
let mut expression_keys: HashMap<String, Vec<SqlValue>> = HashMap::new();
for (index_name, metadata) in expression_indexes {
let mut key_values = Vec::new();
for col in &metadata.columns {
let value = if let Some(expr) = col.get_expression() {
match evaluator.eval(expr, row) {
Ok(v) => v,
Err(e) => {
log::warn!(
"Failed to evaluate expression for index '{}' during delete: {:?}",
index_name,
e
);
SqlValue::Null
}
}
} else if let Some(col_name) = col.column_name() {
if let Some(col_idx) = table_schema.get_column_index(col_name) {
row.values[col_idx].clone()
} else {
SqlValue::Null
}
} else {
SqlValue::Null
};
key_values.push(value);
}
expression_keys.insert(index_name, key_values);
}
db.update_expression_indexes_for_delete(table_name, row_index, &expression_keys);
}
pub fn rebuild_expression_indexes_after_compaction(db: &mut Database, table_name: &str) {
if !db.has_expression_indexes(table_name) {
return;
}
let table_schema = match db.catalog.get_table(table_name) {
Some(schema) => schema.clone(),
None => return,
};
let rows: Vec<vibesql_storage::Row> = match db.get_table(table_name) {
Some(table) => table.scan().to_vec(),
None => return,
};
let expression_indexes: Vec<(String, vibesql_storage::database::indexes::IndexMetadata)> = db
.get_expression_indexes_for_table(table_name)
.into_iter()
.map(|(name, metadata)| (name, metadata.clone()))
.collect();
if expression_indexes.is_empty() {
return;
}
let evaluator = ExpressionEvaluator::new(&table_schema);
db.clear_expression_index_data(table_name);
for (row_index, row) in rows.iter().enumerate() {
let mut expression_keys: HashMap<String, Vec<SqlValue>> = HashMap::new();
for (index_name, metadata) in &expression_indexes {
let mut key_values = Vec::new();
for col in &metadata.columns {
let value = if let Some(expr) = col.get_expression() {
match evaluator.eval(expr, row) {
Ok(v) => v,
Err(e) => {
log::warn!(
"Failed to evaluate expression for index '{}' during rebuild: {:?}",
index_name,
e
);
SqlValue::Null
}
}
} else if let Some(col_name) = col.column_name() {
if let Some(col_idx) = table_schema.get_column_index(col_name) {
row.values[col_idx].clone()
} else {
SqlValue::Null
}
} else {
SqlValue::Null
};
key_values.push(value);
}
expression_keys.insert(index_name.clone(), key_values);
}
db.add_to_expression_indexes_for_insert(table_name, row_index, &expression_keys);
}
}