From ccc9387657f9b2358690f5da07fb9ea3cd8a5b3a Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Fri, 29 Oct 2021 13:56:19 -0400 Subject: [PATCH] Add database support for SELECT DISTINCT Signed-off-by: Andrew Richardson --- internal/database/sqlcommon/filter_sql.go | 3 +++ internal/database/sqlcommon/filter_sql_test.go | 14 ++++++++++++++ pkg/database/filter.go | 14 ++++++++++++++ pkg/database/filter_test.go | 8 ++++++++ 4 files changed, 39 insertions(+) diff --git a/internal/database/sqlcommon/filter_sql.go b/internal/database/sqlcommon/filter_sql.go index aed34d2e45..cf40804448 100644 --- a/internal/database/sqlcommon/filter_sql.go +++ b/internal/database/sqlcommon/filter_sql.go @@ -70,6 +70,9 @@ func (s *SQLCommon) filterSelect(ctx context.Context, tableName string, sel sq.S sel = sel.Limit(fi.Limit) } } + if fi.Distinct { + sel = sel.Distinct() + } return sel, fop, fi, err } diff --git a/internal/database/sqlcommon/filter_sql_test.go b/internal/database/sqlcommon/filter_sql_test.go index f7f20730d5..9b64254593 100644 --- a/internal/database/sqlcommon/filter_sql_test.go +++ b/internal/database/sqlcommon/filter_sql_test.go @@ -169,3 +169,17 @@ func TestSQLQueryFactoryDefaultSortBadType(t *testing.T) { s.filterSelect(context.Background(), "", sel, f, nil, []interface{}{100}) }) } + +func TestSQLQueryFactorySelectDistinct(t *testing.T) { + + s, _ := newMockProvider().init() + sel := squirrel.Select("name").From("mytable") + fb := database.MessageQueryFactory.NewFilter(context.Background()) + f := fb.And().Distinct(true) + sel, _, _, err := s.filterSelect(context.Background(), "", sel, f, nil, []interface{}{"name"}) + assert.NoError(t, err) + + sqlFilter, _, err := sel.ToSql() + assert.NoError(t, err) + assert.Equal(t, "SELECT DISTINCT name FROM mytable WHERE (1=1) ORDER BY name DESC", sqlFilter) +} diff --git a/pkg/database/filter.go b/pkg/database/filter.go index f9fb5433af..7c5e6c4f1e 100644 --- a/pkg/database/filter.go +++ b/pkg/database/filter.go @@ -46,6 +46,9 @@ type Filter interface { // Request a count to be returned on the total number that match the query Count(c bool) Filter + // Select distinct rows + Distinct(bool) Filter + // Finalize completes the filter, and for the plugin to validated output structure to convert Finalize() (*FilterInfo, error) @@ -156,6 +159,7 @@ type FilterInfo struct { Skip uint64 Limit uint64 Count bool + Distinct bool Field string Op FilterOp Values []FieldSerialization @@ -231,6 +235,9 @@ func (f *FilterInfo) String() string { if f.Count { val.WriteString(" count=true") } + if f.Distinct { + val.WriteString(" distinct=true") + } return val.String() } @@ -254,6 +261,7 @@ type filterBuilder struct { count bool forceAscending bool forceDescending bool + distinct bool } type baseFilter struct { @@ -327,6 +335,7 @@ func (f *baseFilter) Finalize() (fi *FilterInfo, err error) { Skip: f.fb.skip, Limit: f.fb.limit, Count: f.fb.count, + Distinct: f.fb.distinct, }, nil } @@ -372,6 +381,11 @@ func (f *baseFilter) Descending() Filter { return f } +func (f *baseFilter) Distinct(d bool) Filter { + f.fb.distinct = true + return f +} + type andFilter struct { baseFilter } diff --git a/pkg/database/filter_test.go b/pkg/database/filter_test.go index 2243d0038a..aa93b1c1bf 100644 --- a/pkg/database/filter_test.go +++ b/pkg/database/filter_test.go @@ -79,6 +79,14 @@ func TestBuildMessageFilter3(t *testing.T) { assert.Equal(t, "( created IN [1000000000,2000000000,3000000000] ) && ( created NI [1000000000,2000000000,3000000000] ) && ( created < 0 ) && ( created <= 0 ) && ( created >= 0 ) && ( created != 0 ) && ( sequence > 12345 ) && ( topics %= 'abc' ) && ( topics %! 'def' ) && ( topics ^= 'ghi' ) && ( topics ^! 'jkl' ) sort=-created,topics,-sequence", f.String()) } +func TestBuildMessageFilterDistinct(t *testing.T) { + fb := MessageQueryFactory.NewFilter(context.Background()) + f, err := fb.And().Distinct(true).Finalize() + + assert.NoError(t, err) + assert.Equal(t, " distinct=true", f.String()) +} + func TestBuildMessageBadInFilterField(t *testing.T) { fb := MessageQueryFactory.NewFilter(context.Background()) _, err := fb.And(