@@ -4,6 +4,7 @@ package quesma
44
55import (
66 "fmt"
7+ "quesma/clickhouse"
78 "quesma/common_table"
89 "quesma/logger"
910 "quesma/model"
@@ -15,7 +16,8 @@ import (
1516)
1617
1718type SchemaCheckPass struct {
18- cfg * config.QuesmaConfiguration
19+ cfg * config.QuesmaConfiguration
20+ tableDiscovery clickhouse.TableDiscovery
1921}
2022
2123func (s * SchemaCheckPass ) applyBooleanLiteralLowering (index schema.Schema , query * model.Query ) (* model.Query , error ) {
@@ -466,7 +468,7 @@ func (s *SchemaCheckPass) applyWildcardExpansion(indexSchema schema.Schema, quer
466468 for _ , col := range indexSchema .Fields {
467469 // Take only fields that are ingested
468470 if col .Origin == schema .FieldSourceIngest {
469- cols = append (cols , col .InternalPropertyName .AsString ())
471+ cols = append (cols , col .PropertyName .AsString ())
470472 }
471473 }
472474
@@ -630,29 +632,96 @@ func (s *SchemaCheckPass) applyTimestampField(indexSchema schema.Schema, query *
630632}
631633
632634func (s * SchemaCheckPass ) applyFieldEncoding (indexSchema schema.Schema , query * model.Query ) (* model.Query , error ) {
635+ table , ok := s .tableDiscovery .TableDefinitions ().Load (query .TableName )
636+ if ! ok {
637+ return nil , fmt .Errorf ("table %s not found" , query .TableName )
638+ }
639+ _ , hasAttributesValuesColumn := table .Cols [clickhouse .AttributesValuesColumn ]
633640
634641 visitor := model .NewBaseVisitor ()
635642
636- var err error
637-
638643 visitor .OverrideVisitColumnRef = func (b * model.BaseExprVisitor , e model.ColumnRef ) interface {} {
639644
645+ // we don't want to resolve our well know technical fields
646+ if e .ColumnName == model .FullTextFieldNamePlaceHolder || e .ColumnName == common_table .IndexNameColumn {
647+ return e
648+ }
649+
650+ // This is workaround.
651+ // Our query parse resolves columns sometimes. Here we detect it and skip the resolution.
652+ if _ , ok := indexSchema .ResolveFieldByInternalName (e .ColumnName ); ok {
653+ logger .Warn ().Msgf ("Got field already resolved %s" , e .ColumnName )
654+ return e
655+ }
656+
640657 if resolvedField , ok := indexSchema .ResolveField (e .ColumnName ); ok {
641658 return model .NewColumnRef (resolvedField .InternalPropertyName .AsString ())
642659 } else {
643- return e
660+ if hasAttributesValuesColumn {
661+ return model .NewArrayAccess (model .NewColumnRef (clickhouse .AttributesValuesColumn ), model .NewLiteral (fmt .Sprintf ("'%s'" , e .ColumnName )))
662+ } else {
663+ return model .NewLiteral ("NULL" )
664+ }
644665 }
645666 }
646667
647- expr := query .SelectCommand .Accept (visitor )
668+ visitor .OverrideVisitSelectCommand = func (v * model.BaseExprVisitor , query model.SelectCommand ) interface {} {
669+ var columns , groupBy []model.Expr
670+ var orderBy []model.OrderByExpr
671+ from := query .FromClause
672+ where := query .WhereClause
648673
649- if err != nil {
650- return nil , err
674+ for _ , expr := range query .Columns {
675+ var alias string
676+ if e , ok := expr .(model.ColumnRef ); ok {
677+ alias = e .ColumnName
678+ }
679+
680+ col := expr .Accept (v ).(model.Expr )
681+
682+ if e , ok := col .(model.ArrayAccess ); ok && alias != "" {
683+ col = model .NewAliasedExpr (e , alias )
684+ } else if e , ok := col .(model.LiteralExpr ); ok && alias != "" && e .Value == "NULL" {
685+ col = model .NewAliasedExpr (e , alias )
686+ }
687+
688+ columns = append (columns , col )
689+ }
690+ for _ , expr := range query .GroupBy {
691+ groupBy = append (groupBy , expr .Accept (v ).(model.Expr ))
692+ }
693+ for _ , expr := range query .OrderBy {
694+ orderBy = append (orderBy , expr .Accept (v ).(model.OrderByExpr ))
695+ }
696+ if query .FromClause != nil {
697+ from = query .FromClause .Accept (v ).(model.Expr )
698+ }
699+ if query .WhereClause != nil {
700+ where = query .WhereClause .Accept (v ).(model.Expr )
701+ }
702+
703+ var namedCTEs []* model.CTE
704+ if query .NamedCTEs != nil {
705+ for _ , cte := range query .NamedCTEs {
706+ namedCTEs = append (namedCTEs , cte .Accept (v ).(* model.CTE ))
707+ }
708+ }
709+
710+ var limitBy []model.Expr
711+ if query .LimitBy != nil {
712+ for _ , expr := range query .LimitBy {
713+ limitBy = append (limitBy , expr .Accept (v ).(model.Expr ))
714+ }
715+ }
716+ return model .NewSelectCommand (columns , groupBy , orderBy , from , where , limitBy , query .Limit , query .SampleLimit , query .IsDistinct , namedCTEs )
651717 }
652718
719+ expr := query .SelectCommand .Accept (visitor )
720+
653721 if _ , ok := expr .(* model.SelectCommand ); ok {
654722 query .SelectCommand = * expr .(* model.SelectCommand )
655723 }
724+
656725 return query , nil
657726}
658727
@@ -726,7 +795,7 @@ func (s *SchemaCheckPass) convertQueryDateTimeFunctionToClickhouse(indexSchema s
726795
727796func (s * SchemaCheckPass ) checkAggOverUnsupportedType (indexSchema schema.Schema , query * model.Query ) (* model.Query , error ) {
728797
729- aggFunctionPrefixes := []string {"sum" , "avg" }
798+ aggFunctionPrefixes := []string {"sum" , "avg" , "quantiles" }
730799
731800 dbTypePrefixes := []string {"DateTime" , "String" , "LowCardinality(String)" }
732801
@@ -751,6 +820,15 @@ func (s *SchemaCheckPass) checkAggOverUnsupportedType(indexSchema schema.Schema,
751820 }
752821 }
753822 }
823+ // attributes values are always string,
824+ if access , ok := e .Args [0 ].(model.ArrayAccess ); ok {
825+ if access .ColumnRef .ColumnName == clickhouse .AttributesValuesColumn {
826+ logger .Warn ().Msgf ("Unsupported case. Aggregation '%s' over attribute named: '%s'" , e .Name , access .Index )
827+ args := b .VisitChildren (e .Args )
828+ args [0 ] = model .NewLiteral ("NULL" )
829+ return model .NewFunction (e .Name , args ... )
830+ }
831+ }
754832 }
755833 }
756834 }
0 commit comments