Skip to content

Commit

Permalink
Support multiple map entries for LIKE
Browse files Browse the repository at this point in the history
Signed-off-by: Andrew Richardson <andrew.richardson@kaleido.io>
  • Loading branch information
awrichar committed Jul 6, 2023
1 parent c241a79 commit 2cf8fb0
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 22 deletions.
54 changes: 42 additions & 12 deletions pkg/dbsql/filter_sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,54 @@ type NotLikeEscape sq.NotLike
type ILikeEscape sq.ILike
type NotILikeEscape sq.NotILike

func (lke LikeEscape) ToSql() (sql string, args []interface{}, err error) {
sql, args, err = sq.Like(lke).ToSql()
return fmt.Sprintf("%s ESCAPE '%s'", sql, escapeChar), args, err
// Split a map into a list of maps with a single entry each
func splitMap[T ~map[string]interface{}](m T) []T {
var exprs []T
for key, val := range m {
exprs = append(exprs, T{key: val})
}
return exprs
}

// Convert a list of Sqlizer operations to sq.And
func toAnd[T sq.Sqlizer](ops []T) sq.And {
var and sq.And
for _, op := range ops {
and = append(and, op)
}
return and
}

func (lk LikeEscape) ToSql() (sql string, args []interface{}, err error) {
if len(lk) == 1 {
sql, args, err = sq.Like(lk).ToSql()
return fmt.Sprintf("%s ESCAPE '%s'", sql, escapeChar), args, err
}
return toAnd(splitMap(lk)).ToSql()
}

func (lke NotLikeEscape) ToSql() (sql string, args []interface{}, err error) {
sql, args, err = sq.NotLike(lke).ToSql()
return fmt.Sprintf("%s ESCAPE '%s'", sql, escapeChar), args, err
func (lk NotLikeEscape) ToSql() (sql string, args []interface{}, err error) {
if len(lk) == 1 {
sql, args, err = sq.NotLike(lk).ToSql()
return fmt.Sprintf("%s ESCAPE '%s'", sql, escapeChar), args, err
}
return toAnd(splitMap(lk)).ToSql()
}

func (lke ILikeEscape) ToSql() (sql string, args []interface{}, err error) {
sql, args, err = sq.ILike(lke).ToSql()
return fmt.Sprintf("%s ESCAPE '%s'", sql, escapeChar), args, err
func (lk ILikeEscape) ToSql() (sql string, args []interface{}, err error) {
if len(lk) == 1 {
sql, args, err = sq.ILike(lk).ToSql()
return fmt.Sprintf("%s ESCAPE '%s'", sql, escapeChar), args, err
}
return toAnd(splitMap(lk)).ToSql()
}

func (lke NotILikeEscape) ToSql() (sql string, args []interface{}, err error) {
sql, args, err = sq.NotILike(lke).ToSql()
return fmt.Sprintf("%s ESCAPE '%s'", sql, escapeChar), args, err
func (lk NotILikeEscape) ToSql() (sql string, args []interface{}, err error) {
if len(lk) == 1 {
sql, args, err = sq.NotILike(lk).ToSql()
return fmt.Sprintf("%s ESCAPE '%s'", sql, escapeChar), args, err
}
return toAnd(splitMap(lk)).ToSql()
}

func (s *Database) escapeLike(value ffapi.FieldSerialization) string {
Expand Down
16 changes: 6 additions & 10 deletions pkg/dbsql/filter_sql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,18 +161,14 @@ func TestSQLQueryFactoryEvenMoreOps(t *testing.T) {

func TestSQLQueryFactoryEscapeLike(t *testing.T) {

s, _ := NewMockProvider().UTInit()
fb := TestQueryFactory.NewFilter(context.Background())
f := fb.And(fb.Contains("topics", "[%test_topic%]"))
sel := squirrel.Select("*").From("mytable AS mt").
Where(LikeEscape{"a": 1, "b": 2}).
Where(NotLikeEscape{"a": 1, "b": 2}).
Where(ILikeEscape{"a": 1, "b": 2}).
Where(NotILikeEscape{"a": 1, "b": 2})

sel := squirrel.Select("*").From("mytable AS mt")
sel, _, _, err := s.FilterSelect(context.Background(), "mt", sel, f, nil, []interface{}{"sequence"})
assert.NoError(t, err)

sqlFilter, args, err := sel.ToSql()
_, _, err := sel.ToSql()
assert.NoError(t, err)
assert.Equal(t, "SELECT * FROM mytable AS mt WHERE (mt.topics LIKE ? ESCAPE '[') ORDER BY mt.seq DESC", sqlFilter)
assert.Equal(t, []interface{}{"%[[[%test[_topic[%]%"}, args)
}

func TestSQLQueryFactoryFinalizeFail(t *testing.T) {
Expand Down

0 comments on commit 2cf8fb0

Please sign in to comment.