Skip to content

Commit ce39a97

Browse files
author
Roman M
committed
Move adhoc filters processing to shared function
1 parent 162344c commit ce39a97

File tree

1 file changed

+75
-180
lines changed

1 file changed

+75
-180
lines changed

pkg/resource_handlers.go

Lines changed: 75 additions & 180 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,75 @@ func findGroupByProperties(ast *eval.EvalAST) []interface{} {
255255
return []interface{}{}
256256
}
257257

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+
258327
// handleCreateQuery processes query creation with macro expansion and time range handling
259328
func (ds *ClickHouseDatasource) handleCreateQuery(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
260329
var request CreateQueryRequest
@@ -419,66 +488,8 @@ func (ds *ClickHouseDatasource) handleApplyAdhocFilters(ctx context.Context, req
419488
}, http.StatusInternalServerError)
420489
}
421490

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)
482493

483494
// Handle conditions differently based on $adhoc presence
484495
if !strings.Contains(query, "$adhoc") {
@@ -758,66 +769,8 @@ func (ds *ClickHouseDatasource) handleProcessQueryBatch(ctx context.Context, req
758769
})
759770
}
760771

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)
821774

822775
// Handle conditions differently based on $adhoc presence
823776
if !strings.Contains(sql, "$adhoc") {
@@ -1260,66 +1213,8 @@ func (ds *ClickHouseDatasource) handleCreateQueryWithAdhoc(ctx context.Context,
12601213
}, http.StatusInternalServerError)
12611214
}
12621215

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)
13231218

13241219
// Handle conditions differently based on $adhoc presence
13251220
if !strings.Contains(sql, "$adhoc") {

0 commit comments

Comments
 (0)