@@ -255,6 +255,75 @@ func findGroupByProperties(ast *eval.EvalAST) []interface{} {
255
255
return []interface {}{}
256
256
}
257
257
258
+ // processAdhocFilters extracts the common logic for processing adhoc filters
259
+ // Returns a slice of SQL condition strings that can be used in WHERE clauses
260
+ func processAdhocFilters (adhocFilters []AdhocFilter , targetDatabase , targetTable string ) []string {
261
+ var adhocConditions []string
262
+
263
+ // Process each adhoc filter
264
+ for _ , filter := range adhocFilters {
265
+ var parts []string
266
+ if strings .Contains (filter .Key , "." ) {
267
+ parts = strings .Split (filter .Key , "." )
268
+ } else {
269
+ parts = []string {targetDatabase , targetTable , filter .Key }
270
+ }
271
+
272
+ // Add missing parts
273
+ if len (parts ) == 1 {
274
+ parts = append ([]string {targetTable }, parts ... )
275
+ }
276
+ if len (parts ) == 2 {
277
+ parts = append ([]string {targetTable }, parts ... )
278
+ }
279
+ if len (parts ) < 3 {
280
+ continue
281
+ }
282
+
283
+ if targetDatabase != parts [0 ] || targetTable != parts [1 ] {
284
+ continue
285
+ }
286
+
287
+ // Convert operator
288
+ operator := filter .Operator
289
+ switch operator {
290
+ case "=~" :
291
+ operator = "LIKE"
292
+ case "!~" :
293
+ operator = "NOT LIKE"
294
+ }
295
+
296
+ // Format value with consistent quoting
297
+ var value string
298
+ switch v := filter .Value .(type ) {
299
+ case float64 :
300
+ value = fmt .Sprintf ("%g" , v )
301
+ case string :
302
+ // Don't quote if it's already a number or contains special SQL syntax
303
+ if regexp .MustCompile (`^\s*\d+(\.\d+)?\s*$` ).MatchString (v ) ||
304
+ strings .Contains (v , "'" ) ||
305
+ strings .Contains (v , ", " ) {
306
+ value = v
307
+ } else {
308
+ // Escape single quotes in string values
309
+ escaped := strings .ReplaceAll (v , "'" , "''" )
310
+ value = fmt .Sprintf ("'%s'" , escaped )
311
+ }
312
+ default :
313
+ // For any other type, convert to string and escape quotes
314
+ str := fmt .Sprintf ("%v" , v )
315
+ escaped := strings .ReplaceAll (str , "'" , "''" )
316
+ value = fmt .Sprintf ("'%s'" , escaped )
317
+ }
318
+
319
+ // Build the condition with proper spacing
320
+ condition := fmt .Sprintf ("%s %s %s" , parts [2 ], operator , value )
321
+ adhocConditions = append (adhocConditions , condition )
322
+ }
323
+
324
+ return adhocConditions
325
+ }
326
+
258
327
// handleCreateQuery processes query creation with macro expansion and time range handling
259
328
func (ds * ClickHouseDatasource ) handleCreateQuery (ctx context.Context , req * backend.CallResourceRequest , sender backend.CallResourceResponseSender ) error {
260
329
var request CreateQueryRequest
@@ -419,66 +488,8 @@ func (ds *ClickHouseDatasource) handleApplyAdhocFilters(ctx context.Context, req
419
488
}, http .StatusInternalServerError )
420
489
}
421
490
422
- // Process each adhoc filter
423
- for _ , filter := range adhocFilters {
424
- var parts []string
425
- if strings .Contains (filter .Key , "." ) {
426
- parts = strings .Split (filter .Key , "." )
427
- } else {
428
- parts = []string {targetDatabase , targetTable , filter .Key }
429
- }
430
-
431
- // Add missing parts
432
- if len (parts ) == 1 {
433
- parts = append ([]string {targetTable }, parts ... )
434
- }
435
- if len (parts ) == 2 {
436
- parts = append ([]string {targetTable }, parts ... )
437
- }
438
- if len (parts ) < 3 {
439
- continue
440
- }
441
-
442
- if targetDatabase != parts [0 ] || targetTable != parts [1 ] {
443
- continue
444
- }
445
-
446
- // Convert operator
447
- operator := filter .Operator
448
- switch operator {
449
- case "=~" :
450
- operator = "LIKE"
451
- case "!~" :
452
- operator = "NOT LIKE"
453
- }
454
-
455
- // Format value with consistent quoting
456
- var value string
457
- switch v := filter .Value .(type ) {
458
- case float64 :
459
- value = fmt .Sprintf ("%g" , v )
460
- case string :
461
- // Don't quote if it's already a number or contains special SQL syntax
462
- if regexp .MustCompile (`^\s*\d+(\.\d+)?\s*$` ).MatchString (v ) ||
463
- strings .Contains (v , "'" ) ||
464
- strings .Contains (v , ", " ) {
465
- value = v
466
- } else {
467
- // Escape single quotes in string values
468
- escaped := strings .ReplaceAll (v , "'" , "''" )
469
- value = fmt .Sprintf ("'%s'" , escaped )
470
- }
471
- default :
472
- // For any other type, convert to string and escape quotes
473
- str := fmt .Sprintf ("%v" , v )
474
- escaped := strings .ReplaceAll (str , "'" , "''" )
475
- value = fmt .Sprintf ("'%s'" , escaped )
476
- }
477
-
478
- // Build the condition with proper spacing
479
- condition := fmt .Sprintf ("%s %s %s" , parts [2 ], operator , value )
480
- adhocConditions = append (adhocConditions , condition )
481
- }
491
+ // Process adhoc filters using shared utility function
492
+ adhocConditions = processAdhocFilters (adhocFilters , targetDatabase , targetTable )
482
493
483
494
// Handle conditions differently based on $adhoc presence
484
495
if ! strings .Contains (query , "$adhoc" ) {
@@ -758,66 +769,8 @@ func (ds *ClickHouseDatasource) handleProcessQueryBatch(ctx context.Context, req
758
769
})
759
770
}
760
771
761
- // Process each adhoc filter
762
- for _ , filter := range adhocFilters {
763
- var parts []string
764
- if strings .Contains (filter .Key , "." ) {
765
- parts = strings .Split (filter .Key , "." )
766
- } else {
767
- parts = []string {targetDatabase , targetTable , filter .Key }
768
- }
769
-
770
- // Add missing parts
771
- if len (parts ) == 1 {
772
- parts = append ([]string {targetTable }, parts ... )
773
- }
774
- if len (parts ) == 2 {
775
- parts = append ([]string {targetTable }, parts ... )
776
- }
777
- if len (parts ) < 3 {
778
- continue
779
- }
780
-
781
- if targetDatabase != parts [0 ] || targetTable != parts [1 ] {
782
- continue
783
- }
784
-
785
- // Convert operator
786
- operator := filter .Operator
787
- switch operator {
788
- case "=~" :
789
- operator = "LIKE"
790
- case "!~" :
791
- operator = "NOT LIKE"
792
- }
793
-
794
- // Format value with consistent quoting
795
- var value string
796
- switch v := filter .Value .(type ) {
797
- case float64 :
798
- value = fmt .Sprintf ("%g" , v )
799
- case string :
800
- // Don't quote if it's already a number or contains special SQL syntax
801
- if regexp .MustCompile (`^\s*\d+(\.\d+)?\s*$` ).MatchString (v ) ||
802
- strings .Contains (v , "'" ) ||
803
- strings .Contains (v , ", " ) {
804
- value = v
805
- } else {
806
- // Escape single quotes in string values
807
- escaped := strings .ReplaceAll (v , "'" , "''" )
808
- value = fmt .Sprintf ("'%s'" , escaped )
809
- }
810
- default :
811
- // For any other type, convert to string and escape quotes
812
- str := fmt .Sprintf ("%v" , v )
813
- escaped := strings .ReplaceAll (str , "'" , "''" )
814
- value = fmt .Sprintf ("'%s'" , escaped )
815
- }
816
-
817
- // Build the condition with proper spacing
818
- condition := fmt .Sprintf ("%s %s %s" , parts [2 ], operator , value )
819
- adhocConditions = append (adhocConditions , condition )
820
- }
772
+ // Process adhoc filters using shared utility function
773
+ adhocConditions := processAdhocFilters (adhocFilters , targetDatabase , targetTable )
821
774
822
775
// Handle conditions differently based on $adhoc presence
823
776
if ! strings .Contains (sql , "$adhoc" ) {
@@ -1260,66 +1213,8 @@ func (ds *ClickHouseDatasource) handleCreateQueryWithAdhoc(ctx context.Context,
1260
1213
}, http .StatusInternalServerError )
1261
1214
}
1262
1215
1263
- // Process each adhoc filter
1264
- for _ , filter := range adhocFilters {
1265
- var parts []string
1266
- if strings .Contains (filter .Key , "." ) {
1267
- parts = strings .Split (filter .Key , "." )
1268
- } else {
1269
- parts = []string {targetDatabase , targetTable , filter .Key }
1270
- }
1271
-
1272
- // Add missing parts
1273
- if len (parts ) == 1 {
1274
- parts = append ([]string {targetTable }, parts ... )
1275
- }
1276
- if len (parts ) == 2 {
1277
- parts = append ([]string {targetTable }, parts ... )
1278
- }
1279
- if len (parts ) < 3 {
1280
- continue
1281
- }
1282
-
1283
- if targetDatabase != parts [0 ] || targetTable != parts [1 ] {
1284
- continue
1285
- }
1286
-
1287
- // Convert operator
1288
- operator := filter .Operator
1289
- switch operator {
1290
- case "=~" :
1291
- operator = "LIKE"
1292
- case "!~" :
1293
- operator = "NOT LIKE"
1294
- }
1295
-
1296
- // Format value with consistent quoting
1297
- var value string
1298
- switch v := filter .Value .(type ) {
1299
- case float64 :
1300
- value = fmt .Sprintf ("%g" , v )
1301
- case string :
1302
- // Don't quote if it's already a number or contains special SQL syntax
1303
- if regexp .MustCompile (`^\s*\d+(\.\d+)?\s*$` ).MatchString (v ) ||
1304
- strings .Contains (v , "'" ) ||
1305
- strings .Contains (v , ", " ) {
1306
- value = v
1307
- } else {
1308
- // Escape single quotes in string values
1309
- escaped := strings .ReplaceAll (v , "'" , "''" )
1310
- value = fmt .Sprintf ("'%s'" , escaped )
1311
- }
1312
- default :
1313
- // For any other type, convert to string and escape quotes
1314
- str := fmt .Sprintf ("%v" , v )
1315
- escaped := strings .ReplaceAll (str , "'" , "''" )
1316
- value = fmt .Sprintf ("'%s'" , escaped )
1317
- }
1318
-
1319
- // Build the condition with proper spacing
1320
- condition := fmt .Sprintf ("%s %s %s" , parts [2 ], operator , value )
1321
- adhocConditions = append (adhocConditions , condition )
1322
- }
1216
+ // Process adhoc filters using shared utility function
1217
+ adhocConditions = processAdhocFilters (adhocFilters , targetDatabase , targetTable )
1323
1218
1324
1219
// Handle conditions differently based on $adhoc presence
1325
1220
if ! strings .Contains (sql , "$adhoc" ) {
0 commit comments