Files
Rodrigo ZhouandGitHub 5d64c0b65f Unified query converter for Visibility (#8307)
## What changed?
Unify Visibility query converters.

The new query converter is the struct `query.QueryConverter[ExprT]`. The
generic parameter specify the output type of the converter (in ES is
`elastic.Query`, in SQL is `sqlparser.Expr`).

The query converter has a `query.StoreQueryConverter[ExprT]`. This is
the Visibility store specific implementation for building the output
query.

For example, the store needs to implement `BuildAndExpr(exprs)` to tell
the query converter how to build the `AND` expression. In SQL, it's
`*sqlparser.AndExpr{exprs}`. In Elasticsearch, it's
`elastic.NewBoolQuery().Filter(exprs)`.

The store query converter for SQL needs a plugin query converter called
`sqlplugin.VisibilityQueryConverter` which is implemented by each plugin
(MySQL, PostgreSQL, SQLite). This interface is needed to build DB
specific syntax for `KeywordList` and `Text` searches as well as to
build the final `SELECT` statements.

Added dynamic config `system.VisibilityEnableUnifiedQueryConverter` that
acts as switch between the legacy and the unified query converters.

## Why?
There are two query converters: one for Elasticsearch, and another for
SQL.
They are somewhat similar, and have quite a few code duplications for
validation, modifying the query, etc.
Unifying the query converter ensures that we provide the exact same
behavior across different Visibility stores.

## How did you test it?
- [x] built
- [x] run locally and tested manually
- [x] covered by existing tests
- [x] added new unit test(s)
- [ ] added new functional test(s)

I've added a lot of unit tests for the new code with coverage close to
100%.

Note that there has been basically no changes to functional tests, which
suggests that the change works well.

## Potential risks
There might be some edge cases that either query converters that this
unified query converter might deal differently.
2025-11-11 01:48:34 +00:00

94 lines
2.0 KiB
Go

package query
import (
"go.temporal.io/server/common/namespace"
"go.temporal.io/server/common/searchattribute"
)
// nilStoreQueryConverter is a dummy query converter implementation that returns nil value as the
// result of converting the query.
// It can be useful if you just need to traverse the query and collect information using the
// SearchAttributeInterceptor.
type nilStoreQueryConverter struct{}
var _ StoreQueryConverter[any] = (*nilStoreQueryConverter)(nil)
func (c *nilStoreQueryConverter) GetDatetimeFormat() string {
return ""
}
func (c *nilStoreQueryConverter) BuildParenExpr(expr any) (any, error) {
return nil, nil
}
func (c *nilStoreQueryConverter) BuildNotExpr(expr any) (any, error) {
return nil, nil
}
func (c *nilStoreQueryConverter) BuildAndExpr(exprs ...any) (any, error) {
return nil, nil
}
func (c *nilStoreQueryConverter) BuildOrExpr(exprs ...any) (any, error) {
return nil, nil
}
func (c *nilStoreQueryConverter) ConvertComparisonExpr(
operator string,
col *SAColumn,
value any,
) (any, error) {
return nil, nil
}
func (c *nilStoreQueryConverter) ConvertKeywordComparisonExpr(
operator string,
col *SAColumn,
value any,
) (any, error) {
return nil, nil
}
func (c *nilStoreQueryConverter) ConvertKeywordListComparisonExpr(
operator string,
col *SAColumn,
value any,
) (any, error) {
return nil, nil
}
func (c *nilStoreQueryConverter) ConvertTextComparisonExpr(
operator string,
col *SAColumn,
value any,
) (any, error) {
return nil, nil
}
func (c *nilStoreQueryConverter) ConvertRangeExpr(
operator string,
col *SAColumn,
from, to any,
) (any, error) {
return nil, nil
}
func (c *nilStoreQueryConverter) ConvertIsExpr(operator string, col *SAColumn) (any, error) {
return nil, nil
}
type NilQueryConverter = *QueryConverter[any]
func NewNilQueryConverter(
namespaceName namespace.Name,
saTypeMap searchattribute.NameTypeMap,
saMapper searchattribute.Mapper,
) NilQueryConverter {
return NewQueryConverter(
&nilStoreQueryConverter{},
namespaceName,
saTypeMap,
saMapper,
)
}