Compare commits

..

5 Commits

Author SHA1 Message Date
Piyush Singariya
4bac933968 chore: remove unused var 2026-06-02 19:28:20 +05:30
Piyush Singariya
8df70ed4be chore: minor changes 2026-06-02 19:27:25 +05:30
Piyush Singariya
806f1d0062 fix: direct use function 2026-06-02 19:23:25 +05:30
Piyush Singariya
19d7d5b2ad Merge branch 'fts-logs' into fts-3 2026-06-02 18:58:20 +05:30
Piyush Singariya
2f762a86b3 chore: changes based on review 2026-06-02 18:54:08 +05:30
26 changed files with 87 additions and 148 deletions

View File

@@ -112,7 +112,7 @@ functionCall
;
/*
* Search call: search(field) or search("query text")
* Search call: search() function
* First-class rule so search-specific semantics can be extended independently.
*/
searchCall

View File

@@ -105,6 +105,3 @@ func (c *conditionBuilder) ConditionFor(
return "", errors.NewInvalidInputf(errors.CodeInvalidInput, "unsupported operator: %v", operator)
}
func (c *conditionBuilder) ConditionForContext(_ context.Context, _ telemetrytypes.FieldContext, _ any, _ *sqlbuilder.SelectBuilder) (string, error) {
return "", nil
}

View File

@@ -64,7 +64,3 @@ func (m *fieldMapper) ColumnExpressionFor(ctx context.Context, tsStart, tsEnd ui
}
return fmt.Sprintf("%s AS `%s`", sqlbuilder.Escape(colName), field.Name), nil
}
func (m *fieldMapper) GetColumns(_ context.Context, _ telemetrytypes.FieldContext) []*schema.Column {
return nil
}

View File

@@ -120,6 +120,7 @@ func newProvider(
logAggExprRewriter,
telemetrylogs.DefaultFullTextColumn,
telemetrylogs.GetBodyJSONKey,
logConditionBuilder.ConditionForSearch,
flagger,
)

View File

@@ -88,6 +88,7 @@ func prepareQuerierForLogs(t *testing.T, telemetryStore telemetrystore.Telemetry
logAggExprRewriter,
telemetrylogs.DefaultFullTextColumn,
telemetrylogs.GetBodyJSONKey,
logConditionBuilder.ConditionForSearch,
fl,
)

View File

@@ -12,14 +12,6 @@ const (
// FullTextSearchDefaultWarning is emitted when a search() function call is used.
FullTextSearchDefaultWarning = "Full text searches across all fields and will be slow and expensive. Consider using specific field to search e.g. <context>.<field_key>:<type>"
// FTSInternalKey is the sentinel Name on TelemetryFieldKey instances that represent
// wildcard map searches (all attribute/resource keys+values). The unconventional value
// prevents collision with any real field name a user could type.
FTSInternalKey = "_X_INTERNAL_FTS_KEY"
// SearchFunctionName is the grammar function name for full-text search.
SearchFunctionName = "search"
// FTSMaxWindowNs is the maximum allowed time range for a search() query (6 hours).
FTSMaxWindowNs = uint64(6 * 60 * 60 * 1_000_000_000)
)

View File

