iridium-db 0.2.0

A high-performance vector-graph hybrid storage and indexing engine
use super::{Ast, BitmapPredicate, ProjectionItem, VectorPredicate, WhereClause};

pub(super) fn ast_to_json_pretty(ast: &Ast) -> String {
    let predicate = ast
        .where_predicate
        .as_ref()
        .map(vector_predicate_json)
        .unwrap_or_else(|| "null".to_string());
    let bitmap_predicate = ast
        .where_bitmap_predicate
        .as_ref()
        .map(bitmap_predicate_json)
        .unwrap_or_else(|| "null".to_string());
    let where_clause = ast
        .where_clause
        .as_ref()
        .map(where_clause_json)
        .unwrap_or_else(|| "null".to_string());
    let with_items = projections_json(&ast.with_items);
    let return_items = projections_json(&ast.return_items);
    let match_aliases = ast
        .match_aliases
        .iter()
        .map(|alias| format!("\"{}\"", alias))
        .collect::<Vec<_>>()
        .join(", ");
    let limit = ast
        .limit
        .map(|v| v.to_string())
        .unwrap_or_else(|| "null".to_string());

    format!(
        concat!(
            "{{\n",
            "  \"match\": {{ \"aliases\": [{}], \"primary_alias\": \"{}\" }},\n",
            "  \"where\": {},\n",
            "  \"where_vector\": {},\n",
            "  \"where_bitmap\": {},\n",
            "  \"with\": [{}],\n",
            "  \"return\": {{ \"items\": [{}], \"primary_alias\": \"{}\" }},\n",
            "  \"limit\": {}\n",
            "}}\n"
        ),
        match_aliases,
        ast.match_alias,
        where_clause,
        predicate,
        bitmap_predicate,
        with_items,
        return_items,
        ast.return_alias,
        limit
    )
}

fn projections_json(items: &[ProjectionItem]) -> String {
    items
        .iter()
        .map(|item| match item {
            ProjectionItem::Identifier(value) => format!("\"{}\"", value),
            ProjectionItem::Function {
                name,
                argument,
                alias,
            } => {
                if let Some(alias) = alias {
                    format!(
                        "{{\"function\":\"{}\",\"argument\":\"{}\",\"alias\":\"{}\"}}",
                        name, argument, alias
                    )
                } else {
                    format!(
                        "{{\"function\":\"{}\",\"argument\":\"{}\",\"alias\":null}}",
                        name, argument
                    )
                }
            }
        })
        .collect::<Vec<_>>()
        .join(", ")
}

fn vector_predicate_json(pred: &VectorPredicate) -> String {
    format!(
        concat!(
            "{{\n",
            "    \"function\": \"{}\",\n",
            "    \"target\": \"{}\",\n",
            "    \"param\": \"{}\",\n",
            "    \"operator\": \"{}\",\n",
            "    \"threshold\": \"{}\"\n",
            "  }}"
        ),
        pred.function, pred.target, pred.param, pred.operator, pred.threshold
    )
}

fn bitmap_predicate_json(pred: &BitmapPredicate) -> String {
    format!(
        concat!(
            "{{\n",
            "    \"function\": \"{}\",\n",
            "    \"index_name\": \"{}\",\n",
            "    \"value_key\": \"{}\"\n",
            "  }}"
        ),
        pred.function, pred.index_name, pred.value_key
    )
}

fn where_clause_json(where_clause: &WhereClause) -> String {
    match where_clause {
        WhereClause::Function {
            function,
            args,
            operator,
            threshold,
        } => format!(
            "{{\"kind\":\"function\",\"function\":\"{}\",\"args\":[{}],\"operator\":\"{}\",\"threshold\":\"{}\"}}",
            function,
            args.iter()
                .map(|arg| format!("\"{}\"", arg))
                .collect::<Vec<_>>()
                .join(", "),
            operator,
            threshold
        ),
        WhereClause::Comparison {
            left,
            operator,
            right,
        } => format!(
            "{{\"kind\":\"comparison\",\"left\":\"{}\",\"operator\":\"{}\",\"right\":\"{}\"}}",
            left, operator, right
        ),
    }
}