Skip to content

Commit

Permalink
feat(chsql): add more helpers to build predicates
Browse files Browse the repository at this point in the history
  • Loading branch information
tdakkota committed Jun 7, 2024
1 parent 567c14c commit 703a3e5
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 16 deletions.
17 changes: 9 additions & 8 deletions internal/chstorage/chsql/chsql.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,16 +123,17 @@ func (p *Printer) WriteExpr(e Expr) error {

return nil
case exprBinaryOp:
if l := len(e.args); l != 2 {
return errors.Errorf("binary expression must have exacty two args, got %d", l)
if l := len(e.args); l < 2 {
return errors.Errorf("binary expression must have at least two args, got %d", l)
}

if err := p.WriteExpr(e.args[0]); err != nil {
return err
}
p.Ident(e.tok)
if err := p.WriteExpr(e.args[1]); err != nil {
return err
for i, arg := range e.args {
if i != 0 {
p.Ident(e.tok)
}
if err := p.WriteExpr(arg); err != nil {
return err
}
}

return nil
Expand Down
20 changes: 15 additions & 5 deletions internal/chstorage/chsql/function.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,21 @@ func ToFloat64(arg Expr) Expr {
return Function("toFloat64", arg)
}

// ToUnixTimestamp64Nano returns `toUnixTimestamp64Nano(<arg>)` function call expression.
func ToUnixTimestamp64Nano(arg Expr) Expr {
return Function("toUnixTimestamp64Nano", arg)
}

// Coalesce returns `coalesce(<args>...)` function call expression.
func Coalesce(args ...Expr) Expr {
return Function("coalesce", args...)
}

// Has returns `has(<arr>, <elem>)` function call expression.
func Has(arr, elem Expr) Expr {
return Function("has", arr, elem)
}

// Map returns `map(<args>...)` function call expression.
func Map(args ...Expr) Expr {
return Function("map", args...)
Expand Down Expand Up @@ -55,6 +65,11 @@ func Unhex(arg Expr) Expr {
return Function("unhex", arg)
}

// Length returns `length(<arg>)` function call expression.
func Length(arg Expr) Expr {
return Function("length", arg)
}

// PositionUTF8 returns `positionUTF8(<haystack>, <needle>)` function call expression.
func PositionUTF8(haystack, needle Expr) Expr {
return Function("positionUTF8", haystack, needle)
Expand All @@ -65,11 +80,6 @@ func Match(haystack, pattern Expr) Expr {
return Function("match", haystack, pattern)
}

// Length returns `length(<arg>)` function call expression.
func Length(arg Expr) Expr {
return Function("length", arg)
}

// JSONExtract returns `JSONExtract(<from>, <typ>)` function call expression.
func JSONExtract(from Expr, typ string) Expr {
return Function("JSONExtract", from, String(typ))
Expand Down
15 changes: 12 additions & 3 deletions internal/chstorage/chsql/op.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,18 @@ func binaryOp(left Expr, op string, right Expr) Expr {
return Expr{typ: exprBinaryOp, tok: op, args: []Expr{left, right}}
}

func joinBinaryOp(op string, args []Expr) Expr {
return Expr{typ: exprBinaryOp, tok: op, args: args}
}

// Eq returns new `=` operation.
func Eq(left, right Expr) Expr {
return binaryOp(left, "=", right)
}

// ColumnEq returns new `=` operation on column and literal.
func ColumnEq[V litValue](left string, right V) Expr {
return binaryOp(Ident(left), "=", Value(right))
// NotEq returns new `!=` operation.
func NotEq(left, right Expr) Expr {
return binaryOp(left, "!=", right)
}

// Gt returns new `>` operation.
Expand Down Expand Up @@ -53,6 +57,11 @@ func Or(left, right Expr) Expr {
return binaryOp(left, "OR", right)
}

// Minus returns new `-` operation.
func Minus(left, right Expr) Expr {
return binaryOp(left, "-", right)
}

// In returns new `IN` operation.
func In(left, right Expr) Expr {
return binaryOp(left, "IN", right)
Expand Down
37 changes: 37 additions & 0 deletions internal/chstorage/chsql/sugar.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,47 @@ func InTimeRange(column string, start, end time.Time) Expr {
return expr
}

// ColumnEq returns new `=` operation on column and literal.
func ColumnEq[V litValue](column string, right V) Expr {
return binaryOp(Ident(column), "=", Value(right))
}

// Contains returns boolean expression to filter strings containing needle.
func Contains(column, needle string) Expr {
return Gt(
PositionUTF8(Ident(column), String(needle)),
Integer(0),
)
}

// JoinAnd joins given expressions using AND op.
//
// - If len(args) == 0, returns `true` literal.
// - If len(args) == 1, returns first argument.
// - Otherwise, joins arguments with AND.
func JoinAnd(args ...Expr) Expr {
switch len(args) {
case 0:
return Bool(true)
case 1:
return args[0]
default:
return joinBinaryOp("AND", args)
}
}

// JoinOr joins given expressions using OR op.
//
// - If len(args) == 0, returns `true` literal.
// - If len(args) == 1, returns first argument.
// - Otherwise, joins arguments with OR.
func JoinOr(args ...Expr) Expr {
switch len(args) {
case 0:
return Bool(true)
case 1:
return args[0]
default:
return joinBinaryOp("OR", args)
}
}
44 changes: 44 additions & 0 deletions internal/chstorage/chsql/sugar_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,47 @@ func TestInTimeRange(t *testing.T) {
})
}
}

func TestJoinAnd(t *testing.T) {
tests := []struct {
args []Expr
want string
wantErr bool
}{
{nil, "true", false},
{
[]Expr{
Ident("foo"),
Ident("bar"),
},
"foo AND bar",
false,
},
{
[]Expr{
Ident("foo"),
Ident("bar"),
Ident("baz"),
},
"foo AND bar AND baz",
false,
},

{[]Expr{Ident("foo")}, "", true},
}
for i, tt := range tests {
tt := tt
t.Run(fmt.Sprintf("Test%d", i+1), func(t *testing.T) {
got := JoinAnd(tt.args...)

p := GetPrinter()
err := p.WriteExpr(got)
if tt.wantErr {
require.Error(t, err)
return
}
require.NoError(t, err)
require.Equal(t, tt.want, p.String())
})
}
}

0 comments on commit 703a3e5

Please sign in to comment.