Skip to content

Commit 53cc486

Browse files
author
Zwei
committed
feat: implement setting field style of json and database
# feat 1. db/sqlexecutor.go: implement setting field style of json and database. # fix 1. demo/todo/tests/fail_test.go: move `fail_test.go` to package fail_test. 2. config/config.go: modify public variable `RoleList` to private variable `roleList`, add public func `RoleList()`; public variable `MethodList` does the same.
1 parent 5545ff4 commit 53cc486

File tree

15 files changed

+497
-40
lines changed

15 files changed

+497
-40
lines changed

config/config.go

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import (
44
"context"
55
"github.com/glennliao/apijson-go/consts"
66
"github.com/gogf/gf/v2/frame/g"
7+
"github.com/gogf/gf/v2/text/gstr"
78
"github.com/samber/lo"
9+
"strings"
810
)
911

1012
var (
@@ -59,22 +61,74 @@ var (
5961
// access 中填写的角色应在角色列表中
6062

6163
var (
62-
RoleList = []string{consts.UNKNOWN, consts.LOGIN, consts.OWNER, consts.ADMIN}
64+
roleList = []string{consts.UNKNOWN, consts.LOGIN, consts.OWNER, consts.ADMIN}
6365
)
6466

6567
// AddRole 增加自定义角色
6668
func AddRole(name string) {
67-
if !lo.Contains(RoleList, name) {
68-
RoleList = append(RoleList, name)
69+
if !lo.Contains(roleList, name) {
70+
roleList = append(roleList, name)
6971
}
7072
}
7173

74+
func RoleList() []string { return roleList }
75+
76+
// ========================= 请求方法 =======================
77+
78+
var methodList = []string{consts.MethodGet, consts.MethodHead, consts.MethodPost, consts.MethodPut, consts.MethodDelete}
79+
80+
func MethodList() []string { return methodList }
81+
7282
// ========================= 字段配置 =======================
7383

74-
// JsonFieldStyle DbFieldStyle 字段命名风格
75-
var JsonFieldStyle = consts.CaseCamel
76-
var DbFieldStyle = consts.CaseSnake
84+
// jsonFieldStyle dbFieldStyle 配置Json字段, 数据库命名风格
85+
var jsonFieldStyle = consts.CaseCamel
86+
var dbFieldStyle = consts.CaseSnake
87+
88+
// TODO 从配置文件读取命名风格
7789

78-
// todo 如果配置 DbFieldStyle 风格下划线, 则前端传进来的字段查询时候都转成下划线, 返回时则根据JsonFieldStyle转换, 如果JsonFieldStyle, DbFieldStyle 一致, 则可以看成不用转
79-
// sqlexecute中处理数据库端的转换
80-
// 返回的可在查询的field字段中使用 user_id as userId 完成转换
90+
// SetJsonFieldStyle 设置返回的 json字段风格, 默认为 lowerCamelCase风格, 参考 gstr.CaseCamelLower
91+
func SetJsonFieldStyle(style string) {
92+
jsonFieldStyle = fieldStyle(style)
93+
}
94+
95+
// SetDbFieldStyle 设置数据库的字段风格, 默认为 snake_case风格, 参考 gstr.CaseSnake
96+
func SetDbFieldStyle(style string) {
97+
dbFieldStyle = fieldStyle(style)
98+
}
99+
100+
func fieldStyle(style string) int {
101+
102+
switch strings.ToUpper(style) {
103+
case consts.CASE_CAMEL:
104+
return consts.CaseCamel
105+
case consts.CASE_CAMEL_UPPER:
106+
return consts.CaseCamelUpper
107+
case consts.CASE_SNAKE:
108+
return consts.CaseSnake
109+
}
110+
111+
return consts.Origin
112+
}
113+
114+
func convFieldStyle(style int, field string) string {
115+
switch style {
116+
117+
case consts.CaseCamel:
118+
return gstr.CaseCamelLower(field)
119+
case consts.CaseCamelUpper:
120+
return gstr.CaseCamel(field)
121+
case consts.CaseSnake:
122+
return gstr.CaseSnake(field)
123+
default:
124+
return field
125+
}
126+
}
127+
128+
func ToDbField(field string) string {
129+
return convFieldStyle(dbFieldStyle, field)
130+
}
131+
132+
func ToJsonField(field string) string {
133+
return convFieldStyle(jsonFieldStyle, field)
134+
}

config/z_regexp_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package config_test
2+
3+
import (
4+
"github.com/gogf/gf/v2/frame/g"
5+
"github.com/gogf/gf/v2/text/gstr"
6+
"log"
7+
"regexp"
8+
"strings"
9+
"testing"
10+
)
11+
12+
const (
13+
countAs = "count(userId) AS CnT,id,username, userId"
14+
count = "count(userId) : CnT,id,username, userId"
15+
)
16+
17+
func TestRegexp(t *testing.T) {
18+
//(\w|\(|\)|,)
19+
20+
exp := regexp.MustCompile(`^\s+[\w()]+`)
21+
22+
list := strings.Split(countAs, ",")
23+
24+
for _, s := range list {
25+
s2 := exp.ReplaceAllStringFunc(s, func(s string) string {
26+
return gstr.CaseSnake(s)
27+
})
28+
29+
log.Println(s, ":", s2)
30+
}
31+
}
32+
33+
func TestRegexpCount(t *testing.T) {
34+
separatorExp := regexp.MustCompile(`[^,;]+`)
35+
wordExp := regexp.MustCompile(`^[\s\w][\w()]+`)
36+
37+
ret := separatorExp.ReplaceAllStringFunc(count, func(s1 string) string {
38+
39+
s2 := wordExp.ReplaceAllStringFunc(s1, func(s2 string) string {
40+
return gstr.CaseSnake(s2)
41+
})
42+
log.Println(s1, ":", s2)
43+
44+
return s2
45+
})
46+
47+
g.Dump("ret", ret)
48+
49+
}

consts/field.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,12 @@ package consts
33
const (
44
Origin = iota
55
CaseCamel
6+
CaseCamelUpper
67
CaseSnake
78
)
9+
10+
const (
11+
CASE_CAMEL = "CASECAMEL"
12+
CASE_CAMEL_UPPER = "CASECAMELUPPER"
13+
CASE_SNAKE = "CASESNAKE"
14+
)

db/access.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,5 @@ func Init() {
9898
func Reload() {
9999
loadAccessMap()
100100
loadRequestMap()
101+
loadTableMeta()
101102
}

db/const.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package db
2+
3+
const (
4+
AS = " AS "
5+
Separator = ", "
6+
DESC = " DESC"
7+
)

db/sqlexecutor.go

Lines changed: 53 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ package db
22

33
import (
44
"context"
5+
"github.com/glennliao/apijson-go/config"
56
"github.com/gogf/gf/v2/database/gdb"
67
"github.com/gogf/gf/v2/frame/g"
78
"github.com/gogf/gf/v2/util/gconv"
9+
"regexp"
810
"strings"
911
)
1012

@@ -25,12 +27,17 @@ func NewSqlExecutor(ctx context.Context, tableName string, accessVerify bool) (*
2527

2628
m := g.DB().Model(tableName)
2729

30+
var columns []string
31+
for _, column := range tableMap[tableName].Columns {
32+
columns = append(columns, column.Name)
33+
}
34+
2835
return &SqlExecutor{
2936
ctx: ctx,
3037
Table: tableName,
3138
m: m,
3239
builder: m.Builder(),
33-
Columns: nil,
40+
Columns: columns,
3441
Order: "",
3542
Group: "",
3643
}, nil
@@ -39,6 +46,8 @@ func NewSqlExecutor(ctx context.Context, tableName string, accessVerify bool) (*
3946
func (e *SqlExecutor) ParseCondition(conditions g.MapStrAny) error {
4047

4148
for k, condition := range conditions {
49+
k = config.ToDbField(k) // 将请求字段转化为数据库字段风格
50+
4251
switch {
4352
case strings.HasSuffix(k, "{}"):
4453
e.parseMultiCondition(k[0:len(k)-2], condition)
@@ -111,24 +120,34 @@ func (e *SqlExecutor) parseMultiCondition(k string, condition any) {
111120

112121
}
113122

114-
func (e *SqlExecutor) ParseCtrl(m g.Map) error {
123+
var exp = regexp.MustCompile(`^[\s\w][\w()]+`) // 匹配 field, COUNT(field)
124+
125+
func (e *SqlExecutor) ParseCtrl(ctrl g.Map) error {
126+
127+
for k, v := range ctrl {
128+
// https://github.com/Tencent/APIJSON/blob/master/Document.md
129+
// 应该用分号 ; 隔开 SQL 函数,改为 "@column":"store_id;sum(amt):totAmt")
130+
fieldStr := strings.ReplaceAll(gconv.String(v), ";", Separator)
131+
132+
fieldList := strings.Split(fieldStr, ",")
133+
for i, item := range fieldList {
134+
fieldList[i] = exp.ReplaceAllStringFunc(item, config.ToDbField) // 将请求字段转化为数据库字段风格
135+
}
136+
137+
fieldStr = strings.Join(fieldList, Separator)
115138

116-
for k, v := range m {
117139
switch k {
118140

119141
case "@order":
120-
order := strings.Replace(gconv.String(v), "-", " desc", -1)
121-
order = strings.Replace(order, "+", " ", -1)
142+
order := strings.ReplaceAll(fieldStr, "-", DESC)
143+
order = strings.ReplaceAll(order, "+", " ")
122144
e.Order = order
123145

124146
case "@column":
125-
columns := gconv.String(v)
126-
columns = strings.Replace(columns, ";", ", ", -1)
127-
columns = strings.Replace(columns, ":", " as ", -1)
128-
e.Columns = strings.Split(columns, ",")
147+
e.Columns = fieldList
129148

130149
case "@group":
131-
e.Group = gconv.String(v)
150+
e.Group = fieldStr
132151
}
133152
}
134153

@@ -160,32 +179,21 @@ func (e *SqlExecutor) List(page int, count int, needTotal bool) (list []g.Map, t
160179
m := e.build()
161180

162181
if needTotal {
163-
total, err = m.Fields("*").Count()
164-
if err != nil {
182+
total, err = m.Count()
183+
if err != nil || total == 0 {
165184
return nil, 0, err
166185
}
167186
}
168187

169-
// 无需下一步查询
170-
if needTotal && total == 0 {
171-
return nil, 0, err
172-
}
173-
174-
if e.Columns != nil {
175-
m = m.Fields(e.Columns)
176-
}
188+
m = m.Fields(e.JsonFields())
177189

178190
m = m.Page(page, count)
179191
all, err := m.All()
180192
if err != nil {
181193
return nil, 0, err
182194
}
183195

184-
for _, item := range all.List() {
185-
list = append(list, item)
186-
}
187-
188-
return
196+
return all.List(), total, nil
189197
}
190198

191199
func (e *SqlExecutor) One() (g.Map, error) {
@@ -195,11 +203,28 @@ func (e *SqlExecutor) One() (g.Map, error) {
195203

196204
m := e.build()
197205

198-
if e.Columns != nil {
199-
m = m.Fields(e.Columns)
200-
}
206+
m = m.Fields(e.JsonFields())
201207

202208
one, err := m.One()
203209

204210
return one.Map(), err
205211
}
212+
213+
// JsonFields 返回 config.ToJsonField 指定的字段格式.
214+
func (e *SqlExecutor) JsonFields() []string {
215+
216+
var fields = make([]string, 0, len(e.Columns))
217+
for _, column := range e.Columns {
218+
column = strings.ReplaceAll(column, ":", AS)
219+
if !strings.Contains(column, AS) {
220+
field := config.ToJsonField(column)
221+
if field != column {
222+
column = column + AS + field
223+
}
224+
}
225+
226+
fields = append(fields, column)
227+
}
228+
229+
return fields
230+
}

db/table.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package db
2+
3+
import (
4+
"context"
5+
"github.com/gogf/gf/v2/frame/g"
6+
)
7+
8+
type (
9+
Column struct {
10+
Name string
11+
}
12+
13+
Table struct {
14+
Name string
15+
Columns []Column
16+
}
17+
)
18+
19+
var tableMap = map[string]Table{}
20+
21+
func loadTableMeta() {
22+
var ctx = context.TODO()
23+
24+
tables, err := g.DB().Tables(ctx)
25+
if err != nil {
26+
panic(err)
27+
}
28+
29+
for _, table := range tables {
30+
fields, err := g.DB().TableFields(ctx, table)
31+
if err != nil {
32+
panic(err)
33+
}
34+
35+
var columns []Column
36+
for field, _ := range fields {
37+
columns = append(columns, Column{Name: field})
38+
}
39+
40+
tableMap[table] = Table{
41+
Name: table,
42+
Columns: columns,
43+
}
44+
}
45+
}

demo/todo/go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ require (
77
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.2.1
88
github.com/gogf/gf/v2 v2.2.1
99
github.com/iancoleman/orderedmap v0.2.0
10+
github.com/stretchr/testify v1.8.0
1011
)
1112

1213
require (
1314
github.com/BurntSushi/toml v1.1.0 // indirect
1415
github.com/cespare/xxhash/v2 v2.1.2 // indirect
1516
github.com/clbanning/mxj/v2 v2.5.5 // indirect
17+
github.com/davecgh/go-spew v1.1.1 // indirect
1618
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
1719
github.com/fatih/color v1.13.0 // indirect
1820
github.com/fsnotify/fsnotify v1.5.4 // indirect
@@ -27,6 +29,7 @@ require (
2729
github.com/mattn/go-isatty v0.0.14 // indirect
2830
github.com/mattn/go-runewidth v0.0.9 // indirect
2931
github.com/olekukonko/tablewriter v0.0.5 // indirect
32+
github.com/pmezard/go-difflib v1.0.0 // indirect
3033
github.com/samber/lo v1.33.0 // indirect
3134
go.opentelemetry.io/otel v1.7.0 // indirect
3235
go.opentelemetry.io/otel/sdk v1.7.0 // indirect

0 commit comments

Comments
 (0)