@@ -10,7 +10,6 @@ import (
1010 "quesma/logger"
1111 "quesma/model"
1212 "quesma/model/bucket_aggregations"
13- "quesma/util"
1413 "sort"
1514 "strconv"
1615 "strings"
@@ -320,78 +319,6 @@ func (cw *ClickhouseQueryTranslator) pancakeTryBucketAggregation(aggregation *pa
320319 return
321320}
322321
323- func (cw * ClickhouseQueryTranslator ) pancakeFindMetricAggregation (queryMap QueryMap , aggregationName string ) model.Expr {
324- notFoundValue := model .NewLiteral ("" )
325-
326- aggsRaw , exists := queryMap ["aggs" ]
327- if ! exists {
328- logger .WarnWithCtx (cw .Ctx ).Msgf ("no aggs in queryMap, queryMap: %+v" , queryMap )
329- return notFoundValue
330- }
331- aggs , ok := aggsRaw .(QueryMap )
332- if ! ok {
333- logger .WarnWithCtx (cw .Ctx ).Msgf ("aggs is not a map, but %T, value: %v. Skipping" , aggsRaw , aggsRaw )
334- return notFoundValue
335- }
336-
337- var percentileNameWeLookFor string
338- weTrySplitByDot := false
339-
340- // We try 2 things here:
341- // First (always): maybe there exists an aggregation with exactly this name
342- // Second (if aggregation_name == X.Y): maybe it's aggregationName.some_value, e.g. "2.75", when "2" aggregation is a percentile, and 75 is its value
343- aggregationNamesToTry := []string {aggregationName }
344- splitByDot := strings .Split (aggregationName , "." )
345- if len (splitByDot ) == 2 {
346- weTrySplitByDot = true
347- percentileNameWeLookFor = splitByDot [1 ]
348- aggregationNamesToTry = append (aggregationNamesToTry , splitByDot [0 ])
349- }
350-
351- for _ , aggNameToTry := range aggregationNamesToTry {
352- currentAggMapRaw , exists := aggs [aggNameToTry ]
353- if ! exists {
354- continue
355- }
356-
357- currentAggMap , ok := currentAggMapRaw .(QueryMap )
358- if ! ok {
359- logger .WarnWithCtx (cw .Ctx ).Msgf ("aggregation %s is not a map, but %T, value: %v. Skipping" ,
360- aggregationName , currentAggMapRaw , currentAggMapRaw )
361- continue
362- }
363-
364- agg , success := cw .tryMetricsAggregation (currentAggMap )
365- if ! success {
366- logger .WarnWithCtx (cw .Ctx ).Msgf ("failed to parse metric aggregation: %v" , agg )
367- continue
368- }
369-
370- // we build a temporary query only to extract the name of the metric
371- columns , err := generateMetricSelectedColumns (cw .Ctx , agg )
372- if err != nil {
373- continue
374- }
375-
376- if aggNameToTry == aggregationName {
377- if len (columns ) != 1 {
378- continue
379- }
380- return columns [0 ]
381- } else if weTrySplitByDot {
382- userPercents := util .MapKeysSortedByValue (agg .Percentiles )
383- for i , percentileName := range userPercents {
384- if percentileName == percentileNameWeLookFor {
385- return columns [i ]
386- }
387- }
388- }
389- }
390-
391- logger .ErrorWithCtx (cw .Ctx ).Msgf ("no given metric aggregation found (name: %v, queryMap: %+v)" , aggregationName , queryMap )
392- return notFoundValue
393- }
394-
395322// samplerRaw - in a proper request should be of QueryMap type.
396323func (cw * ClickhouseQueryTranslator ) parseSampler (samplerRaw any ) bucket_aggregations.Sampler {
397324 const defaultSize = 100
@@ -420,60 +347,60 @@ func (cw *ClickhouseQueryTranslator) parseRandomSampler(randomSamplerRaw any) bu
420347}
421348
422349func (cw * ClickhouseQueryTranslator ) parseOrder (terms , queryMap QueryMap , fieldExpressions []model.Expr ) []model.OrderByExpr {
423- defaultMainOrderBy := model .NewCountFunc ()
424350 defaultDirection := model .DescOrder
351+ defaultOrderBy := model .NewOrderByExpr (model .NewCountFunc (), defaultDirection )
425352
426- fieldOrderBys := make ([]model.OrderByExpr , 0 , len (fieldExpressions ))
427- for _ , fieldExpression := range fieldExpressions {
428- fieldOrderBys = append (fieldOrderBys , model.OrderByExpr {Expr : fieldExpression })
429- }
430-
431- var mainOrderBy model.Expr = defaultMainOrderBy
432- fullOrderBy := []model.OrderByExpr { // default
433- {Expr : mainOrderBy , Direction : defaultDirection },
434- }
435- fullOrderBy = append (fullOrderBy , fieldOrderBys ... )
436- direction := defaultDirection
437-
438- orderRaw , exists := terms ["order" ]
353+ ordersRaw , exists := terms ["order" ]
439354 if ! exists {
440- return fullOrderBy
355+ return []model. OrderByExpr { defaultOrderBy }
441356 }
442357
443- order , ok := orderRaw .(QueryMap ) // TODO it can be array too, don't handle it yet
444- if ! ok {
445- logger .WarnWithCtx (cw .Ctx ).Msgf ("order is not a map, but %T, value: %v. Using default order" , orderRaw , orderRaw )
446- return fullOrderBy
447- }
448- if len (order ) != 1 {
449- logger .WarnWithCtx (cw .Ctx ).Msgf ("order should have 1 key, but has %d. Order: %+v. Using default" , len (order ), order )
450- return fullOrderBy
358+ // order can be either a single order {}, or a list of such single orders [{}(,{}...)]
359+ orders := make ([]QueryMap , 0 )
360+ switch ordersTyped := ordersRaw .(type ) {
361+ case QueryMap :
362+ orders = append (orders , ordersTyped )
363+ case []any :
364+ for _ , order := range ordersTyped {
365+ if orderTyped , ok := order .(QueryMap ); ok {
366+ orders = append (orders , orderTyped )
367+ } else {
368+ logger .WarnWithCtx (cw .Ctx ).Msgf ("invalid order: %v" , order )
369+ }
370+ }
371+ default :
372+ logger .WarnWithCtx (cw .Ctx ).Msgf ("order is not a map/list of maps, but %T, value: %v. Using default order" , ordersRaw , ordersRaw )
373+ return []model.OrderByExpr {defaultOrderBy }
451374 }
452375
453- for key , valueRaw := range order { // value == "asc" or "desc"
454- value , ok := valueRaw .(string )
455- if ! ok {
456- logger .WarnWithCtx (cw .Ctx ).Msgf ("order value is not a string, but %T, value: %v. Using default (desc)" , valueRaw , valueRaw )
457- value = "desc"
458- }
459- if strings .ToLower (value ) == "asc" {
460- direction = model .AscOrder
376+ fullOrderBy := make ([]model.OrderByExpr , 0 )
377+
378+ for _ , order := range orders {
379+ if len (order ) != 1 {
380+ logger .WarnWithCtx (cw .Ctx ).Msgf ("invalid order length, should be 1: %v" , order )
461381 }
382+ for key , valueRaw := range order { // value == "asc" or "desc"
383+ value , ok := valueRaw .(string )
384+ if ! ok {
385+ logger .WarnWithCtx (cw .Ctx ).Msgf ("order value is not a string, but %T, value: %v. Using default (desc)" , valueRaw , valueRaw )
386+ value = "desc"
387+ }
462388
463- if key == "_key" {
464- fullOrderBy = fieldOrderBys
465- for i := range fullOrderBy {
466- fullOrderBy [i ].Direction = direction
389+ direction := defaultDirection
390+ if strings .ToLower (value ) == "asc" {
391+ direction = model .AscOrder
467392 }
468- break // mainOrderBy remains default
469- } else if key != "_count" {
470- mainOrderBy = cw .pancakeFindMetricAggregation (queryMap , key )
471- }
472393
473- fullOrderBy = []model.OrderByExpr {
474- {Expr : mainOrderBy , Direction : direction },
394+ if key == "_key" {
395+ for _ , fieldExpression := range fieldExpressions {
396+ fullOrderBy = append (fullOrderBy , model.OrderByExpr {Expr : fieldExpression , Direction : direction })
397+ }
398+ } else if key == "_count" {
399+ fullOrderBy = append (fullOrderBy , model .NewOrderByExpr (model .NewCountFunc (), direction ))
400+ } else {
401+ fullOrderBy = append (fullOrderBy , model.OrderByExpr {Expr : model .NewLiteral (key ), Direction : direction })
402+ }
475403 }
476- fullOrderBy = append (fullOrderBy , fieldOrderBys ... )
477404 }
478405
479406 return fullOrderBy
0 commit comments