Fix issue 1205 (#1211)

* fix #1205

* move builder into stores

* remove xrom

* Remove unused code

* Remove unused code

* refactor builderx to builder

Co-authored-by: anqiansong <anqiansong@bytedance.com>
master
anqiansong 3 years ago committed by GitHub
parent c28e01fed3
commit 69a4d213a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,63 @@
package builder
import (
"fmt"
"reflect"
"strings"
)
const dbTag = "db"
// RawFieldNames converts golang struct field into slice string.
func RawFieldNames(in interface{}, postgresSql ...bool) []string {
out := make([]string, 0)
v := reflect.ValueOf(in)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
var pg bool
if len(postgresSql) > 0 {
pg = postgresSql[0]
}
// we only accept structs
if v.Kind() != reflect.Struct {
panic(fmt.Errorf("ToMap only accepts structs; got %T", v))
}
typ := v.Type()
for i := 0; i < v.NumField(); i++ {
// gets us a StructField
fi := typ.Field(i)
if tagv := fi.Tag.Get(dbTag); tagv != "" {
if pg {
out = append(out, tagv)
} else {
out = append(out, fmt.Sprintf("`%s`", tagv))
}
} else {
if pg {
out = append(out, fi.Name)
} else {
out = append(out, fmt.Sprintf("`%s`", fi.Name))
}
}
}
return out
}
// PostgreSqlJoin concatenates the given elements into a string.
func PostgreSqlJoin(elems []string) string {
b := new(strings.Builder)
for index, e := range elems {
b.WriteString(fmt.Sprintf("%s = $%d, ", e, index+2))
}
if b.Len() == 0 {
return b.String()
}
return b.String()[0 : b.Len()-2]
}

@ -0,0 +1,24 @@
package builder
import (
"testing"
"github.com/stretchr/testify/assert"
)
type mockedUser struct {
ID string `db:"id" json:"id,omitempty"`
UserName string `db:"user_name" json:"userName,omitempty"`
Sex int `db:"sex" json:"sex,omitempty"`
UUID string `db:"uuid" uuid:"uuid,omitempty"`
Age int `db:"age" json:"age"`
}
func TestFieldNames(t *testing.T) {
t.Run("new", func(t *testing.T) {
var u mockedUser
out := RawFieldNames(&u)
expected := []string{"`id`", "`user_name`", "`sex`", "`uuid`", "`age`"}
assert.Equal(t, expected, out)
})
}

@ -13,7 +13,6 @@ require (
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8
github.com/go-redis/redis v6.15.9+incompatible github.com/go-redis/redis v6.15.9+incompatible
github.com/go-sql-driver/mysql v1.6.0 github.com/go-sql-driver/mysql v1.6.0
github.com/go-xorm/builder v0.3.4
github.com/golang-jwt/jwt v3.2.1+incompatible github.com/golang-jwt/jwt v3.2.1+incompatible
github.com/golang/mock v1.6.0 github.com/golang/mock v1.6.0
github.com/google/uuid v1.3.0 github.com/google/uuid v1.3.0

@ -154,10 +154,6 @@ github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfC
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-xorm/builder v0.3.4 h1:FxkeGB4Cggdw3tPwutLCpfjng2jugfkg6LDMrd/KsoY=
github.com/go-xorm/builder v0.3.4/go.mod h1:KxkQkNN1DpPKTedxXyTQcmH+rXfvk4LZ9SOOBoZBAxw=
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y=
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=

@ -1,136 +1,20 @@
package builderx package builderx
import ( import (
"fmt" "github.com/tal-tech/go-zero/core/stores/builder"
"reflect"
"strings"
"github.com/go-xorm/builder"
) )
const dbTag = "db" // Deprecated: Use github.com/tal-tech/go-zero/core/stores/builder.RawFieldNames instead.
// NewEq wraps builder.Eq.
func NewEq(in interface{}) builder.Eq {
return builder.Eq(ToMap(in))
}
// NewGt wraps builder.Gt.
func NewGt(in interface{}) builder.Gt {
return builder.Gt(ToMap(in))
}
// ToMap converts interface into map.
func ToMap(in interface{}) map[string]interface{} {
out := make(map[string]interface{})
v := reflect.ValueOf(in)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
// we only accept structs
if v.Kind() != reflect.Struct {
panic(fmt.Errorf("ToMap only accepts structs; got %T", v))
}
typ := v.Type()
for i := 0; i < v.NumField(); i++ {
// gets us a StructField
fi := typ.Field(i)
if tagv := fi.Tag.Get(dbTag); tagv != "" {
// set key of map to value in struct field
val := v.Field(i)
zero := reflect.Zero(val.Type()).Interface()
current := val.Interface()
if reflect.DeepEqual(current, zero) {
continue
}
out[tagv] = current
}
}
return out
}
// FieldNames returns field names from given in.
// deprecated: use RawFieldNames instead automatically while model generating after goctl version v1.1.0
func FieldNames(in interface{}) []string { func FieldNames(in interface{}) []string {
out := make([]string, 0) return builder.RawFieldNames(in)
v := reflect.ValueOf(in)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
// we only accept structs
if v.Kind() != reflect.Struct {
panic(fmt.Errorf("ToMap only accepts structs; got %T", v))
}
typ := v.Type()
for i := 0; i < v.NumField(); i++ {
// gets us a StructField
fi := typ.Field(i)
if tagv := fi.Tag.Get(dbTag); tagv != "" {
out = append(out, tagv)
} else {
out = append(out, fi.Name)
}
}
return out
} }
// RawFieldNames converts golang struct field into slice string. // Deprecated: Use github.com/tal-tech/go-zero/core/stores/builder.RawFieldNames instead.
func RawFieldNames(in interface{}, postgresSql ...bool) []string { func RawFieldNames(in interface{}, postgresSql ...bool) []string {
out := make([]string, 0) return builder.RawFieldNames(in, postgresSql...)
v := reflect.ValueOf(in)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
var pg bool
if len(postgresSql) > 0 {
pg = postgresSql[0]
}
// we only accept structs
if v.Kind() != reflect.Struct {
panic(fmt.Errorf("ToMap only accepts structs; got %T", v))
}
typ := v.Type()
for i := 0; i < v.NumField(); i++ {
// gets us a StructField
fi := typ.Field(i)
if tagv := fi.Tag.Get(dbTag); tagv != "" {
if pg {
out = append(out, tagv)
} else {
out = append(out, fmt.Sprintf("`%s`", tagv))
}
} else {
if pg {
out = append(out, fi.Name)
} else {
out = append(out, fmt.Sprintf("`%s`", fi.Name))
}
}
}
return out
} }
// PostgreSqlJoin concatenates the given elements into a string. // Deprecated: Use github.com/tal-tech/go-zero/core/stores/builderx.PostgreSqlJoin instead.
func PostgreSqlJoin(elems []string) string { func PostgreSqlJoin(elems []string) string {
b := new(strings.Builder) return builder.PostgreSqlJoin(elems)
for index, e := range elems {
b.WriteString(fmt.Sprintf("%s = $%d, ", e, index+2))
}
if b.Len() == 0 {
return b.String()
}
return b.String()[0 : b.Len()-2]
} }

@ -1,125 +0,0 @@
package builderx
import (
"fmt"
"testing"
"github.com/go-xorm/builder"
"github.com/stretchr/testify/assert"
)
type mockedUser struct {
// 自增id
ID string `db:"id" json:"id,omitempty"`
// 姓名
UserName string `db:"user_name" json:"userName,omitempty"`
// 1男,2女
Sex int `db:"sex" json:"sex,omitempty"`
UUID string `db:"uuid" uuid:"uuid,omitempty"`
Age int `db:"age" json:"age"`
}
var (
userFieldsWithRawStringQuote = RawFieldNames(mockedUser{})
userFieldsWithoutRawStringQuote = FieldNames(mockedUser{})
)
func TestFieldNames(t *testing.T) {
t.Run("old", func(t *testing.T) {
var u mockedUser
out := FieldNames(&u)
expected := []string{"id", "user_name", "sex", "uuid", "age"}
assert.Equal(t, expected, out)
})
t.Run("new", func(t *testing.T) {
var u mockedUser
out := RawFieldNames(&u)
expected := []string{"`id`", "`user_name`", "`sex`", "`uuid`", "`age`"}
assert.Equal(t, expected, out)
})
}
func TestNewEq(t *testing.T) {
u := &mockedUser{
ID: "123456",
UserName: "wahaha",
}
out := NewEq(u)
fmt.Println(out)
actual := builder.Eq{"id": "123456", "user_name": "wahaha"}
assert.Equal(t, out, actual)
}
// @see https://github.com/go-xorm/builder
func TestBuilderSql(t *testing.T) {
u := &mockedUser{
ID: "123123",
}
fields := RawFieldNames(u)
eq := NewEq(u)
sql, args, err := builder.Select(fields...).From("user").Where(eq).ToSQL()
fmt.Println(sql, args, err)
actualSQL := "SELECT `id`,`user_name`,`sex`,`uuid`,`age` FROM user WHERE id=?"
actualArgs := []interface{}{"123123"}
assert.Equal(t, sql, actualSQL)
assert.Equal(t, args, actualArgs)
}
func TestBuildSqlDefaultValue(t *testing.T) {
eq := builder.Eq{}
eq["age"] = 0
eq["user_name"] = ""
t.Run("raw", func(t *testing.T) {
sql, args, err := builder.Select(userFieldsWithRawStringQuote...).From("user").Where(eq).ToSQL()
fmt.Println(sql, args, err)
actualSQL := "SELECT `id`,`user_name`,`sex`,`uuid`,`age` FROM user WHERE age=? AND user_name=?"
actualArgs := []interface{}{0, ""}
assert.Equal(t, sql, actualSQL)
assert.Equal(t, args, actualArgs)
})
t.Run("withour raw quote", func(t *testing.T) {
sql, args, err := builder.Select(userFieldsWithoutRawStringQuote...).From("user").Where(eq).ToSQL()
fmt.Println(sql, args, err)
actualSQL := "SELECT id,user_name,sex,uuid,age FROM user WHERE age=? AND user_name=?"
actualArgs := []interface{}{0, ""}
assert.Equal(t, sql, actualSQL)
assert.Equal(t, args, actualArgs)
})
}
func TestBuilderSqlIn(t *testing.T) {
u := &mockedUser{
Age: 18,
}
gtU := NewGt(u)
in := builder.In("id", []string{"1", "2", "3"})
sql, args, err := builder.Select(userFieldsWithRawStringQuote...).From("user").Where(in).And(gtU).ToSQL()
fmt.Println(sql, args, err)
actualSQL := "SELECT `id`,`user_name`,`sex`,`uuid`,`age` FROM user WHERE id IN (?,?,?) AND age>?"
actualArgs := []interface{}{"1", "2", "3", 18}
assert.Equal(t, sql, actualSQL)
assert.Equal(t, args, actualArgs)
}
func TestBuildSqlLike(t *testing.T) {
like := builder.Like{"name", "wang"}
sql, args, err := builder.Select(userFieldsWithRawStringQuote...).From("user").Where(like).ToSQL()
fmt.Println(sql, args, err)
actualSQL := "SELECT `id`,`user_name`,`sex`,`uuid`,`age` FROM user WHERE name LIKE ?"
actualArgs := []interface{}{"%wang%"}
assert.Equal(t, sql, actualSQL)
assert.Equal(t, args, actualArgs)
}
func TestJoin(t *testing.T) {
ret := PostgreSqlJoin([]string{"name", "age"})
assert.Equal(t, "name = $2, age = $3", ret)
}

@ -12,7 +12,7 @@ var (
"github.com/tal-tech/go-zero/core/stores/sqlc" "github.com/tal-tech/go-zero/core/stores/sqlc"
"github.com/tal-tech/go-zero/core/stores/sqlx" "github.com/tal-tech/go-zero/core/stores/sqlx"
"github.com/tal-tech/go-zero/core/stringx" "github.com/tal-tech/go-zero/core/stringx"
"github.com/tal-tech/go-zero/tools/goctl/model/sql/builderx" "github.com/tal-tech/go-zero/core/stores/builderx"
) )
` `
// ImportsNoCache defines a import template for model in normal case // ImportsNoCache defines a import template for model in normal case
@ -25,7 +25,7 @@ var (
"github.com/tal-tech/go-zero/core/stores/sqlc" "github.com/tal-tech/go-zero/core/stores/sqlc"
"github.com/tal-tech/go-zero/core/stores/sqlx" "github.com/tal-tech/go-zero/core/stores/sqlx"
"github.com/tal-tech/go-zero/core/stringx" "github.com/tal-tech/go-zero/core/stringx"
"github.com/tal-tech/go-zero/tools/goctl/model/sql/builderx" "github.com/tal-tech/go-zero/core/stores/builderx"
) )
` `
) )

