fix: wherecluase fixes

Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com>
This commit is contained in:
Shivanshu Raj Shrivastava 2025-05-05 06:31:48 +05:30
parent bad8aa7899
commit 6faf323f00
No known key found for this signature in database
GPG Key ID: D34D26C62AC3E9AE
2 changed files with 120 additions and 28 deletions

View File

@ -4,6 +4,14 @@ import (
"fmt"
)
// Helper function to format clause with AND if not empty
func formatClause(clause string) string {
if clause == "" {
return ""
}
return fmt.Sprintf("AND %s", clause)
}
func BuildTwoStepFunnelValidationQuery(
containsErrorT1 int,
containsErrorT2 int,
@ -87,8 +95,8 @@ LIMIT 5;`
spanNameT1,
serviceNameT2,
spanNameT2,
clauseStep1,
clauseStep2,
formatClause(clauseStep1),
formatClause(clauseStep2),
)
return query
@ -205,9 +213,9 @@ LIMIT 5;`
spanNameT2,
serviceNameT3,
spanNameT3,
clauseStep1,
clauseStep2,
clauseStep3,
formatClause(clauseStep1),
formatClause(clauseStep2),
formatClause(clauseStep3),
)
return query
@ -307,8 +315,8 @@ FROM joined;`
spanNameT1,
serviceNameT2,
spanNameT2,
clauseStep1,
clauseStep2,
formatClause(clauseStep1),
formatClause(clauseStep2),
)
return query
@ -456,9 +464,9 @@ FROM joined_t3;`
spanNameT2,
serviceNameT3,
spanNameT3,
clauseStep1,
clauseStep2,
clauseStep3,
formatClause(clauseStep1),
formatClause(clauseStep2),
formatClause(clauseStep3),
)
return query
@ -603,9 +611,9 @@ FROM joined_t3;`
spanNameT2,
serviceNameT3,
spanNameT3,
clauseStep1,
clauseStep2,
clauseStep3,
formatClause(clauseStep1),
formatClause(clauseStep2),
formatClause(clauseStep3),
)
return query
@ -700,8 +708,8 @@ FROM joined;`
spanNameT1,
serviceNameT2,
spanNameT2,
clauseStep1,
clauseStep2,
formatClause(clauseStep1),
formatClause(clauseStep2),
)
return query
@ -840,9 +848,9 @@ FROM joined_t3;`
spanNameT2,
serviceNameT3,
spanNameT3,
clauseStep1,
clauseStep2,
clauseStep3,
formatClause(clauseStep1),
formatClause(clauseStep2),
formatClause(clauseStep3),
)
return query
@ -955,8 +963,8 @@ LIMIT 5;`
spanNameT1,
serviceNameT2,
spanNameT2,
clauseStep1,
clauseStep2,
formatClause(clauseStep1),
formatClause(clauseStep2),
)
return query
@ -1074,8 +1082,8 @@ LIMIT 5;`
spanNameT1,
serviceNameT2,
spanNameT2,
clauseStep1,
clauseStep2,
formatClause(clauseStep1),
formatClause(clauseStep2),
)
return query

View File

@ -1,22 +1,106 @@
package tracefunnel
import (
tracesv3 "github.com/SigNoz/signoz/pkg/query-service/app/traces/v3"
"fmt"
"strings"
v3 "github.com/SigNoz/signoz/pkg/query-service/model/v3"
"github.com/SigNoz/signoz/pkg/query-service/utils"
tracefunnel "github.com/SigNoz/signoz/pkg/types/tracefunnel"
)
func getColumnName(key v3.AttributeKey) string {
if key.IsColumn {
return key.Key
}
filterType, filterDataType := getClickhouseTracesColumnDataTypeAndType(key)
return fmt.Sprintf("%s%s['%s']", filterDataType, filterType, key.Key)
}
func getClickhouseTracesColumnDataTypeAndType(key v3.AttributeKey) (v3.AttributeKeyType, string) {
filterType := key.Type
filterDataType := "string"
if key.DataType == v3.AttributeKeyDataTypeFloat64 || key.DataType == v3.AttributeKeyDataTypeInt64 {
filterDataType = "number"
} else if key.DataType == v3.AttributeKeyDataTypeBool {
filterDataType = "bool"
}
if filterType == v3.AttributeKeyTypeTag {
filterType = "TagMap"
} else {
filterType = "resourceTagsMap"
filterDataType = ""
}
return filterType, filterDataType
}
// buildFilterClause converts a FilterSet into a SQL WHERE clause string
func buildFilterClause(filters *v3.FilterSet) string {
if filters == nil {
if filters == nil || len(filters.Items) == 0 {
return ""
}
clause, err := tracesv3.BuildTracesFilterQuery(filters)
if err != nil {
return ""
var conditions []string
for _, item := range filters.Items {
// Get the column name based on the key type
columnName := getColumnName(item.Key)
// Convert operator to lowercase for consistency
op := strings.ToLower(string(item.Operator))
// Format the value based on its type
var valueStr string
var err error
if op != "exists" && op != "nexists" {
item.Value, err = utils.ValidateAndCastValue(item.Value, item.Key.DataType)
if err != nil {
continue // Skip invalid values
}
valueStr = utils.ClickHouseFormattedValue(item.Value)
}
// Build the condition based on the operator
var condition string
switch op {
case "exists":
if item.Key.IsColumn {
condition = fmt.Sprintf("%s != ''", columnName)
} else {
columnType, columnDataType := getClickhouseTracesColumnDataTypeAndType(item.Key)
condition = fmt.Sprintf("has(%s%s, '%s')", columnDataType, columnType, item.Key.Key)
}
case "nexists":
if item.Key.IsColumn {
condition = fmt.Sprintf("%s = ''", columnName)
} else {
columnType, columnDataType := getClickhouseTracesColumnDataTypeAndType(item.Key)
condition = fmt.Sprintf("NOT has(%s%s, '%s')", columnDataType, columnType, item.Key.Key)
}
case "contains", "ncontains":
val := utils.QuoteEscapedString(fmt.Sprintf("%v", item.Value))
operator := "ILIKE"
if op == "ncontains" {
operator = "NOT ILIKE"
}
condition = fmt.Sprintf("%s %s '%%%s%%'", columnName, operator, val)
case "regex", "nregex":
operator := "match"
if op == "nregex" {
operator = "NOT match"
}
condition = fmt.Sprintf("%s(%s, %s)", operator, columnName, valueStr)
default:
condition = fmt.Sprintf("%s %s %s", columnName, strings.ToUpper(op), valueStr)
}
conditions = append(conditions, condition)
}
return clause
// Join conditions with the operator (AND/OR)
operator := strings.ToUpper(filters.Operator)
if operator == "" {
operator = "AND" // Default to AND if not specified
}
return strings.Join(conditions, fmt.Sprintf(" %s ", operator))
}
func ValidateTraces(funnel *tracefunnel.Funnel, timeRange tracefunnel.TimeRange) (*v3.ClickHouseQuery, error) {