@@ -38,7 +38,8 @@ type filterExpressionVisitor struct {
jsonKeyToKey qbtypes.JsonKeyToFieldFunc
bodyJSONEnabled bool
skipResourceFilter bool
skipFullTextFilter bool
skipFreeTextFilter bool
skipFullTextSearch bool
skipFunctionCalls bool
ignoreNotFoundKeys bool
variables map[string]qbtypes.VariableItem
@@ -46,7 +47,7 @@ type filterExpressionVisitor struct {
keysWithWarnings map[string]bool
startNs uint64
endNs uint64
ftsContexts []telemetrytypes.FieldContext
ftsCondition qbtypes.FTSConditionFunc
}
type FilterExprVisitorOpts struct {
@@ -58,17 +59,16 @@ type FilterExprVisitorOpts struct {
Builder *sqlbuilder.SelectBuilder
FreeTextColumn *telemetrytypes.TelemetryFieldKey
JsonKeyToKey qbtypes.JsonKeyToFieldFunc
FTSCondition qbtypes.FTSConditionFunc
BodyJSONEnabled bool
SkipResourceFilter bool
SkipFullTextFilter bool
SkipFreeTextFilter bool
SkipFullTextSearch bool
SkipFunctionCalls bool
IgnoreNotFoundKeys bool
Variables map[string]qbtypes.VariableItem
StartNs uint64
EndNs uint64
// FTSContexts enables search() for this query context. nil disables search()
// (traces, metrics, and non-log callers leave this nil).
FTSContexts []telemetrytypes.FieldContext
}
// newFilterExpressionVisitor creates a new filterExpressionVisitor.
@@ -82,16 +82,17 @@ func newFilterExpressionVisitor(opts FilterExprVisitorOpts) *filterExpressionVis
builder: opts.Builder,
freeTextColumn: opts.FreeTextColumn,
jsonKeyToKey: opts.JsonKeyToKey,
ftsCondition: opts.FTSCondition,
bodyJSONEnabled: opts.BodyJSONEnabled,
skipResourceFilter: opts.SkipResourceFilter,
skipFullTextFilter: opts.SkipFullTextFilter,
skipFreeTextFilter: opts.SkipFreeTextFilter,
skipFullTextSearch: opts.SkipFullTextSearch,
skipFunctionCalls: opts.SkipFunctionCalls,
ignoreNotFoundKeys: opts.IgnoreNotFoundKeys,
variables: opts.Variables,
keysWithWarnings: make(map[string]bool),
startNs: opts.StartNs,
endNs: opts.EndNs,
ftsContexts: opts.FTSContexts,
}
}
@@ -342,12 +343,12 @@ func (v *filterExpressionVisitor) VisitPrimary(ctx *grammar.PrimaryContext) any
// Handle standalone key/value as a full text search term
if ctx.GetChildCount() == 1 {
if v.skipFullTextFilter {
if v.skipFreeTextFilter {
return SkipConditionLiteral
}
if v.freeTextColumn == nil {
v.errors = append(v.errors, "full text search is not supported")
v.errors = append(v.errors, "free text search is not supported")
return ErrorConditionLiteral
}
@@ -710,7 +711,7 @@ func (v *filterExpressionVisitor) VisitValueList(ctx *grammar.ValueListContext)
// VisitFullText handles standalone quoted strings for full-text search.
func (v *filterExpressionVisitor) VisitFullText(ctx *grammar.FullTextContext) any {
if v.skipFullTextFilter {
if v.skipFreeTextFilter {
// A skipped FT term must be treated as TrueConditionLiteral, not "".
// Returning "" would silently drop this branch from an OR, incorrectly
// excluding rows that could match the FT condition on the real table.
@@ -726,7 +727,7 @@ func (v *filterExpressionVisitor) VisitFullText(ctx *grammar.FullTextContext) an
}
if v.freeTextColumn == nil {
v.errors = append(v.errors, "full text search is not supported")
v.errors = append(v.errors, "free text search is not supported")
return ErrorConditionLiteral
}
cond, err := v.conditionBuilder.ConditionFor(v.context, v.startNs, v.endNs, v.freeTextColumn, qbtypes.FilterOperatorRegexp, FormatFullTextSearch(text), v.builder)
@@ -744,12 +745,12 @@ func (v *filterExpressionVisitor) VisitFullText(ctx *grammar.FullTextContext) an
// VisitSearchCall handles the search() function call.
func (v *filterExpressionVisitor) VisitSearchCall(ctx *grammar.SearchCallContext) any {
if v.skipFunctionCalls {
if v.skipFunctionCalls || v.skipFullTextSearch {
return SkipConditionLiteral
}
// ftsContexts == nil means search() is not enabled for this signal/query type.
// Only log statement builders set FTSContexts; traces/metrics leave it nil.
if len(v.ftsContexts) == 0 {
// ftsCondition nil means search() is not enabled for this signal.
// Only log statement builders set these; traces/metrics leave them nil.
if v.ftsCondition == nil {
v.errors = append(v.errors, "search() is only supported for log queries")
return ErrorConditionLiteral
}
@@ -774,27 +775,19 @@ func (v *filterExpressionVisitor) VisitSearchCall(ctx *grammar.SearchCallContext
}
if v.endNs > 0 && v.startNs > 0 && (v.endNs-v.startNs) > FTSMaxWindowNs {
v.errors = append(v.errors, "full text search is restricted to a maximum of 6-hour time window")
v.errors = append(v.errors, "search() is restricted to a maximum of 6-hour time window")
return ErrorConditionLiteral
}
formattedText := FormatFullTextSearch(searchText)
var ftsConds []string
for _, fieldCtx := range v.ftsContexts {
cond, err := v.conditionBuilder.ConditionForContext(v.context, fieldCtx, formattedText, v.builder)
if err != nil {
v.errors = append(v.errors, fmt.Sprintf("search() could not build condition for context %q: %s", fieldCtx.StringValue(), err.Error()))
return ErrorConditionLiteral
}
ftsConds = append(ftsConds, cond)
}
if len(ftsConds) == 0 {
v.errors = append(v.errors, "search() failed: no searchable fields could be queried")
cond, err := v.ftsCondition(v.context, formattedText, v.builder)
if err != nil {
v.errors = append(v.errors, fmt.Sprintf("search() could not build condition: %s", err.Error()))
return ErrorConditionLiteral
}
v.warnings = append(v.warnings, FullTextSearchDefaultWarning)
return v.builder.Or(ftsConds...)
return cond
}
// VisitFunctionCall handles function calls like has(), hasAny(), hasAll(), hasToken().

View File

@@ -744,10 +744,6 @@ func (b *resourceConditionBuilder) ConditionFor(
return fmt.Sprintf("%s_cond", key.Name), nil
}
func (b *resourceConditionBuilder) ConditionForContext(_ context.Context, _ telemetrytypes.FieldContext, _ any, _ *sqlbuilder.SelectBuilder) (string, error) {
return "", nil
}
type conditionBuilder struct{}
func (b *conditionBuilder) ConditionFor(
@@ -762,10 +758,6 @@ func (b *conditionBuilder) ConditionFor(
return fmt.Sprintf("%s_cond", key.Name), nil
}
func (b *conditionBuilder) ConditionForContext(_ context.Context, fc telemetrytypes.FieldContext, _ any, sb *sqlbuilder.SelectBuilder) (string, error) {
return fmt.Sprintf("fts_%s_cond", fc.StringValue()), nil
}
// visitComparisonCase is a single test case for the TestVisitComparison_* family.
// Each case is run under two independent configurations:
//
@@ -805,7 +797,7 @@ func visitComparisonOpts(t *testing.T) (rsbOpts, sbOpts FilterExprVisitorOpts) {
ConditionBuilder: &resourceConditionBuilder{},
Variables: allVariable,
SkipResourceFilter: false,
SkipFullTextFilter: true,
SkipFreeTextFilter: true,
SkipFunctionCalls: true,
IgnoreNotFoundKeys: true,
}
@@ -815,7 +807,7 @@ func visitComparisonOpts(t *testing.T) (rsbOpts, sbOpts FilterExprVisitorOpts) {
ConditionBuilder: &conditionBuilder{},
Variables: allVariable,
SkipResourceFilter: true,
SkipFullTextFilter: false,
SkipFreeTextFilter: false,
SkipFunctionCalls: false,
IgnoreNotFoundKeys: false,
FreeTextColumn: bodyCol,
@@ -1701,10 +1693,12 @@ func TestVisitComparison_FullTextSearch(t *testing.T) {
FieldKeys: visitTestKeys,
ConditionBuilder: &conditionBuilder{},
SkipResourceFilter: false,
SkipFullTextFilter: false,
SkipFreeTextFilter: false,
SkipFunctionCalls: false,
IgnoreNotFoundKeys: false,
FTSContexts: []telemetrytypes.FieldContext{telemetrytypes.FieldContextResource},
FTSCondition: func(_ context.Context, _ any, _ *sqlbuilder.SelectBuilder) (string, error) {
return fmt.Sprintf("fts_cond"), nil
},
}
tests := []struct {

View File

@@ -199,6 +199,3 @@ func (c *conditionBuilder) ConditionFor(
return condition, nil
}
func (c *conditionBuilder) ConditionForContext(_ context.Context, _ telemetrytypes.FieldContext, _ any, _ *sqlbuilder.SelectBuilder) (string, error) {
return "", nil
}

View File

@@ -122,7 +122,3 @@ func (m *fieldMapper) ColumnExpressionFor(
return fmt.Sprintf("%s AS `%s`", sqlbuilder.Escape(fieldExpression), field.Name), nil
}
func (m *fieldMapper) GetColumns(_ context.Context, _ telemetrytypes.FieldContext) []*schema.Column {
return nil
}

View File

@@ -25,47 +25,48 @@ func NewConditionBuilder(fm qbtypes.FieldMapper, fl flagger.Flagger) *conditionB
return &conditionBuilder{fm: fm, fl: fl}
}
// ConditionForContext builds the search condition for all FTS columns belonging
// ConditionForSearch builds the search condition for all FTS columns belonging
// to fieldContext. JSON columns are skipped when useJSONBody is disabled.
// Returns ("", nil) when no searchable columns exist for the context.
func (c *conditionBuilder) ConditionForContext(
func (c *conditionBuilder) ConditionForSearch(
ctx context.Context,
fieldContext telemetrytypes.FieldContext,
value any,
sb *sqlbuilder.SelectBuilder,
) (string, error) {
columns := c.fm.GetColumns(ctx, fieldContext)
contexts := []telemetrytypes.FieldContext{
telemetrytypes.FieldContextLog,
telemetrytypes.FieldContextBody,
telemetrytypes.FieldContextAttribute,
telemetrytypes.FieldContextResource,
}
useJSONBody := c.fl.BooleanOrEmpty(ctx, flagger.FeatureUseJSONBody, featuretypes.NewFlaggerEvaluationContext(valuer.UUID{}))
var conditions []string
for _, col := range columns {
switch col.Type.GetType() {
case schema.ColumnTypeEnumMap:
keysExpr := fmt.Sprintf("mapKeys(%s)", col.Name)
valsExpr := fmt.Sprintf("mapValues(%s)", col.Name)
if mc, ok := col.Type.(schema.MapColumnType); ok && mc.ValueType.GetType() != schema.ColumnTypeEnumString {
valsExpr = fmt.Sprintf("arrayMap(x -> toString(x), mapValues(%s))", col.Name)
for _, fieldContext := range contexts {
for _, col := range ftsColumns(ctx, fieldContext, useJSONBody) {
switch col.Type.GetType() {
case schema.ColumnTypeEnumMap:
keysExpr := fmt.Sprintf("mapKeys(%s)", col.Name)
valsExpr := fmt.Sprintf("mapValues(%s)", col.Name)
if mc, ok := col.Type.(schema.MapColumnType); ok && mc.ValueType.GetType() != schema.ColumnTypeEnumString {
valsExpr = fmt.Sprintf("arrayMap(x -> toString(x), mapValues(%s))", col.Name)
}
conditions = append(conditions, sb.Or(
fmt.Sprintf(`arrayExists(x -> match(x, %s), %s)`, sb.Var(value), keysExpr),
fmt.Sprintf(`arrayExists(x -> match(x, %s), %s)`, sb.Var(value), valsExpr),
))
case schema.ColumnTypeEnumJSON:
conditions = append(conditions, fmt.Sprintf(`match(LOWER(toString(%s)), LOWER(%s))`, col.Name, sb.Var(value)))
case schema.ColumnTypeEnumString, schema.ColumnTypeEnumLowCardinality:
conditions = append(conditions, fmt.Sprintf(`match(LOWER(%s), LOWER(%s))`, col.Name, sb.Var(value)))
default:
return "", errors.Newf(errors.TypeInternal, errors.CodeInternal, "FTS unsupported column type %s", col.Type)
}
conditions = append(conditions, sb.Or(
fmt.Sprintf(`arrayExists(x -> match(x, %s), %s)`, sb.Var(value), keysExpr),
fmt.Sprintf(`arrayExists(x -> match(x, %s), %s)`, sb.Var(value), valsExpr),
))
case schema.ColumnTypeEnumJSON:
conditions = append(conditions, fmt.Sprintf(`match(LOWER(toString(%s)), LOWER(%s))`, col.Name, sb.Var(value)))
case schema.ColumnTypeEnumString, schema.ColumnTypeEnumLowCardinality:
conditions = append(conditions, fmt.Sprintf(`match(LOWER(%s), LOWER(%s))`, col.Name, sb.Var(value)))
default:
return "", errors.Newf(errors.TypeInternal, errors.CodeInternal, "FTS unsupported column type %s", col.Type)
}
}
switch len(conditions) {
case 0:
return "", nil
case 1:
return conditions[0], nil
default:
return sb.Or(conditions...), nil
}
return sb.Or(conditions...), nil
}
func (c *conditionBuilder) conditionFor(

View File

@@ -126,16 +126,6 @@ var (
Direction: qbtypes.OrderDirectionDesc,
},
}
// ftsSupportedContexts is the ordered list of field contexts that search()
// fans out across. The field mapper's GetColumns is called for each to
// retrieve the physical columns.
ftsSupportedContexts = []telemetrytypes.FieldContext{
telemetrytypes.FieldContextLog,
telemetrytypes.FieldContextBody,
telemetrytypes.FieldContextAttribute,
telemetrytypes.FieldContextResource,
}
)
func bodyAliasExpression(bodyJSONEnabled bool) string {

View File

@@ -547,7 +547,7 @@ func (m *fieldMapper) buildArrayMap(currentNode *telemetrytypes.JSONAccessNode,
// GetColumns returns the physical columns for the given field context that
// search() fans out across. For FieldContextBody the active column set depends
// on the useJSONBody feature flag.
func (m *fieldMapper) GetColumns(ctx context.Context, fieldContext telemetrytypes.FieldContext) []*schema.Column {
func ftsColumns(ctx context.Context, fieldContext telemetrytypes.FieldContext, useJSONBody bool) []*schema.Column {
switch fieldContext {
case telemetrytypes.FieldContextLog:
return []*schema.Column{
@@ -556,8 +556,7 @@ func (m *fieldMapper) GetColumns(ctx context.Context, fieldContext telemetrytype
logsV2Columns[LogsV2SpanIDColumn],
}
case telemetrytypes.FieldContextBody:
// TODO(Tushar): thread orgID here to evaluate correctly
if m.fl.BooleanOrEmpty(ctx, flagger.FeatureUseJSONBody, featuretypes.NewFlaggerEvaluationContext(valuer.UUID{})) {
if useJSONBody {
return []*schema.Column{logsV2Columns[LogsV2BodyV2Column]}
}
return []*schema.Column{logsV2Columns[LogsV2BodyColumn]}

View File

@@ -1204,6 +1204,7 @@ func buildJSONTestStatementBuilder(t *testing.T, addIndexes bool) (*logQueryStat
aggExprRewriter,
DefaultFullTextColumn,
GetBodyJSONKey,
cb.ConditionForSearch,
fl,
)

View File

@@ -27,8 +27,9 @@ type logQueryStatementBuilder struct {
aggExprRewriter qbtypes.AggExprRewriter
fl flagger.Flagger
freeTextColumn *telemetrytypes.TelemetryFieldKey
jsonKeyToKey qbtypes.JsonKeyToFieldFunc
freeTextColumn *telemetrytypes.TelemetryFieldKey
jsonKeyToKey qbtypes.JsonKeyToFieldFunc
ftsConditionFunc qbtypes.FTSConditionFunc
}
var _ qbtypes.StatementBuilder[qbtypes.LogAggregation] = (*logQueryStatementBuilder)(nil)
@@ -41,6 +42,7 @@ func NewLogQueryStatementBuilder(
aggExprRewriter qbtypes.AggExprRewriter,
freeTextColumn *telemetrytypes.TelemetryFieldKey,
jsonKeyToKey qbtypes.JsonKeyToFieldFunc,
ftsConditionFunc qbtypes.FTSConditionFunc,
fl flagger.Flagger,
) *logQueryStatementBuilder {
logsSettings := factory.NewScopedProviderSettings(settings, "github.com/SigNoz/signoz/pkg/telemetrylogs")
@@ -65,8 +67,9 @@ func NewLogQueryStatementBuilder(
resourceFilterStmtBuilder: resourceFilterStmtBuilder,
aggExprRewriter: aggExprRewriter,
fl: fl,
freeTextColumn: freeTextColumn,
jsonKeyToKey: jsonKeyToKey,
freeTextColumn: freeTextColumn,
jsonKeyToKey: jsonKeyToKey,
ftsConditionFunc: ftsConditionFunc,
}
}
@@ -663,7 +666,7 @@ func (b *logQueryStatementBuilder) addFilterCondition(
EndNs: end,
}
if enableFTS {
opts.FTSContexts = ftsSupportedContexts
opts.FTSCondition = b.ftsConditionFunc
}
// add filter expression

View File

@@ -212,6 +212,7 @@ func TestStatementBuilderTimeSeries(t *testing.T) {
aggExprRewriter,
DefaultFullTextColumn,
GetBodyJSONKey,
cb.ConditionForSearch,
fl,
)
@@ -353,6 +354,7 @@ func TestStatementBuilderListQuery(t *testing.T) {
aggExprRewriter,
DefaultFullTextColumn,
GetBodyJSONKey,
cb.ConditionForSearch,
fl,
)
@@ -483,6 +485,7 @@ func TestStatementBuilderListQueryResourceTests(t *testing.T) {
aggExprRewriter,
DefaultFullTextColumn,
GetBodyJSONKey,
cb.ConditionForSearch,
fl,
)
@@ -559,6 +562,7 @@ func TestStatementBuilderTimeSeriesBodyGroupBy(t *testing.T) {
aggExprRewriter,
DefaultFullTextColumn,
GetBodyJSONKey,
cb.ConditionForSearch,
fl,
)
@@ -654,6 +658,7 @@ func TestStatementBuilderListQueryServiceCollision(t *testing.T) {
aggExprRewriter,
DefaultFullTextColumn,
GetBodyJSONKey,
cb.ConditionForSearch,
fl,
)
@@ -878,6 +883,7 @@ func TestAdjustKey(t *testing.T) {
aggExprRewriter,
DefaultFullTextColumn,
GetBodyJSONKey,
cb.ConditionForSearch,
fl,
)
@@ -1023,6 +1029,7 @@ func TestStmtBuilderBodyField(t *testing.T) {
aggExprRewriter,
DefaultFullTextColumn,
GetBodyJSONKey,
cb.ConditionForSearch,
fl,
)
@@ -1199,6 +1206,7 @@ func TestStmtBuilderTextSearch(t *testing.T) {
aggExprRewriter,
DefaultFullTextColumn,
GetBodyJSONKey,
cb.ConditionForSearch,
fl,
)
startMs := uint64(1747947419000)

View File

@@ -136,6 +136,3 @@ func (c *conditionBuilder) ConditionFor(
return fmt.Sprintf(expr, columns[0].Name, sb.Var(key.Name), cond), nil
}
func (c *conditionBuilder) ConditionForContext(_ context.Context, _ telemetrytypes.FieldContext, _ any, _ *sqlbuilder.SelectBuilder) (string, error) {
return "", nil
}

View File

@@ -116,7 +116,3 @@ func (m *fieldMapper) ColumnExpressionFor(
return fmt.Sprintf("%s AS `%s`", sqlbuilder.Escape(fieldExpression), field.Name), nil
}
func (m *fieldMapper) GetColumns(_ context.Context, _ telemetrytypes.FieldContext) []*schema.Column {
return nil
}

View File

@@ -158,6 +158,3 @@ func (c *conditionBuilder) ConditionFor(
return condition, nil
}
func (c *conditionBuilder) ConditionForContext(_ context.Context, _ telemetrytypes.FieldContext, _ any, _ *sqlbuilder.SelectBuilder) (string, error) {
return "", nil
}

View File

@@ -104,7 +104,3 @@ func (m *fieldMapper) ColumnExpressionFor(
return fmt.Sprintf("%s AS `%s`", sqlbuilder.Escape(fieldExpression), field.Name), nil
}
func (m *fieldMapper) GetColumns(_ context.Context, _ telemetrytypes.FieldContext) []*schema.Column {
return nil
}

View File

@@ -207,6 +207,3 @@ func (b *defaultConditionBuilder) ConditionFor(
return "", qbtypes.ErrUnsupportedOperator
}
func (b *defaultConditionBuilder) ConditionForContext(_ context.Context, _ telemetrytypes.FieldContext, _ any, _ *sqlbuilder.SelectBuilder) (string, error) {
return "", nil
}

View File

@@ -74,7 +74,3 @@ func (m *defaultFieldMapper) ColumnExpressionFor(
}
return fmt.Sprintf("%s AS `%s`", fieldExpression, key.Name), nil
}
func (m *defaultFieldMapper) GetColumns(_ context.Context, _ telemetrytypes.FieldContext) []*schema.Column {
return nil
}

View File

@@ -155,7 +155,8 @@ func (b *resourceFilterStatementBuilder[T]) addConditions(
BodyJSONEnabled: bodyJSONEnabled,
FreeTextColumn: b.fullTextColumn,
JsonKeyToKey: b.jsonKeyToKey,
SkipFullTextFilter: true,
SkipFreeTextFilter: true,
SkipFullTextSearch: true,
SkipFunctionCalls: true,
// there is no need for "key" not found error for resource filtering
IgnoreNotFoundKeys: true,

View File

@@ -265,9 +265,6 @@ func (c *conditionBuilder) ConditionFor(
return condition, nil
}
func (c *conditionBuilder) ConditionForContext(_ context.Context, _ telemetrytypes.FieldContext, _ any, _ *sqlbuilder.SelectBuilder) (string, error) {
return "", nil
}
func (c *conditionBuilder) isSpanScopeField(name string) bool {
keyName := strings.ToLower(name)

View File

@@ -364,7 +364,3 @@ func (m *defaultFieldMapper) ColumnExpressionFor(
return fmt.Sprintf("%s AS `%s`", sqlbuilder.Escape(fieldExpression), field.Name), nil
}
func (m *defaultFieldMapper) GetColumns(_ context.Context, _ telemetrytypes.FieldContext) []*schema.Column {
return nil
}

View File

@@ -19,6 +19,11 @@ var (
type JsonKeyToFieldFunc func(context.Context, *telemetrytypes.TelemetryFieldKey, FilterOperator, any) (string, any)
// FTSConditionFunc builds the search() SQL condition for all FTS columns belonging
// to fieldContext. Returns ("", nil) when no columns are searchable for the
// context (e.g. body JSON when useJSONBody is off). Pass nil to disable search().
type FTSConditionFunc func(ctx context.Context, value any, sb *sqlbuilder.SelectBuilder) (string, error)
// FieldMapper maps the telemetry field key to the table field name.
type FieldMapper interface {
// FieldFor returns the field name for the given key.
@@ -27,20 +32,12 @@ type FieldMapper interface {
ColumnFor(ctx context.Context, tsStart, tsEnd uint64, key *telemetrytypes.TelemetryFieldKey) ([]*schema.Column, error)
// ColumnExpressionFor returns the column expression for the given key.
ColumnExpressionFor(ctx context.Context, tsStart, tsEnd uint64, key *telemetrytypes.TelemetryFieldKey, keys map[string][]*telemetrytypes.TelemetryFieldKey) (string, error)
// GetColumns returns the physical columns to fan out across for FTS search()
// for the given field context. Non-log signal implementations return nil.
GetColumns(ctx context.Context, fieldContext telemetrytypes.FieldContext) []*schema.Column
}
// ConditionBuilder builds the condition for the filter.
type ConditionBuilder interface {
// ConditionFor returns the condition for the given key, operator and value.
ConditionFor(ctx context.Context, startNs uint64, endNs uint64, key *telemetrytypes.TelemetryFieldKey, operator FilterOperator, value any, sb *sqlbuilder.SelectBuilder) (string, error)
// ConditionForContext builds the search expression for all FTS columns belonging
// to fieldContext. Returns ("", nil) when no searchable columns exist for the
// context (e.g. JSON body when useJSONBody is disabled). Non-log
// implementations may return ("", nil) unconditionally.
ConditionForContext(ctx context.Context, fieldContext telemetrytypes.FieldContext, value any, sb *sqlbuilder.SelectBuilder) (string, error)
}
type AggExprRewriter interface {