33package queryparser
44
55import (
6- "quesma/logger"
6+ "errors"
7+ "fmt"
78 "quesma/model"
89 "quesma/model/pipeline_aggregations"
910 "quesma/util"
@@ -12,217 +13,147 @@ import (
1213
1314// CAUTION: maybe "return" everywhere isn't corrent, as maybe there can be multiple pipeline aggregations at one level.
1415// But I've tested some complex queries and it seems to not be the case. So let's keep it this way for now.
15- func (cw * ClickhouseQueryTranslator ) parsePipelineAggregations (queryMap QueryMap ) (aggregationType model.QueryType , success bool ) {
16- if aggregationType , success = cw .parseBucketScriptBasic (queryMap ); success {
17- delete (queryMap , "bucket_script" )
18- return
19- }
20- if aggregationType , success = cw .parseCumulativeSum (queryMap ); success {
21- delete (queryMap , "cumulative_sum" )
22- return
23- }
24- if aggregationType , success = cw .parseDerivative (queryMap ); success {
25- delete (queryMap , "derivative" )
26- return
27- }
28- if aggregationType , success = cw .parseSerialDiff (queryMap ); success {
29- delete (queryMap , "derivative" )
30- return
31- }
32- if aggregationType , success = cw .parseAverageBucket (queryMap ); success {
33- delete (queryMap , "avg_bucket" )
34- return
35- }
36- if aggregationType , success = cw .parseMinBucket (queryMap ); success {
37- delete (queryMap , "min_bucket" )
38- return
39- }
40- if aggregationType , success = cw .parseMaxBucket (queryMap ); success {
41- delete (queryMap , "max_bucket" )
42- return
43- }
44- if aggregationType , success = cw .parseSumBucket (queryMap ); success {
45- delete (queryMap , "sum_bucket" )
46- return
16+ func (cw * ClickhouseQueryTranslator ) parsePipelineAggregations (queryMap QueryMap ) (aggregationType model.QueryType , err error ) {
17+ parsers := map [string ]aggregationParser {
18+ "bucket_script" : cw .parseBucketScriptBasic ,
19+ "cumulative_sum" : cw .parseCumulativeSum ,
20+ "derivative" : cw .parseDerivative ,
21+ "serial_diff" : cw .parseSerialDiff ,
22+ "avg_bucket" : cw .parseAverageBucket ,
23+ "min_bucket" : cw .parseMinBucket ,
24+ "max_bucket" : cw .parseMaxBucket ,
25+ "sum_bucket" : cw .parseSumBucket ,
26+ }
27+
28+ for aggrName , aggrParser := range parsers {
29+ if paramsRaw , exists := queryMap [aggrName ]; exists {
30+ if params , ok := paramsRaw .(QueryMap ); ok {
31+ delete (queryMap , aggrName )
32+ return aggrParser (params )
33+ }
34+ return nil , fmt .Errorf ("%s is not a map, but %T, value: %v" , aggrName , paramsRaw , paramsRaw )
35+ }
4736 }
48- return
49- }
5037
51- func (cw * ClickhouseQueryTranslator ) parseCumulativeSum (queryMap QueryMap ) (aggregationType model.QueryType , success bool ) {
52- cumulativeSumRaw , exists := queryMap ["cumulative_sum" ]
53- if ! exists {
54- return
55- }
56- bucketsPath , ok := cw .parseBucketsPath (cumulativeSumRaw , "cumulative_sum" )
57- if ! ok {
58- return
59- }
60- return pipeline_aggregations .NewCumulativeSum (cw .Ctx , bucketsPath ), true
38+ return nil , nil
6139}
6240
63- func (cw * ClickhouseQueryTranslator ) parseDerivative (queryMap QueryMap ) (aggregationType model.QueryType , success bool ) {
64- derivativeRaw , exists := queryMap ["derivative" ]
65- if ! exists {
66- return
67- }
68- bucketsPath , ok := cw .parseBucketsPath (derivativeRaw , "derivative" )
69- if ! ok {
70- return
41+ func (cw * ClickhouseQueryTranslator ) parseCumulativeSum (params QueryMap ) (model.QueryType , error ) {
42+ bucketsPath , err := cw .parseBucketsPath (params , "cumulative_sum" )
43+ if err != nil {
44+ return nil , err
7145 }
72- return pipeline_aggregations .NewDerivative (cw .Ctx , bucketsPath ), true
46+ return pipeline_aggregations .NewCumulativeSum (cw .Ctx , bucketsPath ), nil
7347}
7448
75- func (cw * ClickhouseQueryTranslator ) parseAverageBucket (queryMap QueryMap ) (aggregationType model.QueryType , success bool ) {
76- avgBucketRaw , exists := queryMap ["avg_bucket" ]
77- if ! exists {
78- return
79- }
80- bucketsPath , ok := cw .parseBucketsPath (avgBucketRaw , "avg_bucket" )
81- if ! ok {
82- return
49+ func (cw * ClickhouseQueryTranslator ) parseDerivative (params QueryMap ) (model.QueryType , error ) {
50+ bucketsPath , err := cw .parseBucketsPath (params , "derivative" )
51+ if err != nil {
52+ return nil , err
8353 }
84- return pipeline_aggregations .NewAverageBucket (cw .Ctx , bucketsPath ), true
54+ return pipeline_aggregations .NewDerivative (cw .Ctx , bucketsPath ), nil
8555}
8656
87- func (cw * ClickhouseQueryTranslator ) parseMinBucket ( queryMap QueryMap ) (aggregationType model.QueryType , success bool ) {
88- minBucketRaw , exists := queryMap [ "min_bucket" ]
89- if ! exists {
90- return
57+ func (cw * ClickhouseQueryTranslator ) parseAverageBucket ( params QueryMap ) (model.QueryType , error ) {
58+ bucketsPath , err := cw . parseBucketsPath ( params , "avg_bucket" )
59+ if err != nil {
60+ return nil , err
9161 }
92- bucketsPath , ok := cw .parseBucketsPath (minBucketRaw , "min_bucket" )
93- if ! ok {
94- return
95- }
96- return pipeline_aggregations .NewMinBucket (cw .Ctx , bucketsPath ), true
62+ return pipeline_aggregations .NewAverageBucket (cw .Ctx , bucketsPath ), nil
9763}
9864
99- func (cw * ClickhouseQueryTranslator ) parseMaxBucket (queryMap QueryMap ) (aggregationType model.QueryType , success bool ) {
100- maxBucketRaw , exists := queryMap ["max_bucket" ]
101- if ! exists {
102- return
103- }
104- bucketsPath , ok := cw .parseBucketsPath (maxBucketRaw , "max_bucket" )
105- if ! ok {
106- return
65+ func (cw * ClickhouseQueryTranslator ) parseMinBucket (params QueryMap ) (model.QueryType , error ) {
66+ bucketsPath , err := cw .parseBucketsPath (params , "min_bucket" )
67+ if err != nil {
68+ return nil , err
10769 }
108- return pipeline_aggregations .NewMaxBucket (cw .Ctx , bucketsPath ), true
70+ return pipeline_aggregations .NewMinBucket (cw .Ctx , bucketsPath ), nil
10971}
11072
111- func (cw * ClickhouseQueryTranslator ) parseSumBucket ( queryMap QueryMap ) (aggregationType model.QueryType , success bool ) {
112- sumBucketRaw , exists := queryMap [ "sum_bucket" ]
113- if ! exists {
114- return
73+ func (cw * ClickhouseQueryTranslator ) parseMaxBucket ( params QueryMap ) (model.QueryType , error ) {
74+ bucketsPath , err := cw . parseBucketsPath ( params , "max_bucket" )
75+ if err != nil {
76+ return nil , err
11577 }
116- bucketsPath , ok := cw .parseBucketsPath (sumBucketRaw , "sum_bucket" )
117- if ! ok {
118- return
119- }
120- return pipeline_aggregations .NewSumBucket (cw .Ctx , bucketsPath ), true
78+ return pipeline_aggregations .NewMaxBucket (cw .Ctx , bucketsPath ), nil
12179}
12280
123- func (cw * ClickhouseQueryTranslator ) parseSerialDiff ( queryMap QueryMap ) (aggregationType model.QueryType , success bool ) {
124- serialDiffRaw , exists := queryMap [ "serial_diff" ]
125- if ! exists {
126- return
81+ func (cw * ClickhouseQueryTranslator ) parseSumBucket ( params QueryMap ) (model.QueryType , error ) {
82+ bucketsPath , err := cw . parseBucketsPath ( params , "sum_bucket" )
83+ if err != nil {
84+ return nil , err
12785 }
86+ return pipeline_aggregations .NewSumBucket (cw .Ctx , bucketsPath ), nil
87+ }
12888
89+ func (cw * ClickhouseQueryTranslator ) parseSerialDiff (params QueryMap ) (model.QueryType , error ) {
12990 // buckets_path
130- bucketsPath , ok := cw .parseBucketsPath (serialDiffRaw , "serial_diff" )
131- if ! ok {
132- return
91+ bucketsPath , err := cw .parseBucketsPath (params , "serial_diff" )
92+ if err != nil {
93+ return nil , err
13394 }
13495
13596 // lag
13697 const defaultLag = 1
137- serialDiff , ok := serialDiffRaw .(QueryMap )
138- if ! ok {
139- logger .WarnWithCtx (cw .Ctx ).Msgf ("serial_diff is not a map, but %T, value: %v" , serialDiffRaw , serialDiffRaw )
140- return
141- }
142- lagRaw , exists := serialDiff ["lag" ]
98+ lagRaw , exists := params ["lag" ]
14399 if ! exists {
144- return pipeline_aggregations .NewSerialDiff (cw .Ctx , bucketsPath , defaultLag ), true
100+ return pipeline_aggregations .NewSerialDiff (cw .Ctx , bucketsPath , defaultLag ), nil
145101 }
146102 if lag , ok := lagRaw .(float64 ); ok {
147- return pipeline_aggregations .NewSerialDiff (cw .Ctx , bucketsPath , int (lag )), true
103+ return pipeline_aggregations .NewSerialDiff (cw .Ctx , bucketsPath , int (lag )), nil
148104 }
149105
150- logger .WarnWithCtx (cw .Ctx ).Msgf ("lag is not a float64, but %T, value: %v" , lagRaw , lagRaw )
151- return
106+ return nil , fmt .Errorf ("lag is not a float64, but %T, value: %v" , lagRaw , lagRaw )
152107}
153108
154- func (cw * ClickhouseQueryTranslator ) parseBucketScriptBasic (queryMap QueryMap ) (aggregationType model.QueryType , success bool ) {
155- bucketScriptRaw , exists := queryMap ["bucket_script" ]
156- if ! exists {
157- return
158- }
159-
160- // so far we only handle "count" here :D
161- delete (queryMap , "bucket_script" )
162- bucketScript , ok := bucketScriptRaw .(QueryMap )
163- if ! ok {
164- logger .WarnWithCtx (cw .Ctx ).Msgf ("bucket_script is not a map, but %T, value: %v. Skipping this aggregation" , bucketScriptRaw , bucketScriptRaw )
165- return
166- }
167-
168- // if ["buckets_path"] != "_count", skip the aggregation
169- bucketsPath , ok := cw .parseBucketsPath (bucketScript , "bucket_script" )
170- if ! ok {
171- return
109+ func (cw * ClickhouseQueryTranslator ) parseBucketScriptBasic (params QueryMap ) (model.QueryType , error ) {
110+ bucketsPath , err := cw .parseBucketsPath (params , "bucket_script" )
111+ if err != nil {
112+ return nil , err
172113 }
173114 if ! strings .HasSuffix (bucketsPath , pipeline_aggregations .BucketsPathCount ) {
174- logger . WarnWithCtx ( cw . Ctx ). Msgf ( "buckets_path is not '_count', but %s. Skipping this aggregation" , bucketsPath )
175- return
115+ //lint:ignore ST1005 I want Quesma capitalized
116+ return nil , fmt . Errorf ( "Quesma limitation, contact us if you need it fixed: buckets_path is not '_count', but %s" , bucketsPath )
176117 }
177118
178- scriptRaw , exists := bucketScript ["script" ]
119+ scriptRaw , exists := params ["script" ]
179120 if ! exists {
180- logger .WarnWithCtx (cw .Ctx ).Msg ("no script in bucket_script. Skipping this aggregation" )
181- return
121+ return nil , errors .New ("no script in bucket_script" )
182122 }
183123 if script , ok := scriptRaw .(string ); ok {
184- return pipeline_aggregations .NewBucketScript (cw .Ctx , bucketsPath , script ), true
124+ return pipeline_aggregations .NewBucketScript (cw .Ctx , bucketsPath , script ), nil
185125 }
186126
187127 script , ok := scriptRaw .(QueryMap )
188128 if ! ok {
189- logger .WarnWithCtx (cw .Ctx ).Msgf ("script is not a map, but %T, value: %v. Skipping this aggregation" , scriptRaw , scriptRaw )
190- return
129+ return nil , fmt .Errorf ("script is not a map, but %T, value: %v" , scriptRaw , scriptRaw )
191130 }
192131 if sourceRaw , exists := script ["source" ]; exists {
193132 if source , ok := sourceRaw .(string ); ok {
194133 if source != "_value" && source != "count * 1" {
195- logger . WarnWithCtx ( cw . Ctx ). Msgf ( "source is not '_value'/'count * 1', but %s. Skipping this aggregation" , source )
196- return
134+ //lint:ignore ST1005 I want Quesma capitalized
135+ return nil , fmt . Errorf ( "Quesma limitation, contact us if you need it fixed: source is not '_value'/'count * 1', but %s" , source )
197136 }
198137 } else {
199- logger .WarnWithCtx (cw .Ctx ).Msgf ("source is not a string, but %T, value: %v. Skipping this aggregation" , sourceRaw , sourceRaw )
200- return
138+ return nil , fmt .Errorf ("source is not a string, but %T, value: %v" , sourceRaw , sourceRaw )
201139 }
202140 } else {
203- logger .WarnWithCtx (cw .Ctx ).Msg ("no source in script. Skipping this aggregation" )
204- return
141+ return nil , errors .New ("no source in script" )
205142 }
206143
207144 // okay, we've checked everything, it's indeed a simple count
208- return pipeline_aggregations .NewBucketScript (cw .Ctx , bucketsPath , "" ), true
145+ return pipeline_aggregations .NewBucketScript (cw .Ctx , bucketsPath , "" ), nil
209146}
210147
211- func (cw * ClickhouseQueryTranslator ) parseBucketsPath (shouldBeQueryMap any , aggregationName string ) (bucketsPathStr string , success bool ) {
212- queryMap , ok := shouldBeQueryMap .(QueryMap )
213- if ! ok {
214- logger .WarnWithCtx (cw .Ctx ).Msgf ("%s is not a map, but %T, value: %v" , aggregationName , shouldBeQueryMap , shouldBeQueryMap )
215- return
216- }
217- bucketsPathRaw , exists := queryMap ["buckets_path" ]
148+ func (cw * ClickhouseQueryTranslator ) parseBucketsPath (params QueryMap , aggregationName string ) (bucketsPathStr string , err error ) {
149+ bucketsPathRaw , exists := params ["buckets_path" ]
218150 if ! exists {
219- logger .WarnWithCtx (cw .Ctx ).Msg ("no buckets_path in avg_bucket" )
220- return
151+ return "" , fmt .Errorf ("no buckets_path in %s" , aggregationName )
221152 }
222153
223154 switch bucketsPath := bucketsPathRaw .(type ) {
224155 case string :
225- return bucketsPath , true
156+ return bucketsPath , nil
226157 case QueryMap :
227158 // TODO: handle arbitrary nr of keys (and arbitrary scripts, because we also handle only one special case)
228159 if len (bucketsPath ) == 1 || len (bucketsPath ) == 2 {
@@ -231,17 +162,15 @@ func (cw *ClickhouseQueryTranslator) parseBucketsPath(shouldBeQueryMap any, aggr
231162 // After fixing the TODO above, it should also get fixed.
232163 for _ , key := range util .MapKeysSorted (bucketsPath ) {
233164 if path , ok := bucketsPath [key ].(string ); ok {
234- return path , true
165+ return path , nil
235166 } else {
236- logger .WarnWithCtx (cw .Ctx ).Msgf ("buckets_path is not a map with string values, but %T. Skipping this aggregation" , path )
237- return
167+ return "" , fmt .Errorf ("buckets_path is not a map with string values, but %T %v" , bucketsPath [key ], bucketsPath [key ])
238168 }
239169 }
240170 } else {
241- logger . WarnWithCtx ( cw . Ctx ). Msgf ( "buckets_path is not a map with one or two keys, but %d. Skipping this aggregation " , len ( bucketsPath ) )
171+ return "" , fmt . Errorf ( "buckets_path is not a map with one or two keys, but it is: %v " , bucketsPath )
242172 }
243173 }
244174
245- logger .WarnWithCtx (cw .Ctx ).Msgf ("buckets_path in wrong format, type: %T, value: %v" , bucketsPathRaw , bucketsPathRaw )
246- return
175+ return "" , fmt .Errorf ("buckets_path in wrong format, type: %T, value: %v" , bucketsPathRaw , bucketsPathRaw )
247176}
0 commit comments