mirror of
https://github.com/hanzoai/o11y.git
synced 2026-10-15 12:58:33 +00:00
Completes the debrand on top of the driver/dscol work already on main: - Repoint to canonical native forks: hanzo-ds/sqlbuilder v1.42.2, hanzo-ds/sqlparser v0.4.16. - Datastore sql flavor now renders native ILIKE (v1.42.2); statement-builder test expectations updated from the LOWER(x) LIKE LOWER(?) emulation. - Mock: expose datastore-go-mock behind a brand-neutral datastoremock.Conn seam so first-party code names no ClickConnMockCommon symbol. - Scrub CH/SigNoz from comments; drop dead SigNoz tracker links. Zero clickhouse/signoz/CH in first-party Go and go.mod.
88 lines
2.5 KiB
Go
88 lines
2.5 KiB
Go
package datastore
|
|
|
|
import (
|
|
"fmt"
|
|
"slices"
|
|
"strings"
|
|
|
|
"github.com/hanzo-ds/sqlparser/parser"
|
|
"github.com/hanzoai/o11y/pkg/variables"
|
|
)
|
|
|
|
// VariableValue represents a variable's assigned value.
|
|
type VariableValue struct {
|
|
Name string
|
|
Values []string
|
|
IsSelectAll bool
|
|
FieldType string // "scalar", "array", "map", etc.
|
|
}
|
|
|
|
// QueryTransformer handles the transformation of queries based on variable values.
|
|
type QueryTransformer struct {
|
|
processor *QueryProcessor
|
|
variables map[string]VariableValue
|
|
originalSQL string
|
|
}
|
|
|
|
// NewQueryTransformer creates a new transformer with the given SQL and variables.
|
|
func NewQueryTransformer(sql string, vars []VariableValue) *QueryTransformer {
|
|
varMap := make(map[string]VariableValue)
|
|
for _, v := range vars {
|
|
if slices.Contains(variables.ReservedTimeVars, v.Name) {
|
|
continue
|
|
}
|
|
varMap[v.Name] = v
|
|
}
|
|
|
|
for _, v := range variables.ReservedTimeVars {
|
|
varMap[v] = VariableValue{
|
|
Name: v,
|
|
IsSelectAll: false,
|
|
FieldType: "scalar",
|
|
}
|
|
}
|
|
|
|
// for each variable, replace the `{{variable_name}}`, [[variable_name]], {{ .variable_name }}, {{.variable_name}}
|
|
// with $variable_name
|
|
for name := range varMap {
|
|
sql = strings.ReplaceAll(sql, fmt.Sprintf("{{%s}}", name), fmt.Sprintf("$%s", name))
|
|
sql = strings.ReplaceAll(sql, fmt.Sprintf("[[%s]]", name), fmt.Sprintf("$%s", name))
|
|
sql = strings.ReplaceAll(sql, fmt.Sprintf("{{ .%s }}", name), fmt.Sprintf("$%s", name))
|
|
sql = strings.ReplaceAll(sql, fmt.Sprintf("{{.%s}}", name), fmt.Sprintf("$%s", name))
|
|
}
|
|
|
|
return &QueryTransformer{
|
|
processor: NewQueryProcessor(),
|
|
variables: varMap,
|
|
originalSQL: sql,
|
|
}
|
|
}
|
|
|
|
// Transform processes the query and returns a transformed version.
|
|
func (t *QueryTransformer) Transform() (string, error) {
|
|
return t.processor.ProcessQuery(t.originalSQL, t.transformFilter)
|
|
}
|
|
|
|
// transformFilter is the callback function that decides what to do with each filter.
|
|
func (t *QueryTransformer) transformFilter(variableName string, expr parser.Expr) FilterAction {
|
|
// Check if we have info about this variable
|
|
varInfo, exists := t.variables[variableName]
|
|
if !exists {
|
|
// If we don't have info, keep the filter as is
|
|
return KeepFilter
|
|
}
|
|
|
|
// If the user selected "__all__", we should remove the filter
|
|
if varInfo.IsSelectAll {
|
|
return RemoveFilter
|
|
}
|
|
|
|
// For maps, we might want to check for existence rather than equality
|
|
if varInfo.FieldType == "map" {
|
|
return ReplaceWithExistsCheck
|
|
}
|
|
|
|
// Otherwise keep the filter as is (it will be filled with the actual values)
|
|
return KeepFilter
|
|
}
|