diff --git a/quesma/queryparser/query_parser.go b/quesma/queryparser/query_parser.go index 814eb414e..5cc2fd5cc 100644 --- a/quesma/queryparser/query_parser.go +++ b/quesma/queryparser/query_parser.go @@ -1200,38 +1200,56 @@ func (cw *ClickhouseQueryTranslator) extractInterval(queryMap QueryMap) string { // parseSortFields parses sort fields from the query // We're skipping ELK internal fields, like "_doc", "_id", etc. (we only accept field starting with "_" if it exists in our table) -func (cw *ClickhouseQueryTranslator) parseSortFields(sortMaps []any) []string { - sortFields := make([]string, 0) - for _, sortMapAsAny := range sortMaps { - sortMap, ok := sortMapAsAny.(QueryMap) - if !ok { - logger.WarnWithCtx(cw.Ctx).Msgf("parseSortFields: unexpected type of value: %T, value: %v", sortMapAsAny, sortMapAsAny) - continue - } - - // sortMap has only 1 key, so we can just iterate over it - for k, v := range sortMap { - if strings.HasPrefix(k, "_") && cw.Table.GetFieldInfo(cw.Ctx, k) == clickhouse.NotExists { - // we're skipping ELK internal fields, like "_doc", "_id", etc. +func (cw *ClickhouseQueryTranslator) parseSortFields(sortMaps any) []string { + switch sortMaps := sortMaps.(type) { + case []any: + sortFields := make([]string, 0) + for _, sortMapAsAny := range sortMaps { + sortMap, ok := sortMapAsAny.(QueryMap) + if !ok { + logger.WarnWithCtx(cw.Ctx).Msgf("parseSortFields: unexpected type of value: %T, value: %v", sortMapAsAny, sortMapAsAny) continue } - fieldName := cw.Table.ResolveField(cw.Ctx, k) - if vAsMap, ok := v.(QueryMap); ok { - if order, ok := vAsMap["order"]; ok { - if orderAsString, ok := order.(string); ok { - sortFields = append(sortFields, strconv.Quote(fieldName)+" "+orderAsString) + + // sortMap has only 1 key, so we can just iterate over it + for k, v := range sortMap { + if strings.HasPrefix(k, "_") && cw.Table.GetFieldInfo(cw.Ctx, k) == clickhouse.NotExists { + // we're skipping ELK internal fields, like "_doc", "_id", etc. + continue + } + fieldName := cw.Table.ResolveField(cw.Ctx, k) + if vAsMap, ok := v.(QueryMap); ok { + if order, ok := vAsMap["order"]; ok { + if orderAsString, ok := order.(string); ok { + sortFields = append(sortFields, strconv.Quote(fieldName)+" "+orderAsString) + } else { + logger.WarnWithCtx(cw.Ctx).Msgf("unexpected order type: %T, value: %v. Skipping", order, order) + } } else { - logger.WarnWithCtx(cw.Ctx).Msgf("unexpected order type: %T, value: %v. Skipping", order, order) + sortFields = append(sortFields, strconv.Quote(fieldName)) } } else { - sortFields = append(sortFields, strconv.Quote(fieldName)) + logger.WarnWithCtx(cw.Ctx).Msgf("unexpected value's type: %T (key, value): (%s, %v). Skipping", v, k, v) } - } else { - logger.WarnWithCtx(cw.Ctx).Msgf("unexpected value's type: %T (key, value): (%s, %v). Skipping", v, k, v) } } + return sortFields + case map[string]string: + sortFields := make([]string, 0) + + for fieldName, fieldValue := range sortMaps { + if strings.HasPrefix(fieldName, "_") && cw.Table.GetFieldInfo(cw.Ctx, fieldName) == clickhouse.NotExists { + // TODO Elastic internal fields will need to be supported in the future + continue + } + sortFields = append(sortFields, fmt.Sprintf("%s %s", strconv.Quote(fieldName), fieldValue)) + } + + return sortFields + default: + logger.ErrorWithCtx(cw.Ctx).Msgf("unexpected type of sortMaps: %T, value: %v", sortMaps, sortMaps) + return []string{} } - return sortFields } func (cw *ClickhouseQueryTranslator) parseSize(queryMap QueryMap) (size int, ok bool) { diff --git a/quesma/queryparser/query_parser_test.go b/quesma/queryparser/query_parser_test.go index 25a6e79c8..0665c1221 100644 --- a/quesma/queryparser/query_parser_test.go +++ b/quesma/queryparser/query_parser_test.go @@ -490,7 +490,7 @@ func TestQueryParseDateMathExpression(t *testing.T) { func Test_parseSortFields(t *testing.T) { tests := []struct { - sortMap []any + sortMap any sortFields []string }{ { @@ -507,6 +507,13 @@ func Test_parseSortFields(t *testing.T) { []any{}, []string{}, }, + { + sortMap: map[string]string{ + "timestamp": "desc", + "_doc": "desc", + }, + sortFields: []string{`"timestamp" desc`}, + }, } table, _ := clickhouse.NewTable(`CREATE TABLE `+tableName+` ( "@timestamp" DateTime64(3, 'UTC'), "service.name" String, "no_order_field" String, "_table_field_with_underscore" Int64 )