@ -2,7 +2,7 @@ package template
// Insert defines a template for insert code in model // Insert defines a template for insert code in model
var Insert = ` var Insert = `
func (m *default{{.upperStartCamelObject}}Model) Insert(data {{.upperStartCamelObject}}) (sql.Result,error) { func (m *default{{.upperStartCamelObject}}Model) Insert(data *{{.upperStartCamelObject}}) (sql.Result,error) {
{{if .withCache}}{{if .containsIndexCache}}{{.keys}} {{if .withCache}}{{if .containsIndexCache}}{{.keys}}
ret, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) { ret, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("insert into %s (%s) values ({{.expression}})", m.table, {{.lowerStartCamelObject}}RowsExpectAutoSet) query := fmt.Sprintf("insert into %s (%s) values ({{.expression}})", m.table, {{.lowerStartCamelObject}}RowsExpectAutoSet)
@ -15,5 +15,5 @@ func (m *default{{.upperStartCamelObject}}Model) Insert(data {{.upperStartCamelO
} }
` `
// InsertMethod defines a interface method template for insert code in model // InsertMethod defines an interface method template for insert code in model
var InsertMethod = `Insert(data {{.upperStartCamelObject}}) (sql.Result,error)` var InsertMethod = `Insert(data *{{.upperStartCamelObject}}) (sql.Result,error)`

@ -2,7 +2,7 @@ package template
// Update defines a template for generating update codes // Update defines a template for generating update codes
var Update = ` var Update = `
func (m *default{{.upperStartCamelObject}}Model) Update(data {{.upperStartCamelObject}}) error { func (m *default{{.upperStartCamelObject}}Model) Update(data *{{.upperStartCamelObject}}) error {
{{if .withCache}}{{.keys}} {{if .withCache}}{{.keys}}
_, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) { _, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("update %s set %s where {{.originalPrimaryKey}} = {{if .postgreSql}}$1{{else}}?{{end}}", m.table, {{.lowerStartCamelObject}}RowsWithPlaceHolder) query := fmt.Sprintf("update %s set %s where {{.originalPrimaryKey}} = {{if .postgreSql}}$1{{else}}?{{end}}", m.table, {{.lowerStartCamelObject}}RowsWithPlaceHolder)
@ -14,4 +14,4 @@ func (m *default{{.upperStartCamelObject}}Model) Update(data {{.upperStartCamelO
` `
// UpdateMethod defines an interface method template for generating update codes // UpdateMethod defines an interface method template for generating update codes
var UpdateMethod = `Update(data {{.upperStartCamelObject}}) error` var UpdateMethod = `Update(data *{{.upperStartCamelObject}}) error`

Loading…
Cancel
Save