flowcode-core 0.4.1-alpha

Core execution engine for FlowCode data scripting language
Documentation
// DuckDB Verb Mapping for FlowCode v0.4-alpha
// This file outlines the mapping of FlowCode operations to SQL queries for DuckDB.

use crate::types::TypedValue;
use std::error::Error;

/// Maps FlowCode operations (verbs) to SQL queries for execution in DuckDB.
/// This is part of Step 4.3 of the DuckDB Adapter MVP.
pub fn map_verb_to_sql(verb: &str, args: &[TypedValue]) -> Result<String, Box<dyn Error>> {
    match verb {
        "select" => map_select(args),
        "filter" => map_filter(args),
        "group" => map_group(args),
        "join" => map_join(args),
        "sort" => map_sort(args),
        _ => Err(format!("Unsupported verb for DuckDB mapping: {}", verb).into()),
    }
}

/// Maps the 'select' verb to a SQL SELECT statement.
fn map_select(args: &[TypedValue]) -> Result<String, Box<dyn Error>> {
    if args.is_empty() {
        return Err("Select verb requires at least one argument (table or columns)".into());
    }

    let mut columns = "*".to_string();
    let table = args[0].to_string();

    // If more args are provided, treat them as column names
    if args.len() > 1 {
        let column_args: Vec<String> = args[1..]
            .iter()
            .map(|arg| arg.to_string())
            .collect();
        if !column_args.is_empty() {
            columns = column_args.join(", ");
        }
    }

    Ok(format!("SELECT {} FROM {}", columns, table))
}

/// Maps the 'filter' verb to a SQL WHERE clause.
fn map_filter(args: &[TypedValue]) -> Result<String, Box<dyn Error>> {
    if args.len() < 2 {
        return Err("Filter verb requires a table and at least one condition".into());
    }

    // Placeholder: Assume first arg is a table
    let table = args[0].to_string();

    let conditions: Vec<String> = args[1..]
        .iter()
        .map(|arg| arg.to_string())
        .collect();

    if conditions.is_empty() {
        return Err("Filter verb requires valid condition arguments".into());
    }

    let condition_str = conditions.join(" AND ");
    Ok(format!("SELECT * FROM {} WHERE {}", table, condition_str))
}

/// Maps the 'group' verb to a SQL GROUP BY clause.
fn map_group(args: &[TypedValue]) -> Result<String, Box<dyn Error>> {
    if args.len() < 2 {
        return Err("Group verb requires a table and at least one grouping column".into());
    }

    // Placeholder: Assume first arg is a table
    let table = args[0].to_string();

    let group_columns: Vec<String> = args[1..]
        .iter()
        .map(|arg| arg.to_string())
        .collect();

    if group_columns.is_empty() {
        return Err("Group verb requires valid column arguments".into());
    }

    let group_str = group_columns.join(", ");
    Ok(format!("SELECT * FROM {} GROUP BY {}", table, group_str))
}

/// Maps the 'join' verb to a SQL JOIN clause.
fn map_join(args: &[TypedValue]) -> Result<String, Box<dyn Error>> {
    if args.len() < 3 {
        return Err("Join verb requires two tables and at least one join condition".into());
    }

    // Placeholder: Assume first two args are tables
    let table1 = args[0].to_string();
    let table2 = args[1].to_string();

    let conditions: Vec<String> = args[2..]
        .iter()
        .map(|arg| arg.to_string())
        .collect();

    if conditions.is_empty() {
        return Err("Join verb requires valid condition arguments".into());
    }

    let condition_str = conditions.join(" AND ");
    Ok(format!("SELECT * FROM {} JOIN {} ON {}", table1, table2, condition_str))
}

/// Maps the 'sort' verb to a SQL ORDER BY clause.
fn map_sort(args: &[TypedValue]) -> Result<String, Box<dyn Error>> {
    if args.len() < 2 {
        return Err("Sort verb requires a table and at least one sorting column".into());
    }

    // Placeholder: Assume first arg is a table
    let table = args[0].to_string();

    let sort_columns: Vec<String> = args[1..]
        .iter()
        .map(|arg| arg.to_string())
        .collect();

    if sort_columns.is_empty() {
        return Err("Sort verb requires valid column arguments".into());
    }

    let sort_str = sort_columns.join(", ");
    Ok(format!("SELECT * FROM {} ORDER BY {}", table, sort_str))
}