Skip to content

Commit

Permalink
Merge pull request #7 from liushun-ing/feat/condition
Browse files Browse the repository at this point in the history
feat: condition for groupby and github-ci
  • Loading branch information
jaronnie authored Dec 6, 2024
2 parents 224c37b + 0cf6523 commit 96758b9
Show file tree
Hide file tree
Showing 15 changed files with 342 additions and 29 deletions.
58 changes: 58 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: jzero-contrib-ci

on:
push:
paths-ignore:
- '**.md'
pull_request:

jobs:
golangci:
name: ci
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: actions/setup-go@v5
with:
go-version: '1.22.3'

- name: Install Tool
run: |
go install github.com/fsgo/go_fmt/cmd/gorgeous@latest
go mod tidy
- name: format go
run: |
gorgeous -d ./...
- uses: actions/checkout@v4
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
with:
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
version: latest

# Optional: working directory, useful for monorepos
working-directory: ./

# Optional: golangci-lint command line arguments.
args: --timeout 300s --verbose

# Optional: show only new issues if it's a pull request. The default value is `false`.
# only-new-issues: true

# Optional: if set to true then the action will use pre-installed Go.
skip-go-installation: true

# Optional: if set to true then the action don't cache or restore ~/go/pkg.
skip-pkg-cache: true

# Optional: if set to true then the action don't cache or restore ~/.cache/go-build.
# skip-build-cache: true
- name: run test case
run: |
go test ./...
21 changes: 21 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
run:
go: '1.21'
linters:
enable:
- thelper
- gofumpt
- tparallel
- unconvert
- wastedassign
- tagliatelle

linters-settings:
gofumpt:
# Module path which contains the source code being formatted.
# Default: ""
module-path: github.com/jzero-io/jzero-contrib
# Choose whether to use the extra rules.
# Default: false
extra-rules: true
staticcheck:
checks: ["-SA5008"] # 忽略 tag 检查
31 changes: 25 additions & 6 deletions condition/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,22 @@ func NewChainWithConditions(conditions ...Condition) Chain {
func (c Chain) addChain(field string, operator Operator, value any, op ...opts.Opt[ChainOperatorOpts]) Chain {
o := opts.DefaultApply(op...)
c.conditions = append(c.conditions, Condition{
Field: field,
Operator: operator,
Value: value,
Skip: o.Skip,
SkipFunc: o.SkipFunc,
OrValuesFunc: o.OrValuesFunc,
Field: field,
Operator: operator,
Value: value,
Skip: o.Skip,
SkipFunc: o.SkipFunc,
})
return c
}

func (c Chain) addChainWithNestedCondition(operator Operator, nestedConditions []Condition, op ...opts.Opt[ChainOperatorOpts]) Chain {
o := opts.DefaultApply(op...)
c.conditions = append(c.conditions, Condition{
Operator: operator,
NestedCondition: nestedConditions,
Skip: o.Skip,
SkipFunc: o.SkipFunc,
})
return c
}
Expand Down Expand Up @@ -140,6 +150,15 @@ func (c Chain) Page(page, pageSize int, op ...opts.Opt[ChainOperatorOpts]) Chain
return c.addChain("", Offset, (page-1)*pageSize, op...).addChain("", Limit, pageSize, op...)
}

func (c Chain) GroupBy(value any, op ...opts.Opt[ChainOperatorOpts]) Chain {
return c.addChain("", GroupBy, value, op...)
}

// Having construct Having clause with own conditions
func (c Chain) Having(conditions []Condition, op ...opts.Opt[ChainOperatorOpts]) Chain {
return c.addChainWithNestedCondition(Having, conditions, op...)
}

func (c Chain) Build() []Condition {
return c.conditions
}
101 changes: 96 additions & 5 deletions condition/condition.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,26 +31,36 @@ const (
Between Operator = "BETWEEN"
NotBetween Operator = "NOT BETWEEN"
OrderBy Operator = "ORDER BY"
GroupBy Operator = "GROUP BY"
Having Operator = "HAVING"
)

type Condition struct {
Skip bool
// Skip indicates whether the condition is effective.
Skip bool

// SkipFunc The priority is higher than Skip.
SkipFunc func() bool

// or condition
// Or indicates an or condition
Or bool

OrOperators []Operator
OrFields []string
OrValues []any
OrValuesFunc func() []any

// and condition
// Field for default and condition
Field string

Operator Operator
Value any
Operator Operator
Value any

// ValueFunc The priority is higher than Value.
ValueFunc func() any

// NestedCondition Only support for having clause
NestedCondition []Condition
}

