package core import ( "fmt" "regexp" "strings" ) var rewriteFieldPattern = regexp.MustCompile(`\b([a-zA-Z_][a-zA-Z0-9_]*)\b`) var rewriteSQLKeywords = map[string]bool{ "AND": true, "OR": true, "NOT": true, "IS": true, "NULL": true, "IN": true, "BETWEEN": true, "LIKE": true, "GLOB": true, "TRUE": true, "FALSE": true, "CASE": true, "WHEN": true, "THEN": true, "ELSE": true, "END": true, "SELECT": true, "FROM": true, "WHERE": true, "AS": true, "CAST": true, } var rewriteSQLFunctions = map[string]bool{ "json_extract": true, "datetime": true, "now": true, "abs": true, "avg": true, "count": true, "max": true, "min": true, "sum": true, "total": true, "length": true, "typeof": true, "coalesce": true, "ifnull": true, "nullif": true, "upper": true, "lower": true, "trim": true, "replace": true, "substr": true, "instr": true, "round": true, } // RewriteRule transforms a rule expression so that bare field names become // json_extract calls on a given JSON column. // For example, with column "metadata": // // "price > 100 AND status IS NOT NULL" // // becomes: // // "json_extract(metadata, '$.price') > 100 AND json_extract(metadata, '$.status') IS NOT NULL" // // If the rule already contains json_extract, it is returned as-is. // SQL keywords and common SQL functions are preserved. func RewriteRule(rule, jsonColumn string) string { if strings.Contains(rule, "json_extract") { return rule } return rewriteFieldPattern.ReplaceAllStringFunc(rule, func(match string) string { upper := strings.ToUpper(match) if rewriteSQLKeywords[upper] { return match } if rewriteSQLFunctions[strings.ToLower(match)] { return match } if match[0] >= '0' && match[0] <= '9' { return match } return fmt.Sprintf("json_extract(%s, '$.%s')", jsonColumn, match) }) }