Skip to content
This repository was archived by the owner on Nov 7, 2025. It is now read-only.

Commit cf0fd3f

Browse files
authored
Fix ids query DSL (#1135)
By accident I noticed our SQL generated for `ids` looks quite nonsensical, e.g. that's what's generated for my new very simple request: ``` WHERE "@timestamp" IN toDateTime64('2024-12-21 07:29:03.367', '2024-12-21 07:29:02.992', 3) ``` Also noticed we have 0 tests for this query. Fixing those 2 things here. (adding `TupleExpr` for just this 1 usecase might seem unnecessary, but it's needed in my 2 other open PRs, so I'd do that) Also, minor: changed `return model.NewSimpleQuery(nil, false)` to more descriptive `return model.NewSimpleQueryInvalid()` everywhere.
1 parent 876f88d commit cf0fd3f

File tree

8 files changed

+196
-70
lines changed

8 files changed

+196
-70
lines changed

quesma/logger/log_with_throttling.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
"time"
99
)
1010

11-
var throttleMap = util.SyncMap[string, time.Time]{}
11+
var throttleMap = util.NewSyncMap[string, time.Time]()
1212

1313
const throttleDuration = 30 * time.Minute
1414

@@ -25,3 +25,14 @@ func WarnWithCtxAndThrottling(ctx context.Context, aggrName, paramName, format s
2525
throttleMap.Store(mapKey, time.Now())
2626
}
2727
}
28+
29+
// WarnWithThrottling - logs a warning message with throttling.
30+
// We only log once per throttleDuration for each warnName, so that we don't spam the logs.
31+
func WarnWithThrottling(warnName, format string, v ...any) {
32+
timestamp, ok := throttleMap.Load(warnName)
33+
weThrottle := ok && time.Since(timestamp) < throttleDuration
34+
if !weThrottle {
35+
Warn().Msgf(format, v...)
36+
throttleMap.Store(warnName, time.Now())
37+
}
38+
}

quesma/model/base_visitor.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package model
55
type BaseExprVisitor struct {
66
OverrideVisitFunction func(b *BaseExprVisitor, e FunctionExpr) interface{}
77
OverrideVisitLiteral func(b *BaseExprVisitor, l LiteralExpr) interface{}
8+
OverrideVisitTuple func(b *BaseExprVisitor, t TupleExpr) interface{}
89
OverrideVisitInfix func(b *BaseExprVisitor, e InfixExpr) interface{}
910
OverrideVisitColumnRef func(b *BaseExprVisitor, e ColumnRef) interface{}
1011
OverrideVisitPrefixExpr func(b *BaseExprVisitor, e PrefixExpr) interface{}
@@ -43,6 +44,14 @@ func (v *BaseExprVisitor) VisitLiteral(e LiteralExpr) interface{} {
4344

4445
return NewLiteral(e.Value)
4546
}
47+
48+
func (v *BaseExprVisitor) VisitTuple(e TupleExpr) interface{} {
49+
if v.OverrideVisitTuple != nil {
50+
return v.OverrideVisitTuple(v, e)
51+
}
52+
return NewTupleExpr(v.VisitChildren(e.Exprs)...)
53+
}
54+
4655
func (v *BaseExprVisitor) VisitInfix(e InfixExpr) interface{} {
4756
if v.OverrideVisitInfix != nil {
4857
return v.OverrideVisitInfix(v, e)

quesma/model/expr.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ type Expr interface {
1212
var (
1313
InvalidExpr = Expr(nil)
1414
TrueExpr = NewLiteral(true)
15+
FalseExpr = NewLiteral(false)
1516
)
1617

1718
// ColumnRef is a reference to a column in a table, we can enrich it with more information (e.g. type used) as we go
@@ -86,6 +87,18 @@ func (e LiteralExpr) Accept(v ExprVisitor) interface{} {
8687
return v.VisitLiteral(e)
8788
}
8889

90+
type TupleExpr struct {
91+
Exprs []Expr
92+
}
93+
94+
func NewTupleExpr(exprs ...Expr) TupleExpr {
95+
return TupleExpr{Exprs: exprs}
96+
}
97+
98+
func (e TupleExpr) Accept(v ExprVisitor) interface{} {
99+
return v.VisitTuple(e)
100+
}
101+
89102
type InfixExpr struct {
90103
Left Expr
91104
Op string
@@ -278,6 +291,7 @@ func (e CTE) Accept(v ExprVisitor) interface{} {
278291
type ExprVisitor interface {
279292
VisitFunction(e FunctionExpr) interface{}
280293
VisitLiteral(l LiteralExpr) interface{}
294+
VisitTuple(t TupleExpr) interface{}
281295
VisitInfix(e InfixExpr) interface{}
282296
VisitColumnRef(e ColumnRef) interface{}
283297
VisitPrefixExpr(e PrefixExpr) interface{}

quesma/model/expr_string_renderer.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package model
44

55
import (
66
"fmt"
7+
"quesma/logger"
78
"quesma/quesma/types"
89
"regexp"
910
"sort"
@@ -68,6 +69,22 @@ func (v *renderer) VisitLiteral(l LiteralExpr) interface{} {
6869
return fmt.Sprintf("%v", l.Value)
6970
}
7071

72+
func (v *renderer) VisitTuple(t TupleExpr) interface{} {
73+
switch len(t.Exprs) {
74+
case 0:
75+
logger.WarnWithThrottling("VisitTuple", "TupleExpr with no expressions")
76+
return "()"
77+
case 1:
78+
return t.Exprs[0].Accept(v)
79+
default:
80+
args := make([]string, len(t.Exprs))
81+
for i, arg := range t.Exprs {
82+
args[i] = arg.Accept(v).(string)
83+
}
84+
return fmt.Sprintf("tuple(%s)", strings.Join(args, ", ")) // can omit "tuple", but I think SQL's more readable with it
85+
}
86+
}
87+
7188
func (v *renderer) VisitInfix(e InfixExpr) interface{} {
7289
var lhs, rhs interface{} // TODO FOR NOW LITTLE PARANOID BUT HELPS ME NOT SEE MANY PANICS WHEN TESTING
7390
if e.Left != nil {

quesma/model/simple_query.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ func NewSimpleQuery(whereClause Expr, canParse bool) SimpleQuery {
2828
return SimpleQuery{WhereClause: whereClause, CanParse: canParse}
2929
}
3030

31+
func NewSimpleQueryInvalid() SimpleQuery {
32+
return SimpleQuery{CanParse: false}
33+
}
34+
3135
// LimitForCount returns (limit, true) if we need count(*) with limit,
3236
// (not-important, false) if we don't need count/limit
3337
func (s *SimpleQuery) LimitForCount() (limit int, doWeNeedLimit bool) {

0 commit comments

Comments
 (0)