func New(conditions ...Condition) []Condition {
Expand Down Expand Up @@ -97,6 +107,78 @@ func buildExpr(cond *sqlbuilder.Cond, field string, operator Operator, value any
return ""
}

func buildExprForSelectBuilder(sb *sqlbuilder.SelectBuilder, field string, operator Operator, value any) string {
switch operator {
case Equal:
return sb.Equal(field, value)
case NotEqual:
return sb.NotEqual(field, value)
case GreaterThan:
return sb.GreaterThan(field, value)
case LessThan:
return sb.LessThan(field, value)
case GreaterEqualThan:
return sb.GreaterEqualThan(field, value)
case LessEqualThan:
return sb.LessEqualThan(field, value)
case In:
if len(castx.ToSlice(value)) > 0 {
return sb.In(field, castx.ToSlice(value)...)
}
case NotIn:
if len(castx.ToSlice(value)) > 0 {
return sb.NotIn(field, castx.ToSlice(value)...)
}
case Like:
return sb.Like(field, value)
case NotLike:
return sb.NotLike(field, value)
case Between:
v := castx.ToSlice(value)
if len(v) == 2 {
return sb.Between(field, v[0], v[1])
}
case NotBetween:
v := castx.ToSlice(value)
if len(v) == 2 {
return sb.NotBetween(field, v[0], v[1])
}
}
return ""
}

func havingClause(sb *sqlbuilder.SelectBuilder, conditions ...Condition) []string {
var clauses []string
for _, c := range conditions {
if c.SkipFunc != nil {
c.Skip = c.SkipFunc()
}
if c.Skip {
continue
}
if c.Or {
if c.OrValuesFunc != nil {
c.OrValues = c.OrValuesFunc()
}
var expr []string
for i, field := range c.OrFields {
if or := buildExprForSelectBuilder(sb, field, c.OrOperators[i], c.OrValues[i]); or != "" {
expr = append(expr, or)
}
}
if len(expr) > 0 {
clauses = append(clauses, sb.Or(expr...))
}
} else {
if c.ValueFunc != nil {
c.Value = c.ValueFunc()
}
clauses = append(clauses, buildExprForSelectBuilder(sb, c.Field, c.Operator, c.Value))
}
}
return clauses
}

func whereClause(conditions ...Condition) *sqlbuilder.WhereClause {
clause := sqlbuilder.NewWhereClause()
cond := sqlbuilder.NewCond()
Expand Down Expand Up @@ -154,6 +236,15 @@ func Select(sb sqlbuilder.SelectBuilder, conditions ...Condition) sqlbuilder.Sel
if len(castx.ToSlice(c.Value)) > 0 {
sb.OrderBy(cast.ToStringSlice(castx.ToSlice(c.Value))...)
}
case GroupBy:
if len(castx.ToSlice(c.Value)) > 0 {
sb.GroupBy(cast.ToStringSlice(castx.ToSlice(c.Value))...)
}
case Having:
subClause := havingClause(&sb, c.NestedCondition...)
if len(subClause) > 0 {
sb.Having(subClause...)
}
}
}
if clause != nil {
Expand Down
95 changes: 95 additions & 0 deletions condition/condition_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"fmt"
"testing"

"github.com/huandu/go-assert"
"github.com/huandu/go-sqlbuilder"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)

func TestSelectWithCondition(t *testing.T) {
Expand Down Expand Up @@ -135,3 +137,96 @@ func TestWhereClause(t *testing.T) {
fmt.Println(statement)
fmt.Println(args)
}

func TestGroupBySelect(t *testing.T) {
sqlbuilder.DefaultFlavor = sqlbuilder.MySQL

var values []any
values = append(values, []int{24, 48}, []int{170, 175})

cds := New(Condition{
Field: "name",
Operator: Equal,
Value: "jaronnie",
}, Condition{
Field: "money",
Operator: GreaterEqualThan,
Value: 100000,
}, Condition{
Or: true,
OrFields: []string{"age", "height"},
OrOperators: []Operator{Between, Between},
OrValues: values,
}, Condition{
Operator: GroupBy,
Value: []string{"class", "subject"},
}, Condition{
Operator: Having,
NestedCondition: []Condition{
{
Field: "classNum",
Operator: GreaterThan,
Value: 1,
},
{
Or: true,
OrFields: []string{"subjectNum", "subjectNum"},
OrOperators: []Operator{LessThan, GreaterThan},
OrValues: []any{10, 20},
},
},
})

sb := sqlbuilder.NewSelectBuilder().Select("name", "age", "height", "COUNT(class) as classNum", "COUNT(subject) as subjectNum").From("user")
builder := Select(*sb, cds...)

sql, args := builder.Build()
fmt.Println(sql)
fmt.Println(args)
assert.Equal(t, len(args), 9)
}

func TestGroupBySelectInAdmin(t *testing.T) {
conn := sqlx.NewMysql("root:123456@tcp(localhost:3306)/jzeroadmin?charset=utf8mb4&parseTime=True&loc=Local")
sqlbuilder.DefaultFlavor = sqlbuilder.MySQL

cds := New(Condition{
Field: "menu_id",
Operator: GreaterThan,
Value: 5,
}, Condition{
Operator: GroupBy,
Value: []string{"role_id"},
}, Condition{
Operator: Having,
NestedCondition: []Condition{
{
Or: true,
OrFields: []string{"menuNum", "menuNum"},
OrOperators: []Operator{LessThan, GreaterThan},
OrValues: []any{10, 20},
},
},
})

sb := sqlbuilder.NewSelectBuilder().Select("role_id", "COUNT(id) as menuNum").From("manage_role_menu")
builder := Select(*sb, cds...)

sql, args := builder.Build()
assert.Equal(t, len(args), 3)
fmt.Println(sql)
fmt.Println(args)

type Res struct {
A int `db:"role_id"`
B int `db:"menuNum"`
}

var res []Res
err := conn.QueryRowsPartial(&res, sql, args...)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(res)
}
2 changes: 1 addition & 1 deletion embedx/embedx.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func WriteToLocalTemp(ef embed.FS, opts ...Opts) ([]string, error) {
return fileList, nil
}

func createTemp(dir string, path string, data []byte) (*os.File, error) {
func createTemp(dir, path string, data []byte) (*os.File, error) {
tmpFile, err := os.CreateTemp(dir, fmt.Sprintf("*%s", filepath.Ext(path)))
if err != nil {
return nil, err
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/Masterminds/sprig/v3 v3.2.3
github.com/eddieowens/opts v0.1.0
github.com/guregu/null/v5 v5.0.0
github.com/huandu/go-assert v1.1.6
github.com/huandu/go-sqlbuilder v1.28.0
github.com/pkg/errors v0.9.1
github.com/spf13/cast v1.3.1
Expand All @@ -21,6 +22,7 @@ require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/fatih/color v1.17.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
Expand Down
Loading

0 comments on commit 96758b9

Please sign in to comment.