Compare commits

...

26 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
84 changed files with 1895 additions and 1119 deletions

View File

@@ -74,27 +74,29 @@ func (rw *RollingWindow) span() int {
func (rw *RollingWindow) updateOffset() {
span := rw.span()
if span > 0 {
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()
if span <= 0 {
return
}
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 {
@@ -118,9 +120,9 @@ type window struct {
}
func newWindow(size int) *window {
var buckets []*Bucket
buckets := make([]*Bucket, size)
for i := 0; i < size; i++ {
buckets = append(buckets, new(Bucket))
buckets[i] = new(Bucket)
}
return &window{
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)) {
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) {
w.buckets[offset].reset()
w.buckets[offset%w.size].reset()
}
func IgnoreCurrentBucket() RollingWindowOption {

View File

@@ -21,6 +21,7 @@ var mock tracespec.Trace = new(mockTrace)
func TestTraceLog(t *testing.T) {
var buf mockWriter
atomic.StoreUint32(&initialized, 1)
ctx := context.WithValue(context.Background(), tracespec.TracingKey, mock)
WithContext(ctx).(*traceLogger).write(&buf, levelInfo, testlog)
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])
options := segments[1:]
if len(options) > 0 {
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
if len(options) == 0 {
return key, nil, 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) {

View File

@@ -556,7 +556,7 @@ func TestRedis_SortedSet(t *testing.T) {
val, err = client.Zscore("key", "value1")
assert.Nil(t, err)
assert.Equal(t, int64(5), val)
val, err = NewRedis(client.Addr, "").Zadds("key")
_, err = NewRedis(client.Addr, "").Zadds("key")
assert.NotNil(t, err)
val, err = client.Zadds("key", Pair{
Key: "value2",
@@ -567,9 +567,9 @@ func TestRedis_SortedSet(t *testing.T) {
})
assert.Nil(t, err)
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)
pairs, err = client.ZRevRangeWithScores("key", 1, 3)
pairs, err := client.ZRevRangeWithScores("key", 1, 3)
assert.Nil(t, err)
assert.EqualValues(t, []Pair{
{

View File

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

View File

@@ -10,7 +10,7 @@ import (
"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) {
var req types.AddReq
if err := httpx.Parse(r, &req); err != nil {

View File

@@ -10,7 +10,7 @@ import (
"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) {
var req types.CheckReq
if err := httpx.Parse(r, &req); err != nil {

View File

@@ -10,16 +10,18 @@ import (
)
func RegisterHandlers(engine *rest.Server, serverCtx *svc.ServiceContext) {
engine.AddRoutes([]rest.Route{
{
Method: http.MethodGet,
Path: "/add",
Handler: addHandler(serverCtx),
engine.AddRoutes(
[]rest.Route{
{
Method: http.MethodGet,
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,
})
if err != nil {
return nil, err
logx.Error(err)
return &types.CheckResp{}, err
}
return &types.CheckResp{

View File

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

View File

@@ -7,8 +7,8 @@ import (
"flag"
"fmt"
"bookstore/rpc/add/add"
"bookstore/rpc/add/internal/config"
add "bookstore/rpc/add/internal/pb"
"bookstore/rpc/add/internal/server"
"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 (
"context"
add "bookstore/rpc/add/internal/pb"
"bookstore/rpc/add/add"
"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) {
adder := add.NewAdderClient(m.cli.Conn())
return adder.Add(ctx, in)
client := add.NewAdderClient(m.cli.Conn())
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 {
zrpc.RpcServerConf
DataSource string
Table string
Cache cache.CacheConf
}

View File

@@ -3,7 +3,7 @@ package logic
import (
"context"
add "bookstore/rpc/add/internal/pb"
add "bookstore/rpc/add/adder"
"bookstore/rpc/add/internal/svc"
"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 (
"context"
"bookstore/rpc/add/add"
"bookstore/rpc/add/internal/logic"
add "bookstore/rpc/add/internal/pb"
"bookstore/rpc/add/internal/svc"
)

View File

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

View File

@@ -7,8 +7,8 @@ import (
"flag"
"fmt"
"bookstore/rpc/check/check"
"bookstore/rpc/check/internal/config"
check "bookstore/rpc/check/internal/pb"
"bookstore/rpc/check/internal/server"
"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 (
"context"
check "bookstore/rpc/check/internal/pb"
"bookstore/rpc/check/check"
"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) {
checker := check.NewCheckerClient(m.cli.Conn())
return checker.Check(ctx, in)
client := check.NewCheckerClient(m.cli.Conn())
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 {
zrpc.RpcServerConf
DataSource string
Table string
Cache cache.CacheConf
}

View File

@@ -3,7 +3,7 @@ package logic
import (
"context"
check "bookstore/rpc/check/internal/pb"
check "bookstore/rpc/check/checker"
"bookstore/rpc/check/internal/svc"
"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 (
"context"
"bookstore/rpc/check/check"
"bookstore/rpc/check/internal/logic"
check "bookstore/rpc/check/internal/pb"
"bookstore/rpc/check/internal/svc"
)

View File

@@ -9,12 +9,12 @@ import (
type ServiceContext struct {
c config.Config
Model *model.BookModel
Model model.BookModel
}
func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
c: c,
Model: model.NewBookModel(sqlx.NewMysql(c.DataSource), c.Cache, c.Table),
c: c,
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"), ",")
bookRowsWithPlaceHolder = strings.Join(stringx.Remove(bookFieldNames, "book", "create_time", "update_time"), "=?,") + "=?"
bookPrefix = "cache#Book#book#"
cacheBookPrefix = "cache#Book#book#"
)
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
table string
}
@@ -33,23 +40,25 @@ type (
}
)
func NewBookModel(conn sqlx.SqlConn, c cache.CacheConf, table string) *BookModel {
return &BookModel{
func NewBookModel(conn sqlx.SqlConn, c cache.CacheConf) BookModel {
return &defaultBookModel{
CachedConn: sqlc.NewConn(conn, c),
table: table,
table: "book",
}
}
func (m *BookModel) Insert(data Book) (sql.Result, error) {
query := `insert into ` + m.table + ` (` + bookRowsExpectAutoSet + `) values (?, ?)`
return m.ExecNoCache(query, data.Book, data.Price)
func (m *defaultBookModel) Insert(data Book) (sql.Result, error) {
query := fmt.Sprintf("insert into %s (%s) values (?, ?)", m.table, bookRowsExpectAutoSet)
ret, err := m.ExecNoCache(query, data.Book, data.Price)
return ret, err
}
func (m *BookModel) FindOne(book string) (*Book, error) {
bookKey := fmt.Sprintf("%s%v", bookPrefix, book)
func (m *defaultBookModel) FindOne(book string) (*Book, error) {
bookKey := fmt.Sprintf("%s%v", cacheBookPrefix, book)
var resp Book
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)
})
switch err {
@@ -62,20 +71,30 @@ func (m *BookModel) FindOne(book string) (*Book, error) {
}
}
func (m *BookModel) Update(data Book) error {
bookKey := fmt.Sprintf("%s%v", bookPrefix, data.Book)
func (m *defaultBookModel) Update(data Book) error {
bookKey := fmt.Sprintf("%s%v", cacheBookPrefix, data.Book)
_, 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)
}, bookKey)
return err
}
func (m *BookModel) Delete(book string) error {
bookKey := fmt.Sprintf("%s%v", bookPrefix, book)
func (m *defaultBookModel) Delete(book string) error {
bookKey := fmt.Sprintf("%s%v", cacheBookPrefix, book)
_, 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)
}, bookKey)
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

@@ -37,6 +37,7 @@ 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/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 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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -49,6 +50,7 @@ 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/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/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.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@@ -131,6 +133,7 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
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/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
@@ -220,6 +223,7 @@ 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/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.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/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
@@ -252,6 +256,7 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6/go.mod h1
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/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/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=

7
go.mod
View File

@@ -1,6 +1,6 @@
module github.com/tal-tech/go-zero
go 1.13
go 1.14
require (
github.com/ClickHouse/clickhouse-go v1.4.3
@@ -11,6 +11,7 @@ require (
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/emicklei/proto v1.9.0
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/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8
github.com/go-redis/redis v6.15.7+incompatible
@@ -55,10 +56,10 @@ require (
golang.org/x/tools v0.0.0-20200410132612-ae9902aceb98 // indirect
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f // indirect
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/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
sigs.k8s.io/yaml v1.2.0 // indirect
)

6
go.sum
View File

@@ -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.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
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/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
@@ -450,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.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
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=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
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-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
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:
```shell
goctl api -o greet.api
goctl api -o greet.api
```
3. generate the go server side code

View File

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

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 {
pr.handleNotFound(w, r)
return
@@ -73,7 +73,7 @@ func (pr *patRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if pr.notAllowed != nil {
pr.notAllowed.ServeHTTP(w, r)
} else {
w.Header().Set(allowHeader, allow)
w.Header().Set(allowHeader, allows)
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
for treeMethod, tree := range pr.trees {

View File

@@ -25,7 +25,7 @@ info(
// TODO: test
// {
type Request struct { // TODO: test
// TOOD
// TODO
Name string ` + "`" + `path:"name,options=you|me"` + "`" + ` // }
} // TODO: test

View File

@@ -75,7 +75,8 @@ func genHandler(dir string, cfg *config.Config, group spec.Group, route spec.Rou
})
}
func doGenToFile(dir, handler string, cfg *config.Config, group spec.Group, route spec.Route, handleObj Handler) error {
func doGenToFile(dir, handler string, cfg *config.Config, group spec.Group,
route spec.Route, handleObj Handler) error {
filename, err := format.FileNamingFormat(cfg.NamingFormat, handler)
if err != nil {
return err

View File

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

View File

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

View File

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

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

View File

@@ -2,33 +2,72 @@ package docker
import (
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"text/template"
"time"
"github.com/logrusorgru/aurora"
"github.com/tal-tech/go-zero/tools/goctl/util"
ctlutil "github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/urfave/cli"
)
const (
etcDir = "etc"
yamlEtx = ".yaml"
dockerfileName = "Dockerfile"
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")
if len(goFile) == 0 {
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)
if err != nil {
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) {
@@ -60,18 +99,22 @@ func findConfig(file, dir string) (string, error) {
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))
if err != nil {
return err
}
pos := strings.IndexByte(projPath, '/')
if pos >= 0 {
projPath = projPath[pos+1:]
if len(projPath) == 0 {
projPath = "."
} 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 {
return err
}
@@ -87,12 +130,16 @@ func generateDockerfile(goFile string, args ...string) error {
builder.WriteString(`, "` + arg + `"`)
}
_, offset := time.Now().Zone()
t := template.Must(template.New("dockerfile").Parse(text))
return t.Execute(out, map[string]string{
"goRelPath": projPath,
"goFile": goFile,
"exeFile": util.FileNameWithoutExt(filepath.Base(goFile)),
"argument": builder.String(),
return t.Execute(out, Docker{
Chinese: offset == cstOffset,
GoRelPath: projPath,
GoFile: goFile,
ExeFile: util.FileNameWithoutExt(filepath.Base(goFile)),
HasPort: port > 0,
Port: port,
Argument: builder.String(),
})
}

View File

@@ -14,31 +14,59 @@ LABEL stage=gobuilder
ENV CGO_ENABLED 0
ENV GOOS linux
ENV GOPROXY https://goproxy.cn,direct
{{if .Chinese}}ENV GOPROXY https://goproxy.cn,direct
{{end}}
WORKDIR /build/zero
ADD go.mod .
ADD go.sum .
RUN go mod download
COPY . .
RUN sh -c "[ -f go.mod ]" || exit
COPY {{.goRelPath}}/etc /app/etc
RUN go build -ldflags="-s -w" -o /app/{{.exeFile}} {{.goRelPath}}/{{.goFile}}
{{if .Argument}}COPY {{.GoRelPath}}/etc /app/etc
{{end}}RUN go build -ldflags="-s -w" -o /app/{{.ExeFile}} {{.GoRelPath}}/{{.GoFile}}
FROM alpine
RUN apk update --no-cache
RUN apk add --no-cache ca-certificates
RUN apk add --no-cache tzdata
RUN apk update --no-cache && apk add --no-cache ca-certificates tzdata
ENV TZ Asia/Shanghai
WORKDIR /app
COPY --from=builder /app/{{.exeFile}} /app/{{.exeFile}}
COPY --from=builder /app/etc /app/etc
CMD ["./{{.exeFile}}"{{.argument}}]
COPY --from=builder /app/{{.ExeFile}} /app/{{.ExeFile}}{{if .Argument}}
COPY --from=builder /app/etc /app/etc{{end}}
{{if .HasPort}}
EXPOSE {{.Port}}
{{end}}
CMD ["./{{.ExeFile}}"{{.Argument}}]
`
)
func Clean() error {
return util.Clean(category)
}
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{
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/configgen"
"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"
"github.com/tal-tech/go-zero/tools/goctl/plugin"
rpc "github.com/tal-tech/go-zero/tools/goctl/rpc/cli"
"github.com/tal-tech/go-zero/tools/goctl/tpl"
"github.com/urfave/cli"
)
var (
BuildVersion = "20201125"
BuildVersion = "1.1.1"
commands = []cli.Command{
{
Name: "api",
@@ -52,14 +54,12 @@ var (
Usage: "the format target dir",
},
cli.BoolFlag{
Name: "iu",
Usage: "ignore update",
Required: false,
Name: "iu",
Usage: "ignore update",
},
cli.BoolFlag{
Name: "stdin",
Usage: "use stdin to input api doc content, press \"ctrl + d\" to send EOF",
Required: false,
Name: "stdin",
Usage: "use stdin to input api doc content, press \"ctrl + d\" to send EOF",
},
},
Action: format.GoFormatApi,
@@ -99,9 +99,8 @@ var (
Usage: "the api file",
},
cli.StringFlag{
Name: "style",
Required: false,
Usage: "the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]",
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,
@@ -134,19 +133,16 @@ var (
Usage: "the api file",
},
cli.StringFlag{
Name: "webapi",
Usage: "the web api file path",
Required: false,
Name: "webapi",
Usage: "the web api file path",
},
cli.StringFlag{
Name: "caller",
Usage: "the web api caller",
Required: false,
Name: "caller",
Usage: "the web api caller",
},
cli.BoolFlag{
Name: "unwrap",
Usage: "unwrap the webapi caller for import",
Required: false,
Name: "unwrap",
Usage: "unwrap the webapi caller for import",
},
},
Action: tsgen.TsCommand,
@@ -185,6 +181,29 @@ var (
},
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,
},
},
},
{
@@ -195,9 +214,101 @@ var (
Name: "go",
Usage: "the file that contains main function",
},
cli.IntFlag{
Name: "port",
Usage: "the port to expose, default none",
Value: 0,
},
},
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",
Usage: "generate rpc code",
@@ -207,9 +318,8 @@ var (
Usage: `generate rpc demo service`,
Flags: []cli.Flag{
cli.StringFlag{
Name: "style",
Required: false,
Usage: "the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]",
Name: "style",
Usage: "the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]",
},
cli.BoolFlag{
Name: "idea",
@@ -246,9 +356,8 @@ var (
Usage: `the target path of the code`,
},
cli.StringFlag{
Name: "style",
Required: false,
Usage: "the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]",
Name: "style",
Usage: "the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]",
},
cli.BoolFlag{
Name: "idea",
@@ -280,9 +389,8 @@ var (
Usage: "the target dir",
},
cli.StringFlag{
Name: "style",
Required: false,
Usage: "the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]",
Name: "style",
Usage: "the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]",
},
cli.BoolFlag{
Name: "cache, c",
@@ -316,9 +424,8 @@ var (
Usage: "the target dir",
},
cli.StringFlag{
Name: "style",
Required: false,
Usage: "the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]",
Name: "style",
Usage: "the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]",
},
cli.BoolFlag{
Name: "idea",
@@ -362,7 +469,7 @@ var (
Flags: []cli.Flag{
cli.StringFlag{
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,
@@ -373,7 +480,7 @@ var (
Flags: []cli.Flag{
cli.StringFlag{
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{
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

@@ -78,8 +78,8 @@ goctl model 为go-zero下的工具模块中的组件之一目前支持识别m
Password string `db:"password"` // 用户密码
Mobile string `db:"mobile"` // 手机号
Gender string `db:"gender"` // 男|女|未公开
Nickname string `db:"nickname"` // 用户昵称
CreateTime time.Time `db:"create_time"`
Nickname sql.NullString `db:"nickname"` // 用户昵称
CreateTime sql.NullTime `db:"create_time"`
UpdateTime time.Time `db:"update_time"`
}
)
@@ -347,3 +347,33 @@ OPTIONS:
目前我认为除了基本的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

@@ -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)]
if !ok {
err = fmt.Errorf("unexpected database type: %s", dataBaseType)
return
return "", fmt.Errorf("unexpected database type: %s", dataBaseType)
}
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) {
v, err := ConvertDataType("tinyint")
v, err := ConvertDataType("tinyint", false)
assert.Nil(t, err)
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.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)
}

View File

@@ -15,3 +15,12 @@ CREATE TABLE `user` (
UNIQUE KEY `mobile_index` (`mobile`)
) 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

@@ -33,7 +33,7 @@ func genDelete(table Table, withCache bool) (string, string, error) {
"upperStartCamelObject": camel,
"withCache": withCache,
"containsIndexCache": table.ContainsUniqueKey,
"lowerStartCamelPrimaryKey": stringx.From(table.PrimaryKey.Name.ToCamel()).UnTitle(),
"lowerStartCamelPrimaryKey": stringx.From(table.PrimaryKey.Name.ToCamel()).Untitle(),
"dataType": table.PrimaryKey.DataType,
"keys": strings.Join(keySet.KeysStr(), "\n"),
"originalPrimaryKey": table.PrimaryKey.Name.Source(),
@@ -52,7 +52,7 @@ func genDelete(table Table, withCache bool) (string, string, error) {
deleteMethodOut, err := util.With("deleteMethod").
Parse(text).
Execute(map[string]interface{}{
"lowerStartCamelPrimaryKey": stringx.From(table.PrimaryKey.Name.ToCamel()).UnTitle(),
"lowerStartCamelPrimaryKey": stringx.From(table.PrimaryKey.Name.ToCamel()).Untitle(),
"dataType": table.PrimaryKey.DataType,
})
if err != nil {

View File

@@ -18,9 +18,9 @@ func genFindOne(table Table, withCache bool) (string, string, error) {
Execute(map[string]interface{}{
"withCache": withCache,
"upperStartCamelObject": camel,
"lowerStartCamelObject": stringx.From(camel).UnTitle(),
"lowerStartCamelObject": stringx.From(camel).Untitle(),
"originalPrimaryKey": table.PrimaryKey.Name.Source(),
"lowerStartCamelPrimaryKey": stringx.From(table.PrimaryKey.Name.ToCamel()).UnTitle(),
"lowerStartCamelPrimaryKey": stringx.From(table.PrimaryKey.Name.ToCamel()).Untitle(),
"dataType": table.PrimaryKey.DataType,
"cacheKey": table.CacheKey[table.PrimaryKey.Name.Source()].KeyExpression,
"cacheKeyVariable": table.CacheKey[table.PrimaryKey.Name.Source()].Variable,
@@ -38,7 +38,7 @@ func genFindOne(table Table, withCache bool) (string, string, error) {
Parse(text).
Execute(map[string]interface{}{
"upperStartCamelObject": camel,
"lowerStartCamelPrimaryKey": stringx.From(table.PrimaryKey.Name.ToCamel()).UnTitle(),
"lowerStartCamelPrimaryKey": stringx.From(table.PrimaryKey.Name.ToCamel()).Untitle(),
"dataType": table.PrimaryKey.DataType,
})
if err != nil {

View File

@@ -32,12 +32,12 @@ func genFindOneByField(table Table, withCache bool) (*findOneCode, error) {
output, err := t.Execute(map[string]interface{}{
"upperStartCamelObject": camelTableName,
"upperField": camelFieldName,
"in": fmt.Sprintf("%s %s", stringx.From(camelFieldName).UnTitle(), field.DataType),
"in": fmt.Sprintf("%s %s", stringx.From(camelFieldName).Untitle(), field.DataType),
"withCache": withCache,
"cacheKey": table.CacheKey[field.Name.Source()].KeyExpression,
"cacheKeyVariable": table.CacheKey[field.Name.Source()].Variable,
"lowerStartCamelObject": stringx.From(camelTableName).UnTitle(),
"lowerStartCamelField": stringx.From(camelFieldName).UnTitle(),
"lowerStartCamelObject": stringx.From(camelTableName).Untitle(),
"lowerStartCamelField": stringx.From(camelFieldName).Untitle(),
"upperStartCamelPrimaryKey": table.PrimaryKey.Name.ToCamel(),
"originalField": field.Name.Source(),
})
@@ -63,7 +63,7 @@ func genFindOneByField(table Table, withCache bool) (*findOneCode, error) {
output, err := t.Execute(map[string]interface{}{
"upperStartCamelObject": camelTableName,
"upperField": camelFieldName,
"in": fmt.Sprintf("%s %s", stringx.From(camelFieldName).UnTitle(), field.DataType),
"in": fmt.Sprintf("%s %s", stringx.From(camelFieldName).Untitle(), field.DataType),
})
if err != nil {
return nil, err
@@ -81,7 +81,7 @@ func genFindOneByField(table Table, withCache bool) (*findOneCode, error) {
out, err := util.With("findOneByFieldExtraMethod").Parse(text).Execute(map[string]interface{}{
"upperStartCamelObject": camelTableName,
"primaryKeyLeft": table.CacheKey[table.PrimaryKey.Name.Source()].Left,
"lowerStartCamelObject": stringx.From(camelTableName).UnTitle(),
"lowerStartCamelObject": stringx.From(camelTableName).Untitle(),
"originalPrimaryField": table.PrimaryKey.Name.Source(),
})
if err != nil {

View File

@@ -45,7 +45,7 @@ func genInsert(table Table, withCache bool) (string, string, error) {
"withCache": withCache,
"containsIndexCache": table.ContainsUniqueKey,
"upperStartCamelObject": camel,
"lowerStartCamelObject": stringx.From(camel).UnTitle(),
"lowerStartCamelObject": stringx.From(camel).Untitle(),
"expression": strings.Join(expressions, ", "),
"expressionValues": strings.Join(expressionValues, ", "),
"keys": strings.Join(keySet.KeysStr(), "\n"),

View File

@@ -28,11 +28,11 @@ func genCacheKeys(table parser.Table) (map[string]Key, error) {
fields := table.Fields
m := make(map[string]Key)
camelTableName := table.Name.ToCamel()
lowerStartCamelTableName := stringx.From(camelTableName).UnTitle()
lowerStartCamelTableName := stringx.From(camelTableName).Untitle()
for _, field := range fields {
if field.IsUniqueKey || field.IsPrimaryKey {
camelFieldName := field.Name.ToCamel()
lowerStartCamelFieldName := stringx.From(camelFieldName).UnTitle()
lowerStartCamelFieldName := stringx.From(camelFieldName).Untitle()
left := fmt.Sprintf("cache%s%sPrefix", camelTableName, camelFieldName)
if strings.ToLower(camelFieldName) == strings.ToLower(camelTableName) {
left = fmt.Sprintf("cache%sPrefix", camelTableName)

View File

@@ -62,11 +62,11 @@ func TestGenCacheKeys(t *testing.T) {
for fieldName, key := range m {
name := stringx.From(fieldName)
assert.Equal(t, fmt.Sprintf(`cacheUser%sPrefix = "cache#User#%s#"`, name.ToCamel(), name.UnTitle()), key.VarExpression)
assert.Equal(t, fmt.Sprintf(`cacheUser%sPrefix = "cache#User#%s#"`, name.ToCamel(), name.Untitle()), key.VarExpression)
assert.Equal(t, fmt.Sprintf(`cacheUser%sPrefix`, name.ToCamel()), key.Left)
assert.Equal(t, fmt.Sprintf(`cache#User#%s#`, name.UnTitle()), key.Right)
assert.Equal(t, fmt.Sprintf(`cache#User#%s#`, name.Untitle()), key.Right)
assert.Equal(t, fmt.Sprintf(`user%sKey`, name.ToCamel()), key.Variable)
assert.Equal(t, `user`+name.ToCamel()+`Key := fmt.Sprintf("%s%v", cacheUser`+name.ToCamel()+`Prefix,`+name.UnTitle()+`)`, key.KeyExpression)
assert.Equal(t, `user`+name.ToCamel()+`Key := fmt.Sprintf("%s%v", cacheUser`+name.ToCamel()+`Prefix,`+name.Untitle()+`)`, key.KeyExpression)
}
}

View File

@@ -54,6 +54,14 @@ var templates = map[string]string{
errTemplateFile: template.Error,
}
func Category() string {
return category
}
func Clean() error {
return util.Clean(category)
}
func GenTemplates(_ *cli.Context) error {
return util.InitTemplates(category, templates)
}
@@ -66,18 +74,10 @@ func RevertTemplate(name string) error {
return util.CreateTemplate(category, name, content)
}
func Clean() error {
return util.Clean(category)
}
func Update(category string) error {
func Update() error {
err := Clean()
if err != nil {
return err
}
return util.InitTemplates(category, templates)
}
func GetCategory() string {
return category
}

View File

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

View File

@@ -34,7 +34,7 @@ func genUpdate(table Table, withCache bool) (string, string, error) {
"upperStartCamelObject": camelTableName,
"primaryCacheKey": table.CacheKey[table.PrimaryKey.Name.Source()].DataKeyExpression,
"primaryKeyVariable": table.CacheKey[table.PrimaryKey.Name.Source()].Variable,
"lowerStartCamelObject": stringx.From(camelTableName).UnTitle(),
"lowerStartCamelObject": stringx.From(camelTableName).Untitle(),
"originalPrimaryKey": table.PrimaryKey.Name.Source(),
"expressionValues": strings.Join(expressionValues, ", "),
})

View File

@@ -23,7 +23,7 @@ func genVars(table Table, withCache bool) (string, error) {
Parse(text).
GoFmt(true).
Execute(map[string]interface{}{
"lowerStartCamelObject": stringx.From(camel).UnTitle(),
"lowerStartCamelObject": stringx.From(camel).Untitle(),
"upperStartCamelObject": camel,
"cacheKeys": strings.Join(keys, "\n"),
"autoIncrement": table.PrimaryKey.AutoIncrement,

View File

@@ -9,11 +9,13 @@ type (
conn sqlx.SqlConn
}
Column struct {
Name string `db:"COLUMN_NAME"`
DataType string `db:"DATA_TYPE"`
Key string `db:"COLUMN_KEY"`
Extra string `db:"EXTRA"`
Comment string `db:"COLUMN_COMMENT"`
Name string `db:"COLUMN_NAME"`
DataType string `db:"DATA_TYPE"`
Key string `db:"COLUMN_KEY"`
Extra string `db:"EXTRA"`
Comment string `db:"COLUMN_COMMENT"`
ColumnDefault interface{} `db:"COLUMN_DEFAULT"`
IsNullAble string `db:"IS_NULLABLE"`
}
)
@@ -33,7 +35,7 @@ func (m *InformationSchemaModel) GetAllTables(database string) ([]string, error)
}
func (m *InformationSchemaModel) FindByTableName(db, table string) ([]*Column, error) {
querySql := `select COLUMN_NAME,DATA_TYPE,COLUMN_KEY,EXTRA,COLUMN_COMMENT from COLUMNS where TABLE_SCHEMA = ? and TABLE_NAME = ?`
querySql := `select COLUMN_NAME,COLUMN_DEFAULT,IS_NULLABLE,DATA_TYPE,COLUMN_KEY,EXTRA,COLUMN_COMMENT from COLUMNS where TABLE_SCHEMA = ? and TABLE_NAME = ?`
var reply []*Column
err := m.conn.QueryRows(&reply, querySql, db, table)
return reply, err

View File

@@ -112,7 +112,17 @@ func Parse(ddl string) (*Table, error) {
if column.Type.Comment != nil {
comment = string(column.Type.Comment.Val)
}
dataType, err := converter.ConvertDataType(column.Type.Type)
var isDefaultNull = true
if column.Type.NotNull {
isDefaultNull = false
} else {
if column.Type.Default == nil {
isDefaultNull = false
} else if string(column.Type.Default.Val) != "null" {
isDefaultNull = false
}
}
dataType, err := converter.ConvertDataType(column.Type.Type, isDefaultNull)
if err != nil {
return nil, err
}
@@ -170,7 +180,8 @@ func ConvertColumn(db, table string, in []*model.Column) (*Table, error) {
}
primaryColumn := primaryColumns[0]
primaryFt, err := converter.ConvertDataType(primaryColumn.DataType)
isDefaultNull := primaryColumn.ColumnDefault == nil && primaryColumn.IsNullAble == "YES"
primaryFt, err := converter.ConvertDataType(primaryColumn.DataType, isDefaultNull)
if err != nil {
return nil, err
}
@@ -189,7 +200,8 @@ func ConvertColumn(db, table string, in []*model.Column) (*Table, error) {
}
for key, columns := range keyMap {
for _, item := range columns {
dt, err := converter.ConvertDataType(item.DataType)
isColumnDefaultNull := item.ColumnDefault == nil && item.IsNullAble == "YES"
dt, err := converter.ConvertDataType(item.DataType, isColumnDefaultNull)
if err != nil {
return nil, err
}

View File

@@ -79,6 +79,7 @@ func TestConvertColumn(t *testing.T) {
for _, item := range table.Fields {
if item.Name.Source() == "mobile" {
assert.True(t, item.IsUniqueKey)
break
}
}
}

View File

@@ -0,0 +1,19 @@
package main
import (
"fmt"
"github.com/tal-tech/go-zero/tools/goctl/plugin"
)
func main() {
plugin, err := plugin.NewPlugin()
if err != nil {
panic(err)
}
if plugin.Api != nil {
fmt.Printf("api: %+v \n", plugin.Api)
}
fmt.Println("Enjoy anything you want.")
}

View File

@@ -0,0 +1,191 @@
package plugin
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/rpc/execx"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/urfave/cli"
)
const (
pluginArg = "_plugin"
)
type Plugin struct {
Api *spec.ApiSpec
ApiFilePath string
Style string
Dir string
}
func PluginCommand(c *cli.Context) error {
ex, err := os.Executable()
if err != nil {
panic(err)
}
var plugin = c.String("plugin")
if len(plugin) == 0 {
return errors.New("missing plugin")
}
transferData, err := prepareArgs(c)
if err != nil {
return err
}
bin, args := getPluginAndArgs(plugin)
bin, download, err := getCommand(bin)
if err != nil {
return err
}
if download {
defer func() {
_ = os.Remove(bin)
}()
}
content, err := execx.Run(bin+" "+args, filepath.Dir(ex), bytes.NewBuffer(transferData))
if err != nil {
return err
}
fmt.Println(content)
return nil
}
func prepareArgs(c *cli.Context) ([]byte, error) {
apiPath := c.String("api")
var transferData Plugin
if len(apiPath) > 0 && util.FileExists(apiPath) {
p, err := parser.NewParser(apiPath)
if err != nil {
return nil, err
}
api, err := p.Parse()
if err != nil {
return nil, err
}
transferData.Api = api
}
absApiFilePath, err := filepath.Abs(apiPath)
if err != nil {
return nil, err
}
transferData.ApiFilePath = absApiFilePath
dirAbs, err := filepath.Abs(c.String("dir"))
if err != nil {
return nil, err
}
transferData.Dir = dirAbs
transferData.Style = c.String("style")
data, err := json.Marshal(transferData)
if err != nil {
return nil, err
}
return data, nil
}
func getCommand(arg string) (string, bool, error) {
p, err := exec.LookPath(arg)
if err == nil {
abs, err := filepath.Abs(p)
if err != nil {
return "", false, err
}
return abs, false, nil
}
var defaultErr = errors.New("invalid plugin value " + arg)
if strings.HasPrefix(arg, "http") {
items := strings.Split(arg, "/")
if len(items) == 0 {
return "", false, defaultErr
}
filename, err := filepath.Abs(pluginArg + items[len(items)-1])
if err != nil {
return "", false, err
}
err = downloadFile(filename, arg)
if err != nil {
return "", false, err
}
os.Chmod(filename, os.ModePerm)
return filename, true, nil
}
return arg, false, nil
}
func downloadFile(filepath string, url string) error {
resp, err := http.Get(url)
if err != nil {
return err
}
defer func() {
_ = resp.Body.Close()
}()
out, err := os.Create(filepath)
if err != nil {
return err
}
defer func() {
_ = out.Close()
}()
_, err = io.Copy(out, resp.Body)
return err
}
func NewPlugin() (*Plugin, error) {
var plugin Plugin
content, err := ioutil.ReadAll(os.Stdin)
if err != nil {
return nil, err
}
err = json.Unmarshal(content, &plugin)
if err != nil {
return nil, err
}
return &plugin, nil
}
func getPluginAndArgs(arg string) (string, string) {
i := strings.Index(arg, "=")
if i <= 0 {
return arg, ""
}
return trimQuote(arg[:i]), trimQuote(arg[i+1:])
}
func trimQuote(in string) string {
in = strings.Trim(in, `"`)
in = strings.Trim(in, `'`)
in = strings.Trim(in, "`")
return in
}

View File

@@ -0,0 +1,29 @@
package plugin
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestGetPluginAndArgs(t *testing.T) {
bin, args := getPluginAndArgs("android")
assert.Equal(t, "android", bin)
assert.Equal(t, "", args)
bin, args = getPluginAndArgs("android=")
assert.Equal(t, "android", bin)
assert.Equal(t, "", args)
bin, args = getPluginAndArgs("android=-javaPackage com.tal")
assert.Equal(t, "android", bin)
assert.Equal(t, "-javaPackage com.tal", args)
bin, args = getPluginAndArgs("android=-javaPackage com.tal --lambda")
assert.Equal(t, "android", bin)
assert.Equal(t, "-javaPackage com.tal --lambda", args)
bin, args = getPluginAndArgs(`https://test-xjy-file.obs.cn-east-2.myhuaweicloud.com/202012/8a7ab6e1-e639-49d1-89cf-2ae6127a1e90n=-v 1`)
assert.Equal(t, "https://test-xjy-file.obs.cn-east-2.myhuaweicloud.com/202012/8a7ab6e1-e639-49d1-89cf-2ae6127a1e90n", bin)
assert.Equal(t, "-v 1", args)
}

View File

@@ -12,7 +12,7 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/vars"
)
func Run(arg string, dir string) (string, error) {
func Run(arg string, dir string, in ...*bytes.Buffer) (string, error) {
goos := runtime.GOOS
var cmd *exec.Cmd
switch goos {
@@ -28,6 +28,9 @@ func Run(arg string, dir string) (string, error) {
}
stdout := new(bytes.Buffer)
stderr := new(bytes.Buffer)
if len(in) > 0 {
cmd.Stdin = in[0]
}
cmd.Stdout = stdout
cmd.Stderr = stderr
err := cmd.Run()

View File

@@ -4,6 +4,7 @@ import (
"go/build"
"os"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/assert"
@@ -44,7 +45,9 @@ func TestRpcGenerate(t *testing.T) {
assert.Nil(t, err)
_, err = execx.Run("go test "+projectName, projectDir)
if err != nil {
assert.Contains(t, err.Error(), "not in GOROOT")
assert.True(t, func() bool {
return strings.Contains(err.Error(), "not in GOROOT") || strings.Contains(err.Error(), "cannot find package")
}())
}
// case go mod
@@ -61,7 +64,9 @@ func TestRpcGenerate(t *testing.T) {
assert.Nil(t, err)
_, err = execx.Run("go test "+projectName, projectDir)
if err != nil {
assert.Contains(t, err.Error(), "not in GOROOT")
assert.True(t, func() bool {
return strings.Contains(err.Error(), "not in GOROOT") || strings.Contains(err.Error(), "cannot find package")
}())
}
// case not in go mod and go path
@@ -69,7 +74,9 @@ func TestRpcGenerate(t *testing.T) {
assert.Nil(t, err)
_, err = execx.Run("go test "+projectName, projectDir)
if err != nil {
assert.Contains(t, err.Error(), "not in GOROOT")
assert.True(t, func() bool {
return strings.Contains(err.Error(), "not in GOROOT") || strings.Contains(err.Error(), "cannot find package")
}())
}
// invalid directory

View File

@@ -40,7 +40,7 @@ func ProtoTmpl(out string) error {
}
err = util.With("t").Parse(text).SaveTo(map[string]string{
"package": serviceName.UnTitle(),
"package": serviceName.Untitle(),
"serviceName": serviceName.Title(),
}, out, false)
return err

View File

@@ -54,14 +54,15 @@ func Clean() error {
return util.Clean(category)
}
func Update(category string) error {
func Update() error {
err := Clean()
if err != nil {
return err
}
return util.InitTemplates(category, templates)
}
func GetCategory() string {
func Category() string {
return category
}

View File

@@ -97,8 +97,7 @@ func TestUpdate(t *testing.T) {
}
assert.Equal(t, "modify", string(data))
err = Update(category)
assert.Nil(t, err)
assert.Nil(t, Update())
data, err = ioutil.ReadFile(mainTpl)
if err != nil {
@@ -109,6 +108,6 @@ func TestUpdate(t *testing.T) {
func TestGetCategory(t *testing.T) {
_ = Clean()
result := GetCategory()
result := Category()
assert.Equal(t, category, result)
}

View File

@@ -7,6 +7,7 @@ import (
"github.com/tal-tech/go-zero/core/errorx"
"github.com/tal-tech/go-zero/tools/goctl/api/gogen"
"github.com/tal-tech/go-zero/tools/goctl/docker"
"github.com/tal-tech/go-zero/tools/goctl/kube"
modelgen "github.com/tal-tech/go-zero/tools/goctl/model/sql/gen"
rpcgen "github.com/tal-tech/go-zero/tools/goctl/rpc/generator"
"github.com/tal-tech/go-zero/tools/goctl/util"
@@ -29,6 +30,9 @@ func GenTemplates(ctx *cli.Context) error {
func() error {
return docker.GenTemplates(ctx)
},
func() error {
return kube.GenTemplates(ctx)
},
); err != nil {
return err
}
@@ -72,12 +76,16 @@ func UpdateTemplates(ctx *cli.Context) (err error) {
}
}()
switch category {
case gogen.GetCategory():
return gogen.Update(category)
case rpcgen.GetCategory():
return rpcgen.Update(category)
case modelgen.GetCategory():
return modelgen.Update(category)
case docker.Category():
return docker.Update()
case gogen.Category():
return gogen.Update()
case kube.Category():
return kube.Update()
case rpcgen.Category():
return rpcgen.Update()
case modelgen.Category():
return modelgen.Update()
default:
err = fmt.Errorf("unexpected category: %s", category)
return
@@ -93,11 +101,15 @@ func RevertTemplates(ctx *cli.Context) (err error) {
}
}()
switch category {
case gogen.GetCategory():
case docker.Category():
return docker.RevertTemplate(filename)
case kube.Category():
return kube.RevertTemplate(filename)
case gogen.Category():
return gogen.RevertTemplate(filename)
case rpcgen.GetCategory():
case rpcgen.Category():
return rpcgen.RevertTemplate(filename)
case modelgen.GetCategory():
case modelgen.Category():
return modelgen.RevertTemplate(filename)
default:
err = fmt.Errorf("unexpected category: %s", category)

View File

@@ -60,7 +60,6 @@ func FindGoModPath(dir string) (string, bool) {
var hasGoMod = false
for {
if FileExists(filepath.Join(tempPath, goModeIdentifier)) {
tempPath = filepath.Dir(tempPath)
rootPath = strings.TrimPrefix(absDir[len(tempPath):], "/")
hasGoMod = true
break
@@ -80,3 +79,30 @@ func FindGoModPath(dir string) (string, bool) {
}
return "", false
}
func FindProjectPath(loc string) (string, bool) {
var dir string
if strings.IndexByte(loc, '/') == 0 {
dir = loc
} else {
wd, err := os.Getwd()
if err != nil {
return "", false
}
dir = filepath.Join(wd, loc)
}
for {
if FileExists(filepath.Join(dir, goModeIdentifier)) {
return dir, true
}
dir = filepath.Dir(dir)
if dir == "/" {
break
}
}
return "", false
}

View File

@@ -17,3 +17,13 @@ func Untitle(s string) string {
return strings.ToLower(s[:1]) + s[1:]
}
func Index(slice []string, item string) int {
for i := range slice {
if slice[i] == item {
return i
}
}
return -1
}

View File

@@ -6,11 +6,9 @@ import (
"unicode"
)
type (
String struct {
source string
}
)
type String struct {
source string
}
func From(data string) String {
return String{source: data}
@@ -30,8 +28,12 @@ func (s String) Lower() string {
return strings.ToLower(s.source)
}
func (s String) Upper() string {
return strings.ToUpper(s.source)
func (s String) ReplaceAll(old, new string) string {
return strings.ReplaceAll(s.source, old, new)
}
func (s String) Source() string {
return s.source
}
func (s String) Title() string {
@@ -64,7 +66,7 @@ func (s String) ToSnake() string {
}
// return original string if rune is not letter at index 0
func (s String) UnTitle() string {
func (s String) Untitle() string {
if s.IsEmptyOrSpace() {
return s.source
}
@@ -75,6 +77,10 @@ func (s String) UnTitle() string {
return string(unicode.ToLower(r)) + s.source[1:]
}
func (s String) Upper() string {
return strings.ToUpper(s.source)
}
// it will not ignore spaces
func (s String) splitBy(fn func(r rune) bool, remove bool) []string {
if s.IsEmptyOrSpace() {
@@ -100,11 +106,3 @@ func (s String) splitBy(fn func(r rune) bool, remove bool) []string {
}
return list
}
func (s String) ReplaceAll(old, new string) string {
return strings.ReplaceAll(s.source, old, new)
}
func (s String) Source() string {
return s.source
}

View File

@@ -14,4 +14,4 @@ func TestWithStreamClientInterceptors(t *testing.T) {
func TestWithUnaryClientInterceptors(t *testing.T) {
opts := WithUnaryClientInterceptors()
assert.NotNil(t, opts)
}
}

View File

@@ -14,4 +14,4 @@ func TestWithStreamServerInterceptors(t *testing.T) {
func TestWithUnaryServerInterceptors(t *testing.T) {
opts := WithUnaryServerInterceptors()
assert.NotNil(t, opts)
}
}