Compare commits

..

52 Commits

Author SHA1 Message Date
Kevin Wan
acd48f0abb optimize dockerfile generation (#284) 2020-12-12 16:53:06 +08:00
kingxt
f919bc6713 refactor (#283) 2020-12-12 11:18:22 +08:00
Kevin Wan
a0030b8f45 format dockerfile on non-chinese mode (#282) 2020-12-12 10:13:33 +08:00
Kevin Wan
a5f0cce1b1 Update readme-en.md 2020-12-12 09:06:09 +08:00
Kevin Wan
4d13dda605 add EXPOSE in dockerfile generation (#281) 2020-12-12 08:18:01 +08:00
songmeizi
b56cc8e459 optimize test case of TestRpcGenerate (#279)
Co-authored-by: anqiansong <anqiansong@xiaoheiban.cn>
2020-12-11 21:57:04 +08:00
Kevin Wan
c435811479 fix gocyclo warnings (#278) 2020-12-11 20:57:48 +08:00
Kevin Wan
c686c93fb5 fix dockerfile generation bug (#277) 2020-12-11 20:31:31 +08:00
Kevin Wan
da8f76e6bd add category docker & kube (#276) 2020-12-11 18:53:40 +08:00
Kevin Wan
99596a4149 fix issue #266 (#275)
* optimize dockerfile

* fix issue #266
2020-12-11 16:12:33 +08:00
wayne
ec2a9f2c57 fix tracelogger_test TestTraceLog (#271) 2020-12-10 17:04:57 +08:00
Kevin Wan
fd73ced6dc optimize dockerfile (#272) 2020-12-10 16:21:06 +08:00
Kevin Wan
5071736ab4 fmt code (#270) 2020-12-10 15:16:13 +08:00
Kevin Wan
0d7f1d23b4 require go 1.14 (#263)
* refactor & format code

* optimized parse tag (#256)

* feature plugin custom flag (#251)

* support plugin custom flags

* add short name

* remove log

* remove log

* require go 1.14

Co-authored-by: kingxt <kingxt4job@gmail.com>
Co-authored-by: songmeizi <anqiansong@xiaoheiban.cn>
2020-12-09 22:43:42 +08:00
songmeizi
84ab11ac09 feature plugin custom flag (#251)
* support plugin custom flags

* add short name

* remove log

* remove log
2020-12-09 18:08:17 +08:00
kingxt
67804a6bb2 optimized parse tag (#256) 2020-12-09 11:16:38 +08:00
Kevin Wan
65ee877236 refactor & format code (#255) 2020-12-08 23:01:25 +08:00
songmeizi
b060867009 Feature bookstore update (#253)
* update bookstore

* update bookstore
2020-12-08 22:36:48 +08:00
songmeizi
4d53045c6b improve data type conversion (#236)
* improve data type conversion

* update doc
2020-12-08 18:06:15 +08:00
kingxt
cecd4b1b75 goctl add plugin support (#243)
* add plugin support

* add plugin support

* add plugin support

* add plugin support

* add plugin support

* add plugin support

* add plugin support

* add plugin support

* add plugin support

* add plugin support

* add plugin support

* remove no need

* add plugin support

* rename

* rename

* add plugin support

* refactor

* update plugin

* refactor

* refactor

* refactor

* update plugin

* newline

Co-authored-by: anqiansong <anqiansong@xiaoheiban.cn>
2020-12-07 14:55:10 +08:00
Kevin Wan
7cd0463953 fix lint errors (#249)
* simplify code, format makefile

* simplify code

* some optimize by kevwan and benying (#240)

Co-authored-by: 杨志泉 <zhiquan.yang@yiducloud.cn>

* optimization (#241)

* optimize docker file generation, make docker build faster

* support k8s deployment yaml generation

* fix lint errors

Co-authored-by: benying <31179034+benyingY@users.noreply.github.com>
Co-authored-by: 杨志泉 <zhiquan.yang@yiducloud.cn>
Co-authored-by: bittoy <bittoy@qq.com>
2020-12-07 11:12:02 +08:00
Kevin Wan
7a82cf80ce support k8s deployment yaml generation (#247)
* simplify code, format makefile

* simplify code

* some optimize by kevwan and benying (#240)

Co-authored-by: 杨志泉 <zhiquan.yang@yiducloud.cn>

* optimization (#241)

* optimize docker file generation, make docker build faster

* support k8s deployment yaml generation

Co-authored-by: benying <31179034+benyingY@users.noreply.github.com>
Co-authored-by: 杨志泉 <zhiquan.yang@yiducloud.cn>
Co-authored-by: bittoy <bittoy@qq.com>
2020-12-07 00:07:50 +08:00
Kevin Wan
f997aee3ba optimize docker file generation, make docker build faster (#244)
* simplify code, format makefile

* simplify code

* some optimize by kevwan and benying (#240)

Co-authored-by: 杨志泉 <zhiquan.yang@yiducloud.cn>

* optimization (#241)

* optimize docker file generation, make docker build faster

Co-authored-by: benying <31179034+benyingY@users.noreply.github.com>
Co-authored-by: 杨志泉 <zhiquan.yang@yiducloud.cn>
Co-authored-by: bittoy <bittoy@qq.com>
2020-12-05 21:48:09 +08:00
bittoy
88ec89bdbd optimization (#241) 2020-12-02 15:00:07 +08:00
benying
7d1b43780a some optimize by kevwan and benying (#240)
Co-authored-by: 杨志泉 <zhiquan.yang@yiducloud.cn>
2020-12-01 06:44:32 +08:00
Kevin Wan
4b5c2de376 simplify code (#234)
* simplify code, format makefile

* simplify code
2020-11-29 12:41:42 +08:00
Kevin Wan
e5c560e8ba simplify code, format makefile (#233) 2020-11-28 22:27:58 +08:00
xuezonggui
bed494d904 optimization (#221) 2020-11-28 19:43:39 +08:00
Keson
2dfecda465 modify the service name from proto (#230) 2020-11-28 11:48:44 +08:00
voidint
3ebb1e0221 Improve Makefile robustness (#224) 2020-11-27 23:40:07 +08:00
kingxt
348184904c set default handler value (#228)
* set default value

* set default value
2020-11-26 11:57:02 +08:00
Keson
7a27fa50a1 update version (#226) 2020-11-25 12:04:22 +08:00
Kevin Wan
8d4951c990 check go.mod before build docker image (#225) 2020-11-24 23:19:31 +08:00
Keson
6e57f6c527 feature model interface (#222)
* make variable declaration more concise

* add model interface

* optimize interface methods

* fix: go test failed

* warp returns

* optimize
2020-11-24 22:36:23 +08:00
kingxt
b9ac51b6c3 feature: file namestyle (#223)
* add api filename style

* new feature: config.yaml

* optimize

* optimize logic generation

* check hanlder valid

* optimize

* reactor naming style

* optimize

* optimize test

* optimize gen middleware

* format

Co-authored-by: anqiansong <anqiansong@xiaoheiban.cn>
Co-authored-by: kim <xutao@xiaoheiban.cn>
2020-11-24 15:11:18 +08:00
kevin
702e8d79ce fix doc errors 2020-11-24 10:39:38 +08:00
kevin
95a9dabf8b format import 2020-11-23 16:35:39 +08:00
Chris
bae66c49c2 1.use local variable i; 2.make sure limiter larger than timer period (#218)
Co-authored-by: chris <feilee1987@163.com>
2020-11-23 16:34:51 +08:00
kingxt
e0afe0b4bb optimize api new (#216) 2020-11-19 16:48:48 +08:00
Keson
24fb29a356 patch model&rpc (#207)
* change column to read from information_schema

* reactor generate mode from datasource

* reactor generate mode from datasource

* add primary key check logic

* resolve rebase conflicts

* add naming style

* add filename test case

* resolve rebase conflicts

* reactor test

* add test case

* change shell script to makefile

* update rpc new

* update gen_test.go

* format code

* format code

* update test

* generates alias
2020-11-18 15:32:53 +08:00
kevin
71083b5e64 update readme 2020-11-17 19:01:14 +08:00
kingxt
1174f17bd9 modify image url (#213) 2020-11-17 18:50:22 +08:00
kingxt
d6d8fc21d8 type should not define nested (#212)
* nest type should not supported

* nest type should not supported

* nest type should not supported

* nest type should not supported

* new test

* new test
2020-11-17 18:08:55 +08:00
kevin
9592639cb4 add error handle tests 2020-11-17 18:04:48 +08:00
kevin
abcb28e506 support error customization 2020-11-17 17:11:06 +08:00
kingxt
a92f65580c support type def without struct token (#210)
* add comment support

* add comment support

* 1. group support multi level folder
2. remove force flag

* bug fix

* refactor parser and remove deprecated code

* refactor parser and remove deprecated code

* refactor parser and remove deprecated code

* refactor parser and remove deprecated code

* refactor parser and remove deprecated code

* refactor parser and remove deprecated code

* refactor parser and remove deprecated code

* support type def without struct token

* support type def without struct token

* support type def without struct token

* support type def without struct token

* support type def without struct token

* support type def without struct token

* support type def without struct token

* optimized

* optimized

* optimized

Co-authored-by: kim <xutao@xiaoheiban.cn>
2020-11-17 15:25:13 +08:00
bittoy
3819f67cf4 add redis geospatial (#209)
* add redis geospatial

* fix go test error
2020-11-16 19:45:43 +08:00
kevin
295c8d2934 fix issue #205 2020-11-16 19:23:24 +08:00
kingxt
88da8685dd optimize parser (#206)
* add comment support

* add comment support

* 1. group support multi level folder
2. remove force flag

* bug fix

* refactor parser and remove deprecated code

* refactor parser and remove deprecated code

* refactor parser and remove deprecated code

* refactor parser and remove deprecated code

* refactor parser and remove deprecated code

* refactor parser and remove deprecated code

* refactor parser and remove deprecated code

* optimized parser

Co-authored-by: kim <xutao@xiaoheiban.cn>
2020-11-16 10:08:28 +08:00
kevin
c7831ac96d update goctl readme 2020-11-15 21:18:02 +08:00
kevin
e898761762 update example 2020-11-15 21:15:29 +08:00
kevin
13d1c5cd00 update example 2020-11-14 22:01:35 +08:00
177 changed files with 4169 additions and 2776 deletions

View File

@@ -74,27 +74,29 @@ func (rw *RollingWindow) span() int {
func (rw *RollingWindow) updateOffset() { func (rw *RollingWindow) updateOffset() {
span := rw.span() span := rw.span()
if span > 0 { if span <= 0 {
offset := rw.offset return
// reset expired buckets
start := offset + 1
steps := start + span
var remainder int
if steps > rw.size {
remainder = steps - rw.size
steps = rw.size
}
for i := start; i < steps; i++ {
rw.win.resetBucket(i)
offset = i
}
for i := 0; i < remainder; i++ {
rw.win.resetBucket(i)
offset = i
}
rw.offset = offset
rw.lastTime = timex.Now()
} }
offset := rw.offset
start := offset + 1
steps := start + span
var remainder int
if steps > rw.size {
remainder = steps - rw.size
steps = rw.size
}
// reset expired buckets
for i := start; i < steps; i++ {
rw.win.resetBucket(i)
}
for i := 0; i < remainder; i++ {
rw.win.resetBucket(i)
}
rw.offset = (offset + span) % rw.size
rw.lastTime = timex.Now()
} }
type Bucket struct { type Bucket struct {
@@ -118,9 +120,9 @@ type window struct {
} }
func newWindow(size int) *window { func newWindow(size int) *window {
var buckets []*Bucket buckets := make([]*Bucket, size)
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
buckets = append(buckets, new(Bucket)) buckets[i] = new(Bucket)
} }
return &window{ return &window{
buckets: buckets, buckets: buckets,
@@ -134,12 +136,12 @@ func (w *window) add(offset int, v float64) {
func (w *window) reduce(start, count int, fn func(b *Bucket)) { func (w *window) reduce(start, count int, fn func(b *Bucket)) {
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
fn(w.buckets[(start+i)%len(w.buckets)]) fn(w.buckets[(start+i)%w.size])
} }
} }
func (w *window) resetBucket(offset int) { func (w *window) resetBucket(offset int) {
w.buckets[offset].reset() w.buckets[offset%w.size].reset()
} }
func IgnoreCurrentBucket() RollingWindowOption { func IgnoreCurrentBucket() RollingWindowOption {

View File

@@ -204,6 +204,7 @@ func (tw *TimingWheel) removeTask(key interface{}) {
timer := val.(*positionEntry) timer := val.(*positionEntry)
timer.item.removed = true timer.item.removed = true
tw.timers.Del(key)
} }
func (tw *TimingWheel) run() { func (tw *TimingWheel) run() {
@@ -248,7 +249,6 @@ func (tw *TimingWheel) scanAndRunTasks(l *list.List) {
if task.removed { if task.removed {
next := e.Next() next := e.Next()
l.Remove(e) l.Remove(e)
tw.timers.Del(task.key)
e = next e = next
continue continue
} else if task.circle > 0 { } else if task.circle > 0 {
@@ -301,6 +301,7 @@ func (tw *TimingWheel) setTask(task *timingEntry) {
func (tw *TimingWheel) setTimerPosition(pos int, task *timingEntry) { func (tw *TimingWheel) setTimerPosition(pos int, task *timingEntry) {
if val, ok := tw.timers.Get(task.key); ok { if val, ok := tw.timers.Get(task.key); ok {
timer := val.(*positionEntry) timer := val.(*positionEntry)
timer.item = task
timer.pos = pos timer.pos = pos
} else { } else {
tw.timers.Set(task.key, &positionEntry{ tw.timers.Set(task.key, &positionEntry{

View File

@@ -594,6 +594,31 @@ func TestTimingWheel_ElapsedAndSetThenMove(t *testing.T) {
} }
} }
func TestMoveAndRemoveTask(t *testing.T) {
ticker := timex.NewFakeTicker()
tick := func(v int) {
for i := 0; i < v; i++ {
ticker.Tick()
}
}
var keys []int
tw, _ := newTimingWheelWithClock(testStep, 10, func(k, v interface{}) {
assert.Equal(t, "any", k)
assert.Equal(t, 3, v.(int))
keys = append(keys, v.(int))
ticker.Done()
}, ticker)
defer tw.Stop()
tw.SetTimer("any", 3, testStep*8)
tick(6)
tw.MoveTimer("any", testStep*7)
tick(3)
tw.RemoveTimer("any")
tick(30)
time.Sleep(time.Millisecond)
assert.Equal(t, 0, len(keys))
}
func BenchmarkTimingWheel(b *testing.B) { func BenchmarkTimingWheel(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()

View File

@@ -3,7 +3,7 @@ package limit
import ( import (
"testing" "testing"
"github.com/alicebob/miniredis" "github.com/alicebob/miniredis/v2"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/core/stores/redis" "github.com/tal-tech/go-zero/core/stores/redis"
"github.com/tal-tech/go-zero/core/stores/redis/redistest" "github.com/tal-tech/go-zero/core/stores/redis/redistest"

View File

@@ -4,7 +4,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/alicebob/miniredis" "github.com/alicebob/miniredis/v2"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/core/logx" "github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/core/stores/redis" "github.com/tal-tech/go-zero/core/stores/redis"

View File

@@ -21,6 +21,7 @@ var mock tracespec.Trace = new(mockTrace)
func TestTraceLog(t *testing.T) { func TestTraceLog(t *testing.T) {
var buf mockWriter var buf mockWriter
atomic.StoreUint32(&initialized, 1)
ctx := context.WithValue(context.Background(), tracespec.TracingKey, mock) ctx := context.WithValue(context.Background(), tracespec.TracingKey, mock)
WithContext(ctx).(*traceLogger).write(&buf, levelInfo, testlog) WithContext(ctx).(*traceLogger).write(&buf, levelInfo, testlog)
assert.True(t, strings.Contains(buf.String(), mockTraceId)) assert.True(t, strings.Contains(buf.String(), mockTraceId))

View File

@@ -153,58 +153,57 @@ func doParseKeyAndOptions(field reflect.StructField, value string) (string, *fie
key := strings.TrimSpace(segments[0]) key := strings.TrimSpace(segments[0])
options := segments[1:] options := segments[1:]
if len(options) > 0 { if len(options) == 0 {
var fieldOpts fieldOptions return key, nil, nil
for _, segment := range options {
option := strings.TrimSpace(segment)
switch {
case option == stringOption:
fieldOpts.FromString = true
case strings.HasPrefix(option, optionalOption):
segs := strings.Split(option, equalToken)
switch len(segs) {
case 1:
fieldOpts.Optional = true
case 2:
fieldOpts.Optional = true
fieldOpts.OptionalDep = segs[1]
default:
return "", nil, fmt.Errorf("field %s has wrong optional", field.Name)
}
case option == optionalOption:
fieldOpts.Optional = true
case strings.HasPrefix(option, optionsOption):
segs := strings.Split(option, equalToken)
if len(segs) != 2 {
return "", nil, fmt.Errorf("field %s has wrong options", field.Name)
} else {
fieldOpts.Options = strings.Split(segs[1], optionSeparator)
}
case strings.HasPrefix(option, defaultOption):
segs := strings.Split(option, equalToken)
if len(segs) != 2 {
return "", nil, fmt.Errorf("field %s has wrong default option", field.Name)
} else {
fieldOpts.Default = strings.TrimSpace(segs[1])
}
case strings.HasPrefix(option, rangeOption):
segs := strings.Split(option, equalToken)
if len(segs) != 2 {
return "", nil, fmt.Errorf("field %s has wrong range", field.Name)
}
if nr, err := parseNumberRange(segs[1]); err != nil {
return "", nil, err
} else {
fieldOpts.Range = nr
}
}
}
return key, &fieldOpts, nil
} }
return key, nil, nil var fieldOpts fieldOptions
for _, segment := range options {
option := strings.TrimSpace(segment)
switch {
case option == stringOption:
fieldOpts.FromString = true
case strings.HasPrefix(option, optionalOption):
segs := strings.Split(option, equalToken)
switch len(segs) {
case 1:
fieldOpts.Optional = true
case 2:
fieldOpts.Optional = true
fieldOpts.OptionalDep = segs[1]
default:
return "", nil, fmt.Errorf("field %s has wrong optional", field.Name)
}
case option == optionalOption:
fieldOpts.Optional = true
case strings.HasPrefix(option, optionsOption):
segs := strings.Split(option, equalToken)
if len(segs) != 2 {
return "", nil, fmt.Errorf("field %s has wrong options", field.Name)
} else {
fieldOpts.Options = strings.Split(segs[1], optionSeparator)
}
case strings.HasPrefix(option, defaultOption):
segs := strings.Split(option, equalToken)
if len(segs) != 2 {
return "", nil, fmt.Errorf("field %s has wrong default option", field.Name)
} else {
fieldOpts.Default = strings.TrimSpace(segs[1])
}
case strings.HasPrefix(option, rangeOption):
segs := strings.Split(option, equalToken)
if len(segs) != 2 {
return "", nil, fmt.Errorf("field %s has wrong range", field.Name)
}
if nr, err := parseNumberRange(segs[1]); err != nil {
return "", nil, err
} else {
fieldOpts.Range = nr
}
}
}
return key, &fieldOpts, nil
} }
func implicitValueRequiredStruct(tag string, tp reflect.Type) (bool, error) { func implicitValueRequiredStruct(tag string, tp reflect.Type) (bool, error) {

View File

@@ -9,7 +9,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/alicebob/miniredis" "github.com/alicebob/miniredis/v2"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/core/logx" "github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/core/mathx" "github.com/tal-tech/go-zero/core/mathx"

View File

@@ -4,7 +4,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/alicebob/miniredis" "github.com/alicebob/miniredis/v2"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/core/hash" "github.com/tal-tech/go-zero/core/hash"
"github.com/tal-tech/go-zero/core/stores/cache" "github.com/tal-tech/go-zero/core/stores/cache"

View File

@@ -42,6 +42,12 @@ type (
red.Cmdable red.Cmdable
} }
// GeoLocation is used with GeoAdd to add geospatial location.
GeoLocation = red.GeoLocation
// GeoRadiusQuery is used with GeoRadius to query geospatial index.
GeoRadiusQuery = red.GeoRadiusQuery
GeoPos = red.GeoPos
Pipeliner = red.Pipeliner Pipeliner = red.Pipeliner
// Z represents sorted set member. // Z represents sorted set member.
@@ -173,6 +179,107 @@ func (s *Redis) Expireat(key string, expireTime int64) error {
}, acceptable) }, acceptable)
} }
func (s *Redis) GeoAdd(key string, geoLocation ...*GeoLocation) (val int64, err error) {
err = s.brk.DoWithAcceptable(func() error {
conn, err := getRedis(s)
if err != nil {
return err
}
if v, err := conn.GeoAdd(key, geoLocation...).Result(); err != nil {
return err
} else {
val = v
return nil
}
}, acceptable)
return
}
func (s *Redis) GeoDist(key string, member1, member2, unit string) (val float64, err error) {
err = s.brk.DoWithAcceptable(func() error {
conn, err := getRedis(s)
if err != nil {
return err
}
if v, err := conn.GeoDist(key, member1, member2, unit).Result(); err != nil {
return err
} else {
val = v
return nil
}
}, acceptable)
return
}
func (s *Redis) GeoHash(key string, members ...string) (val []string, err error) {
err = s.brk.DoWithAcceptable(func() error {
conn, err := getRedis(s)
if err != nil {
return err
}
if v, err := conn.GeoHash(key, members...).Result(); err != nil {
return err
} else {
val = v
return nil
}
}, acceptable)
return
}
func (s *Redis) GeoRadius(key string, longitude, latitude float64, query *GeoRadiusQuery) (val []GeoLocation, err error) {
err = s.brk.DoWithAcceptable(func() error {
conn, err := getRedis(s)
if err != nil {
return err
}
if v, err := conn.GeoRadius(key, longitude, latitude, query).Result(); err != nil {
return err
} else {
val = v
return nil
}
}, acceptable)
return
}
func (s *Redis) GeoRadiusByMember(key, member string, query *GeoRadiusQuery) (val []GeoLocation, err error) {
err = s.brk.DoWithAcceptable(func() error {
conn, err := getRedis(s)
if err != nil {
return err
}
if v, err := conn.GeoRadiusByMember(key, member, query).Result(); err != nil {
return err
} else {
val = v
return nil
}
}, acceptable)
return
}
func (s *Redis) GeoPos(key string, members ...string) (val []*GeoPos, err error) {
err = s.brk.DoWithAcceptable(func() error {
conn, err := getRedis(s)
if err != nil {
return err
}
if v, err := conn.GeoPos(key, members...).Result(); err != nil {
return err
} else {
val = v
return nil
}
}, acceptable)
return
}
func (s *Redis) Get(key string) (val string, err error) { func (s *Redis) Get(key string) (val string, err error) {
err = s.brk.DoWithAcceptable(func() error { err = s.brk.DoWithAcceptable(func() error {
conn, err := getRedis(s) conn, err := getRedis(s)

View File

@@ -6,7 +6,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/alicebob/miniredis" "github.com/alicebob/miniredis/v2"
red "github.com/go-redis/redis" red "github.com/go-redis/redis"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@@ -556,7 +556,7 @@ func TestRedis_SortedSet(t *testing.T) {
val, err = client.Zscore("key", "value1") val, err = client.Zscore("key", "value1")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, int64(5), val) assert.Equal(t, int64(5), val)
val, err = NewRedis(client.Addr, "").Zadds("key") _, err = NewRedis(client.Addr, "").Zadds("key")
assert.NotNil(t, err) assert.NotNil(t, err)
val, err = client.Zadds("key", Pair{ val, err = client.Zadds("key", Pair{
Key: "value2", Key: "value2",
@@ -567,9 +567,9 @@ func TestRedis_SortedSet(t *testing.T) {
}) })
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, int64(2), val) assert.Equal(t, int64(2), val)
pairs, err := NewRedis(client.Addr, "").ZRevRangeWithScores("key", 1, 3) _, err = NewRedis(client.Addr, "").ZRevRangeWithScores("key", 1, 3)
assert.NotNil(t, err) assert.NotNil(t, err)
pairs, err = client.ZRevRangeWithScores("key", 1, 3) pairs, err := client.ZRevRangeWithScores("key", 1, 3)
assert.Nil(t, err) assert.Nil(t, err)
assert.EqualValues(t, []Pair{ assert.EqualValues(t, []Pair{
{ {
@@ -816,6 +816,38 @@ func TestRedisBlpopEx(t *testing.T) {
}) })
} }
func TestRedisGeo(t *testing.T) {
runOnRedis(t, func(client *Redis) {
client.Ping()
var geoLocation = []*GeoLocation{{Longitude: 13.361389, Latitude: 38.115556, Name: "Palermo"}, {Longitude: 15.087269, Latitude: 37.502669, Name: "Catania"}}
v, err := client.GeoAdd("sicily", geoLocation...)
assert.Nil(t, err)
assert.Equal(t, int64(2), v)
v2, err := client.GeoDist("sicily", "Palermo", "Catania", "m")
assert.Nil(t, err)
assert.Equal(t, 166274, int(v2))
// GeoHash not support
v3, err := client.GeoPos("sicily", "Palermo", "Catania")
assert.Nil(t, err)
assert.Equal(t, int64(v3[0].Longitude), int64(13))
assert.Equal(t, int64(v3[0].Latitude), int64(38))
assert.Equal(t, int64(v3[1].Longitude), int64(15))
assert.Equal(t, int64(v3[1].Latitude), int64(37))
v4, err := client.GeoRadius("sicily", 15, 37, &red.GeoRadiusQuery{WithDist: true, Unit: "km", Radius: 200})
assert.Nil(t, err)
assert.Equal(t, int64(v4[0].Dist), int64(190))
assert.Equal(t, int64(v4[1].Dist), int64(56))
var geoLocation2 = []*GeoLocation{{Longitude: 13.583333, Latitude: 37.316667, Name: "Agrigento"}}
v5, err := client.GeoAdd("sicily", geoLocation2...)
assert.Nil(t, err)
assert.Equal(t, int64(1), v5)
v6, err := client.GeoRadiusByMember("sicily", "Agrigento", &red.GeoRadiusQuery{Unit: "km", Radius: 100})
assert.Nil(t, err)
assert.Equal(t, v6[0].Name, "Agrigento")
assert.Equal(t, v6[1].Name, "Palermo")
})
}
func runOnRedis(t *testing.T, fn func(client *Redis)) { func runOnRedis(t *testing.T, fn func(client *Redis)) {
s, err := miniredis.Run() s, err := miniredis.Run()
assert.Nil(t, err) assert.Nil(t, err)

View File

@@ -3,7 +3,7 @@ package redistest
import ( import (
"time" "time"
"github.com/alicebob/miniredis" "github.com/alicebob/miniredis/v2"
"github.com/tal-tech/go-zero/core/lang" "github.com/tal-tech/go-zero/core/lang"
"github.com/tal-tech/go-zero/core/stores/redis" "github.com/tal-tech/go-zero/core/stores/redis"
) )

View File

@@ -14,7 +14,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/alicebob/miniredis" "github.com/alicebob/miniredis/v2"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/core/fx" "github.com/tal-tech/go-zero/core/fx"
"github.com/tal-tech/go-zero/core/logx" "github.com/tal-tech/go-zero/core/logx"

View File

@@ -1,33 +1,29 @@
type ( type (
addReq struct { addReq {
book string `form:"book"` book string `form:"book"`
price int64 `form:"price"` price int64 `form:"price"`
} }
addResp struct { addResp {
ok bool `json:"ok"` ok bool `json:"ok"`
} }
) )
type ( type (
checkReq struct { checkReq {
book string `form:"book"` book string `form:"book"`
} }
checkResp struct { checkResp {
found bool `json:"found"` found bool `json:"found"`
price int64 `json:"price"` price int64 `json:"price"`
} }
) )
service bookstore-api { service bookstore-api {
@server( @handler AddHandler
handler: AddHandler get /add (addReq) returns (addResp)
)
get /add (addReq) returns (addResp)
@server( @handler CheckHandler
handler: CheckHandler get /check (checkReq) returns (checkResp)
)
get /check (checkReq) returns (checkResp)
} }

View File

@@ -10,7 +10,7 @@ import (
"github.com/tal-tech/go-zero/rest/httpx" "github.com/tal-tech/go-zero/rest/httpx"
) )
func addHandler(ctx *svc.ServiceContext) http.HandlerFunc { func AddHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
var req types.AddReq var req types.AddReq
if err := httpx.Parse(r, &req); err != nil { if err := httpx.Parse(r, &req); err != nil {

View File

@@ -10,7 +10,7 @@ import (
"github.com/tal-tech/go-zero/rest/httpx" "github.com/tal-tech/go-zero/rest/httpx"
) )
func checkHandler(ctx *svc.ServiceContext) http.HandlerFunc { func CheckHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
var req types.CheckReq var req types.CheckReq
if err := httpx.Parse(r, &req); err != nil { if err := httpx.Parse(r, &req); err != nil {

View File

@@ -10,16 +10,18 @@ import (
) )
func RegisterHandlers(engine *rest.Server, serverCtx *svc.ServiceContext) { func RegisterHandlers(engine *rest.Server, serverCtx *svc.ServiceContext) {
engine.AddRoutes([]rest.Route{ engine.AddRoutes(
{ []rest.Route{
Method: http.MethodGet, {
Path: "/add", Method: http.MethodGet,
Handler: addHandler(serverCtx), Path: "/add",
Handler: AddHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/check",
Handler: CheckHandler(serverCtx),
},
}, },
{ )
Method: http.MethodGet,
Path: "/check",
Handler: checkHandler(serverCtx),
},
})
} }

View File

@@ -29,7 +29,8 @@ func (l *CheckLogic) Check(req types.CheckReq) (*types.CheckResp, error) {
Book: req.Book, Book: req.Book,
}) })
if err != nil { if err != nil {
return nil, err logx.Error(err)
return &types.CheckResp{}, err
} }
return &types.CheckResp{ return &types.CheckResp{

View File

@@ -5,7 +5,8 @@ go 1.15
require ( require (
github.com/golang/mock v1.4.3 github.com/golang/mock v1.4.3
github.com/golang/protobuf v1.4.2 github.com/golang/protobuf v1.4.2
github.com/tal-tech/go-zero v1.0.16 github.com/tal-tech/go-zero v1.0.27
golang.org/x/net v0.0.0-20200707034311-ab3426394381 golang.org/x/net v0.0.0-20200707034311-ab3426394381
google.golang.org/grpc v1.29.1 google.golang.org/grpc v1.29.1
google.golang.org/protobuf v1.25.0
) )

View File

@@ -36,6 +36,7 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
github.com/coreos/go-systemd/v22 v22.0.0 h1:XJIw/+VlJ+87J+doOxznsAWIdmWuViOVhkQamW5YV28= github.com/coreos/go-systemd/v22 v22.0.0 h1:XJIw/+VlJ+87J+doOxznsAWIdmWuViOVhkQamW5YV28=
github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -46,6 +47,7 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
github.com/dsymonds/gotoc v0.0.0-20160928043926-5aebcfc91819/go.mod h1:MvzMVHq8BH2Ji/o8TGDocVA70byvLrAgFTxkEnmjO4Y= github.com/dsymonds/gotoc v0.0.0-20160928043926-5aebcfc91819/go.mod h1:MvzMVHq8BH2Ji/o8TGDocVA70byvLrAgFTxkEnmjO4Y=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4 h1:qk/FSDDxo05wdJH28W+p5yivv7LuLYLRXPPD8KQCtZs= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4 h1:qk/FSDDxo05wdJH28W+p5yivv7LuLYLRXPPD8KQCtZs=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/emicklei/proto v1.9.0/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -122,9 +124,11 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.14.3 h1:OCJlWkOUoTnl0neNGlf4fUm3TmbEtguw7vR+nGtnDjY= github.com/grpc-ecosystem/grpc-gateway v1.14.3 h1:OCJlWkOUoTnl0neNGlf4fUm3TmbEtguw7vR+nGtnDjY=
github.com/grpc-ecosystem/grpc-gateway v1.14.3/go.mod h1:6CwZWGDSPRJidgKAtJVvND6soZe6fT7iteq8wDPdhb0= github.com/grpc-ecosystem/grpc-gateway v1.14.3/go.mod h1:6CwZWGDSPRJidgKAtJVvND6soZe6fT7iteq8wDPdhb0=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/iancoleman/strcase v0.1.2/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
@@ -175,6 +179,7 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -210,6 +215,7 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
@@ -232,11 +238,14 @@ github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/tal-tech/go-zero v1.0.16 h1:oT7sOFftEUdD/XcXF0xEugX9yhnw4DcQkeMNFLi5KO8= github.com/tal-tech/go-zero v1.0.16 h1:oT7sOFftEUdD/XcXF0xEugX9yhnw4DcQkeMNFLi5KO8=
github.com/tal-tech/go-zero v1.0.16/go.mod h1:y2wBHTkxNJw79K9/wCSeDKzv2pCT6x45oOmXEsJdQK8= github.com/tal-tech/go-zero v1.0.16/go.mod h1:y2wBHTkxNJw79K9/wCSeDKzv2pCT6x45oOmXEsJdQK8=
github.com/tal-tech/go-zero v1.0.27 h1:QMIbaTxibMc/OsO5RTAuKZ8ndbl2dGN6pITQEtp2x/A=
github.com/tal-tech/go-zero v1.0.27/go.mod h1:JtNXlsh/CgeIHyQnt5C5M2IcSevW7V0NAnqO93TQgm8=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6 h1:lYIiVDtZnyTWlNwiAxLj0bbpTcx1BWCFhXjfsvmPdNc= github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6 h1:lYIiVDtZnyTWlNwiAxLj0bbpTcx1BWCFhXjfsvmPdNc=
github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
@@ -382,6 +391,7 @@ gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qS
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
@@ -393,6 +403,8 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=

View File

@@ -7,8 +7,8 @@ import (
"flag" "flag"
"fmt" "fmt"
"bookstore/rpc/add/add"
"bookstore/rpc/add/internal/config" "bookstore/rpc/add/internal/config"
add "bookstore/rpc/add/internal/pb"
"bookstore/rpc/add/internal/server" "bookstore/rpc/add/internal/server"
"bookstore/rpc/add/internal/svc" "bookstore/rpc/add/internal/svc"

View File

@@ -0,0 +1,305 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.14.0
// source: add.proto
package add
import (
context "context"
proto "github.com/golang/protobuf/proto"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type AddReq struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Book string `protobuf:"bytes,1,opt,name=book,proto3" json:"book,omitempty"`
Price int64 `protobuf:"varint,2,opt,name=price,proto3" json:"price,omitempty"`
}
func (x *AddReq) Reset() {
*x = AddReq{}
if protoimpl.UnsafeEnabled {
mi := &file_add_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AddReq) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AddReq) ProtoMessage() {}
func (x *AddReq) ProtoReflect() protoreflect.Message {
mi := &file_add_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AddReq.ProtoReflect.Descriptor instead.
func (*AddReq) Descriptor() ([]byte, []int) {
return file_add_proto_rawDescGZIP(), []int{0}
}
func (x *AddReq) GetBook() string {
if x != nil {
return x.Book
}
return ""
}
func (x *AddReq) GetPrice() int64 {
if x != nil {
return x.Price
}
return 0
}
type AddResp struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Ok bool `protobuf:"varint,1,opt,name=ok,proto3" json:"ok,omitempty"`
}
func (x *AddResp) Reset() {
*x = AddResp{}
if protoimpl.UnsafeEnabled {
mi := &file_add_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AddResp) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AddResp) ProtoMessage() {}
func (x *AddResp) ProtoReflect() protoreflect.Message {
mi := &file_add_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AddResp.ProtoReflect.Descriptor instead.
func (*AddResp) Descriptor() ([]byte, []int) {
return file_add_proto_rawDescGZIP(), []int{1}
}
func (x *AddResp) GetOk() bool {
if x != nil {
return x.Ok
}
return false
}
var File_add_proto protoreflect.FileDescriptor
var file_add_proto_rawDesc = []byte{
0x0a, 0x09, 0x61, 0x64, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03, 0x61, 0x64, 0x64,
0x22, 0x32, 0x0a, 0x06, 0x61, 0x64, 0x64, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f,
0x6f, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, 0x6f, 0x6b, 0x12, 0x14,
0x0a, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x70,
0x72, 0x69, 0x63, 0x65, 0x22, 0x19, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12,
0x0e, 0x0a, 0x02, 0x6f, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x02, 0x6f, 0x6b, 0x32,
0x29, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, 0x72, 0x12, 0x20, 0x0a, 0x03, 0x61, 0x64, 0x64, 0x12,
0x0b, 0x2e, 0x61, 0x64, 0x64, 0x2e, 0x61, 0x64, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x0c, 0x2e, 0x61,
0x64, 0x64, 0x2e, 0x61, 0x64, 0x64, 0x52, 0x65, 0x73, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (
file_add_proto_rawDescOnce sync.Once
file_add_proto_rawDescData = file_add_proto_rawDesc
)
func file_add_proto_rawDescGZIP() []byte {
file_add_proto_rawDescOnce.Do(func() {
file_add_proto_rawDescData = protoimpl.X.CompressGZIP(file_add_proto_rawDescData)
})
return file_add_proto_rawDescData
}
var file_add_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_add_proto_goTypes = []interface{}{
(*AddReq)(nil), // 0: add.addReq
(*AddResp)(nil), // 1: add.addResp
}
var file_add_proto_depIdxs = []int32{
0, // 0: add.adder.add:input_type -> add.addReq
1, // 1: add.adder.add:output_type -> add.addResp
1, // [1:2] is the sub-list for method output_type
0, // [0:1] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_add_proto_init() }
func file_add_proto_init() {
if File_add_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_add_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AddReq); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_add_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AddResp); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_add_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_add_proto_goTypes,
DependencyIndexes: file_add_proto_depIdxs,
MessageInfos: file_add_proto_msgTypes,
}.Build()
File_add_proto = out.File
file_add_proto_rawDesc = nil
file_add_proto_goTypes = nil
file_add_proto_depIdxs = nil
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConnInterface
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion6
// AdderClient is the client API for Adder service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type AdderClient interface {
Add(ctx context.Context, in *AddReq, opts ...grpc.CallOption) (*AddResp, error)
}
type adderClient struct {
cc grpc.ClientConnInterface
}
func NewAdderClient(cc grpc.ClientConnInterface) AdderClient {
return &adderClient{cc}
}
func (c *adderClient) Add(ctx context.Context, in *AddReq, opts ...grpc.CallOption) (*AddResp, error) {
out := new(AddResp)
err := c.cc.Invoke(ctx, "/add.adder/add", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// AdderServer is the server API for Adder service.
type AdderServer interface {
Add(context.Context, *AddReq) (*AddResp, error)
}
// UnimplementedAdderServer can be embedded to have forward compatible implementations.
type UnimplementedAdderServer struct {
}
func (*UnimplementedAdderServer) Add(context.Context, *AddReq) (*AddResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method Add not implemented")
}
func RegisterAdderServer(s *grpc.Server, srv AdderServer) {
s.RegisterService(&_Adder_serviceDesc, srv)
}
func _Adder_Add_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AddReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AdderServer).Add(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/add.adder/Add",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AdderServer).Add(ctx, req.(*AddReq))
}
return interceptor(ctx, in, info, handler)
}
var _Adder_serviceDesc = grpc.ServiceDesc{
ServiceName: "add.adder",
HandlerType: (*AdderServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "add",
Handler: _Adder_Add_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "add.proto",
}

View File

@@ -8,7 +8,7 @@ package adder
import ( import (
"context" "context"
add "bookstore/rpc/add/internal/pb" "bookstore/rpc/add/add"
"github.com/tal-tech/go-zero/zrpc" "github.com/tal-tech/go-zero/zrpc"
) )
@@ -33,6 +33,6 @@ func NewAdder(cli zrpc.Client) Adder {
} }
func (m *defaultAdder) Add(ctx context.Context, in *AddReq) (*AddResp, error) { func (m *defaultAdder) Add(ctx context.Context, in *AddReq) (*AddResp, error) {
adder := add.NewAdderClient(m.cli.Conn()) client := add.NewAdderClient(m.cli.Conn())
return adder.Add(ctx, in) return client.Add(ctx, in)
} }

View File

@@ -1,49 +0,0 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: adder.go
// Package adder is a generated GoMock package.
package adder
import (
context "context"
gomock "github.com/golang/mock/gomock"
reflect "reflect"
)
// MockAdder is a mock of Adder interface
type MockAdder struct {
ctrl *gomock.Controller
recorder *MockAdderMockRecorder
}
// MockAdderMockRecorder is the mock recorder for MockAdder
type MockAdderMockRecorder struct {
mock *MockAdder
}
// NewMockAdder creates a new mock instance
func NewMockAdder(ctrl *gomock.Controller) *MockAdder {
mock := &MockAdder{ctrl: ctrl}
mock.recorder = &MockAdderMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockAdder) EXPECT() *MockAdderMockRecorder {
return m.recorder
}
// Add mocks base method
func (m *MockAdder) Add(ctx context.Context, in *AddReq) (*AddResp, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Add", ctx, in)
ret0, _ := ret[0].(*AddResp)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Add indicates an expected call of Add
func (mr *MockAdderMockRecorder) Add(ctx, in interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Add", reflect.TypeOf((*MockAdder)(nil).Add), ctx, in)
}

View File

@@ -8,6 +8,5 @@ import (
type Config struct { type Config struct {
zrpc.RpcServerConf zrpc.RpcServerConf
DataSource string DataSource string
Table string
Cache cache.CacheConf Cache cache.CacheConf
} }

View File

@@ -3,7 +3,7 @@ package logic
import ( import (
"context" "context"
add "bookstore/rpc/add/internal/pb" add "bookstore/rpc/add/adder"
"bookstore/rpc/add/internal/svc" "bookstore/rpc/add/internal/svc"
"bookstore/rpc/model" "bookstore/rpc/model"

View File

@@ -1,167 +0,0 @@
// Code generated by protoc-gen-go.
// source: add.proto
// DO NOT EDIT!
/*
Package add is a generated protocol buffer package.
It is generated from these files:
add.proto
It has these top-level messages:
AddReq
AddResp
*/
package add
import (
"fmt"
"math"
"github.com/golang/protobuf/proto"
"golang.org/x/net/context"
"google.golang.org/grpc"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type AddReq struct {
Book string `protobuf:"bytes,1,opt,name=book" json:"book,omitempty"`
Price int64 `protobuf:"varint,2,opt,name=price" json:"price,omitempty"`
}
func (m *AddReq) Reset() { *m = AddReq{} }
func (m *AddReq) String() string { return proto.CompactTextString(m) }
func (*AddReq) ProtoMessage() {}
func (*AddReq) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (m *AddReq) GetBook() string {
if m != nil {
return m.Book
}
return ""
}
func (m *AddReq) GetPrice() int64 {
if m != nil {
return m.Price
}
return 0
}
type AddResp struct {
Ok bool `protobuf:"varint,1,opt,name=ok" json:"ok,omitempty"`
}
func (m *AddResp) Reset() { *m = AddResp{} }
func (m *AddResp) String() string { return proto.CompactTextString(m) }
func (*AddResp) ProtoMessage() {}
func (*AddResp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (m *AddResp) GetOk() bool {
if m != nil {
return m.Ok
}
return false
}
func init() {
proto.RegisterType((*AddReq)(nil), "add.addReq")
proto.RegisterType((*AddResp)(nil), "add.addResp")
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// Client API for Adder service
type AdderClient interface {
Add(ctx context.Context, in *AddReq, opts ...grpc.CallOption) (*AddResp, error)
}
type adderClient struct {
cc *grpc.ClientConn
}
func NewAdderClient(cc *grpc.ClientConn) AdderClient {
return &adderClient{cc}
}
func (c *adderClient) Add(ctx context.Context, in *AddReq, opts ...grpc.CallOption) (*AddResp, error) {
out := new(AddResp)
err := grpc.Invoke(ctx, "/add.adder/add", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Adder service
type AdderServer interface {
Add(context.Context, *AddReq) (*AddResp, error)
}
func RegisterAdderServer(s *grpc.Server, srv AdderServer) {
s.RegisterService(&_Adder_serviceDesc, srv)
}
func _Adder_Add_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AddReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AdderServer).Add(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/add.adder/Add",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AdderServer).Add(ctx, req.(*AddReq))
}
return interceptor(ctx, in, info, handler)
}
var _Adder_serviceDesc = grpc.ServiceDesc{
ServiceName: "add.adder",
HandlerType: (*AdderServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "add",
Handler: _Adder_Add_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "add.proto",
}
func init() { proto.RegisterFile("add.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 136 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0x4c, 0x4c, 0x49, 0xd1,
0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x4e, 0x4c, 0x49, 0x51, 0x32, 0xe2, 0x62, 0x4b, 0x4c,
0x49, 0x09, 0x4a, 0x2d, 0x14, 0x12, 0xe2, 0x62, 0x49, 0xca, 0xcf, 0xcf, 0x96, 0x60, 0x54, 0x60,
0xd4, 0xe0, 0x0c, 0x02, 0xb3, 0x85, 0x44, 0xb8, 0x58, 0x0b, 0x8a, 0x32, 0x93, 0x53, 0x25, 0x98,
0x14, 0x18, 0x35, 0x98, 0x83, 0x20, 0x1c, 0x25, 0x49, 0x2e, 0x76, 0xb0, 0x9e, 0xe2, 0x02, 0x21,
0x3e, 0x2e, 0x26, 0xa8, 0x16, 0x8e, 0x20, 0xa6, 0xfc, 0x6c, 0x23, 0x4d, 0x2e, 0xd6, 0xc4, 0x94,
0x94, 0xd4, 0x22, 0x21, 0x05, 0x2e, 0x90, 0xf1, 0x42, 0xdc, 0x7a, 0x20, 0xfb, 0x20, 0x36, 0x48,
0xf1, 0x20, 0x38, 0xc5, 0x05, 0x49, 0x6c, 0x60, 0x57, 0x18, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff,
0xe2, 0x6d, 0xb5, 0x91, 0x92, 0x00, 0x00, 0x00,
}

View File

@@ -6,8 +6,8 @@ package server
import ( import (
"context" "context"
"bookstore/rpc/add/add"
"bookstore/rpc/add/internal/logic" "bookstore/rpc/add/internal/logic"
add "bookstore/rpc/add/internal/pb"
"bookstore/rpc/add/internal/svc" "bookstore/rpc/add/internal/svc"
) )

View File

@@ -9,12 +9,12 @@ import (
type ServiceContext struct { type ServiceContext struct {
c config.Config c config.Config
Model *model.BookModel Model model.BookModel
} }
func NewServiceContext(c config.Config) *ServiceContext { func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{ return &ServiceContext{
c: c, c: c,
Model: model.NewBookModel(sqlx.NewMysql(c.DataSource), c.Cache, c.Table), Model: model.NewBookModel(sqlx.NewMysql(c.DataSource), c.Cache),
} }
} }

View File

@@ -7,8 +7,8 @@ import (
"flag" "flag"
"fmt" "fmt"
"bookstore/rpc/check/check"
"bookstore/rpc/check/internal/config" "bookstore/rpc/check/internal/config"
check "bookstore/rpc/check/internal/pb"
"bookstore/rpc/check/internal/server" "bookstore/rpc/check/internal/server"
"bookstore/rpc/check/internal/svc" "bookstore/rpc/check/internal/svc"

View File

@@ -0,0 +1,306 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.14.0
// source: check.proto
package check
import (
context "context"
proto "github.com/golang/protobuf/proto"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type CheckReq struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Book string `protobuf:"bytes,1,opt,name=book,proto3" json:"book,omitempty"`
}
func (x *CheckReq) Reset() {
*x = CheckReq{}
if protoimpl.UnsafeEnabled {
mi := &file_check_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CheckReq) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CheckReq) ProtoMessage() {}
func (x *CheckReq) ProtoReflect() protoreflect.Message {
mi := &file_check_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CheckReq.ProtoReflect.Descriptor instead.
func (*CheckReq) Descriptor() ([]byte, []int) {
return file_check_proto_rawDescGZIP(), []int{0}
}
func (x *CheckReq) GetBook() string {
if x != nil {
return x.Book
}
return ""
}
type CheckResp struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Found bool `protobuf:"varint,1,opt,name=found,proto3" json:"found,omitempty"`
Price int64 `protobuf:"varint,2,opt,name=price,proto3" json:"price,omitempty"`
}
func (x *CheckResp) Reset() {
*x = CheckResp{}
if protoimpl.UnsafeEnabled {
mi := &file_check_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CheckResp) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CheckResp) ProtoMessage() {}
func (x *CheckResp) ProtoReflect() protoreflect.Message {
mi := &file_check_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CheckResp.ProtoReflect.Descriptor instead.
func (*CheckResp) Descriptor() ([]byte, []int) {
return file_check_proto_rawDescGZIP(), []int{1}
}
func (x *CheckResp) GetFound() bool {
if x != nil {
return x.Found
}
return false
}
func (x *CheckResp) GetPrice() int64 {
if x != nil {
return x.Price
}
return 0
}
var File_check_proto protoreflect.FileDescriptor
var file_check_proto_rawDesc = []byte{
0x0a, 0x0b, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x63,
0x68, 0x65, 0x63, 0x6b, 0x22, 0x1e, 0x0a, 0x08, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71,
0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x6f, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
0x62, 0x6f, 0x6f, 0x6b, 0x22, 0x37, 0x0a, 0x09, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73,
0x70, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08,
0x52, 0x05, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x32, 0x35, 0x0a,
0x07, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x05, 0x63, 0x68, 0x65, 0x63,
0x6b, 0x12, 0x0f, 0x2e, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x52,
0x65, 0x71, 0x1a, 0x10, 0x2e, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x63, 0x68, 0x65, 0x63, 0x6b,
0x52, 0x65, 0x73, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_check_proto_rawDescOnce sync.Once
file_check_proto_rawDescData = file_check_proto_rawDesc
)
func file_check_proto_rawDescGZIP() []byte {
file_check_proto_rawDescOnce.Do(func() {
file_check_proto_rawDescData = protoimpl.X.CompressGZIP(file_check_proto_rawDescData)
})
return file_check_proto_rawDescData
}
var file_check_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_check_proto_goTypes = []interface{}{
(*CheckReq)(nil), // 0: check.checkReq
(*CheckResp)(nil), // 1: check.checkResp
}
var file_check_proto_depIdxs = []int32{
0, // 0: check.checker.check:input_type -> check.checkReq
1, // 1: check.checker.check:output_type -> check.checkResp
1, // [1:2] is the sub-list for method output_type
0, // [0:1] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_check_proto_init() }
func file_check_proto_init() {
if File_check_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_check_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CheckReq); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_check_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CheckResp); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_check_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_check_proto_goTypes,
DependencyIndexes: file_check_proto_depIdxs,
MessageInfos: file_check_proto_msgTypes,
}.Build()
File_check_proto = out.File
file_check_proto_rawDesc = nil
file_check_proto_goTypes = nil
file_check_proto_depIdxs = nil
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConnInterface
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion6
// CheckerClient is the client API for Checker service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type CheckerClient interface {
Check(ctx context.Context, in *CheckReq, opts ...grpc.CallOption) (*CheckResp, error)
}
type checkerClient struct {
cc grpc.ClientConnInterface
}
func NewCheckerClient(cc grpc.ClientConnInterface) CheckerClient {
return &checkerClient{cc}
}
func (c *checkerClient) Check(ctx context.Context, in *CheckReq, opts ...grpc.CallOption) (*CheckResp, error) {
out := new(CheckResp)
err := c.cc.Invoke(ctx, "/check.checker/check", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// CheckerServer is the server API for Checker service.
type CheckerServer interface {
Check(context.Context, *CheckReq) (*CheckResp, error)
}
// UnimplementedCheckerServer can be embedded to have forward compatible implementations.
type UnimplementedCheckerServer struct {
}
func (*UnimplementedCheckerServer) Check(context.Context, *CheckReq) (*CheckResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method Check not implemented")
}
func RegisterCheckerServer(s *grpc.Server, srv CheckerServer) {
s.RegisterService(&_Checker_serviceDesc, srv)
}
func _Checker_Check_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CheckReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(CheckerServer).Check(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/check.checker/Check",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(CheckerServer).Check(ctx, req.(*CheckReq))
}
return interceptor(ctx, in, info, handler)
}
var _Checker_serviceDesc = grpc.ServiceDesc{
ServiceName: "check.checker",
HandlerType: (*CheckerServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "check",
Handler: _Checker_Check_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "check.proto",
}

View File

@@ -8,7 +8,7 @@ package checker
import ( import (
"context" "context"
check "bookstore/rpc/check/internal/pb" "bookstore/rpc/check/check"
"github.com/tal-tech/go-zero/zrpc" "github.com/tal-tech/go-zero/zrpc"
) )
@@ -33,6 +33,6 @@ func NewChecker(cli zrpc.Client) Checker {
} }
func (m *defaultChecker) Check(ctx context.Context, in *CheckReq) (*CheckResp, error) { func (m *defaultChecker) Check(ctx context.Context, in *CheckReq) (*CheckResp, error) {
checker := check.NewCheckerClient(m.cli.Conn()) client := check.NewCheckerClient(m.cli.Conn())
return checker.Check(ctx, in) return client.Check(ctx, in)
} }

View File

@@ -1,49 +0,0 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: checker.go
// Package checker is a generated GoMock package.
package checker
import (
context "context"
gomock "github.com/golang/mock/gomock"
reflect "reflect"
)
// MockChecker is a mock of Checker interface
type MockChecker struct {
ctrl *gomock.Controller
recorder *MockCheckerMockRecorder
}
// MockCheckerMockRecorder is the mock recorder for MockChecker
type MockCheckerMockRecorder struct {
mock *MockChecker
}
// NewMockChecker creates a new mock instance
func NewMockChecker(ctrl *gomock.Controller) *MockChecker {
mock := &MockChecker{ctrl: ctrl}
mock.recorder = &MockCheckerMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockChecker) EXPECT() *MockCheckerMockRecorder {
return m.recorder
}
// Check mocks base method
func (m *MockChecker) Check(ctx context.Context, in *CheckReq) (*CheckResp, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Check", ctx, in)
ret0, _ := ret[0].(*CheckResp)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Check indicates an expected call of Check
func (mr *MockCheckerMockRecorder) Check(ctx, in interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Check", reflect.TypeOf((*MockChecker)(nil).Check), ctx, in)
}

View File

@@ -8,6 +8,5 @@ import (
type Config struct { type Config struct {
zrpc.RpcServerConf zrpc.RpcServerConf
DataSource string DataSource string
Table string
Cache cache.CacheConf Cache cache.CacheConf
} }

View File

@@ -3,7 +3,7 @@ package logic
import ( import (
"context" "context"
check "bookstore/rpc/check/internal/pb" check "bookstore/rpc/check/checker"
"bookstore/rpc/check/internal/svc" "bookstore/rpc/check/internal/svc"
"github.com/tal-tech/go-zero/core/logx" "github.com/tal-tech/go-zero/core/logx"

View File

@@ -1,167 +0,0 @@
// Code generated by protoc-gen-go.
// source: check.proto
// DO NOT EDIT!
/*
Package check is a generated protocol buffer package.
It is generated from these files:
check.proto
It has these top-level messages:
CheckReq
CheckResp
*/
package check
import (
"fmt"
"math"
"github.com/golang/protobuf/proto"
"golang.org/x/net/context"
"google.golang.org/grpc"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type CheckReq struct {
Book string `protobuf:"bytes,1,opt,name=book" json:"book,omitempty"`
}
func (m *CheckReq) Reset() { *m = CheckReq{} }
func (m *CheckReq) String() string { return proto.CompactTextString(m) }
func (*CheckReq) ProtoMessage() {}
func (*CheckReq) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (m *CheckReq) GetBook() string {
if m != nil {
return m.Book
}
return ""
}
type CheckResp struct {
Found bool `protobuf:"varint,1,opt,name=found" json:"found,omitempty"`
Price int64 `protobuf:"varint,2,opt,name=price" json:"price,omitempty"`
}
func (m *CheckResp) Reset() { *m = CheckResp{} }
func (m *CheckResp) String() string { return proto.CompactTextString(m) }
func (*CheckResp) ProtoMessage() {}
func (*CheckResp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (m *CheckResp) GetFound() bool {
if m != nil {
return m.Found
}
return false
}
func (m *CheckResp) GetPrice() int64 {
if m != nil {
return m.Price
}
return 0
}
func init() {
proto.RegisterType((*CheckReq)(nil), "check.checkReq")
proto.RegisterType((*CheckResp)(nil), "check.checkResp")
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// Client API for Checker service
type CheckerClient interface {
Check(ctx context.Context, in *CheckReq, opts ...grpc.CallOption) (*CheckResp, error)
}
type checkerClient struct {
cc *grpc.ClientConn
}
func NewCheckerClient(cc *grpc.ClientConn) CheckerClient {
return &checkerClient{cc}
}
func (c *checkerClient) Check(ctx context.Context, in *CheckReq, opts ...grpc.CallOption) (*CheckResp, error) {
out := new(CheckResp)
err := grpc.Invoke(ctx, "/check.checker/check", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Checker service
type CheckerServer interface {
Check(context.Context, *CheckReq) (*CheckResp, error)
}
func RegisterCheckerServer(s *grpc.Server, srv CheckerServer) {
s.RegisterService(&_Checker_serviceDesc, srv)
}
func _Checker_Check_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CheckReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(CheckerServer).Check(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/check.checker/Check",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(CheckerServer).Check(ctx, req.(*CheckReq))
}
return interceptor(ctx, in, info, handler)
}
var _Checker_serviceDesc = grpc.ServiceDesc{
ServiceName: "check.checker",
HandlerType: (*CheckerServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "check",
Handler: _Checker_Check_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "check.proto",
}
func init() { proto.RegisterFile("check.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 136 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0x4e, 0xce, 0x48, 0x4d,
0xce, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x05, 0x73, 0x94, 0xe4, 0xb8, 0x38, 0xc0,
0x8c, 0xa0, 0xd4, 0x42, 0x21, 0x21, 0x2e, 0x96, 0xa4, 0xfc, 0xfc, 0x6c, 0x09, 0x46, 0x05, 0x46,
0x0d, 0xce, 0x20, 0x30, 0x5b, 0xc9, 0x9c, 0x8b, 0x13, 0x2a, 0x5f, 0x5c, 0x20, 0x24, 0xc2, 0xc5,
0x9a, 0x96, 0x5f, 0x9a, 0x97, 0x02, 0x56, 0xc1, 0x11, 0x04, 0xe1, 0x80, 0x44, 0x0b, 0x8a, 0x32,
0x93, 0x53, 0x25, 0x98, 0x14, 0x18, 0x35, 0x98, 0x83, 0x20, 0x1c, 0x23, 0x53, 0x2e, 0x76, 0xb0,
0xc6, 0xd4, 0x22, 0x21, 0x2d, 0x2e, 0x88, 0x65, 0x42, 0xfc, 0x7a, 0x10, 0x17, 0xc0, 0x6c, 0x94,
0x12, 0x40, 0x15, 0x28, 0x2e, 0x48, 0x62, 0x03, 0xbb, 0xce, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff,
0x6e, 0x6f, 0xa7, 0x1d, 0xac, 0x00, 0x00, 0x00,
}

View File

@@ -6,8 +6,8 @@ package server
import ( import (
"context" "context"
"bookstore/rpc/check/check"
"bookstore/rpc/check/internal/logic" "bookstore/rpc/check/internal/logic"
check "bookstore/rpc/check/internal/pb"
"bookstore/rpc/check/internal/svc" "bookstore/rpc/check/internal/svc"
) )

View File

@@ -9,12 +9,12 @@ import (
type ServiceContext struct { type ServiceContext struct {
c config.Config c config.Config
Model *model.BookModel Model model.BookModel
} }
func NewServiceContext(c config.Config) *ServiceContext { func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{ return &ServiceContext{
c: c, c: c,
Model: model.NewBookModel(sqlx.NewMysql(c.DataSource), c.Cache, c.Table), Model: model.NewBookModel(sqlx.NewMysql(c.DataSource), c.Cache),
} }
} }

View File

@@ -18,11 +18,18 @@ var (
bookRowsExpectAutoSet = strings.Join(stringx.Remove(bookFieldNames, "create_time", "update_time"), ",") bookRowsExpectAutoSet = strings.Join(stringx.Remove(bookFieldNames, "create_time", "update_time"), ",")
bookRowsWithPlaceHolder = strings.Join(stringx.Remove(bookFieldNames, "book", "create_time", "update_time"), "=?,") + "=?" bookRowsWithPlaceHolder = strings.Join(stringx.Remove(bookFieldNames, "book", "create_time", "update_time"), "=?,") + "=?"
cacheBookBookPrefix = "cache#Book#book#" cacheBookPrefix = "cache#Book#book#"
) )
type ( type (
BookModel struct { BookModel interface {
Insert(data Book) (sql.Result, error)
FindOne(book string) (*Book, error)
Update(data Book) error
Delete(book string) error
}
defaultBookModel struct {
sqlc.CachedConn sqlc.CachedConn
table string table string
} }
@@ -33,23 +40,25 @@ type (
} }
) )
func NewBookModel(conn sqlx.SqlConn, c cache.CacheConf, table string) *BookModel { func NewBookModel(conn sqlx.SqlConn, c cache.CacheConf) BookModel {
return &BookModel{ return &defaultBookModel{
CachedConn: sqlc.NewConn(conn, c), CachedConn: sqlc.NewConn(conn, c),
table: table, table: "book",
} }
} }
func (m *BookModel) Insert(data Book) (sql.Result, error) { func (m *defaultBookModel) Insert(data Book) (sql.Result, error) {
query := `insert into ` + m.table + ` (` + bookRowsExpectAutoSet + `) values (?, ?)` query := fmt.Sprintf("insert into %s (%s) values (?, ?)", m.table, bookRowsExpectAutoSet)
return m.ExecNoCache(query, data.Book, data.Price) ret, err := m.ExecNoCache(query, data.Book, data.Price)
return ret, err
} }
func (m *BookModel) FindOne(book string) (*Book, error) { func (m *defaultBookModel) FindOne(book string) (*Book, error) {
bookBookKey := fmt.Sprintf("%s%v", cacheBookBookPrefix, book) bookKey := fmt.Sprintf("%s%v", cacheBookPrefix, book)
var resp Book var resp Book
err := m.QueryRow(&resp, bookBookKey, func(conn sqlx.SqlConn, v interface{}) error { err := m.QueryRow(&resp, bookKey, func(conn sqlx.SqlConn, v interface{}) error {
query := `select ` + bookRows + ` from ` + m.table + ` where book = ? limit 1` query := fmt.Sprintf("select %s from %s where book = ? limit 1", bookRows, m.table)
return conn.QueryRow(v, query, book) return conn.QueryRow(v, query, book)
}) })
switch err { switch err {
@@ -62,21 +71,30 @@ func (m *BookModel) FindOne(book string) (*Book, error) {
} }
} }
func (m *BookModel) Update(data Book) error { func (m *defaultBookModel) Update(data Book) error {
bookBookKey := fmt.Sprintf("%s%v", cacheBookBookPrefix, data.Book) bookKey := fmt.Sprintf("%s%v", cacheBookPrefix, data.Book)
_, 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 := `update ` + m.table + ` set ` + bookRowsWithPlaceHolder + ` where book = ?` query := fmt.Sprintf("update %s set %s where book = ?", m.table, bookRowsWithPlaceHolder)
return conn.Exec(query, data.Price, data.Book) return conn.Exec(query, data.Price, data.Book)
}, bookBookKey) }, bookKey)
return err return err
} }
func (m *BookModel) Delete(book string) error { func (m *defaultBookModel) Delete(book string) error {
bookBookKey := fmt.Sprintf("%s%v", cacheBookBookPrefix, book) bookKey := fmt.Sprintf("%s%v", cacheBookPrefix, book)
_, 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 := `delete from ` + m.table + ` where book = ?` query := fmt.Sprintf("delete from %s where book = ?", m.table)
return conn.Exec(query, book) return conn.Exec(query, book)
}, bookBookKey) }, bookKey)
return err return err
} }
func (m *defaultBookModel) formatPrimary(primary interface{}) string {
return fmt.Sprintf("%s%v", cacheBookPrefix, primary)
}
func (m *defaultBookModel) queryPrimary(conn sqlx.SqlConn, v, primary interface{}) error {
query := fmt.Sprintf("select %s from %s where book = ? limit 1", bookRows, m.table)
return conn.QueryRow(v, query, primary)
}

0
example/bookstore/rpc/model/vars.go Executable file → Normal file
View File

View File

@@ -41,6 +41,7 @@ func main() {
var allowed, denied int32 var allowed, denied int32
var wait sync.WaitGroup var wait sync.WaitGroup
for i := 0; i < *threads; i++ { for i := 0; i < *threads; i++ {
i := i
wait.Add(1) wait.Add(1)
go func() { go func() {
for { for {

View File

@@ -5,7 +5,7 @@ go 1.15
require ( require (
github.com/golang/mock v1.4.3 github.com/golang/mock v1.4.3
github.com/golang/protobuf v1.4.2 github.com/golang/protobuf v1.4.2
github.com/tal-tech/go-zero v1.0.16 github.com/tal-tech/go-zero v1.0.27
golang.org/x/net v0.0.0-20200707034311-ab3426394381 golang.org/x/net v0.0.0-20200707034311-ab3426394381
google.golang.org/grpc v1.29.1 google.golang.org/grpc v1.29.1
) )

View File

@@ -37,6 +37,8 @@ github.com/coreos/go-systemd/v22 v22.0.0 h1:XJIw/+VlJ+87J+doOxznsAWIdmWuViOVhkQa
github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -48,6 +50,8 @@ github.com/dsymonds/gotoc v0.0.0-20160928043926-5aebcfc91819 h1:9778zj477h/VauD8
github.com/dsymonds/gotoc v0.0.0-20160928043926-5aebcfc91819/go.mod h1:MvzMVHq8BH2Ji/o8TGDocVA70byvLrAgFTxkEnmjO4Y= github.com/dsymonds/gotoc v0.0.0-20160928043926-5aebcfc91819/go.mod h1:MvzMVHq8BH2Ji/o8TGDocVA70byvLrAgFTxkEnmjO4Y=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4 h1:qk/FSDDxo05wdJH28W+p5yivv7LuLYLRXPPD8KQCtZs= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4 h1:qk/FSDDxo05wdJH28W+p5yivv7LuLYLRXPPD8KQCtZs=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/emicklei/proto v1.9.0 h1:l0QiNT6Qs7Yj0Mb4X6dnWBQer4ebei2BFcgQLbGqUDc=
github.com/emicklei/proto v1.9.0/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -124,10 +128,13 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.14.3 h1:OCJlWkOUoTnl0neNGlf4fUm3TmbEtguw7vR+nGtnDjY= github.com/grpc-ecosystem/grpc-gateway v1.14.3 h1:OCJlWkOUoTnl0neNGlf4fUm3TmbEtguw7vR+nGtnDjY=
github.com/grpc-ecosystem/grpc-gateway v1.14.3/go.mod h1:6CwZWGDSPRJidgKAtJVvND6soZe6fT7iteq8wDPdhb0= github.com/grpc-ecosystem/grpc-gateway v1.14.3/go.mod h1:6CwZWGDSPRJidgKAtJVvND6soZe6fT7iteq8wDPdhb0=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334 h1:VHgatEHNcBFEB7inlalqfNqw65aNkM1lGX2yt3NmbS8= github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334 h1:VHgatEHNcBFEB7inlalqfNqw65aNkM1lGX2yt3NmbS8=
github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/iancoleman/strcase v0.1.2 h1:gnomlvw9tnV3ITTAxzKSgTF+8kFWcU/f+TgttpXGz1U=
github.com/iancoleman/strcase v0.1.2/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
@@ -179,6 +186,7 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -215,6 +223,8 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
@@ -238,12 +248,16 @@ github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/tal-tech/go-zero v1.0.16 h1:oT7sOFftEUdD/XcXF0xEugX9yhnw4DcQkeMNFLi5KO8= github.com/tal-tech/go-zero v1.0.16 h1:oT7sOFftEUdD/XcXF0xEugX9yhnw4DcQkeMNFLi5KO8=
github.com/tal-tech/go-zero v1.0.16/go.mod h1:y2wBHTkxNJw79K9/wCSeDKzv2pCT6x45oOmXEsJdQK8= github.com/tal-tech/go-zero v1.0.16/go.mod h1:y2wBHTkxNJw79K9/wCSeDKzv2pCT6x45oOmXEsJdQK8=
github.com/tal-tech/go-zero v1.0.27 h1:QMIbaTxibMc/OsO5RTAuKZ8ndbl2dGN6pITQEtp2x/A=
github.com/tal-tech/go-zero v1.0.27/go.mod h1:JtNXlsh/CgeIHyQnt5C5M2IcSevW7V0NAnqO93TQgm8=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6 h1:lYIiVDtZnyTWlNwiAxLj0bbpTcx1BWCFhXjfsvmPdNc= github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6 h1:lYIiVDtZnyTWlNwiAxLj0bbpTcx1BWCFhXjfsvmPdNc=
github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA= github.com/urfave/cli v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA=
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
@@ -390,6 +404,7 @@ gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qS
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
@@ -401,6 +416,8 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=

12
go.mod
View File

@@ -1,17 +1,17 @@
module github.com/tal-tech/go-zero module github.com/tal-tech/go-zero
go 1.13 go 1.14
require ( require (
github.com/ClickHouse/clickhouse-go v1.4.3 github.com/ClickHouse/clickhouse-go v1.4.3
github.com/DATA-DOG/go-sqlmock v1.4.1 github.com/DATA-DOG/go-sqlmock v1.4.1
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6 // indirect github.com/alicebob/miniredis/v2 v2.14.1
github.com/alicebob/miniredis v2.5.0+incompatible
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
github.com/dchest/siphash v1.2.1 github.com/dchest/siphash v1.2.1
github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/emicklei/proto v1.9.0 github.com/emicklei/proto v1.9.0
github.com/fatih/color v1.9.0 // indirect github.com/fatih/color v1.9.0 // indirect
github.com/fatih/structtag v1.2.0
github.com/frankban/quicktest v1.7.2 // indirect github.com/frankban/quicktest v1.7.2 // indirect
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.7+incompatible github.com/go-redis/redis v6.15.7+incompatible
@@ -21,7 +21,6 @@ require (
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
github.com/golang/mock v1.4.3 github.com/golang/mock v1.4.3
github.com/golang/protobuf v1.4.2 github.com/golang/protobuf v1.4.2
github.com/gomodule/redigo v2.0.0+incompatible // indirect
github.com/google/gops v0.3.7 github.com/google/gops v0.3.7
github.com/google/uuid v1.1.1 github.com/google/uuid v1.1.1
github.com/gorilla/websocket v1.4.2 // indirect github.com/gorilla/websocket v1.4.2 // indirect
@@ -47,7 +46,6 @@ require (
github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6 // indirect github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6 // indirect
github.com/urfave/cli v1.22.5 github.com/urfave/cli v1.22.5
github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2 github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb // indirect
go.etcd.io/etcd v0.0.0-20200402134248-51bdeb39e698 go.etcd.io/etcd v0.0.0-20200402134248-51bdeb39e698
go.uber.org/automaxprocs v1.3.0 go.uber.org/automaxprocs v1.3.0
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
@@ -58,10 +56,10 @@ require (
golang.org/x/tools v0.0.0-20200410132612-ae9902aceb98 // indirect golang.org/x/tools v0.0.0-20200410132612-ae9902aceb98 // indirect
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f // indirect google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f // indirect
google.golang.org/grpc v1.29.1 google.golang.org/grpc v1.29.1
google.golang.org/protobuf v1.25.0 google.golang.org/protobuf v1.25.0 // indirect
gopkg.in/cheggaaa/pb.v1 v1.0.28 gopkg.in/cheggaaa/pb.v1 v1.0.28
gopkg.in/h2non/gock.v1 v1.0.15 gopkg.in/h2non/gock.v1 v1.0.15
gopkg.in/yaml.v2 v2.3.0 gopkg.in/yaml.v2 v2.4.0
honnef.co/go/tools v0.0.1-2020.1.4 // indirect honnef.co/go/tools v0.0.1-2020.1.4 // indirect
sigs.k8s.io/yaml v1.2.0 // indirect sigs.k8s.io/yaml v1.2.0 // indirect
) )

22
go.sum
View File

@@ -11,10 +11,10 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafo
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6 h1:45bxf7AZMwWcqkLzDAQugVEwedisr5nRJ1r+7LYnv0U= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk=
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
github.com/alicebob/miniredis v2.5.0+incompatible h1:yBHoLpsyjupjz3NL3MhKMVkR41j82Yjf3KFv7ApYzUI= github.com/alicebob/miniredis/v2 v2.14.1 h1:GjlbSeoJ24bzdLRs13HoMEeaRZx9kg5nHoRW7QV/nCs=
github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk= github.com/alicebob/miniredis/v2 v2.14.1/go.mod h1:uS970Sw5Gs9/iK3yBg0l9Uj9s25wXxSpQUE9EaJ/Blg=
github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@@ -63,6 +63,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/frankban/quicktest v1.7.2 h1:2QxQoC1TS09S7fhCPsrvqYdvP1H5M1P1ih5ABm3BTYk= github.com/frankban/quicktest v1.7.2 h1:2QxQoC1TS09S7fhCPsrvqYdvP1H5M1P1ih5ABm3BTYk=
github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o= github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
@@ -114,8 +116,6 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -147,8 +147,6 @@ github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslC
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334 h1:VHgatEHNcBFEB7inlalqfNqw65aNkM1lGX2yt3NmbS8=
github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/iancoleman/strcase v0.1.2 h1:gnomlvw9tnV3ITTAxzKSgTF+8kFWcU/f+TgttpXGz1U= github.com/iancoleman/strcase v0.1.2 h1:gnomlvw9tnV3ITTAxzKSgTF+8kFWcU/f+TgttpXGz1U=
github.com/iancoleman/strcase v0.1.2/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= github.com/iancoleman/strcase v0.1.2/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
@@ -211,6 +209,7 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4=
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8= github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
@@ -281,8 +280,6 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1
github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6 h1:lYIiVDtZnyTWlNwiAxLj0bbpTcx1BWCFhXjfsvmPdNc= github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6 h1:lYIiVDtZnyTWlNwiAxLj0bbpTcx1BWCFhXjfsvmPdNc=
github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA=
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU= github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
@@ -425,6 +422,7 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
@@ -454,8 +452,8 @@ gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=

View File

@@ -129,7 +129,7 @@ go get -u github.com/tal-tech/go-zero
the .api files also can be generate by goctl, like below: the .api files also can be generate by goctl, like below:
```shell ```shell
goctl api -o greet.api goctl api -o greet.api
``` ```
3. generate the go server side code 3. generate the go server side code
@@ -174,7 +174,7 @@ goctl api -o greet.api
you can check it by curl: you can check it by curl:
```shell ```shell
curl -i http://localhost:8888/greet/from/you curl -i http://localhost:8888/from/you
``` ```
the response looks like: the response looks like:

View File

@@ -1,4 +1,4 @@
<img align="right" width="150px" src="doc/images/go-zero.png"> <img align="right" width="150px" src="https://gitee.com/kevwan/static/raw/master/doc/images/go-zero.png">
# go-zero # go-zero
@@ -25,7 +25,7 @@ go-zero 包含极简的 API 定义和生成工具 goctl可以根据定义的
* 自动校验客户端请求参数合法性 * 自动校验客户端请求参数合法性
* 大量微服务治理和并发工具包 * 大量微服务治理和并发工具包
<img src="doc/images/architecture.png" alt="架构图" width="1500" /> <img src="https://gitee.com/kevwan/static/raw/master/doc/images/architecture.png" alt="架构图" width="1500" />
## 1. go-zero 框架背景 ## 1. go-zero 框架背景
@@ -77,7 +77,7 @@ go-zero 是一个集成了各种工程实践的包含 web 和 rpc 框架,有
如下图,我们从多个层面保障了整体服务的高可用: 如下图,我们从多个层面保障了整体服务的高可用:
![弹性设计](doc/images/resilience.jpg) ![弹性设计](https://gitee.com/kevwan/static/raw/master/doc/images/resilience.jpg)
觉得不错的话,别忘 **star** 👏 觉得不错的话,别忘 **star** 👏
@@ -120,7 +120,7 @@ GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/tal-tech/
默认侦听在 8888 端口(可以在配置文件里修改),可以通过 curl 请求: 默认侦听在 8888 端口(可以在配置文件里修改),可以通过 curl 请求:
```shell ```shell
curl -i http://localhost:8888/greet/from/you curl -i http://localhost:8888/from/you
``` ```
返回如下: 返回如下:
@@ -150,7 +150,7 @@ GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/tal-tech/
## 6. Benchmark ## 6. Benchmark
![benchmark](doc/images/benchmark.png) ![benchmark](https://gitee.com/kevwan/static/raw/master/doc/images/benchmark.png)
[测试代码见这里](https://github.com/smallnest/go-web-framework-benchmark) [测试代码见这里](https://github.com/smallnest/go-web-framework-benchmark)
@@ -189,5 +189,3 @@ GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/tal-tech/
项目地址:[https://github.com/tal-tech/go-zero](https://github.com/tal-tech/go-zero) 项目地址:[https://github.com/tal-tech/go-zero](https://github.com/tal-tech/go-zero)
码云地址:[https://gitee.com/kevwan/go-zero](https://gitee.com/kevwan/go-zero) (国内用户可访问gitee每日自动从github同步代码) 码云地址:[https://gitee.com/kevwan/go-zero](https://gitee.com/kevwan/go-zero) (国内用户可访问gitee每日自动从github同步代码)
开源中国年度评选,给 **go-zero** 投上一票:[https://www.oschina.net/p/go-zero](https://www.oschina.net/p/go-zero)

View File

@@ -26,11 +26,11 @@ func ContentSecurityHandler(decrypters map[string]codec.RsaDecrypter, tolerance
case http.MethodDelete, http.MethodGet, http.MethodPost, http.MethodPut: case http.MethodDelete, http.MethodGet, http.MethodPost, http.MethodPut:
header, err := security.ParseContentSecurity(decrypters, r) header, err := security.ParseContentSecurity(decrypters, r)
if err != nil { if err != nil {
logx.Infof("Signature parse failed, X-Content-Security: %s, error: %s", logx.Errorf("Signature parse failed, X-Content-Security: %s, error: %s",
r.Header.Get(contentSecurity), err.Error()) r.Header.Get(contentSecurity), err.Error())
executeCallbacks(w, r, next, strict, httpx.CodeSignatureInvalidHeader, callbacks) executeCallbacks(w, r, next, strict, httpx.CodeSignatureInvalidHeader, callbacks)
} else if code := security.VerifySignature(r, header, tolerance); code != httpx.CodeSignaturePass { } else if code := security.VerifySignature(r, header, tolerance); code != httpx.CodeSignaturePass {
logx.Infof("Signature verification failed, X-Content-Security: %s", logx.Errorf("Signature verification failed, X-Content-Security: %s",
r.Header.Get(contentSecurity)) r.Header.Get(contentSecurity))
executeCallbacks(w, r, next, strict, code, callbacks) executeCallbacks(w, r, next, strict, code, callbacks)
} else if r.ContentLength > 0 && header.Encrypted() { } else if r.ContentLength > 0 && header.Encrypted() {
@@ -54,7 +54,7 @@ func executeCallbacks(w http.ResponseWriter, r *http.Request, next http.Handler,
func handleVerificationFailure(w http.ResponseWriter, r *http.Request, next http.Handler, strict bool, code int) { func handleVerificationFailure(w http.ResponseWriter, r *http.Request, next http.Handler, strict bool, code int) {
if strict { if strict {
w.WriteHeader(http.StatusUnauthorized) w.WriteHeader(http.StatusForbidden)
} else { } else {
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
} }

View File

@@ -113,7 +113,7 @@ func TestContentSecurityHandler(t *testing.T) {
strict: true, strict: true,
crypt: true, crypt: true,
timestamp: time.Now().Add(timeDiff).Unix(), timestamp: time.Now().Add(timeDiff).Unix(),
statusCode: http.StatusUnauthorized, statusCode: http.StatusForbidden,
}, },
{ {
method: http.MethodPost, method: http.MethodPost,
@@ -122,7 +122,7 @@ func TestContentSecurityHandler(t *testing.T) {
strict: true, strict: true,
crypt: true, crypt: true,
timestamp: time.Now().Add(-timeDiff).Unix(), timestamp: time.Now().Add(-timeDiff).Unix(),
statusCode: http.StatusUnauthorized, statusCode: http.StatusForbidden,
}, },
{ {
method: http.MethodPost, method: http.MethodPost,
@@ -148,7 +148,7 @@ func TestContentSecurityHandler(t *testing.T) {
crypt: true, crypt: true,
timestamp: time.Now().Add(-timeDiff).Unix(), timestamp: time.Now().Add(-timeDiff).Unix(),
fingerprint: "badone", fingerprint: "badone",
statusCode: http.StatusUnauthorized, statusCode: http.StatusForbidden,
}, },
{ {
method: http.MethodPost, method: http.MethodPost,
@@ -157,7 +157,7 @@ func TestContentSecurityHandler(t *testing.T) {
strict: true, strict: true,
crypt: true, crypt: true,
missHeader: true, missHeader: true,
statusCode: http.StatusUnauthorized, statusCode: http.StatusForbidden,
}, },
{ {
method: http.MethodHead, method: http.MethodHead,
@@ -171,7 +171,7 @@ func TestContentSecurityHandler(t *testing.T) {
strict: true, strict: true,
crypt: false, crypt: false,
signature: "badone", signature: "badone",
statusCode: http.StatusUnauthorized, statusCode: http.StatusForbidden,
}, },
} }

View File

@@ -10,7 +10,6 @@ import (
) )
const ( const (
multipartFormData = "multipart/form-data"
formKey = "form" formKey = "form"
pathKey = "path" pathKey = "path"
emptyJson = "{}" emptyJson = "{}"
@@ -39,12 +38,12 @@ func Parse(r *http.Request, v interface{}) error {
// Parses the form request. // Parses the form request.
func ParseForm(r *http.Request, v interface{}) error { func ParseForm(r *http.Request, v interface{}) error {
if strings.Contains(r.Header.Get(ContentType), multipartFormData) { if err := r.ParseForm(); err != nil {
if err := r.ParseMultipartForm(maxMemory); err != nil { return err
return err }
}
} else { if err := r.ParseMultipartForm(maxMemory); err != nil {
if err := r.ParseForm(); err != nil { if err != http.ErrNotMultipart {
return err return err
} }
} }

View File

@@ -3,12 +3,33 @@ package httpx
import ( import (
"encoding/json" "encoding/json"
"net/http" "net/http"
"sync"
"github.com/tal-tech/go-zero/core/logx" "github.com/tal-tech/go-zero/core/logx"
) )
var (
errorHandler func(error) (int, interface{})
lock sync.RWMutex
)
func Error(w http.ResponseWriter, err error) { func Error(w http.ResponseWriter, err error) {
http.Error(w, err.Error(), http.StatusBadRequest) lock.RLock()
handler := errorHandler
lock.RUnlock()
if handler == nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
code, body := errorHandler(err)
e, ok := body.(error)
if ok {
http.Error(w, e.Error(), code)
} else {
WriteJson(w, code, body)
}
} }
func Ok(w http.ResponseWriter) { func Ok(w http.ResponseWriter) {
@@ -19,6 +40,12 @@ func OkJson(w http.ResponseWriter, v interface{}) {
WriteJson(w, http.StatusOK, v) WriteJson(w, http.StatusOK, v)
} }
func SetErrorHandler(handler func(error) (int, interface{})) {
lock.Lock()
defer lock.Unlock()
errorHandler = handler
}
func WriteJson(w http.ResponseWriter, code int, v interface{}) { func WriteJson(w http.ResponseWriter, code int, v interface{}) {
w.Header().Set(ContentType, ApplicationJson) w.Header().Set(ContentType, ApplicationJson)
w.WriteHeader(code) w.WriteHeader(code)

View File

@@ -19,13 +19,65 @@ func init() {
} }
func TestError(t *testing.T) { func TestError(t *testing.T) {
const body = "foo" const (
w := tracedResponseWriter{ body = "foo"
headers: make(map[string][]string), wrappedBody = `"foo"`
)
tests := []struct {
name string
input string
errorHandler func(error) (int, interface{})
expectBody string
expectCode int
}{
{
name: "default error handler",
input: body,
expectBody: body,
expectCode: http.StatusBadRequest,
},
{
name: "customized error handler return string",
input: body,
errorHandler: func(err error) (int, interface{}) {
return http.StatusForbidden, err.Error()
},
expectBody: wrappedBody,
expectCode: http.StatusForbidden,
},
{
name: "customized error handler return error",
input: body,
errorHandler: func(err error) (int, interface{}) {
return http.StatusForbidden, err
},
expectBody: body,
expectCode: http.StatusForbidden,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
w := tracedResponseWriter{
headers: make(map[string][]string),
}
if test.errorHandler != nil {
lock.RLock()
prev := errorHandler
lock.RUnlock()
SetErrorHandler(test.errorHandler)
defer func() {
lock.Lock()
errorHandler = prev
lock.Unlock()
}()
}
Error(&w, errors.New(test.input))
assert.Equal(t, test.expectCode, w.code)
assert.Equal(t, test.expectBody, strings.TrimSpace(w.builder.String()))
})
} }
Error(&w, errors.New(body))
assert.Equal(t, http.StatusBadRequest, w.code)
assert.Equal(t, body, strings.TrimSpace(w.builder.String()))
} }
func TestOk(t *testing.T) { func TestOk(t *testing.T) {

View File

@@ -64,7 +64,7 @@ func (pr *patRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
} }
} }
allow, ok := pr.methodNotAllowed(r.Method, reqPath) allows, ok := pr.methodsAllowed(r.Method, reqPath)
if !ok { if !ok {
pr.handleNotFound(w, r) pr.handleNotFound(w, r)
return return
@@ -73,7 +73,7 @@ func (pr *patRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if pr.notAllowed != nil { if pr.notAllowed != nil {
pr.notAllowed.ServeHTTP(w, r) pr.notAllowed.ServeHTTP(w, r)
} else { } else {
w.Header().Set(allowHeader, allow) w.Header().Set(allowHeader, allows)
w.WriteHeader(http.StatusMethodNotAllowed) w.WriteHeader(http.StatusMethodNotAllowed)
} }
} }
@@ -94,7 +94,7 @@ func (pr *patRouter) handleNotFound(w http.ResponseWriter, r *http.Request) {
} }
} }
func (pr *patRouter) methodNotAllowed(method, path string) (string, bool) { func (pr *patRouter) methodsAllowed(method, path string) (string, bool) {
var allows []string var allows []string
for treeMethod, tree := range pr.trees { for treeMethod, tree := range pr.trees {

View File

@@ -2,13 +2,13 @@ version := $(shell /bin/date "+%Y-%m-%d %H:%M")
build: build:
go build -ldflags="-s -w" -ldflags="-X 'main.BuildTime=$(version)'" goctl.go go build -ldflags="-s -w" -ldflags="-X 'main.BuildTime=$(version)'" goctl.go
command -v upx &> /dev/null && upx goctl $(if $(shell command -v upx), upx goctl)
mac: mac:
GOOS=darwin go build -ldflags="-s -w" -ldflags="-X 'main.BuildTime=$(version)'" -o goctl-darwin goctl.go GOOS=darwin go build -ldflags="-s -w" -ldflags="-X 'main.BuildTime=$(version)'" -o goctl-darwin goctl.go
command -v upx &> /dev/null && upx goctl-darwin $(if $(shell command -v upx), upx goctl-darwin)
win: win:
GOOS=windows go build -ldflags="-s -w" -ldflags="-X 'main.BuildTime=$(version)'" -o goctl.exe goctl.go GOOS=windows go build -ldflags="-s -w" -ldflags="-X 'main.BuildTime=$(version)'" -o goctl.exe goctl.go
command -v upx &> /dev/null && upx goctl.exe $(if $(shell command -v upx), upx goctl.exe)
linux: linux:
GOOS=linux go build -ldflags="-s -w" -ldflags="-X 'main.BuildTime=$(version)'" -o goctl-linux goctl.go GOOS=linux go build -ldflags="-s -w" -ldflags="-X 'main.BuildTime=$(version)'" -o goctl-linux goctl.go
command -v upx &> /dev/null && upx goctl-linux $(if $(shell command -v upx), upx goctl-linux)

View File

@@ -28,10 +28,10 @@ type response struct {
} }
service {{.serviceName}} { service {{.serviceName}} {
@handler // TODO: set handler name and delete this comment @handler GetUser // TODO: set handler name and delete this comment
get /users/id/:userId(request) returns(response) get /users/id/:userId(request) returns(response)
@handler // TODO: set handler name and delete this comment @handler CreateUser // TODO: set handler name and delete this comment
post /users/create(request) post /users/create(request)
} }
` `

View File

@@ -4,13 +4,10 @@ import (
"bufio" "bufio"
"errors" "errors"
"fmt" "fmt"
"go/format"
"go/scanner" "go/scanner"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"regexp"
"strconv"
"strings" "strings"
"github.com/tal-tech/go-zero/core/errorx" "github.com/tal-tech/go-zero/core/errorx"
@@ -19,8 +16,11 @@ import (
"github.com/urfave/cli" "github.com/urfave/cli"
) )
var ( const (
reg = regexp.MustCompile("type (?P<name>.*)[\\s]+{") leftParenthesis = "("
rightParenthesis = ")"
leftBrace = "{"
rightBrace = "}"
) )
func GoFormatApi(c *cli.Context) error { func GoFormatApi(c *cli.Context) error {
@@ -95,86 +95,32 @@ func ApiFormatByPath(apiFilePath string) error {
} }
func apiFormat(data string) (string, error) { func apiFormat(data string) (string, error) {
r := reg.ReplaceAllStringFunc(data, func(m string) string { _, err := parser.ParseApi(data)
parts := reg.FindStringSubmatch(m)
if len(parts) < 2 {
return m
}
if !strings.Contains(m, "struct") {
return "type " + parts[1] + " struct {"
}
return m
})
apiStruct, err := parser.ParseApi(r)
if err != nil { if err != nil {
return "", err return "", err
} }
info := strings.TrimSpace(apiStruct.Info)
if len(apiStruct.Service) == 0 {
return data, nil
}
fs, err := format.Source([]byte(strings.TrimSpace(apiStruct.Type)))
if err != nil {
str := err.Error()
lineNumber := strings.Index(str, ":")
if lineNumber > 0 {
ln, err := strconv.ParseInt(str[:lineNumber], 10, 64)
if err != nil {
return "", err
}
pn := 0
if len(info) > 0 {
pn = countRune(info, '\n') + 1
}
number := int(ln) + pn + 1
return "", errors.New(fmt.Sprintf("line: %d, %s", number, str[lineNumber+1:]))
}
return "", err
}
var result string
if len(strings.TrimSpace(info)) > 0 {
result += strings.TrimSpace(info) + "\n\n"
}
if len(strings.TrimSpace(apiStruct.Imports)) > 0 {
result += strings.TrimSpace(apiStruct.Imports) + "\n\n"
}
if len(strings.TrimSpace(string(fs))) > 0 {
result += strings.TrimSpace(string(fs)) + "\n\n"
}
if len(strings.TrimSpace(apiStruct.Service)) > 0 {
result += formatService(apiStruct.Service) + "\n\n"
}
return strings.TrimSpace(result), nil
}
func formatService(str string) string {
var builder strings.Builder var builder strings.Builder
scanner := bufio.NewScanner(strings.NewReader(str)) s := bufio.NewScanner(strings.NewReader(data))
var tapCount = 0 var tapCount = 0
for scanner.Scan() { for s.Scan() {
line := strings.TrimSpace(scanner.Text()) line := strings.TrimSpace(s.Text())
if line == ")" || line == "}" { noCommentLine := util.RemoveComment(line)
if noCommentLine == rightParenthesis || noCommentLine == rightBrace {
tapCount -= 1 tapCount -= 1
} }
if tapCount < 0 {
line = strings.TrimSuffix(line, rightBrace)
line = strings.TrimSpace(line)
if strings.HasSuffix(line, leftBrace) {
tapCount += 1
}
}
util.WriteIndent(&builder, tapCount) util.WriteIndent(&builder, tapCount)
builder.WriteString(line + "\n") builder.WriteString(line + "\n")
if strings.HasSuffix(line, "(") || strings.HasSuffix(line, "{") { if strings.HasSuffix(noCommentLine, leftParenthesis) || strings.HasSuffix(noCommentLine, leftBrace) {
tapCount += 1 tapCount += 1
} }
} }
return strings.TrimSpace(builder.String()) return strings.TrimSpace(builder.String()), nil
}
func countRune(s string, r rune) int {
count := 0
for _, c := range s {
if c == r {
count++
}
}
return count
} }

View File

@@ -12,13 +12,13 @@ import (
"time" "time"
"github.com/logrusorgru/aurora" "github.com/logrusorgru/aurora"
"github.com/urfave/cli"
"github.com/tal-tech/go-zero/core/logx" "github.com/tal-tech/go-zero/core/logx"
apiformat "github.com/tal-tech/go-zero/tools/goctl/api/format" apiformat "github.com/tal-tech/go-zero/tools/goctl/api/format"
"github.com/tal-tech/go-zero/tools/goctl/api/parser" "github.com/tal-tech/go-zero/tools/goctl/api/parser"
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util" apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util" "github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/urfave/cli"
) )
const tmpFile = "%s-%d" const tmpFile = "%s-%d"
@@ -28,6 +28,8 @@ var tmpDir = path.Join(os.TempDir(), "goctl")
func GoCommand(c *cli.Context) error { func GoCommand(c *cli.Context) error {
apiFile := c.String("api") apiFile := c.String("api")
dir := c.String("dir") dir := c.String("dir")
namingStyle := c.String("style")
if len(apiFile) == 0 { if len(apiFile) == 0 {
return errors.New("missing -api") return errors.New("missing -api")
} }
@@ -35,10 +37,10 @@ func GoCommand(c *cli.Context) error {
return errors.New("missing -dir") return errors.New("missing -dir")
} }
return DoGenProject(apiFile, dir) return DoGenProject(apiFile, dir, namingStyle)
} }
func DoGenProject(apiFile, dir string) error { func DoGenProject(apiFile, dir, style string) error {
p, err := parser.NewParser(apiFile) p, err := parser.NewParser(apiFile)
if err != nil { if err != nil {
return err return err
@@ -48,15 +50,21 @@ func DoGenProject(apiFile, dir string) error {
return err return err
} }
cfg, err := config.NewConfig(style)
if err != nil {
return err
}
logx.Must(util.MkdirIfNotExist(dir)) logx.Must(util.MkdirIfNotExist(dir))
logx.Must(genEtc(dir, api)) logx.Must(genEtc(dir, cfg, api))
logx.Must(genConfig(dir, api)) logx.Must(genConfig(dir, cfg, api))
logx.Must(genMain(dir, api)) logx.Must(genMain(dir, cfg, api))
logx.Must(genServiceContext(dir, api)) logx.Must(genServiceContext(dir, cfg, api))
logx.Must(genTypes(dir, api)) logx.Must(genTypes(dir, cfg, api))
logx.Must(genHandlers(dir, api)) logx.Must(genRoutes(dir, cfg, api))
logx.Must(genRoutes(dir, api)) logx.Must(genHandlers(dir, cfg, api))
logx.Must(genLogic(dir, api)) logx.Must(genLogic(dir, cfg, api))
logx.Must(genMiddleware(dir, cfg, api))
if err := backupAndSweep(apiFile); err != nil { if err := backupAndSweep(apiFile); err != nil {
return err return err

View File

@@ -22,10 +22,14 @@ info(
version: 1.0 version: 1.0
) )
type Request struct { // TODO: test
// {
type Request struct { // TODO: test
// TODO
Name string ` + "`" + `path:"name,options=you|me"` + "`" + ` // } Name string ` + "`" + `path:"name,options=you|me"` + "`" + ` // }
} } // TODO: test
// TODO: test
type Response struct { type Response struct {
Message string ` + "`" + `json:"message"` + "`" + ` Message string ` + "`" + `json:"message"` + "`" + `
} }
@@ -279,6 +283,42 @@ service A-api {
} }
` `
const noStructTagApi = `
type Request {
Name string ` + "`" + `path:"name,options=you|me"` + "`" + `
}
type XXX {}
type (
Response {
Message string ` + "`" + `json:"message"` + "`" + `
}
A {}
B struct {}
)
service A-api {
@handler GreetHandler
get /greet/from/:name(Request) returns (Response)
}
`
const nestTypeApi = `
type Request {
Name string ` + "`" + `path:"name,options=you|me"` + "`" + `
XXX struct {
}
}
service A-api {
@handler GreetHandler
get /greet/from/:name(Request)
}
`
func TestParser(t *testing.T) { func TestParser(t *testing.T) {
filename := "greet.api" filename := "greet.api"
err := ioutil.WriteFile(filename, []byte(testApiTemplate), os.ModePerm) err := ioutil.WriteFile(filename, []byte(testApiTemplate), os.ModePerm)
@@ -494,13 +534,55 @@ func TestHasImportApi(t *testing.T) {
} }
} }
assert.True(t, hasInline) assert.True(t, hasInline)
validate(t, filename) validate(t, filename)
} }
func TestNoStructApi(t *testing.T) {
filename := "greet.api"
err := ioutil.WriteFile(filename, []byte(noStructTagApi), os.ModePerm)
assert.Nil(t, err)
defer os.Remove(filename)
parser, err := parser.NewParser(filename)
assert.Nil(t, err)
spec, err := parser.Parse()
assert.Nil(t, err)
assert.Equal(t, len(spec.Types), 5)
validate(t, filename)
}
func TestNestTypeApi(t *testing.T) {
filename := "greet.api"
err := ioutil.WriteFile(filename, []byte(nestTypeApi), os.ModePerm)
assert.Nil(t, err)
defer os.Remove(filename)
_, err = parser.NewParser(filename)
assert.NotNil(t, err)
}
func TestCamelStyle(t *testing.T) {
filename := "greet.api"
err := ioutil.WriteFile(filename, []byte(testApiTemplate), os.ModePerm)
assert.Nil(t, err)
defer os.Remove(filename)
_, err = parser.NewParser(filename)
assert.Nil(t, err)
validateWithCamel(t, filename, "GoZero")
}
func validate(t *testing.T, api string) { func validate(t *testing.T, api string) {
validateWithCamel(t, api, "gozero")
}
func validateWithCamel(t *testing.T, api, camel string) {
dir := "_go" dir := "_go"
os.RemoveAll(dir) os.RemoveAll(dir)
err := DoGenProject(api, dir) err := DoGenProject(api, dir, camel)
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
assert.Nil(t, err) assert.Nil(t, err)
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {

View File

@@ -8,12 +8,14 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/api/util" "github.com/tal-tech/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/config"
ctlutil "github.com/tal-tech/go-zero/tools/goctl/util" ctlutil "github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/format"
"github.com/tal-tech/go-zero/tools/goctl/vars" "github.com/tal-tech/go-zero/tools/goctl/vars"
) )
const ( const (
configFile = "config.go" configFile = "config"
configTemplate = `package config configTemplate = `package config
import {{.authImport}} import {{.authImport}}
@@ -31,8 +33,13 @@ type Config struct {
` `
) )
func genConfig(dir string, api *spec.ApiSpec) error { func genConfig(dir string, cfg *config.Config, api *spec.ApiSpec) error {
fp, created, err := util.MaybeCreateFile(dir, configDir, configFile) filename, err := format.FileNamingFormat(cfg.NamingFormat, configFile)
if err != nil {
return err
}
fp, created, err := util.MaybeCreateFile(dir, configDir, filename+".go")
if err != nil { if err != nil {
return err return err
} }

View File

@@ -8,7 +8,9 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/api/util" "github.com/tal-tech/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/config"
ctlutil "github.com/tal-tech/go-zero/tools/goctl/util" ctlutil "github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/format"
) )
const ( const (
@@ -20,8 +22,13 @@ Port: {{.port}}
` `
) )
func genEtc(dir string, api *spec.ApiSpec) error { func genEtc(dir string, cfg *config.Config, api *spec.ApiSpec) error {
fp, created, err := util.MaybeCreateFile(dir, etcDir, fmt.Sprintf("%s.yaml", api.Service.Name)) filename, err := format.FileNamingFormat(cfg.NamingFormat, api.Service.Name)
if err != nil {
return err
}
fp, created, err := util.MaybeCreateFile(dir, etcDir, fmt.Sprintf("%s.yaml", filename))
if err != nil { if err != nil {
return err return err
} }

View File

@@ -2,14 +2,18 @@ package gogen
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"path" "path"
"strings" "strings"
"text/template" "text/template"
"unicode"
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/tal-tech/go-zero/tools/goctl/api/spec"
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util" apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util" "github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/format"
"github.com/tal-tech/go-zero/tools/goctl/vars" "github.com/tal-tech/go-zero/tools/goctl/vars"
) )
@@ -50,13 +54,8 @@ type Handler struct {
HasRequest bool HasRequest bool
} }
func genHandler(dir string, group spec.Group, route spec.Route) error { func genHandler(dir string, cfg *config.Config, group spec.Group, route spec.Route) error {
handler, ok := apiutil.GetAnnotationValue(route.Annotations, "server", "handler") handler := getHandlerName(route)
if !ok {
return fmt.Errorf("missing handler annotation for %q", route.Path)
}
handler = getHandlerName(handler)
if getHandlerFolderPath(group, route) != handlerDir { if getHandlerFolderPath(group, route) != handlerDir {
handler = strings.Title(handler) handler = strings.Title(handler)
} }
@@ -65,27 +64,25 @@ func genHandler(dir string, group spec.Group, route spec.Route) error {
return err return err
} }
return doGenToFile(dir, handler, group, route, Handler{ return doGenToFile(dir, handler, cfg, group, route, Handler{
ImportPackages: genHandlerImports(group, route, parentPkg), ImportPackages: genHandlerImports(group, route, parentPkg),
HandlerName: handler, HandlerName: handler,
RequestType: util.Title(route.RequestType.Name), RequestType: util.Title(route.RequestType.Name),
LogicType: strings.TrimSuffix(strings.Title(handler), "Handler") + "Logic", LogicType: strings.Title(getLogicName(route)),
Call: strings.Title(strings.TrimSuffix(handler, "Handler")), Call: strings.Title(strings.TrimSuffix(handler, "Handler")),
HasResp: len(route.ResponseType.Name) > 0, HasResp: len(route.ResponseType.Name) > 0,
HasRequest: len(route.RequestType.Name) > 0, HasRequest: len(route.RequestType.Name) > 0,
}) })
} }
func doGenToFile(dir, handler string, group spec.Group, route spec.Route, handleObj Handler) error { func doGenToFile(dir, handler string, cfg *config.Config, group spec.Group,
if getHandlerFolderPath(group, route) != handlerDir { route spec.Route, handleObj Handler) error {
handler = strings.Title(handler) filename, err := format.FileNamingFormat(cfg.NamingFormat, handler)
} if err != nil {
filename := strings.ToLower(handler) return err
if strings.HasSuffix(filename, "handler") {
filename = filename + ".go"
} else {
filename = filename + "handler.go"
} }
filename = filename + ".go"
fp, created, err := apiutil.MaybeCreateFile(dir, getHandlerFolderPath(group, route), filename) fp, created, err := apiutil.MaybeCreateFile(dir, getHandlerFolderPath(group, route), filename)
if err != nil { if err != nil {
return err return err
@@ -111,10 +108,10 @@ func doGenToFile(dir, handler string, group spec.Group, route spec.Route, handle
return err return err
} }
func genHandlers(dir string, api *spec.ApiSpec) error { func genHandlers(dir string, cfg *config.Config, api *spec.ApiSpec) error {
for _, group := range api.Service.Groups { for _, group := range api.Service.Groups {
for _, route := range group.Routes { for _, route := range group.Routes {
if err := genHandler(dir, group, route); err != nil { if err := genHandler(dir, cfg, group, route); err != nil {
return err return err
} }
} }
@@ -136,14 +133,23 @@ func genHandlerImports(group spec.Group, route spec.Route, parentPkg string) str
return strings.Join(imports, "\n\t") return strings.Join(imports, "\n\t")
} }
func getHandlerBaseName(handler string) string { func getHandlerBaseName(route spec.Route) (string, error) {
handlerName := util.Untitle(handler) handler, ok := apiutil.GetAnnotationValue(route.Annotations, "server", "handler")
if strings.HasSuffix(handlerName, "handler") { if !ok {
handlerName = strings.ReplaceAll(handlerName, "handler", "") return "", fmt.Errorf("missing handler annotation for %q", route.Path)
} else if strings.HasSuffix(handlerName, "Handler") {
handlerName = strings.ReplaceAll(handlerName, "Handler", "")
} }
return handlerName
for _, char := range handler {
if !unicode.IsDigit(char) && !unicode.IsLetter(char) {
return "", errors.New(fmt.Sprintf("route [%s] handler [%s] invalid, handler name should only contains letter or digit",
route.Path, handler))
}
}
handler = strings.TrimSpace(handler)
handler = strings.TrimSuffix(handler, "handler")
handler = strings.TrimSuffix(handler, "Handler")
return handler, nil
} }
func getHandlerFolderPath(group spec.Group, route spec.Route) string { func getHandlerFolderPath(group spec.Group, route spec.Route) string {
@@ -159,6 +165,20 @@ func getHandlerFolderPath(group spec.Group, route spec.Route) string {
return path.Join(handlerDir, folder) return path.Join(handlerDir, folder)
} }
func getHandlerName(handler string) string { func getHandlerName(route spec.Route) string {
return getHandlerBaseName(handler) + "Handler" handler, err := getHandlerBaseName(route)
if err != nil {
panic(err)
}
return handler + "Handler"
}
func getLogicName(route spec.Route) string {
handler, err := getHandlerBaseName(route)
if err != nil {
panic(err)
}
return handler + "Logic"
} }

View File

@@ -9,7 +9,9 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/api/util" "github.com/tal-tech/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/config"
ctlutil "github.com/tal-tech/go-zero/tools/goctl/util" ctlutil "github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/format"
"github.com/tal-tech/go-zero/tools/goctl/vars" "github.com/tal-tech/go-zero/tools/goctl/vars"
) )
@@ -40,10 +42,10 @@ func (l *{{.logic}}) {{.function}}({{.request}}) {{.responseType}} {
} }
` `
func genLogic(dir string, api *spec.ApiSpec) error { func genLogic(dir string, cfg *config.Config, api *spec.ApiSpec) error {
for _, g := range api.Service.Groups { for _, g := range api.Service.Groups {
for _, r := range g.Routes { for _, r := range g.Routes {
err := genLogicByRoute(dir, g, r) err := genLogicByRoute(dir, cfg, g, r)
if err != nil { if err != nil {
return err return err
} }
@@ -52,16 +54,14 @@ func genLogic(dir string, api *spec.ApiSpec) error {
return nil return nil
} }
func genLogicByRoute(dir string, group spec.Group, route spec.Route) error { func genLogicByRoute(dir string, cfg *config.Config, group spec.Group, route spec.Route) error {
handler, ok := util.GetAnnotationValue(route.Annotations, "server", "handler") logic := getLogicName(route)
if !ok { goFile, err := format.FileNamingFormat(cfg.NamingFormat, logic)
return fmt.Errorf("missing handler annotation for %q", route.Path) if err != nil {
return err
} }
handler = strings.TrimSuffix(handler, "handler") goFile = goFile + ".go"
handler = strings.TrimSuffix(handler, "Handler")
filename := strings.ToLower(handler)
goFile := filename + "logic.go"
fp, created, err := util.MaybeCreateFile(dir, getLogicFolderPath(group, route), goFile) fp, created, err := util.MaybeCreateFile(dir, getLogicFolderPath(group, route), goFile)
if err != nil { if err != nil {
return err return err
@@ -102,8 +102,8 @@ func genLogicByRoute(dir string, group spec.Group, route spec.Route) error {
buffer := new(bytes.Buffer) buffer := new(bytes.Buffer)
err = t.Execute(fp, map[string]string{ err = t.Execute(fp, map[string]string{
"imports": imports, "imports": imports,
"logic": strings.Title(handler) + "Logic", "logic": strings.Title(logic),
"function": strings.Title(strings.TrimSuffix(handler, "Handler")), "function": strings.Title(strings.TrimSuffix(logic, "Logic")),
"responseType": responseString, "responseType": responseString,
"returnString": returnString, "returnString": returnString,
"request": requestString, "request": requestString,

View File

@@ -8,7 +8,9 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/api/util" "github.com/tal-tech/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/config"
ctlutil "github.com/tal-tech/go-zero/tools/goctl/util" ctlutil "github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/format"
"github.com/tal-tech/go-zero/tools/goctl/vars" "github.com/tal-tech/go-zero/tools/goctl/vars"
) )
@@ -40,12 +42,17 @@ func main() {
} }
` `
func genMain(dir string, api *spec.ApiSpec) error { func genMain(dir string, cfg *config.Config, api *spec.ApiSpec) error {
name := strings.ToLower(api.Service.Name) name := strings.ToLower(api.Service.Name)
if strings.HasSuffix(name, "-api") { if strings.HasSuffix(name, "-api") {
name = strings.ReplaceAll(name, "-api", "") name = strings.ReplaceAll(name, "-api", "")
} }
goFile := name + ".go" filename, err := format.FileNamingFormat(cfg.NamingFormat, name)
if err != nil {
return err
}
goFile := filename + ".go"
fp, created, err := util.MaybeCreateFile(dir, "", goFile) fp, created, err := util.MaybeCreateFile(dir, "", goFile)
if err != nil { if err != nil {
return err return err

View File

@@ -5,7 +5,10 @@ import (
"strings" "strings"
"text/template" "text/template"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/api/util" "github.com/tal-tech/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util/format"
) )
var middlewareImplementCode = ` var middlewareImplementCode = `
@@ -30,9 +33,16 @@ func (m *{{.name}})Handle(next http.HandlerFunc) http.HandlerFunc {
} }
` `
func genMiddleware(dir string, middlewares []string) error { func genMiddleware(dir string, cfg *config.Config, api *spec.ApiSpec) error {
var middlewares = getMiddleware(api)
for _, item := range middlewares { for _, item := range middlewares {
filename := strings.TrimSuffix(strings.ToLower(item), "middleware") + "middleware" + ".go" middlewareFilename := strings.TrimSuffix(strings.ToLower(item), "middleware") + "_middleware"
formatName, err := format.FileNamingFormat(cfg.NamingFormat, middlewareFilename)
if err != nil {
return err
}
filename := formatName + ".go"
fp, created, err := util.MaybeCreateFile(dir, middlewareDir, filename) fp, created, err := util.MaybeCreateFile(dir, middlewareDir, filename)
if err != nil { if err != nil {
return err return err

View File

@@ -12,12 +12,14 @@ import (
"github.com/tal-tech/go-zero/core/collection" "github.com/tal-tech/go-zero/core/collection"
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/tal-tech/go-zero/tools/goctl/api/spec"
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util" apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util" "github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/format"
"github.com/tal-tech/go-zero/tools/goctl/vars" "github.com/tal-tech/go-zero/tools/goctl/vars"
) )
const ( const (
routesFilename = "routes.go" routesFilename = "routes"
routesTemplate = `// Code generated by goctl. DO NOT EDIT. routesTemplate = `// Code generated by goctl. DO NOT EDIT.
package handler package handler
@@ -62,7 +64,7 @@ type (
} }
) )
func genRoutes(dir string, api *spec.ApiSpec) error { func genRoutes(dir string, cfg *config.Config, api *spec.ApiSpec) error {
var builder strings.Builder var builder strings.Builder
groups, err := getRoutes(api) groups, err := getRoutes(api)
if err != nil { if err != nil {
@@ -121,10 +123,16 @@ func genRoutes(dir string, api *spec.ApiSpec) error {
return err return err
} }
filename := path.Join(dir, handlerDir, routesFilename) routeFilename, err := format.FileNamingFormat(cfg.NamingFormat, routesFilename)
if err != nil {
return err
}
routeFilename = routeFilename + ".go"
filename := path.Join(dir, handlerDir, routeFilename)
os.Remove(filename) os.Remove(filename)
fp, created, err := apiutil.MaybeCreateFile(dir, handlerDir, routesFilename) fp, created, err := apiutil.MaybeCreateFile(dir, handlerDir, routeFilename)
if err != nil { if err != nil {
return err return err
} }
@@ -176,11 +184,8 @@ func getRoutes(api *spec.ApiSpec) ([]group, error) {
for _, g := range api.Service.Groups { for _, g := range api.Service.Groups {
var groupedRoutes group var groupedRoutes group
for _, r := range g.Routes { for _, r := range g.Routes {
handler, ok := apiutil.GetAnnotationValue(r.Annotations, "server", "handler") handler := getHandlerName(r)
if !ok { handler = handler + "(serverCtx)"
return nil, fmt.Errorf("missing handler annotation for route %q", r.Path)
}
handler = getHandlerBaseName(handler) + "Handler(serverCtx)"
folder, ok := apiutil.GetAnnotationValue(r.Annotations, "server", groupProperty) folder, ok := apiutil.GetAnnotationValue(r.Annotations, "server", groupProperty)
if ok { if ok {
handler = toPrefix(folder) + "." + strings.ToUpper(handler[:1]) + handler[1:] handler = toPrefix(folder) + "." + strings.ToUpper(handler[:1]) + handler[1:]

View File

@@ -8,12 +8,14 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/api/util" "github.com/tal-tech/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/config"
ctlutil "github.com/tal-tech/go-zero/tools/goctl/util" ctlutil "github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/format"
"github.com/tal-tech/go-zero/tools/goctl/vars" "github.com/tal-tech/go-zero/tools/goctl/vars"
) )
const ( const (
contextFilename = "servicecontext.go" contextFilename = "service_context"
contextTemplate = `package svc contextTemplate = `package svc
import ( import (
@@ -35,8 +37,13 @@ func NewServiceContext(c {{.config}}) *ServiceContext {
` `
) )
func genServiceContext(dir string, api *spec.ApiSpec) error { func genServiceContext(dir string, cfg *config.Config, api *spec.ApiSpec) error {
fp, created, err := util.MaybeCreateFile(dir, contextDir, contextFilename) filename, err := format.FileNamingFormat(cfg.NamingFormat, contextFilename)
if err != nil {
return err
}
fp, created, err := util.MaybeCreateFile(dir, contextDir, filename+".go")
if err != nil { if err != nil {
return err return err
} }
@@ -64,10 +71,6 @@ func genServiceContext(dir string, api *spec.ApiSpec) error {
var middlewareStr string var middlewareStr string
var middlewareAssignment string var middlewareAssignment string
var middlewares = getMiddleware(api) var middlewares = getMiddleware(api)
err = genMiddleware(dir, middlewares)
if err != nil {
return err
}
for _, item := range middlewares { for _, item := range middlewares {
middlewareStr += fmt.Sprintf("%s rest.Middleware\n", item) middlewareStr += fmt.Sprintf("%s rest.Middleware\n", item)

View File

@@ -12,11 +12,13 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/tal-tech/go-zero/tools/goctl/api/spec"
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util" apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util" "github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/format"
) )
const ( const (
typesFile = "types.go" typesFile = "types"
typesTemplate = `// Code generated by goctl. DO NOT EDIT. typesTemplate = `// Code generated by goctl. DO NOT EDIT.
package types{{if .containsTime}} package types{{if .containsTime}}
import ( import (
@@ -43,19 +45,25 @@ func BuildTypes(types []spec.Type) (string, error) {
return builder.String(), nil return builder.String(), nil
} }
func genTypes(dir string, api *spec.ApiSpec) error { func genTypes(dir string, cfg *config.Config, api *spec.ApiSpec) error {
val, err := BuildTypes(api.Types) val, err := BuildTypes(api.Types)
if err != nil { if err != nil {
return err return err
} }
filename := path.Join(dir, typesDir, typesFile) typeFilename, err := format.FileNamingFormat(cfg.NamingFormat, typesFile)
os.Remove(filename)
fp, created, err := apiutil.MaybeCreateFile(dir, typesDir, typesFile)
if err != nil { if err != nil {
return err return err
} }
typeFilename = typeFilename + ".go"
filename := path.Join(dir, typesDir, typeFilename)
os.Remove(filename)
fp, created, err := apiutil.MaybeCreateFile(dir, typesDir, typeFilename)
if err != nil {
return err
}
if !created { if !created {
return nil return nil
} }

View File

@@ -38,11 +38,12 @@ func RevertTemplate(name string) error {
return util.CreateTemplate(category, name, content) return util.CreateTemplate(category, name, content)
} }
func Update(category string) error { func Update() error {
err := Clean() err := Clean()
if err != nil { if err != nil {
return err return err
} }
return util.InitTemplates(category, templates) return util.InitTemplates(category, templates)
} }
@@ -50,6 +51,6 @@ func Clean() error {
return util.Clean(category) return util.Clean(category)
} }
func GetCategory() string { func Category() string {
return category return category
} }

View File

@@ -84,7 +84,7 @@ func TestUpdate(t *testing.T) {
assert.Equal(t, string(data), modifyData) assert.Equal(t, string(data), modifyData)
assert.Nil(t, Update(category)) assert.Nil(t, Update())
data, err = ioutil.ReadFile(file) data, err = ioutil.ReadFile(file)
assert.Nil(t, err) assert.Nil(t, err)

View File

@@ -3,25 +3,27 @@ package new
import ( import (
"os" "os"
"path/filepath" "path/filepath"
"strings"
"text/template" "text/template"
"github.com/tal-tech/go-zero/tools/goctl/api/gogen" "github.com/tal-tech/go-zero/tools/goctl/api/gogen"
conf "github.com/tal-tech/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util" "github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
const apiTemplate = ` const apiTemplate = `
type Request struct { type Request {
Name string ` + "`" + `path:"name,options=you|me"` + "`" + ` Name string ` + "`" + `path:"name,options=you|me"` + "`" + `
} }
type Response struct { type Response {
Message string ` + "`" + `json:"message"` + "`" + ` Message string ` + "`" + `json:"message"` + "`" + `
} }
service {{.name}}-api { service {{.name}}-api {
@handler GreetHandler @handler {{.handler}}Handler
get /greet/from/:name(Request) returns (Response); get /from/:name(Request) returns (Response);
} }
` `
@@ -53,11 +55,12 @@ func NewService(c *cli.Context) error {
defer fp.Close() defer fp.Close()
t := template.Must(template.New("template").Parse(apiTemplate)) t := template.Must(template.New("template").Parse(apiTemplate))
if err := t.Execute(fp, map[string]string{ if err := t.Execute(fp, map[string]string{
"name": dirName, "name": dirName,
"handler": strings.Title(dirName),
}); err != nil { }); err != nil {
return err return err
} }
err = gogen.DoGenProject(apiFilePath, abs) err = gogen.DoGenProject(apiFilePath, abs, conf.DefaultFormat)
return err return err
} }

View File

@@ -7,6 +7,9 @@ import (
"fmt" "fmt"
"io" "io"
"strings" "strings"
"github.com/tal-tech/go-zero/core/stringx"
"github.com/tal-tech/go-zero/tools/goctl/api/util"
) )
const ( const (
@@ -15,6 +18,7 @@ const (
tokenType = "type" tokenType = "type"
tokenService = "service" tokenService = "service"
tokenServiceAnnotation = "@server" tokenServiceAnnotation = "@server"
tokenStruct = "struct"
) )
type ( type (
@@ -72,7 +76,7 @@ func ParseApi(src string) (*ApiStruct, error) {
} }
} }
func (s *apiRootState) process(api *ApiStruct, token string) (apiFileState, error) { func (s *apiRootState) process(api *ApiStruct, _ string) (apiFileState, error) {
var builder strings.Builder var builder strings.Builder
for { for {
ch, err := s.readSkipComment() ch, err := s.readSkipComment()
@@ -124,7 +128,7 @@ func (s *apiInfoState) process(api *ApiStruct, token string) (apiFileState, erro
return nil, err return nil, err
} }
api.Info += "\n" + token + line api.Info += newline + token + line
token = "" token = ""
if strings.TrimSpace(line) == string(rightParenthesis) { if strings.TrimSpace(line) == string(rightParenthesis) {
return &apiRootState{s.baseState}, nil return &apiRootState{s.baseState}, nil
@@ -139,39 +143,60 @@ func (s *apiImportState) process(api *ApiStruct, token string) (apiFileState, er
} }
line = token + line line = token + line
line = util.RemoveComment(line)
if len(strings.Fields(line)) != 2 { if len(strings.Fields(line)) != 2 {
return nil, errors.New("import syntax error: " + line) return nil, errors.New("import syntax error: " + line)
} }
api.Imports += "\n" + line api.Imports += newline + line
return &apiRootState{s.baseState}, nil return &apiRootState{s.baseState}, nil
} }
func (s *apiTypeState) process(api *ApiStruct, token string) (apiFileState, error) { func (s *apiTypeState) process(api *ApiStruct, token string) (apiFileState, error) {
var blockCount = 0 var blockCount = 0
var braceCount = 0
for { for {
line, err := s.readLine() line, err := s.readLine()
if err != nil { if err != nil {
return nil, err return nil, err
} }
api.Type += "\n\n" + token + line line = token + line
token = "" if braceCount == 0 {
line = mayInsertStructKeyword(line)
}
api.Type += newline + newline + line
line = strings.TrimSpace(line) line = strings.TrimSpace(line)
line = removeComment(line) line = util.RemoveComment(line)
token = ""
if strings.HasSuffix(line, leftBrace) { if strings.HasSuffix(line, leftBrace) {
blockCount++ blockCount++
braceCount++
} }
if strings.HasSuffix(line, string(leftParenthesis)) { if strings.HasSuffix(line, string(leftParenthesis)) {
blockCount++ blockCount++
} }
if strings.HasSuffix(line, string(rightBrace)) { if strings.HasSuffix(line, string(rightBrace)) {
blockCount-- blockCount--
braceCount--
} }
if strings.HasSuffix(line, string(rightParenthesis)) { if strings.HasSuffix(line, string(rightParenthesis)) {
blockCount-- blockCount--
} }
if braceCount >= 2 {
return nil, errors.New("nested type not supported: " + line)
}
if braceCount < 0 {
line = strings.TrimSuffix(line, string(rightBrace))
line = strings.TrimSpace(line)
if strings.HasSuffix(line, leftBrace) {
blockCount++
braceCount++
}
}
if blockCount == 0 { if blockCount == 0 {
return &apiRootState{s.baseState}, nil return &apiRootState{s.baseState}, nil
} }
@@ -188,9 +213,10 @@ func (s *apiServiceState) process(api *ApiStruct, token string) (apiFileState, e
line = token + line line = token + line
token = "" token = ""
api.Service += "\n" + line api.Service += newline + line
line = strings.TrimSpace(line) line = strings.TrimSpace(line)
line = removeComment(line) line = util.RemoveComment(line)
if strings.HasSuffix(line, leftBrace) { if strings.HasSuffix(line, leftBrace) {
blockCount++ blockCount++
} }
@@ -210,10 +236,33 @@ func (s *apiServiceState) process(api *ApiStruct, token string) (apiFileState, e
} }
} }
func removeComment(line string) string { func mayInsertStructKeyword(line string) string {
var commentIdx = strings.Index(line, "//") line = util.RemoveComment(line)
if commentIdx >= 0 { if !strings.HasSuffix(line, leftBrace) && !strings.HasSuffix(line, string(rightBrace)) {
return line[:commentIdx] return line
} }
return line
fields := strings.Fields(line)
if stringx.Contains(fields, tokenStruct) ||
stringx.Contains(fields, tokenStruct+leftBrace) ||
stringx.Contains(fields, tokenStruct+leftBrace+string(rightBrace)) ||
len(fields) <= 1 {
return line
}
var insertIndex int
if fields[0] == tokenType {
insertIndex = 2
} else {
insertIndex = 1
}
if insertIndex >= len(fields) {
return line
}
var result []string
result = append(result, fields[:insertIndex]...)
result = append(result, tokenStruct)
result = append(result, fields[insertIndex:]...)
return strings.Join(result, " ")
} }

View File

@@ -15,9 +15,8 @@ import (
) )
type Parser struct { type Parser struct {
r *bufio.Reader r *bufio.Reader
typeDef string api *ApiStruct
api *ApiStruct
} }
func NewParser(filename string) (*Parser, error) { func NewParser(filename string) (*Parser, error) {
@@ -73,15 +72,14 @@ func NewParser(filename string) (*Parser, error) {
var buffer = new(bytes.Buffer) var buffer = new(bytes.Buffer)
buffer.WriteString(apiStruct.Service) buffer.WriteString(apiStruct.Service)
return &Parser{ return &Parser{
r: bufio.NewReader(buffer), r: bufio.NewReader(buffer),
typeDef: apiStruct.Type, api: apiStruct,
api: apiStruct,
}, nil }, nil
} }
func (p *Parser) Parse() (api *spec.ApiSpec, err error) { func (p *Parser) Parse() (api *spec.ApiSpec, err error) {
api = new(spec.ApiSpec) api = new(spec.ApiSpec)
var sp = StructParser{Src: p.typeDef} var sp = StructParser{Src: p.api.Type}
types, err := sp.Parse() types, err := sp.Parse()
if err != nil { if err != nil {
return nil, err return nil, err

View File

@@ -16,4 +16,5 @@ const (
multilineBeginTag = '>' multilineBeginTag = '>'
multilineEndTag = '<' multilineEndTag = '<'
semicolon = ';' semicolon = ';'
newline = "\n"
) )

View File

@@ -2,30 +2,15 @@ package spec
import ( import (
"errors" "errors"
"regexp"
"strings" "strings"
"github.com/tal-tech/go-zero/core/stringx" "github.com/tal-tech/go-zero/core/stringx"
"github.com/tal-tech/go-zero/tools/goctl/util" "github.com/tal-tech/go-zero/tools/goctl/util"
) )
const ( const bodyTagKey = "json"
TagKey = "tag"
NameKey = "name"
OptionKey = "option"
BodyTag = "json"
)
var ( var definedKeys = []string{"json", "form", "path"}
TagRe = regexp.MustCompile(`(?P<tag>\w+):"(?P<name>[^,"]+)[,]?(?P<option>[^"]*)"`)
TagSubNames = TagRe.SubexpNames()
definedTags = []string{TagKey, NameKey, OptionKey}
)
type Attribute struct {
Key string
value string
}
func (s Service) Routes() []Route { func (s Service) Routes() []Route {
var result []Route var result []Route
@@ -35,81 +20,62 @@ func (s Service) Routes() []Route {
return result return result
} }
func (m Member) IsOptional() bool { func (m Member) Tags() []*Tag {
var option string tags, err := Parse(m.Tag)
if err != nil {
matches := TagRe.FindStringSubmatch(m.Tag) panic(m.Tag + ", " + err.Error())
for i := range matches {
name := TagSubNames[i]
if name == OptionKey {
option = matches[i]
}
} }
if len(option) == 0 { return tags.Tags()
}
func (m Member) IsOptional() bool {
if !m.IsBodyMember() {
return false return false
} }
fields := strings.Split(option, ",") tag := m.Tags()
for _, field := range fields { for _, item := range tag {
if field == "optional" || strings.HasPrefix(field, "default=") { if item.Key == bodyTagKey {
return true if stringx.Contains(item.Options, "optional") {
return true
}
} }
} }
return false return false
} }
func (m Member) IsOmitempty() bool { func (m Member) IsOmitempty() bool {
var option string if !m.IsBodyMember() {
matches := TagRe.FindStringSubmatch(m.Tag)
for i := range matches {
name := TagSubNames[i]
if name == OptionKey {
option = matches[i]
}
}
if len(option) == 0 {
return false return false
} }
fields := strings.Split(option, ",") tag := m.Tags()
for _, field := range fields { for _, item := range tag {
if field == "omitempty" { if item.Key == bodyTagKey {
return true if stringx.Contains(item.Options, "omitempty") {
return true
}
} }
} }
return false return false
} }
func (m Member) GetAttributes() []Attribute {
matches := TagRe.FindStringSubmatch(m.Tag)
var result []Attribute
for i := range matches {
name := TagSubNames[i]
if stringx.Contains(definedTags, name) {
result = append(result, Attribute{
Key: name,
value: matches[i],
})
}
}
return result
}
func (m Member) GetPropertyName() (string, error) { func (m Member) GetPropertyName() (string, error) {
attrs := m.GetAttributes() tags := m.Tags()
for _, attr := range attrs { if len(tags) == 0 {
if attr.Key == NameKey && len(attr.value) > 0 { return "", errors.New("json property name not exist, member: " + m.Name)
if attr.value == "-" { }
for _, tag := range tags {
if stringx.Contains(definedKeys, tag.Key) {
if tag.Name == "-" {
return util.Untitle(m.Name), nil return util.Untitle(m.Name), nil
} }
return attr.value, nil return tag.Name, nil
} }
} }
return "", errors.New("json property name not exist, member: " + m.Name) return "", errors.New("json property name not exist, member: " + m.Name)
} }
@@ -121,9 +87,10 @@ func (m Member) IsBodyMember() bool {
if m.IsInline { if m.IsInline {
return true return true
} }
attrs := m.GetAttributes()
for _, attr := range attrs { tags := m.Tags()
if attr.value == BodyTag { for _, tag := range tags {
if tag.Key == bodyTagKey {
return true return true
} }
} }

View File

@@ -0,0 +1,67 @@
package spec
import (
"errors"
"strings"
"github.com/fatih/structtag"
)
var errTagNotExist = errors.New("tag does not exist")
type (
Tag struct {
// Key is the tag key, such as json, xml, etc..
// i.e: `json:"foo,omitempty". Here key is: "json"
Key string
// Name is a part of the value
// i.e: `json:"foo,omitempty". Here name is: "foo"
Name string
// Options is a part of the value. It contains a slice of tag options i.e:
// `json:"foo,omitempty". Here options is: ["omitempty"]
Options []string
}
Tags struct {
tags []*Tag
}
)
func Parse(tag string) (*Tags, error) {
tag = strings.TrimPrefix(tag, "`")
tag = strings.TrimSuffix(tag, "`")
tags, err := structtag.Parse(tag)
if err != nil {
return nil, err
}
var result Tags
for _, item := range tags.Tags() {
result.tags = append(result.tags, &Tag{Key: item.Key, Name: item.Name, Options: item.Options})
}
return &result, nil
}
func (t *Tags) Get(key string) (*Tag, error) {
for _, tag := range t.tags {
if tag.Key == key {
return tag, nil
}
}
return nil, errTagNotExist
}
func (t *Tags) Keys() []string {
var keys []string
for _, tag := range t.tags {
keys = append(keys, tag.Key)
}
return keys
}
func (t *Tags) Tags() []*Tag {
return t.tags
}

View File

@@ -26,19 +26,6 @@ func MaybeCreateFile(dir, subdir, file string) (fp *os.File, created bool, err e
return return
} }
func ClearAndOpenFile(fpath string) (*os.File, error) {
f, err := os.OpenFile(fpath, os.O_WRONLY|os.O_TRUNC, 0600)
if err != nil {
return nil, err
}
_, err = f.WriteString("")
if err != nil {
return nil, err
}
return f, nil
}
func WrapErr(err error, message string) error { func WrapErr(err error, message string) error {
return errors.New(message + ", " + err.Error()) return errors.New(message + ", " + err.Error())
} }
@@ -81,3 +68,11 @@ func WriteIndent(writer io.Writer, indent int) {
fmt.Fprint(writer, "\t") fmt.Fprint(writer, "\t")
} }
} }
func RemoveComment(line string) string {
var commentIdx = strings.Index(line, "//")
if commentIdx >= 0 {
return strings.TrimSpace(line[:commentIdx])
}
return strings.TrimSpace(line)
}

View File

@@ -0,0 +1,122 @@
package config
import (
"errors"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/tal-tech/go-zero/tools/goctl/util"
"gopkg.in/yaml.v2"
)
const (
configFile = "config.yaml"
configFolder = "config"
DefaultFormat = "gozero"
)
const defaultYaml = `# namingFormat is used to define the naming format of the generated file name.
# just like time formatting, you can specify the formatting style through the
# two format characters go, and zero. for example: snake format you can
# define as go_zero, camel case format you can it is defined as goZero,
# and even split characters can be specified, such as go#zero. in theory,
# any combination can be used, but the prerequisite must meet the naming conventions
# of each operating system file name. if you want to independently control the file
# naming style of the api, rpc, and model layers, you can set it through apiNamingFormat,
# rpcNamingFormat, modelNamingFormat, and independent control is not enabled by default.
# for more information, please see #{apiNamingFormat},#{rpcNamingFormat},#{modelNamingFormat}
# Note: namingFormat is based on snake or camel string
namingFormat: gozero
`
type Config struct {
// NamingFormat is used to define the naming format of the generated file name.
// just like time formatting, you can specify the formatting style through the
// two format characters go, and zero. for example: snake format you can
// define as go_zero, camel case format you can it is defined as goZero,
// and even split characters can be specified, such as go#zero. in theory,
// any combination can be used, but the prerequisite must meet the naming conventions
// of each operating system file name.
// Note: NamingFormat is based on snake or camel string
NamingFormat string `yaml:"namingFormat"`
}
func NewConfig(format string) (*Config, error) {
if len(format) == 0 {
format = DefaultFormat
}
cfg := &Config{NamingFormat: format}
err := validate(cfg)
return cfg, err
}
func InitOrGetConfig() (*Config, error) {
var (
defaultConfig Config
)
err := yaml.Unmarshal([]byte(defaultYaml), &defaultConfig)
if err != nil {
return nil, err
}
goctlHome, err := util.GetGoctlHome()
if err != nil {
return nil, err
}
configDir := filepath.Join(goctlHome, configFolder)
configFilename := filepath.Join(configDir, configFile)
if util.FileExists(configFilename) {
data, err := ioutil.ReadFile(configFilename)
if err != nil {
return nil, err
}
err = yaml.Unmarshal(data, &defaultConfig)
if err != nil {
return nil, err
}
err = validate(&defaultConfig)
if err != nil {
return nil, err
}
return &defaultConfig, nil
}
err = util.MkdirIfNotExist(configDir)
if err != nil {
return nil, err
}
f, err := os.Create(configFilename)
if err != nil {
return nil, err
}
defer func() {
_ = f.Close()
}()
_, err = f.WriteString(defaultYaml)
if err != nil {
return nil, err
}
err = validate(&defaultConfig)
if err != nil {
return nil, err
}
return &defaultConfig, nil
}
func validate(cfg *Config) error {
if len(strings.TrimSpace(cfg.NamingFormat)) == 0 {
return errors.New("missing namingFormat")
}
return nil
}

View File

@@ -0,0 +1,50 @@
# 配置项管理
| 名称 | 是否可选 | 说明 |
|-------------------|----------|-----------------------------------------------|
| namingFormat | YES | 文件名称格式化符 |
# naming-format
`namingFormat`可以用于对生成代码的文件名称进行格式化和日期格式化符yyyy-MM-dd类似在代码生成时可以根据这些配置项的格式化符进行格式化。
## 格式化符(gozero)
格式化符有`go`,`zero`组成,如常见的三种格式化风格你可以这样编写:
* lower: `gozero`
* camel: `goZero`
* snake: `go_zero`
常见格式化符生成示例
源字符welcome_to_go_zero
| 格式化符 | 格式化结果 | 说明 |
|------------|-----------------------|---------------------------|
| gozero | welcometogozero | 小写 |
| goZero | welcomeToGoZero | 驼峰 |
| go_zero | welcome_to_go_zero | snake |
| Go#zero | Welcome#to#go#zero | #号分割Title类型 |
| GOZERO | WELCOMETOGOZERO | 大写 |
| \_go#zero_ | \_welcome#to#go#zero_ | 下划线做前后缀,并且#分割 |
错误格式化符示例
* go
* gOZero
* zero
* goZEro
* goZERo
* goZeRo
* tal
# 使用方法
目前可通过在生成api、rpc、model时通过`--style`参数指定format格式
```shell script
goctl api go test.api -dir . -style gozero
```
```shell script
goctl rpc proto -src test.proto -dir . -style go_zero
```
```shell script
goctl model mysql datasource -url="" -table="*" -dir ./snake -style GoZero
```
# 默认值
当不指定-style时默认值为`gozero`

View File

@@ -43,8 +43,8 @@ func GenConfigCommand(c *cli.Context) error {
return errors.New("abs failed: " + c.String("path")) return errors.New("abs failed: " + c.String("path"))
} }
goModPath, hasFound := util.FindGoModPath(path) goModPath, found := util.FindGoModPath(path)
if !hasFound { if !found {
return errors.New("go mod not initial") return errors.New("go mod not initial")
} }

View File

@@ -2,33 +2,72 @@ package docker
import ( import (
"errors" "errors"
"fmt"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"text/template" "text/template"
"time"
"github.com/logrusorgru/aurora"
"github.com/tal-tech/go-zero/tools/goctl/util" "github.com/tal-tech/go-zero/tools/goctl/util"
ctlutil "github.com/tal-tech/go-zero/tools/goctl/util" ctlutil "github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
const ( const (
etcDir = "etc" dockerfileName = "Dockerfile"
yamlEtx = ".yaml" etcDir = "etc"
yamlEtx = ".yaml"
cstOffset = 60 * 60 * 8 // 8 hours offset for Chinese Standard Time
) )
func DockerCommand(c *cli.Context) error { type Docker struct {
Chinese bool
GoRelPath string
GoFile string
ExeFile string
HasPort bool
Port int
Argument string
}
func DockerCommand(c *cli.Context) (err error) {
defer func() {
if err == nil {
fmt.Println(aurora.Green("Done."))
}
}()
goFile := c.String("go") goFile := c.String("go")
if len(goFile) == 0 { if len(goFile) == 0 {
return errors.New("-go can't be empty") return errors.New("-go can't be empty")
} }
if !util.FileExists(goFile) {
return fmt.Errorf("file %q not found", goFile)
}
port := c.Int("port")
if _, err := os.Stat(etcDir); os.IsNotExist(err) {
return generateDockerfile(goFile, port)
}
cfg, err := findConfig(goFile, etcDir) cfg, err := findConfig(goFile, etcDir)
if err != nil { if err != nil {
return err return err
} }
return generateDockerfile(goFile, "-f", "etc/"+cfg) if err := generateDockerfile(goFile, port, "-f", "etc/"+cfg); err != nil {
return err
}
projDir, ok := util.FindProjectPath(goFile)
if ok {
fmt.Printf("Hint: run \"docker build ...\" command in dir %q\n", projDir)
}
return nil
} }
func findConfig(file, dir string) (string, error) { func findConfig(file, dir string) (string, error) {
@@ -60,18 +99,22 @@ func findConfig(file, dir string) (string, error) {
return files[0], nil return files[0], nil
} }
func generateDockerfile(goFile string, args ...string) error { func generateDockerfile(goFile string, port int, args ...string) error {
projPath, err := getFilePath(filepath.Dir(goFile)) projPath, err := getFilePath(filepath.Dir(goFile))
if err != nil { if err != nil {
return err return err
} }
pos := strings.IndexByte(projPath, '/') if len(projPath) == 0 {
if pos >= 0 { projPath = "."
projPath = projPath[pos+1:] } else {
pos := strings.IndexByte(projPath, os.PathSeparator)
if pos >= 0 {
projPath = projPath[pos+1:]
}
} }
out, err := util.CreateIfNotExist("Dockerfile") out, err := util.CreateIfNotExist(dockerfileName)
if err != nil { if err != nil {
return err return err
} }
@@ -87,12 +130,16 @@ func generateDockerfile(goFile string, args ...string) error {
builder.WriteString(`, "` + arg + `"`) builder.WriteString(`, "` + arg + `"`)
} }
_, offset := time.Now().Zone()
t := template.Must(template.New("dockerfile").Parse(text)) t := template.Must(template.New("dockerfile").Parse(text))
return t.Execute(out, map[string]string{ return t.Execute(out, Docker{
"goRelPath": projPath, Chinese: offset == cstOffset,
"goFile": goFile, GoRelPath: projPath,
"exeFile": util.FileNameWithoutExt(filepath.Base(goFile)), GoFile: goFile,
"argument": builder.String(), ExeFile: util.FileNameWithoutExt(filepath.Base(goFile)),
HasPort: port > 0,
Port: port,
Argument: builder.String(),
}) })
} }

View File

@@ -14,30 +14,59 @@ LABEL stage=gobuilder
ENV CGO_ENABLED 0 ENV CGO_ENABLED 0
ENV GOOS linux ENV GOOS linux
ENV GOPROXY https://goproxy.cn,direct {{if .Chinese}}ENV GOPROXY https://goproxy.cn,direct
{{end}}
WORKDIR /build/zero WORKDIR /build/zero
ADD go.mod .
ADD go.sum .
RUN go mod download
COPY . . COPY . .
COPY {{.goRelPath}}/etc /app/etc {{if .Argument}}COPY {{.GoRelPath}}/etc /app/etc
RUN go build -ldflags="-s -w" -o /app/{{.exeFile}} {{.goRelPath}}/{{.goFile}} {{end}}RUN go build -ldflags="-s -w" -o /app/{{.ExeFile}} {{.GoRelPath}}/{{.GoFile}}
FROM alpine FROM alpine
RUN apk update --no-cache RUN apk update --no-cache && apk add --no-cache ca-certificates tzdata
RUN apk add --no-cache ca-certificates
RUN apk add --no-cache tzdata
ENV TZ Asia/Shanghai ENV TZ Asia/Shanghai
WORKDIR /app WORKDIR /app
COPY --from=builder /app/{{.exeFile}} /app/{{.exeFile}} COPY --from=builder /app/{{.ExeFile}} /app/{{.ExeFile}}{{if .Argument}}
COPY --from=builder /app/etc /app/etc COPY --from=builder /app/etc /app/etc{{end}}
{{if .HasPort}}
CMD ["./{{.exeFile}}"{{.argument}}] EXPOSE {{.Port}}
{{end}}
CMD ["./{{.ExeFile}}"{{.Argument}}]
` `
) )
func Clean() error {
return util.Clean(category)
}
func GenTemplates(_ *cli.Context) error { func GenTemplates(_ *cli.Context) error {
return initTemplate()
}
func Category() string {
return category
}
func RevertTemplate(name string) error {
return util.CreateTemplate(category, name, dockerTemplate)
}
func Update() error {
err := Clean()
if err != nil {
return err
}
return initTemplate()
}
func initTemplate() error {
return util.InitTemplates(category, map[string]string{ return util.InitTemplates(category, map[string]string{
dockerTemplateFile: dockerTemplate, dockerTemplateFile: dockerTemplate,
}) })

View File

@@ -18,14 +18,16 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/api/validate" "github.com/tal-tech/go-zero/tools/goctl/api/validate"
"github.com/tal-tech/go-zero/tools/goctl/configgen" "github.com/tal-tech/go-zero/tools/goctl/configgen"
"github.com/tal-tech/go-zero/tools/goctl/docker" "github.com/tal-tech/go-zero/tools/goctl/docker"
"github.com/tal-tech/go-zero/tools/goctl/kube"
model "github.com/tal-tech/go-zero/tools/goctl/model/sql/command" model "github.com/tal-tech/go-zero/tools/goctl/model/sql/command"
"github.com/tal-tech/go-zero/tools/goctl/plugin"
rpc "github.com/tal-tech/go-zero/tools/goctl/rpc/cli" rpc "github.com/tal-tech/go-zero/tools/goctl/rpc/cli"
"github.com/tal-tech/go-zero/tools/goctl/tpl" "github.com/tal-tech/go-zero/tools/goctl/tpl"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
var ( var (
BuildVersion = "20201108" BuildVersion = "1.1.1"
commands = []cli.Command{ commands = []cli.Command{
{ {
Name: "api", Name: "api",
@@ -52,14 +54,12 @@ var (
Usage: "the format target dir", Usage: "the format target dir",
}, },
cli.BoolFlag{ cli.BoolFlag{
Name: "iu", Name: "iu",
Usage: "ignore update", Usage: "ignore update",
Required: false,
}, },
cli.BoolFlag{ cli.BoolFlag{
Name: "stdin", Name: "stdin",
Usage: "use stdin to input api doc content, press \"ctrl + d\" to send EOF", Usage: "use stdin to input api doc content, press \"ctrl + d\" to send EOF",
Required: false,
}, },
}, },
Action: format.GoFormatApi, Action: format.GoFormatApi,
@@ -98,6 +98,10 @@ var (
Name: "api", Name: "api",
Usage: "the api file", Usage: "the api file",
}, },
cli.StringFlag{
Name: "style",
Usage: "the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]",
},
}, },
Action: gogen.GoCommand, Action: gogen.GoCommand,
}, },
@@ -129,19 +133,16 @@ var (
Usage: "the api file", Usage: "the api file",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "webapi", Name: "webapi",
Usage: "the web api file path", Usage: "the web api file path",
Required: false,
}, },
cli.StringFlag{ cli.StringFlag{
Name: "caller", Name: "caller",
Usage: "the web api caller", Usage: "the web api caller",
Required: false,
}, },
cli.BoolFlag{ cli.BoolFlag{
Name: "unwrap", Name: "unwrap",
Usage: "unwrap the webapi caller for import", Usage: "unwrap the webapi caller for import",
Required: false,
}, },
}, },
Action: tsgen.TsCommand, Action: tsgen.TsCommand,
@@ -180,6 +181,29 @@ var (
}, },
Action: ktgen.KtCommand, Action: ktgen.KtCommand,
}, },
{
Name: "plugin",
Usage: "custom file generator",
Flags: []cli.Flag{
cli.StringFlag{
Name: "plugin, p",
Usage: "the plugin file",
},
cli.StringFlag{
Name: "dir",
Usage: "the target directory",
},
cli.StringFlag{
Name: "api",
Usage: "the api file",
},
cli.StringFlag{
Name: "style",
Usage: "the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]",
},
},
Action: plugin.PluginCommand,
},
}, },
}, },
{ {
@@ -190,9 +214,101 @@ var (
Name: "go", Name: "go",
Usage: "the file that contains main function", Usage: "the file that contains main function",
}, },
cli.IntFlag{
Name: "port",
Usage: "the port to expose, default none",
Value: 0,
},
}, },
Action: docker.DockerCommand, Action: docker.DockerCommand,
}, },
{
Name: "kube",
Usage: "generate kubernetes files",
Subcommands: []cli.Command{
{
Name: "deploy",
Usage: "generate deployment yaml file",
Flags: []cli.Flag{
cli.StringFlag{
Name: "name",
Usage: "the name of deployment",
Required: true,
},
cli.StringFlag{
Name: "namespace",
Usage: "the namespace of deployment",
Required: true,
},
cli.StringFlag{
Name: "image",
Usage: "the docker image of deployment",
Required: true,
},
cli.StringFlag{
Name: "secret",
Usage: "the secret to image pull from registry",
},
cli.IntFlag{
Name: "requestCpu",
Usage: "the request cpu to deploy",
Value: 500,
},
cli.IntFlag{
Name: "requestMem",
Usage: "the request memory to deploy",
Value: 512,
},
cli.IntFlag{
Name: "limitCpu",
Usage: "the limit cpu to deploy",
Value: 1000,
},
cli.IntFlag{
Name: "limitMem",
Usage: "the limit memory to deploy",
Value: 1024,
},
cli.StringFlag{
Name: "o",
Usage: "the output yaml file",
Required: true,
},
cli.IntFlag{
Name: "replicas",
Usage: "the number of replicas to deploy",
Value: 3,
},
cli.IntFlag{
Name: "revisions",
Usage: "the number of revision history to limit",
Value: 5,
},
cli.IntFlag{
Name: "port",
Usage: "the port of the deployment to listen on pod",
Required: true,
},
cli.IntFlag{
Name: "nodePort",
Usage: "the nodePort of the deployment to expose",
Value: 0,
},
cli.IntFlag{
Name: "minReplicas",
Usage: "the min replicas to deploy",
Value: 3,
},
cli.IntFlag{
Name: "maxReplicas",
Usage: "the max replicas of deploy",
Value: 10,
},
},
Action: kube.DeploymentCommand,
},
},
},
{ {
Name: "rpc", Name: "rpc",
Usage: "generate rpc code", Usage: "generate rpc code",
@@ -201,6 +317,10 @@ var (
Name: "new", Name: "new",
Usage: `generate rpc demo service`, Usage: `generate rpc demo service`,
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.StringFlag{
Name: "style",
Usage: "the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]",
},
cli.BoolFlag{ cli.BoolFlag{
Name: "idea", Name: "idea",
Usage: "whether the command execution environment is from idea plugin. [optional]", Usage: "whether the command execution environment is from idea plugin. [optional]",
@@ -235,6 +355,10 @@ var (
Name: "dir, d", Name: "dir, d",
Usage: `the target path of the code`, Usage: `the target path of the code`,
}, },
cli.StringFlag{
Name: "style",
Usage: "the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]",
},
cli.BoolFlag{ cli.BoolFlag{
Name: "idea", Name: "idea",
Usage: "whether the command execution environment is from idea plugin. [optional]", Usage: "whether the command execution environment is from idea plugin. [optional]",
@@ -266,7 +390,7 @@ var (
}, },
cli.StringFlag{ cli.StringFlag{
Name: "style", Name: "style",
Usage: "the file naming style, lower|camel|underline,default is lower", Usage: "the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]",
}, },
cli.BoolFlag{ cli.BoolFlag{
Name: "cache, c", Name: "cache, c",
@@ -301,7 +425,7 @@ var (
}, },
cli.StringFlag{ cli.StringFlag{
Name: "style", Name: "style",
Usage: "the file naming style, lower|camel|snake, default is lower", Usage: "the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]",
}, },
cli.BoolFlag{ cli.BoolFlag{
Name: "idea", Name: "idea",
@@ -345,7 +469,7 @@ var (
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.StringFlag{ cli.StringFlag{
Name: "category,c", Name: "category,c",
Usage: "the category of template, enum [api,rpc,model]", Usage: "the category of template, enum [api,rpc,model,docker,kube]",
}, },
}, },
Action: tpl.UpdateTemplates, Action: tpl.UpdateTemplates,
@@ -356,7 +480,7 @@ var (
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.StringFlag{ cli.StringFlag{
Name: "category,c", Name: "category,c",
Usage: "the category of template, enum [api,rpc,model]", Usage: "the category of template, enum [api,rpc,model,docker,kube]",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "name,n", Name: "name,n",

View File

@@ -1,130 +0,0 @@
package k8s
var apiRpcTmeplate = `apiVersion: apps/v1
kind: Deployment
metadata:
name: {{.name}}
namespace: {{.namespace}}
labels:
app: {{.name}}
spec:
replicas: {{.replicas}}
revisionHistoryLimit: {{.revisionHistoryLimit}}
selector:
matchLabels:
app: {{.name}}
template:
metadata:
labels:
app: {{.name}}
spec:{{if .envIsDev}}
terminationGracePeriodSeconds: 60{{end}}
containers:
- name: {{.name}}
image: registry-vpc.cn-hangzhou.aliyuncs.com/{{.namespace}}/
lifecycle:
preStop:
exec:
command: ["sh","-c","sleep 5"]
ports:
- containerPort: {{.port}}
readinessProbe:
tcpSocket:
port: {{.port}}
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
tcpSocket:
port: {{.port}}
initialDelaySeconds: 15
periodSeconds: 20
env:
- name: aliyun_logs_k8slog
value: "stdout"
- name: aliyun_logs_k8slog_tags
value: "stage={{.env}}"
- name: aliyun_logs_k8slog_format
value: "json"
resources:
limits:
cpu: {{.limitCpu}}m
memory: {{.limitMem}}Mi
requests:
cpu: {{.requestCpu}}m
memory: {{.requestMem}}Mi
command:
- ./{{.serviceName}}
- -f
- ./{{.name}}.json
volumeMounts:
- name: timezone
mountPath: /etc/localtime
imagePullSecrets:
- name: {{.namespace}}
volumes:
- name: timezone
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
---
apiVersion: v1
kind: Service
metadata:
name: {{.name}}-svc
namespace: {{.namespace}}
spec:
ports:
- nodePort: 3{{.port}}
port: {{.port}}
protocol: TCP
targetPort: {{.port}}
selector:
app: {{.name}}
sessionAffinity: None
type: NodePort{{if .envIsPreOrPro}}
---
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: {{.name}}-hpa-c
namespace: {{.namespace}}
labels:
app: {{.name}}-hpa-c
spec:
scaleTargetRef:
apiVersion: apps/v1beta1
kind: Deployment
name: di-api
minReplicas: {{.minReplicas}}
maxReplicas: {{.maxReplicas}}
metrics:
- type: Resource
resource:
name: cpu
targetAverageUtilization: 80
---
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: {{.name}}-hpa-m
namespace: {{.namespace}}
labels:
app: {{.name}}-hpa-m
spec:
scaleTargetRef:
apiVersion: apps/v1beta1
kind: Deployment
name: {{.name}}
minReplicas: {{.minReplicas}}
maxReplicas: {{.maxReplicas}}
metrics:
- type: Resource
resource:
name: memory
targetAverageUtilization: 80{{end}}
`

View File

@@ -1,46 +0,0 @@
package k8s
var jobTmeplate = `apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: {{.name}}
namespace: {{.namespace}}
spec:
successfulJobsHistoryLimit: {{.successfulJobsHistoryLimit}}
schedule: "{{.schedule}}"
jobTemplate:
spec:
template:
spec:
containers:
- name: {{.name}}
image: registry-vpc.cn-hangzhou.aliyuncs.com/{{.namespace}}/
env:
- name: aliyun_logs_k8slog
value: "stdout"
- name: aliyun_logs_k8slog_tags
value: "stage={{.env}}"
- name: aliyun_logs_k8slog_format
value: "json"
resources:
limits:
cpu: {{.limitCpu}}m
memory: {{.limitMem}}Mi
requests:
cpu: {{.requestCpu}}m
memory: {{.requestMem}}Mi
command:
- ./{{.serviceName}}
- -f
- ./{{.name}}.json
volumeMounts:
- name: timezone
mountPath: /etc/localtime
imagePullSecrets:
- name: {{.namespace}}
restartPolicy: OnFailure
volumes:
- name: timezone
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
`

View File

@@ -1,103 +0,0 @@
package k8s
import (
"bytes"
"errors"
"fmt"
"text/template"
)
const (
ServiceTypeApi ServiceType = "api"
ServiceTypeRpc ServiceType = "rpc"
ServiceTypeJob ServiceType = "job"
envDev = "dev"
)
var errUnknownServiceType = errors.New("unknown service type")
type (
ServiceType string
KubeRequest struct {
Env string
ServiceName string
ServiceType ServiceType
Namespace string
Schedule string
Replicas int
RevisionHistoryLimit int
Port int
LimitCpu int
LimitMem int
RequestCpu int
RequestMem int
SuccessfulJobsHistoryLimit int
HpaMinReplicas int
HpaMaxReplicas int
}
)
func Gen(req KubeRequest) (string, error) {
switch req.ServiceType {
case ServiceTypeApi, ServiceTypeRpc:
return genApiRpc(req)
case ServiceTypeJob:
return genJob(req)
default:
return "", errUnknownServiceType
}
}
func genApiRpc(req KubeRequest) (string, error) {
t, err := template.New("api_rpc").Parse(apiRpcTmeplate)
if err != nil {
return "", err
}
buffer := new(bytes.Buffer)
err = t.Execute(buffer, map[string]interface{}{
"name": fmt.Sprintf("%s-%s", req.ServiceName, req.ServiceType),
"namespace": req.Namespace,
"replicas": req.Replicas,
"revisionHistoryLimit": req.RevisionHistoryLimit,
"port": req.Port,
"limitCpu": req.LimitCpu,
"limitMem": req.LimitMem,
"requestCpu": req.RequestCpu,
"requestMem": req.RequestMem,
"serviceName": req.ServiceName,
"env": req.Env,
"envIsPreOrPro": req.Env != envDev,
"envIsDev": req.Env == envDev,
"minReplicas": req.HpaMinReplicas,
"maxReplicas": req.HpaMaxReplicas,
})
if err != nil {
return "", nil
}
return buffer.String(), nil
}
func genJob(req KubeRequest) (string, error) {
t, err := template.New("job").Parse(jobTmeplate)
if err != nil {
return "", err
}
buffer := new(bytes.Buffer)
err = t.Execute(buffer, map[string]interface{}{
"name": fmt.Sprintf("%s-%s", req.ServiceName, req.ServiceType),
"namespace": req.Namespace,
"schedule": req.Schedule,
"successfulJobsHistoryLimit": req.SuccessfulJobsHistoryLimit,
"limitCpu": req.LimitCpu,
"limitMem": req.LimitMem,
"requestCpu": req.RequestCpu,
"requestMem": req.RequestMem,
"serviceName": req.ServiceName,
"env": req.Env,
})
if err != nil {
return "", nil
}
return buffer.String(), nil
}

View File

@@ -0,0 +1,117 @@
package kube
var deploymentTemplate = `apiVersion: apps/v1
kind: Deployment
metadata:
name: {{.Name}}
namespace: {{.Namespace}}
labels:
app: {{.Name}}
spec:
replicas: {{.Replicas}}
revisionHistoryLimit: {{.Revisions}}
selector:
matchLabels:
app: {{.Name}}
template:
metadata:
labels:
app: {{.Name}}
spec:
containers:
- name: {{.Name}}
image: {{.Image}}
lifecycle:
preStop:
exec:
command: ["sh","-c","sleep 5"]
ports:
- containerPort: {{.Port}}
readinessProbe:
tcpSocket:
port: {{.Port}}
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
tcpSocket:
port: {{.Port}}
initialDelaySeconds: 15
periodSeconds: 20
resources:
requests:
cpu: {{.RequestCpu}}m
memory: {{.RequestMem}}Mi
limits:
cpu: {{.LimitCpu}}m
memory: {{.LimitMem}}Mi
volumeMounts:
- name: timezone
mountPath: /etc/localtime
{{if .Secret}}imagePullSecrets:
- name: {{.Secret}}
{{end}}volumes:
- name: timezone
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
---
apiVersion: v1
kind: Service
metadata:
name: {{.Name}}-svc
namespace: {{.Namespace}}
spec:
ports:
{{if .UseNodePort}}- nodePort: {{.NodePort}}
port: {{.Port}}
protocol: TCP
targetPort: {{.Port}}
type: NodePort{{else}}- port: {{.Port}}{{end}}
selector:
app: {{.Name}}
---
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: {{.Name}}-hpa-c
namespace: {{.Namespace}}
labels:
app: {{.Name}}-hpa-c
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{.Name}}
minReplicas: {{.MinReplicas}}
maxReplicas: {{.MaxReplicas}}
metrics:
- type: Resource
resource:
name: cpu
targetAverageUtilization: 80
---
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: {{.Name}}-hpa-m
namespace: {{.Namespace}}
labels:
app: {{.Name}}-hpa-m
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{.Name}}
minReplicas: {{.MinReplicas}}
maxReplicas: {{.MaxReplicas}}
metrics:
- type: Resource
resource:
name: memory
targetAverageUtilization: 80
`

39
tools/goctl/kube/job.go Normal file
View File

@@ -0,0 +1,39 @@
package kube
var jobTmeplate = `apiVersion: batch/v1
kind: CronJob
metadata:
name: {{.Name}}
namespace: {{.Namespace}}
spec:
successfulJobsHistoryLimit: {{.SuccessfulJobsHistoryLimit}}
schedule: "{{.Schedule}}"
jobTemplate:
spec:
template:
spec:
containers:
- name: {{.Name}}
image: # todo image url
resources:
requests:
cpu: {{.RequestCpu}}m
memory: {{.RequestMem}}Mi
limits:
cpu: {{.LimitCpu}}m
memory: {{.LimitMem}}Mi
command:
- ./{{.ServiceName}}
- -f
- ./{{.Name}}.yaml
volumeMounts:
- name: timezone
mountPath: /etc/localtime
imagePullSecrets:
- name: # registry secret, if no, remove this
restartPolicy: OnFailure
volumes:
- name: timezone
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
`

112
tools/goctl/kube/kube.go Normal file
View File

@@ -0,0 +1,112 @@
package kube
import (
"errors"
"fmt"
"text/template"
"github.com/logrusorgru/aurora"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/urfave/cli"
)
const (
category = "kube"
deployTemplateFile = "deployment.tpl"
jobTemplateFile = "job.tpl"
basePort = 30000
portLimit = 32767
)
type Deployment struct {
Name string
Namespace string
Image string
Secret string
Replicas int
Revisions int
Port int
NodePort int
UseNodePort bool
RequestCpu int
RequestMem int
LimitCpu int
LimitMem int
MinReplicas int
MaxReplicas int
}
func DeploymentCommand(c *cli.Context) error {
nodePort := c.Int("nodePort")
// 0 to disable the nodePort type
if nodePort != 0 && (nodePort < basePort || nodePort > portLimit) {
return errors.New("nodePort should be between 30000 and 32767")
}
text, err := util.LoadTemplate(category, deployTemplateFile, deploymentTemplate)
if err != nil {
return err
}
out, err := util.CreateIfNotExist(c.String("o"))
if err != nil {
return err
}
defer out.Close()
t := template.Must(template.New("deploymentTemplate").Parse(text))
err = t.Execute(out, Deployment{
Name: c.String("name"),
Namespace: c.String("namespace"),
Image: c.String("image"),
Secret: c.String("secret"),
Replicas: c.Int("replicas"),
Revisions: c.Int("revisions"),
Port: c.Int("port"),
NodePort: nodePort,
UseNodePort: nodePort > 0,
RequestCpu: c.Int("requestCpu"),
RequestMem: c.Int("requestMem"),
LimitCpu: c.Int("limitCpu"),
LimitMem: c.Int("limitMem"),
MinReplicas: c.Int("minReplicas"),
MaxReplicas: c.Int("maxReplicas"),
})
if err != nil {
return err
}
fmt.Println(aurora.Green("Done."))
return nil
}
func Category() string {
return category
}
func Clean() error {
return util.Clean(category)
}
func GenTemplates(_ *cli.Context) error {
return util.InitTemplates(category, map[string]string{
deployTemplateFile: deploymentTemplate,
jobTemplateFile: jobTmeplate,
})
}
func RevertTemplate(name string) error {
return util.CreateTemplate(category, name, deploymentTemplate)
}
func Update() error {
err := Clean()
if err != nil {
return err
}
return util.InitTemplates(category, map[string]string{
deployTemplateFile: deploymentTemplate,
jobTemplateFile: jobTmeplate,
})
}

View File

@@ -7,7 +7,7 @@ goctl model 为go-zero下的工具模块中的组件之一目前支持识别m
* 通过ddl生成 * 通过ddl生成
```shell script ```shell script
goctl model mysql ddl -src="./*.sql" -dir="./sql/model" -c=true goctl model mysql ddl -src="./*.sql" -dir="./sql/model" -c
``` ```
执行上述命令后即可快速生成CURD代码。 执行上述命令后即可快速生成CURD代码。
@@ -30,155 +30,190 @@ goctl model 为go-zero下的工具模块中的组件之一目前支持识别m
package model package model
import ( import (
"database/sql" "database/sql"
"fmt" "fmt"
"strings" "strings"
"time" "time"
"github.com/tal-tech/go-zero/core/stores/cache" "github.com/tal-tech/go-zero/core/stores/cache"
"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/tools/goctl/model/sql/builderx"
) )
var ( var (
userFieldNames = builderx.FieldNames(&User{}) userFieldNames = builderx.FieldNames(&User{})
userRows = strings.Join(userFieldNames, ",") userRows = strings.Join(userFieldNames, ",")
userRowsExpectAutoSet = strings.Join(stringx.Remove(userFieldNames, "id", "create_time", "update_time"), ",") userRowsExpectAutoSet = strings.Join(stringx.Remove(userFieldNames, "id", "create_time", "update_time"), ",")
userRowsWithPlaceHolder = strings.Join(stringx.Remove(userFieldNames, "id", "create_time", "update_time"), "=?,") + "=?" userRowsWithPlaceHolder = strings.Join(stringx.Remove(userFieldNames, "id", "create_time", "update_time"), "=?,") + "=?"
cacheUserIdPrefix = "cache#User#id#" cacheUserPrefix = "cache#User#user#"
cacheUserNamePrefix = "cache#User#name#" cacheUserNamePrefix = "cache#User#name#"
cacheUserMobilePrefix = "cache#User#mobile#" cacheUserMobilePrefix = "cache#User#mobile#"
) cacheUserIdPrefix = "cache#User#id#"
)
type ( type (
UserModel struct { UserModel interface {
sqlc.CachedConn Insert(data User) (sql.Result, error)
table string FindOne(id int64) (*User, error)
} FindOneByUser(user string) (*User, error)
FindOneByName(name string) (*User, error)
FindOneByMobile(mobile string) (*User, error)
Update(data User) error
Delete(id int64) error
}
User struct { defaultUserModel struct {
Id int64 `db:"id"` sqlc.CachedConn
Name string `db:"name"` // 用户名称 table string
Password string `db:"password"` // 用户密码 }
Mobile string `db:"mobile"` // 手机号
Gender string `db:"gender"` // 男|女|未公开
Nickname string `db:"nickname"` // 用户昵称
CreateTime time.Time `db:"create_time"`
UpdateTime time.Time `db:"update_time"`
}
)
func NewUserModel(conn sqlx.SqlConn, c cache.CacheConf) *UserModel { User struct {
return &UserModel{ Id int64 `db:"id"`
CachedConn: sqlc.NewConn(conn, c), User string `db:"user"` // 用户
table: "user", Name string `db:"name"` // 用户名称
} Password string `db:"password"` // 用户密码
} Mobile string `db:"mobile"` // 手机号
Gender string `db:"gender"` // 男|女|未公开
Nickname sql.NullString `db:"nickname"` // 用户昵称
CreateTime sql.NullTime `db:"create_time"`
UpdateTime time.Time `db:"update_time"`
}
)
func (m *UserModel) Insert(data User) (sql.Result, error) { func NewUserModel(conn sqlx.SqlConn, c cache.CacheConf) UserModel {
userNameKey := fmt.Sprintf("%s%v", cacheUserNamePrefix, data.Name) return &defaultUserModel{
userMobileKey := fmt.Sprintf("%s%v", cacheUserMobilePrefix, data.Mobile) CachedConn: sqlc.NewConn(conn, c),
ret, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) { table: "user",
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?)", m.table, userRowsExpectAutoSet) }
return conn.Exec(query, data.Name, data.Password, data.Mobile, data.Gender, data.Nickname) }
}, userNameKey, userMobileKey)
return ret, err
}
func (m *UserModel) FindOne(id int64) (*User, error) { func (m *defaultUserModel) Insert(data User) (sql.Result, error) {
userIdKey := fmt.Sprintf("%s%v", cacheUserIdPrefix, id) userKey := fmt.Sprintf("%s%v", cacheUserPrefix, data.User)
var resp User userNameKey := fmt.Sprintf("%s%v", cacheUserNamePrefix, data.Name)
err := m.QueryRow(&resp, userIdKey, func(conn sqlx.SqlConn, v interface{}) error { userMobileKey := fmt.Sprintf("%s%v", cacheUserMobilePrefix, data.Mobile)
query := fmt.Sprintf("select %s from %s where id = ? limit 1", userRows, m.table) ret, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
return conn.QueryRow(v, query, id) query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?)", m.table, userRowsExpectAutoSet)
}) return conn.Exec(query, data.User, data.Name, data.Password, data.Mobile, data.Gender, data.Nickname)
switch err { }, userMobileKey, userKey, userNameKey)
case nil: return ret, err
return &resp, nil }
case sqlc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *UserModel) FindOneByName(name string) (*User, error) { func (m *defaultUserModel) FindOne(id int64) (*User, error) {
userNameKey := fmt.Sprintf("%s%v", cacheUserNamePrefix, name) userIdKey := fmt.Sprintf("%s%v", cacheUserIdPrefix, id)
var resp User var resp User
err := m.QueryRowIndex(&resp, userNameKey, m.formatPrimary, func(conn sqlx.SqlConn, v interface{}) (i interface{}, e error) { err := m.QueryRow(&resp, userIdKey, func(conn sqlx.SqlConn, v interface{}) error {
query := fmt.Sprintf("select %s from %s where name = ? limit 1", userRows, m.table) query := fmt.Sprintf("select %s from %s where id = ? limit 1", userRows, m.table)
if err := conn.QueryRow(&resp, query, name); err != nil { return conn.QueryRow(v, query, id)
return nil, err })
} switch err {
return resp.Id, nil case nil:
}, m.queryPrimary) return &resp, nil
switch err { case sqlc.ErrNotFound:
case nil: return nil, ErrNotFound
return &resp, nil default:
case sqlc.ErrNotFound: return nil, err
return nil, ErrNotFound }
default: }
return nil, err
}
}
func (m *UserModel) FindOneByMobile(mobile string) (*User, error) { func (m *defaultUserModel) FindOneByUser(user string) (*User, error) {
userMobileKey := fmt.Sprintf("%s%v", cacheUserMobilePrefix, mobile) userKey := fmt.Sprintf("%s%v", cacheUserPrefix, user)
var resp User var resp User
err := m.QueryRowIndex(&resp, userMobileKey, m.formatPrimary, func(conn sqlx.SqlConn, v interface{}) (i interface{}, e error) { err := m.QueryRowIndex(&resp, userKey, m.formatPrimary, func(conn sqlx.SqlConn, v interface{}) (i interface{}, e error) {
query := fmt.Sprintf("select %s from %s where mobile = ? limit 1", userRows, m.table) query := fmt.Sprintf("select %s from %s where user = ? limit 1", userRows, m.table)
if err := conn.QueryRow(&resp, query, mobile); err != nil { if err := conn.QueryRow(&resp, query, user); err != nil {
return nil, err return nil, err
} }
return resp.Id, nil return resp.Id, nil
}, m.queryPrimary) }, m.queryPrimary)
switch err { switch err {
case nil: case nil:
return &resp, nil return &resp, nil
case sqlc.ErrNotFound: case sqlc.ErrNotFound:
return nil, ErrNotFound return nil, ErrNotFound
default: default:
return nil, err return nil, err
} }
} }
func (m *UserModel) Update(data User) error { func (m *defaultUserModel) FindOneByName(name string) (*User, error) {
userIdKey := fmt.Sprintf("%s%v", cacheUserIdPrefix, data.Id) userNameKey := fmt.Sprintf("%s%v", cacheUserNamePrefix, name)
_, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) { var resp User
query := fmt.Sprintf("update %s set %s where id = ?", m.table, userRowsWithPlaceHolder) err := m.QueryRowIndex(&resp, userNameKey, m.formatPrimary, func(conn sqlx.SqlConn, v interface{}) (i interface{}, e error) {
return conn.Exec(query, data.Name, data.Password, data.Mobile, data.Gender, data.Nickname, data.Id) query := fmt.Sprintf("select %s from %s where name = ? limit 1", userRows, m.table)
}, userIdKey) if err := conn.QueryRow(&resp, query, name); err != nil {
return err return nil, err
} }
return resp.Id, nil
}, m.queryPrimary)
switch err {
case nil:
return &resp, nil
case sqlc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *UserModel) Delete(id int64) error { func (m *defaultUserModel) FindOneByMobile(mobile string) (*User, error) {
data, err := m.FindOne(id) userMobileKey := fmt.Sprintf("%s%v", cacheUserMobilePrefix, mobile)
if err != nil { var resp User
return err err := m.QueryRowIndex(&resp, userMobileKey, m.formatPrimary, func(conn sqlx.SqlConn, v interface{}) (i interface{}, e error) {
} query := fmt.Sprintf("select %s from %s where mobile = ? limit 1", userRows, m.table)
if err := conn.QueryRow(&resp, query, mobile); err != nil {
return nil, err
}
return resp.Id, nil
}, m.queryPrimary)
switch err {
case nil:
return &resp, nil
case sqlc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
userMobileKey := fmt.Sprintf("%s%v", cacheUserMobilePrefix, data.Mobile) func (m *defaultUserModel) Update(data User) error {
userIdKey := fmt.Sprintf("%s%v", cacheUserIdPrefix, id) userIdKey := fmt.Sprintf("%s%v", cacheUserIdPrefix, data.Id)
userNameKey := fmt.Sprintf("%s%v", cacheUserNamePrefix, data.Name) _, 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 id = ?", m.table, userRowsWithPlaceHolder)
query := fmt.Sprintf("delete from %s where id = ?", m.table) return conn.Exec(query, data.User, data.Name, data.Password, data.Mobile, data.Gender, data.Nickname, data.Id)
return conn.Exec(query, id) }, userIdKey)
}, userMobileKey, userIdKey, userNameKey) return err
return err }
}
func (m *UserModel) formatPrimary(primary interface{}) string { func (m *defaultUserModel) Delete(id int64) error {
return fmt.Sprintf("%s%v", cacheUserIdPrefix, primary) data, err := m.FindOne(id)
} if err != nil {
return err
}
userIdKey := fmt.Sprintf("%s%v", cacheUserIdPrefix, id)
userKey := fmt.Sprintf("%s%v", cacheUserPrefix, data.User)
userNameKey := fmt.Sprintf("%s%v", cacheUserNamePrefix, data.Name)
userMobileKey := fmt.Sprintf("%s%v", cacheUserMobilePrefix, data.Mobile)
_, err = m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("delete from %s where id = ?", m.table)
return conn.Exec(query, id)
}, userIdKey, userKey, userNameKey, userMobileKey)
return err
}
func (m *defaultUserModel) formatPrimary(primary interface{}) string {
return fmt.Sprintf("%s%v", cacheUserIdPrefix, primary)
}
func (m *defaultUserModel) queryPrimary(conn sqlx.SqlConn, v, primary interface{}) error {
query := fmt.Sprintf("select %s from %s where id = ? limit 1", userRows, m.table)
return conn.QueryRow(v, query, primary)
}
func (m *UserModel) queryPrimary(conn sqlx.SqlConn, v, primary interface{}) error {
query := fmt.Sprintf("select %s from %s where id = ? limit 1", userRows, m.table)
return conn.QueryRow(v, query, primary)
}
``` ```
## 用法 ## 用法
@@ -211,25 +246,24 @@ OPTIONS:
* ddl * ddl
```shell script ```shell script
goctl model mysql -src={patterns} -dir={dir} -cache=true goctl model mysql -src={patterns} -dir={dir} -cache
``` ```
help help
``` ```
NAME: NAME:
goctl model mysql ddl - generate mysql model from ddl goctl model mysql ddl - generate mysql model from ddl
USAGE: USAGE:
goctl model mysql ddl [command options] [arguments...] goctl model mysql ddl [command options] [arguments...]
OPTIONS:
--src value, -s value the path or path globbing patterns of the ddl
--dir value, -d value the target dir
--style value the file naming style, lower|camel|underline,default is lower
--cache, -c generate code with cache [optional]
--idea for idea plugin [optional]
OPTIONS:
--src value, -s value the path or path globbing patterns of the ddl
--dir value, -d value the target dir
--style value the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]
--cache, -c generate code with cache [optional]
--idea for idea plugin [optional]
``` ```
* datasource * datasource
@@ -242,18 +276,19 @@ OPTIONS:
``` ```
NAME: NAME:
goctl model mysql datasource - generate model from datasource goctl model mysql datasource - generate model from datasource
USAGE: USAGE:
goctl model mysql datasource [command options] [arguments...] goctl model mysql datasource [command options] [arguments...]
OPTIONS:
--url value the data source of database,like "root:password@tcp(127.0.0.1:3306)/database
--table value, -t value the table or table globbing patterns in the database
--cache, -c generate code with cache [optional]
--dir value, -d value the target dir
--style value the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]
--idea for idea plugin [optional]
OPTIONS:
--url value the data source of database,like "root:password@tcp(127.0.0.1:3306)/database
--table value, -t value the table or table globbing patterns in the database
--cache, -c generate code with cache [optional]
--dir value, -d value the target dir
--style value the file naming style, lower|camel|snake, default is lower
--idea for idea plugin [optional]
``` ```
@@ -281,13 +316,13 @@ OPTIONS:
* ddl * ddl
```shell script ```shell script
goctl model -src={patterns} -dir={dir} -cache=false goctl model -src={patterns} -dir={dir}
``` ```
* datasource * datasource
```shell script ```shell script
goctl model mysql datasource -url={datasource} -table={patterns} -dir={dir} -cache=false goctl model mysql datasource -url={datasource} -table={patterns} -dir={dir}
``` ```
生成代码仅基本的CURD结构。 生成代码仅基本的CURD结构。
@@ -312,3 +347,33 @@ OPTIONS:
目前我认为除了基本的CURD外其他的代码均属于<i>业务型</i>代码,这个我觉得开发人员根据业务需要进行编写更好。 目前我认为除了基本的CURD外其他的代码均属于<i>业务型</i>代码,这个我觉得开发人员根据业务需要进行编写更好。
# 类型转换规则
| mysql dataType | golang dataType | golang dataType(if null&&default null) |
|----------------|-----------------|----------------------------------------|
| bool | int64 | sql.NullInt64 |
| boolean | int64 | sql.NullInt64 |
| tinyint | int64 | sql.NullInt64 |
| smallint | int64 | sql.NullInt64 |
| mediumint | int64 | sql.NullInt64 |
| int | int64 | sql.NullInt64 |
| integer | int64 | sql.NullInt64 |
| bigint | int64 | sql.NullInt64 |
| float | float64 | sql.NullFloat64 |
| double | float64 | sql.NullFloat64 |
| decimal | float64 | sql.NullFloat64 |
| date | time.Time | sql.NullTime |
| datetime | time.Time | sql.NullTime |
| timestamp | time.Time | sql.NullTime |
| time | string | sql.NullString |
| year | time.Time | sql.NullInt64 |
| char | string | sql.NullString |
| varchar | string | sql.NullString |
| binary | string | sql.NullString |
| varbinary | string | sql.NullString |
| tinytext | string | sql.NullString |
| text | string | sql.NullString |
| mediumtext | string | sql.NullString |
| longtext | string | sql.NullString |
| enum | string | sql.NullString |
| set | string | sql.NullString |
| json | string | sql.NullString |

View File

@@ -68,30 +68,3 @@ func FieldNames(in interface{}) []string {
} }
return out return out
} }
func FieldNamesAlias(in interface{}, alias string) []string {
out := make([]string, 0)
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)
tagName := ""
if tagv := fi.Tag.Get(dbTag); tagv != "" {
tagName = tagv
} else {
tagName = fi.Name
}
if len(alias) > 0 {
tagName = alias + "." + tagName
}
out = append(out, tagName)
}
return out
}

View File

@@ -2,7 +2,6 @@ package command
import ( import (
"errors" "errors"
"fmt"
"io/ioutil" "io/ioutil"
"path/filepath" "path/filepath"
"strings" "strings"
@@ -10,6 +9,7 @@ import (
"github.com/go-sql-driver/mysql" "github.com/go-sql-driver/mysql"
"github.com/tal-tech/go-zero/core/logx" "github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/core/stores/sqlx" "github.com/tal-tech/go-zero/core/stores/sqlx"
"github.com/tal-tech/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/model/sql/gen" "github.com/tal-tech/go-zero/tools/goctl/model/sql/gen"
"github.com/tal-tech/go-zero/tools/goctl/model/sql/model" "github.com/tal-tech/go-zero/tools/goctl/model/sql/model"
"github.com/tal-tech/go-zero/tools/goctl/model/sql/util" "github.com/tal-tech/go-zero/tools/goctl/model/sql/util"
@@ -17,14 +17,16 @@ import (
"github.com/urfave/cli" "github.com/urfave/cli"
) )
var errNotMatched = errors.New("sql not matched")
const ( const (
flagSrc = "src" flagSrc = "src"
flagDir = "dir" flagDir = "dir"
flagCache = "cache" flagCache = "cache"
flagIdea = "idea" flagIdea = "idea"
flagStyle = "style"
flagUrl = "url" flagUrl = "url"
flagTable = "table" flagTable = "table"
flagStyle = "style"
) )
func MysqlDDL(ctx *cli.Context) error { func MysqlDDL(ctx *cli.Context) error {
@@ -32,49 +34,64 @@ func MysqlDDL(ctx *cli.Context) error {
dir := ctx.String(flagDir) dir := ctx.String(flagDir)
cache := ctx.Bool(flagCache) cache := ctx.Bool(flagCache)
idea := ctx.Bool(flagIdea) idea := ctx.Bool(flagIdea)
namingStyle := strings.TrimSpace(ctx.String(flagStyle)) style := ctx.String(flagStyle)
cfg, err := config.NewConfig(style)
if err != nil {
return err
}
return fromDDl(src, dir, cfg, cache, idea)
}
func MyDataSource(ctx *cli.Context) error {
url := strings.TrimSpace(ctx.String(flagUrl))
dir := strings.TrimSpace(ctx.String(flagDir))
cache := ctx.Bool(flagCache)
idea := ctx.Bool(flagIdea)
style := ctx.String(flagStyle)
pattern := strings.TrimSpace(ctx.String(flagTable))
cfg, err := config.NewConfig(style)
if err != nil {
return err
}
return fromDataSource(url, pattern, dir, cfg, cache, idea)
}
func fromDDl(src, dir string, cfg *config.Config, cache, idea bool) error {
log := console.NewConsole(idea) log := console.NewConsole(idea)
src = strings.TrimSpace(src) src = strings.TrimSpace(src)
if len(src) == 0 { if len(src) == 0 {
return errors.New("expected path or path globbing patterns, but nothing found") return errors.New("expected path or path globbing patterns, but nothing found")
} }
switch namingStyle {
case gen.NamingLower, gen.NamingCamel, gen.NamingSnake:
case "":
namingStyle = gen.NamingLower
default:
return fmt.Errorf("unexpected naming style: %s", namingStyle)
}
files, err := util.MatchFiles(src) files, err := util.MatchFiles(src)
if err != nil { if err != nil {
return err return err
} }
if len(files) == 0 {
return errNotMatched
}
var source []string var source []string
for _, file := range files { for _, file := range files {
data, err := ioutil.ReadFile(file) data, err := ioutil.ReadFile(file)
if err != nil { if err != nil {
return err return err
} }
source = append(source, string(data)) source = append(source, string(data))
} }
generator := gen.NewDefaultGenerator(strings.Join(source, "\n"), dir, namingStyle, gen.WithConsoleOption(log)) generator, err := gen.NewDefaultGenerator(dir, cfg, gen.WithConsoleOption(log))
err = generator.Start(cache)
if err != nil { if err != nil {
log.Error("%v", err) return err
} }
return nil
err = generator.StartFromDDL(strings.Join(source, "\n"), cache)
return err
} }
func MyDataSource(ctx *cli.Context) error { func fromDataSource(url, pattern, dir string, cfg *config.Config, cache, idea bool) error {
url := strings.TrimSpace(ctx.String(flagUrl))
dir := strings.TrimSpace(ctx.String(flagDir))
cache := ctx.Bool(flagCache)
idea := ctx.Bool(flagIdea)
namingStyle := strings.TrimSpace(ctx.String(flagStyle))
pattern := strings.TrimSpace(ctx.String(flagTable))
log := console.NewConsole(idea) log := console.NewConsole(idea)
if len(url) == 0 { if len(url) == 0 {
log.Error("%v", "expected data source of mysql, but nothing found") log.Error("%v", "expected data source of mysql, but nothing found")
@@ -86,32 +103,22 @@ func MyDataSource(ctx *cli.Context) error {
return nil return nil
} }
switch namingStyle { dsn, err := mysql.ParseDSN(url)
case gen.NamingLower, gen.NamingCamel, gen.NamingSnake:
case "":
namingStyle = gen.NamingLower
default:
return fmt.Errorf("unexpected naming style: %s", namingStyle)
}
cfg, err := mysql.ParseDSN(url)
if err != nil { if err != nil {
return err return err
} }
logx.Disable() logx.Disable()
conn := sqlx.NewMysql(url) databaseSource := strings.TrimSuffix(url, "/"+dsn.DBName) + "/information_schema"
databaseSource := strings.TrimSuffix(url, "/"+cfg.DBName) + "/information_schema"
db := sqlx.NewMysql(databaseSource) db := sqlx.NewMysql(databaseSource)
m := model.NewDDLModel(conn)
im := model.NewInformationSchemaModel(db) im := model.NewInformationSchemaModel(db)
tables, err := im.GetAllTables(cfg.DBName) tables, err := im.GetAllTables(dsn.DBName)
if err != nil { if err != nil {
return err return err
} }
var matchTables []string matchTables := make(map[string][]*model.Column)
for _, item := range tables { for _, item := range tables {
match, err := filepath.Match(pattern, item) match, err := filepath.Match(pattern, item)
if err != nil { if err != nil {
@@ -121,24 +128,22 @@ func MyDataSource(ctx *cli.Context) error {
if !match { if !match {
continue continue
} }
columns, err := im.FindByTableName(dsn.DBName, item)
matchTables = append(matchTables, item) if err != nil {
return err
}
matchTables[item] = columns
} }
if len(matchTables) == 0 { if len(matchTables) == 0 {
return errors.New("no tables matched") return errors.New("no tables matched")
} }
ddl, err := m.ShowDDL(matchTables...) generator, err := gen.NewDefaultGenerator(dir, cfg, gen.WithConsoleOption(log))
if err != nil { if err != nil {
log.Error("%v", err) return err
return nil
} }
generator := gen.NewDefaultGenerator(strings.Join(ddl, "\n"), dir, namingStyle, gen.WithConsoleOption(log)) err = generator.StartFromInformationSchema(dsn.DBName, matchTables, cache)
err = generator.Start(cache) return err
if err != nil {
log.Error("%v", err)
}
return nil
} }

View File

@@ -0,0 +1,71 @@
package command
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util"
)
var sql = "-- 用户表 --\nCREATE TABLE `user` (\n `id` bigint(10) NOT NULL AUTO_INCREMENT,\n `name` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户名称',\n `password` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户密码',\n `mobile` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '手机号',\n `gender` char(5) COLLATE utf8mb4_general_ci NOT NULL COMMENT '男|女|未公开',\n `nickname` varchar(255) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '用户昵称',\n `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,\n `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n PRIMARY KEY (`id`),\n UNIQUE KEY `name_index` (`name`),\n UNIQUE KEY `mobile_index` (`mobile`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;\n\n"
var cfg = &config.Config{
NamingFormat: "gozero",
}
func TestFromDDl(t *testing.T) {
err := fromDDl("./user.sql", t.TempDir(), cfg, true, false)
assert.Equal(t, errNotMatched, err)
// case dir is not exists
unknownDir := filepath.Join(t.TempDir(), "test", "user.sql")
err = fromDDl(unknownDir, t.TempDir(), cfg, true, false)
assert.True(t, func() bool {
switch err.(type) {
case *os.PathError:
return true
default:
return false
}
}())
// case empty src
err = fromDDl("", t.TempDir(), cfg, true, false)
if err != nil {
assert.Equal(t, "expected path or path globbing patterns, but nothing found", err.Error())
}
tempDir := filepath.Join(t.TempDir(), "test")
err = util.MkdirIfNotExist(tempDir)
if err != nil {
return
}
user1Sql := filepath.Join(tempDir, "user1.sql")
user2Sql := filepath.Join(tempDir, "user2.sql")
err = ioutil.WriteFile(user1Sql, []byte(sql), os.ModePerm)
if err != nil {
return
}
err = ioutil.WriteFile(user2Sql, []byte(sql), os.ModePerm)
if err != nil {
return
}
_, err = os.Stat(user1Sql)
assert.Nil(t, err)
_, err = os.Stat(user2Sql)
assert.Nil(t, err)
err = fromDDl(filepath.Join(tempDir, "user*.sql"), tempDir, cfg, true, false)
assert.Nil(t, err)
_, err = os.Stat(filepath.Join(tempDir, "usermodel.go"))
assert.Nil(t, err)
}

View File

@@ -41,12 +41,34 @@ var (
} }
) )
func ConvertDataType(dataBaseType string) (goDataType string, err error) { func ConvertDataType(dataBaseType string, isDefaultNull bool) (string, error) {
tp, ok := commonMysqlDataTypeMap[strings.ToLower(dataBaseType)] tp, ok := commonMysqlDataTypeMap[strings.ToLower(dataBaseType)]
if !ok { if !ok {
err = fmt.Errorf("unexpected database type: %s", dataBaseType) return "", fmt.Errorf("unexpected database type: %s", dataBaseType)
return }
return mayConvertNullType(tp, isDefaultNull), nil
}
func mayConvertNullType(goDataType string, isDefaultNull bool) string {
if !isDefaultNull {
return goDataType
}
switch goDataType {
case "int64":
return "sql.NullInt64"
case "int32":
return "sql.NullInt32"
case "float64":
return "sql.NullFloat64"
case "bool":
return "sql.NullBool"
case "string":
return "sql.NullString"
case "time.Time":
return "sql.NullTime"
default:
return goDataType
} }
goDataType = tp
return
} }

View File

@@ -7,14 +7,22 @@ import (
) )
func TestConvertDataType(t *testing.T) { func TestConvertDataType(t *testing.T) {
v, err := ConvertDataType("tinyint") v, err := ConvertDataType("tinyint", false)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, "int64", v) assert.Equal(t, "int64", v)
v, err = ConvertDataType("timestamp") v, err = ConvertDataType("tinyint", true)
assert.Nil(t, err)
assert.Equal(t, "sql.NullInt64", v)
v, err = ConvertDataType("timestamp", false)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, "time.Time", v) assert.Equal(t, "time.Time", v)
_, err = ConvertDataType("float32") v, err = ConvertDataType("timestamp", true)
assert.Nil(t, err)
assert.Equal(t, "sql.NullTime", v)
_, err = ConvertDataType("float32", false)
assert.NotNil(t, err) assert.NotNil(t, err)
} }

View File

@@ -1,11 +0,0 @@
#!/bin/bash
# generate model with cache from ddl
goctl model mysql ddl -src="./sql/*.sql" -dir="./sql/model/user" -c
# generate model with cache from data source
#user=root
#password=password
#datasource=127.0.0.1:3306
#database=test
#goctl model mysql datasource -url="${user}:${password}@tcp(${datasource})/${database}" -table="*" -dir ./model

View File

@@ -0,0 +1,15 @@
#!/bin/bash
# generate model with cache from ddl
fromDDL:
goctl model mysql ddl -src="./sql/*.sql" -dir="./sql/model/user" -cache
# generate model with cache from data source
user=root
password=password
datasource=127.0.0.1:3306
database=gozero
fromDataSource:
goctl model mysql datasource -url="$(user):$(password)@tcp($(datasource))/$(database)" -table="*" -dir ./model/cache -c -style gozero

View File

@@ -1,6 +1,7 @@
-- 用户表 -- -- 用户表 --
CREATE TABLE `user` ( CREATE TABLE `user` (
`id` bigint(10) NOT NULL AUTO_INCREMENT, `id` bigint(10) NOT NULL AUTO_INCREMENT,
`user` varchar(50) NOT NULL DEFAULT '' COMMENT '用户',
`name` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户名称', `name` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户名称',
`password` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户密码', `password` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户密码',
`mobile` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '手机号', `mobile` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '手机号',
@@ -10,6 +11,16 @@ CREATE TABLE `user` (
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY `name_index` (`name`), UNIQUE KEY `name_index` (`name`),
UNIQUE KEY `user_index` (`user`),
UNIQUE KEY `mobile_index` (`mobile`) UNIQUE KEY `mobile_index` (`mobile`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE `student` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8mb4_bin NOT NULL DEFAULT '',
`age` tinyint DEFAULT NULL,
`score` float(10,0) DEFAULT NULL,
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

View File

@@ -1,15 +0,0 @@
-- 用户表 --
CREATE TABLE `user1` (
`id` bigint(10) NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户名称',
`password` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户密码',
`mobile` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '手机号',
`gender` char(5) COLLATE utf8mb4_general_ci NOT NULL COMMENT '男|女|未公开',
`nickname` varchar(255) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '用户昵称',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `name_index` (`name`),
UNIQUE KEY `mobile_index` (`mobile`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

View File

@@ -9,7 +9,7 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/util/stringx" "github.com/tal-tech/go-zero/tools/goctl/util/stringx"
) )
func genDelete(table Table, withCache bool) (string, error) { func genDelete(table Table, withCache bool) (string, string, error) {
keySet := collection.NewSet() keySet := collection.NewSet()
keyVariableSet := collection.NewSet() keyVariableSet := collection.NewSet()
for fieldName, key := range table.CacheKey { for fieldName, key := range table.CacheKey {
@@ -24,7 +24,7 @@ func genDelete(table Table, withCache bool) (string, error) {
camel := table.Name.ToCamel() camel := table.Name.ToCamel()
text, err := util.LoadTemplate(category, deleteTemplateFile, template.Delete) text, err := util.LoadTemplate(category, deleteTemplateFile, template.Delete)
if err != nil { if err != nil {
return "", err return "", "", err
} }
output, err := util.With("delete"). output, err := util.With("delete").
@@ -33,14 +33,30 @@ func genDelete(table Table, withCache bool) (string, error) {
"upperStartCamelObject": camel, "upperStartCamelObject": camel,
"withCache": withCache, "withCache": withCache,
"containsIndexCache": table.ContainsUniqueKey, "containsIndexCache": table.ContainsUniqueKey,
"lowerStartCamelPrimaryKey": stringx.From(table.PrimaryKey.Name.ToCamel()).UnTitle(), "lowerStartCamelPrimaryKey": stringx.From(table.PrimaryKey.Name.ToCamel()).Untitle(),
"dataType": table.PrimaryKey.DataType, "dataType": table.PrimaryKey.DataType,
"keys": strings.Join(keySet.KeysStr(), "\n"), "keys": strings.Join(keySet.KeysStr(), "\n"),
"originalPrimaryKey": table.PrimaryKey.Name.Source(), "originalPrimaryKey": table.PrimaryKey.Name.Source(),
"keyValues": strings.Join(keyVariableSet.KeysStr(), ", "), "keyValues": strings.Join(keyVariableSet.KeysStr(), ", "),
}) })
if err != nil { if err != nil {
return "", err return "", "", err
} }
return output.String(), nil
// interface method
text, err = util.LoadTemplate(category, deleteMethodTemplateFile, template.DeleteMethod)
if err != nil {
return "", "", err
}
deleteMethodOut, err := util.With("deleteMethod").
Parse(text).
Execute(map[string]interface{}{
"lowerStartCamelPrimaryKey": stringx.From(table.PrimaryKey.Name.ToCamel()).Untitle(),
"dataType": table.PrimaryKey.DataType,
})
if err != nil {
return "", "", err
}
return output.String(), deleteMethodOut.String(), nil
} }

View File

@@ -15,6 +15,7 @@ func genFields(fields []parser.Field) (string, error) {
if err != nil { if err != nil {
return "", err return "", err
} }
list = append(list, result) list = append(list, result)
} }
return strings.Join(list, "\n"), nil return strings.Join(list, "\n"), nil
@@ -43,5 +44,6 @@ func genField(field parser.Field) (string, error) {
if err != nil { if err != nil {
return "", err return "", err
} }
return output.String(), nil return output.String(), nil
} }

Some files were not shown because too many files have changed in this diff Show More