Skip to content

Commit

Permalink
Merge pull request ecodeclub#118 from gotomicro/main
Browse files Browse the repository at this point in the history
启用 Dev 作为开发分支
  • Loading branch information
flycash authored Dec 15, 2022
2 parents de3b6e6 + 140b746 commit 8d8b674
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 8 deletions.
9 changes: 5 additions & 4 deletions .CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
## 开发中:
## 开发中

## v0.0.1:
- [Init Project](https://github.com/gotomicro/eorm/pull/1)
- [Selector Definition](https://github.com/gotomicro/eorm/pull/2)
- [Deleter Definition](https://github.com/gotomicro/eorm/pull/4)
Expand Down Expand Up @@ -46,8 +48,7 @@
- [eorm: GetMulti功能](https://github.com/gotomicro/eorm/pull/109)
- [eorm: 支持基本类型作为返回值](https://github.com/gotomicro/eorm/pull/110)
- [eorm: 为组合模型增加集成测试](https://github.com/gotomicro/eorm/pull/111)

### 文档, 代码质量以及文档
- [Add examples and docs for Aggregate and Assign](https://github.com/gotomicro/eorm/pull/50)
- [Add examples for Column and columns](https://github.com/gotomicro/eorm/pull/51)
- [Add examples for DB, Predicate, Deleter, Inserter](https://github.com/gotomicro/eorm/pull/52)
- [Add examples for DB, Predicate, Deleter, Inserter](https://github.com/gotomicro/eorm/pull/520)
- [eorm: Distinct功能](https://github.com/gotomicro/eorm/pull/116)
30 changes: 26 additions & 4 deletions aggregate.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ package eorm

// Aggregate represents aggregate expression, including AVG, MAX, MIN...
type Aggregate struct {
fn string
arg string
alias string
fn string
arg string
alias string
distinct bool
}

// As specifies the alias
Expand Down Expand Up @@ -70,7 +71,28 @@ func Sum(c string) Aggregate {
}
}

func (a Aggregate) selected() {}
// CountDistinct represents COUNT(DISTINCT XXX)
func CountDistinct(col string) Aggregate {
a := Count(col)
a.distinct = true
return a
}

// AvgDistinct represents AVG(DISTINCT XXX)
func AvgDistinct(col string) Aggregate {
a := Avg(col)
a.distinct = true
return a
}

// SumDistinct represents SUM(DISTINCT XXX)
func SumDistinct(col string) Aggregate {
a := Sum(col)
a.distinct = true
return a
}

func (Aggregate) selected() {}

func (a Aggregate) EQ(val interface{}) Predicate {
return Predicate{
Expand Down
15 changes: 15 additions & 0 deletions aggregate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,21 @@ func TestAggregate(t *testing.T) {
builder: NewSelector[TestModel](db).Select(Count("Age")).From(&TestModel{}),
wantSql: "SELECT COUNT(`age`) FROM `test_model`;",
},
{
name: "count distinct",
builder: NewSelector[TestModel](db).From(&TestModel{}).Select(CountDistinct("FirstName")),
wantSql: "SELECT COUNT(DISTINCT `first_name`) FROM `test_model`;",
},
{
name: "avg distinct",
builder: NewSelector[TestModel](db).From(&TestModel{}).Select(AvgDistinct("FirstName")),
wantSql: "SELECT AVG(DISTINCT `first_name`) FROM `test_model`;",
},
{
name: "SUM distinct",
builder: NewSelector[TestModel](db).From(&TestModel{}).Select(SumDistinct("FirstName")),
wantSql: "SELECT SUM(DISTINCT `first_name`) FROM `test_model`;",
},
}

for _, tc := range testCases {
Expand Down
4 changes: 4 additions & 0 deletions builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,11 @@ func (b *builder) buildPredicates(predicates []Predicate) error {

func (b *builder) buildHavingAggregate(aggregate Aggregate) error {
_, _ = b.buffer.WriteString(aggregate.fn)

_ = b.buffer.WriteByte('(')
if aggregate.distinct {
_, _ = b.buffer.WriteString("DISTINCT ")
}
cMeta, ok := b.meta.FieldMap[aggregate.arg]
if !ok {
return errs.NewInvalidFieldError(aggregate.arg)
Expand Down
58 changes: 58 additions & 0 deletions internal/integration/select_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -701,3 +701,61 @@ func (s *SelectTestSuiteGetMulti) TestRawQueryGetMultiBaseType() {
})
}
}

func (s *SelectTestSuiteGetMulti) TestSelectorDistinct() {

testcases := []struct {
name string
s func() (any, error)
wantErr error
wantRes any
}{
{
name: "distinct col",
s: func() (any, error) {
return eorm.NewSelector[test.SimpleStruct](s.orm).From(&test.SimpleStruct{}).Select(eorm.C("Int")).Distinct().GetMulti(context.Background())

},
wantRes: []*test.SimpleStruct{
&test.SimpleStruct{
Int: 12,
},
},
},
{
name: "count distinct",
s: func() (any, error) {
return eorm.NewSelector[int](s.orm).Select(eorm.CountDistinct("Bool")).From(&test.SimpleStruct{}).GetMulti(context.Background())
},
wantRes: func() []*int {
val := 1
return []*int{&val}
}(),
},
{
name: "having count distinct",
s: func() (any, error) {
return eorm.NewSelector[test.SimpleStruct](s.orm).From(&test.SimpleStruct{}).Select(eorm.C("JsonColumn")).GroupBy("JsonColumn").Having(eorm.CountDistinct("JsonColumn").EQ(1)).GetMulti(context.Background())
},
wantRes: []*test.SimpleStruct{
&test.SimpleStruct{
JsonColumn: &test.JsonColumn{
Val: test.User{Name: "Tom"},
Valid: true,
},
},
},
},
}
for _, tc := range testcases {
s.T().Run(tc.name, func(t *testing.T) {
res, err := tc.s()
assert.Equal(t, tc.wantErr, err)
if err != nil {
return
}
assert.Equal(t, tc.wantRes, res)
})
}

}
7 changes: 7 additions & 0 deletions select.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ func (s *Selector[T]) Build() (*Query, error) {
return nil, err
}
s.writeString("SELECT ")
if s.distinct {
s.writeString("DISTINCT ")
}
if len(s.columns) == 0 {
s.buildAllColumns()
} else {
Expand Down Expand Up @@ -201,7 +204,11 @@ func (s *Selector[T]) buildSelectedList() error {
}
func (s *Selector[T]) selectAggregate(aggregate Aggregate) error {
s.writeString(aggregate.fn)

s.writeByte('(')
if aggregate.distinct {
s.writeString("DISTINCT ")
}
cMeta, ok := s.meta.FieldMap[aggregate.arg]
s.aliases[aggregate.alias] = struct{}{}
if !ok {
Expand Down
44 changes: 44 additions & 0 deletions select_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -976,6 +976,22 @@ func TestSelectable(t *testing.T) {
wantSql: "SELECT `id`,`first_name`,`age`,`last_name` FROM `test_model` GROUP BY `first_name` HAVING `last_name` NOT LIKE ?;",
wantArgs: []interface{}{"%yy%"},
},
{
name: "distinct single row",
builder: NewSelector[TestModel](db).From(&TestModel{}).Distinct().Select(C("FirstName")),
wantSql: "SELECT DISTINCT `first_name` FROM `test_model`;",
},
{
name: "count distinct",
builder: NewSelector[TestModel](db).From(&TestModel{}).Select(CountDistinct("FirstName")),
wantSql: "SELECT COUNT(DISTINCT `first_name`) FROM `test_model`;",
},
{
name: "having count distinct",
builder: NewSelector[TestModel](db).From(&TestModel{}).Select(C("FirstName")).GroupBy("FirstName").Having(CountDistinct("FirstName").EQ("jack")),
wantSql: "SELECT `first_name` FROM `test_model` GROUP BY `first_name` HAVING COUNT(DISTINCT `first_name`)=?;",
wantArgs: []interface{}{"jack"},
},
}

for _, tc := range testCases {
Expand Down Expand Up @@ -1195,3 +1211,31 @@ func ExampleSelector_Select() {
// SQL: SELECT COUNT(DISTINCT `age`) AS `age_cnt` FROM `test_model`;
// Args: []interface {}(nil)
}

func ExampleSelector_Distinct() {
db := memoryDB()
tm := &TestModel{}
cases := []*Selector[TestModel]{
// case0: disinct column
NewSelector[TestModel](db).From(tm).Distinct().Select(C("FirstName")),
// case1: aggregation function using distinct
NewSelector[TestModel](db).From(tm).Select(CountDistinct("FirstName")),
// case2: having using distinct
NewSelector[TestModel](db).From(tm).Select(C("FirstName")).GroupBy("FirstName").Having(CountDistinct("FirstName").EQ("jack")),
}

for index, tc := range cases {
query, _ := tc.Build()
fmt.Printf("case%d:\n%s", index, query.string())
}
// Output:
// case0:
// SQL: SELECT DISTINCT `first_name` FROM `test_model`;
// Args: []interface {}(nil)
// case1:
// SQL: SELECT COUNT(DISTINCT `first_name`) FROM `test_model`;
// Args: []interface {}(nil)
// case2:
// SQL: SELECT `first_name` FROM `test_model` GROUP BY `first_name` HAVING COUNT(DISTINCT `first_name`)=?;
// Args: []interface {}{"jack"}
}

0 comments on commit 8d8b674

Please sign in to comment.