Compare commits

..

13 Commits

Author SHA1 Message Date
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
73 changed files with 1699 additions and 989 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

@@ -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/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -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/dsymonds/gotoc v0.0.0-20160928043926-5aebcfc91819/go.mod h1:MvzMVHq8BH2Ji/o8TGDocVA70byvLrAgFTxkEnmjO4Y=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4 h1:qk/FSDDxo05wdJH28W+p5yivv7LuLYLRXPPD8KQCtZs= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4 h1:qk/FSDDxo05wdJH28W+p5yivv7LuLYLRXPPD8KQCtZs=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/emicklei/proto v1.9.0 h1:l0QiNT6Qs7Yj0Mb4X6dnWBQer4ebei2BFcgQLbGqUDc=
github.com/emicklei/proto v1.9.0/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= github.com/emicklei/proto v1.9.0/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@@ -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/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334 h1:VHgatEHNcBFEB7inlalqfNqw65aNkM1lGX2yt3NmbS8= github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334 h1:VHgatEHNcBFEB7inlalqfNqw65aNkM1lGX2yt3NmbS8=
github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/iancoleman/strcase v0.1.2 h1:gnomlvw9tnV3ITTAxzKSgTF+8kFWcU/f+TgttpXGz1U=
github.com/iancoleman/strcase v0.1.2/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= github.com/iancoleman/strcase v0.1.2/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
@@ -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/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
@@ -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.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA= github.com/urfave/cli v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA=
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=

7
go.mod
View File

@@ -1,6 +1,6 @@
module github.com/tal-tech/go-zero module github.com/tal-tech/go-zero
go 1.13 go 1.14
require ( require (
github.com/ClickHouse/clickhouse-go v1.4.3 github.com/ClickHouse/clickhouse-go v1.4.3
@@ -11,6 +11,7 @@ require (
github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/emicklei/proto v1.9.0 github.com/emicklei/proto v1.9.0
github.com/fatih/color v1.9.0 // indirect github.com/fatih/color v1.9.0 // indirect
github.com/fatih/structtag v1.2.0
github.com/frankban/quicktest v1.7.2 // indirect github.com/frankban/quicktest v1.7.2 // indirect
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8
github.com/go-redis/redis v6.15.7+incompatible github.com/go-redis/redis v6.15.7+incompatible
@@ -55,10 +56,10 @@ require (
golang.org/x/tools v0.0.0-20200410132612-ae9902aceb98 // indirect golang.org/x/tools v0.0.0-20200410132612-ae9902aceb98 // indirect
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f // indirect google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f // indirect
google.golang.org/grpc v1.29.1 google.golang.org/grpc v1.29.1
google.golang.org/protobuf v1.25.0 google.golang.org/protobuf v1.25.0 // indirect
gopkg.in/cheggaaa/pb.v1 v1.0.28 gopkg.in/cheggaaa/pb.v1 v1.0.28
gopkg.in/h2non/gock.v1 v1.0.15 gopkg.in/h2non/gock.v1 v1.0.15
gopkg.in/yaml.v2 v2.3.0 gopkg.in/yaml.v2 v2.4.0
honnef.co/go/tools v0.0.1-2020.1.4 // indirect honnef.co/go/tools v0.0.1-2020.1.4 // indirect
sigs.k8s.io/yaml v1.2.0 // indirect sigs.k8s.io/yaml v1.2.0 // indirect
) )

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.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/frankban/quicktest v1.7.2 h1:2QxQoC1TS09S7fhCPsrvqYdvP1H5M1P1ih5ABm3BTYk= github.com/frankban/quicktest v1.7.2 h1:2QxQoC1TS09S7fhCPsrvqYdvP1H5M1P1ih5ABm3BTYk=
github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o= github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
@@ -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.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=

View File

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

View File

@@ -25,7 +25,7 @@ info(
// TODO: test // TODO: test
// { // {
type Request struct { // TODO: test type Request struct { // TODO: test
// TOOD // TODO
Name string ` + "`" + `path:"name,options=you|me"` + "`" + ` // } Name string ` + "`" + `path:"name,options=you|me"` + "`" + ` // }
} // TODO: test } // 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) filename, err := format.FileNamingFormat(cfg.NamingFormat, handler)
if err != nil { if err != nil {
return err return err

View File

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

View File

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

View File

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

View File

@@ -2,10 +2,12 @@ package docker
import ( import (
"errors" "errors"
"fmt"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"text/template" "text/template"
"time"
"github.com/tal-tech/go-zero/tools/goctl/util" "github.com/tal-tech/go-zero/tools/goctl/util"
ctlutil "github.com/tal-tech/go-zero/tools/goctl/util" ctlutil "github.com/tal-tech/go-zero/tools/goctl/util"
@@ -13,22 +15,48 @@ import (
) )
const ( const (
etcDir = "etc" etcDir = "etc"
yamlEtx = ".yaml" yamlEtx = ".yaml"
cstOffset = 60 * 60 * 8 // 8 hours offset for Chinese Standard Time
) )
type Docker struct {
Chinese bool
GoRelPath string
GoFile string
ExeFile string
Argument string
}
func DockerCommand(c *cli.Context) error { func DockerCommand(c *cli.Context) error {
goFile := c.String("go") goFile := c.String("go")
if len(goFile) == 0 { if len(goFile) == 0 {
return errors.New("-go can't be empty") return errors.New("-go can't be empty")
} }
if !util.FileExists(goFile) {
return fmt.Errorf("file %q not found", goFile)
}
if _, err := os.Stat(etcDir); os.IsNotExist(err) {
return generateDockerfile(goFile)
}
cfg, err := findConfig(goFile, etcDir) cfg, err := findConfig(goFile, etcDir)
if err != nil { if err != nil {
return err return err
} }
return generateDockerfile(goFile, "-f", "etc/"+cfg) if err := generateDockerfile(goFile, "-f", "etc/"+cfg); err != nil {
return err
}
projDir, ok := util.FindProjectPath(goFile)
if ok {
fmt.Printf("Run \"docker build ...\" command in dir %q\n", projDir)
}
return nil
} }
func findConfig(file, dir string) (string, error) { func findConfig(file, dir string) (string, error) {
@@ -87,12 +115,14 @@ func generateDockerfile(goFile string, args ...string) error {
builder.WriteString(`, "` + arg + `"`) builder.WriteString(`, "` + arg + `"`)
} }
_, offset := time.Now().Zone()
t := template.Must(template.New("dockerfile").Parse(text)) t := template.Must(template.New("dockerfile").Parse(text))
return t.Execute(out, map[string]string{ return t.Execute(out, Docker{
"goRelPath": projPath, Chinese: offset == cstOffset,
"goFile": goFile, GoRelPath: projPath,
"exeFile": util.FileNameWithoutExt(filepath.Base(goFile)), GoFile: goFile,
"argument": builder.String(), ExeFile: util.FileNameWithoutExt(filepath.Base(goFile)),
Argument: builder.String(),
}) })
} }

View File

@@ -14,13 +14,16 @@ LABEL stage=gobuilder
ENV CGO_ENABLED 0 ENV CGO_ENABLED 0
ENV GOOS linux ENV GOOS linux
ENV GOPROXY https://goproxy.cn,direct {{if .Chinese}}ENV GOPROXY https://goproxy.cn,direct{{end}}
WORKDIR /build/zero WORKDIR /build/zero
ADD go.mod .
ADD go.sum .
RUN go mod download
COPY . . COPY . .
RUN sh -c "[ -f go.mod ]" || exit COPY {{.GoRelPath}}/etc /app/etc
COPY {{.goRelPath}}/etc /app/etc RUN go build -ldflags="-s -w" -o /app/{{.ExeFile}} {{.GoRelPath}}/{{.GoFile}}
RUN go build -ldflags="-s -w" -o /app/{{.exeFile}} {{.goRelPath}}/{{.goFile}}
FROM alpine FROM alpine
@@ -31,10 +34,10 @@ RUN apk add --no-cache tzdata
ENV TZ Asia/Shanghai ENV TZ Asia/Shanghai
WORKDIR /app WORKDIR /app
COPY --from=builder /app/{{.exeFile}} /app/{{.exeFile}} COPY --from=builder /app/{{.ExeFile}} /app/{{.ExeFile}}
COPY --from=builder /app/etc /app/etc COPY --from=builder /app/etc /app/etc
CMD ["./{{.exeFile}}"{{.argument}}] CMD ["./{{.ExeFile}}"{{.Argument}}]
` `
) )

View File

@@ -18,7 +18,9 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/api/validate" "github.com/tal-tech/go-zero/tools/goctl/api/validate"
"github.com/tal-tech/go-zero/tools/goctl/configgen" "github.com/tal-tech/go-zero/tools/goctl/configgen"
"github.com/tal-tech/go-zero/tools/goctl/docker" "github.com/tal-tech/go-zero/tools/goctl/docker"
"github.com/tal-tech/go-zero/tools/goctl/kube"
model "github.com/tal-tech/go-zero/tools/goctl/model/sql/command" model "github.com/tal-tech/go-zero/tools/goctl/model/sql/command"
"github.com/tal-tech/go-zero/tools/goctl/plugin"
rpc "github.com/tal-tech/go-zero/tools/goctl/rpc/cli" rpc "github.com/tal-tech/go-zero/tools/goctl/rpc/cli"
"github.com/tal-tech/go-zero/tools/goctl/tpl" "github.com/tal-tech/go-zero/tools/goctl/tpl"
"github.com/urfave/cli" "github.com/urfave/cli"
@@ -185,6 +187,30 @@ var (
}, },
Action: ktgen.KtCommand, Action: ktgen.KtCommand,
}, },
{
Name: "plugin",
Usage: "custom file generator",
Flags: []cli.Flag{
cli.StringFlag{
Name: "plugin, p",
Usage: "the plugin file",
},
cli.StringFlag{
Name: "dir",
Usage: "the target directory",
},
cli.StringFlag{
Name: "api",
Usage: "the api file",
},
cli.StringFlag{
Name: "style",
Required: false,
Usage: "the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]",
},
},
Action: plugin.PluginCommand,
},
}, },
}, },
{ {
@@ -198,6 +224,94 @@ var (
}, },
Action: docker.DockerCommand, Action: docker.DockerCommand,
}, },
{
Name: "kube",
Usage: "generate kubernetes files",
Subcommands: []cli.Command{
{
Name: "deploy",
Usage: "generate deployment yaml file",
Flags: []cli.Flag{
cli.StringFlag{
Name: "name",
Usage: "the name of deployment",
Required: true,
},
cli.StringFlag{
Name: "namespace",
Usage: "the namespace of deployment",
Required: true,
},
cli.StringFlag{
Name: "image",
Usage: "the docker image of deployment",
Required: true,
},
cli.StringFlag{
Name: "secret",
Usage: "the image pull secret",
Required: true,
},
cli.IntFlag{
Name: "requestCpu",
Usage: "the request cpu to deploy",
Value: 500,
},
cli.IntFlag{
Name: "requestMem",
Usage: "the request memory to deploy",
Value: 512,
},
cli.IntFlag{
Name: "limitCpu",
Usage: "the limit cpu to deploy",
Value: 1000,
},
cli.IntFlag{
Name: "limitMem",
Usage: "the limit memory to deploy",
Value: 1024,
},
cli.StringFlag{
Name: "o",
Usage: "the output yaml file",
Required: true,
},
cli.IntFlag{
Name: "replicas",
Usage: "the number of replicas to deploy",
Value: 3,
},
cli.IntFlag{
Name: "revisions",
Usage: "the number of revision history to limit",
Value: 5,
},
cli.IntFlag{
Name: "port",
Usage: "the port of the deployment to listen on pod",
Required: true,
},
cli.IntFlag{
Name: "nodePort",
Usage: "the nodePort of the deployment to expose",
Value: 0,
},
cli.IntFlag{
Name: "minReplicas",
Usage: "the min replicas to deploy",
Value: 3,
},
cli.IntFlag{
Name: "maxReplicas",
Usage: "the max replicas of deploy",
Value: 10,
},
},
Action: kube.DeploymentCommand,
},
},
},
{ {
Name: "rpc", Name: "rpc",
Usage: "generate rpc code", Usage: "generate rpc code",

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
imagePullSecrets:
- name: {{.Secret}}
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
`

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

@@ -0,0 +1,104 @@
package kube
import (
"errors"
"text/template"
"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
)
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
}
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))
return 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"),
})
}
func GenTemplates(_ *cli.Context) error {
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"` // 用户密码 Password string `db:"password"` // 用户密码
Mobile string `db:"mobile"` // 手机号 Mobile string `db:"mobile"` // 手机号
Gender string `db:"gender"` // 男|女|未公开 Gender string `db:"gender"` // 男|女|未公开
Nickname string `db:"nickname"` // 用户昵称 Nickname sql.NullString `db:"nickname"` // 用户昵称
CreateTime time.Time `db:"create_time"` CreateTime sql.NullTime `db:"create_time"`
UpdateTime time.Time `db:"update_time"` UpdateTime time.Time `db:"update_time"`
} }
) )
@@ -347,3 +347,33 @@ OPTIONS:
目前我认为除了基本的CURD外其他的代码均属于<i>业务型</i>代码,这个我觉得开发人员根据业务需要进行编写更好。 目前我认为除了基本的CURD外其他的代码均属于<i>业务型</i>代码,这个我觉得开发人员根据业务需要进行编写更好。
# 类型转换规则
| mysql dataType | golang dataType | golang dataType(if null&&default null) |
|----------------|-----------------|----------------------------------------|
| bool | int64 | sql.NullInt64 |
| boolean | int64 | sql.NullInt64 |
| tinyint | int64 | sql.NullInt64 |
| smallint | int64 | sql.NullInt64 |
| mediumint | int64 | sql.NullInt64 |
| int | int64 | sql.NullInt64 |
| integer | int64 | sql.NullInt64 |
| bigint | int64 | sql.NullInt64 |
| float | float64 | sql.NullFloat64 |
| double | float64 | sql.NullFloat64 |
| decimal | float64 | sql.NullFloat64 |
| date | time.Time | sql.NullTime |
| datetime | time.Time | sql.NullTime |
| timestamp | time.Time | sql.NullTime |
| time | string | sql.NullString |
| year | time.Time | sql.NullInt64 |
| char | string | sql.NullString |
| varchar | string | sql.NullString |
| binary | string | sql.NullString |
| varbinary | string | sql.NullString |
| tinytext | string | sql.NullString |
| text | string | sql.NullString |
| mediumtext | string | sql.NullString |
| longtext | string | sql.NullString |
| enum | string | sql.NullString |
| set | string | sql.NullString |
| json | string | sql.NullString |

View File

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

View File

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

View File

@@ -15,3 +15,12 @@ CREATE TABLE `user` (
UNIQUE KEY `mobile_index` (`mobile`) UNIQUE KEY `mobile_index` (`mobile`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE `student` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8mb4_bin NOT NULL DEFAULT '',
`age` tinyint DEFAULT NULL,
`score` float(10,0) DEFAULT NULL,
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -62,11 +62,11 @@ func TestGenCacheKeys(t *testing.T) {
for fieldName, key := range m { for fieldName, key := range m {
name := stringx.From(fieldName) 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(`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, 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

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

View File

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

View File

@@ -9,11 +9,13 @@ type (
conn sqlx.SqlConn conn sqlx.SqlConn
} }
Column struct { Column struct {
Name string `db:"COLUMN_NAME"` Name string `db:"COLUMN_NAME"`
DataType string `db:"DATA_TYPE"` DataType string `db:"DATA_TYPE"`
Key string `db:"COLUMN_KEY"` Key string `db:"COLUMN_KEY"`
Extra string `db:"EXTRA"` Extra string `db:"EXTRA"`
Comment string `db:"COLUMN_COMMENT"` 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) { 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 var reply []*Column
err := m.conn.QueryRows(&reply, querySql, db, table) err := m.conn.QueryRows(&reply, querySql, db, table)
return reply, err return reply, err

View File

@@ -112,7 +112,17 @@ func Parse(ddl string) (*Table, error) {
if column.Type.Comment != nil { if column.Type.Comment != nil {
comment = string(column.Type.Comment.Val) 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 { if err != nil {
return nil, err return nil, err
} }
@@ -170,7 +180,8 @@ func ConvertColumn(db, table string, in []*model.Column) (*Table, error) {
} }
primaryColumn := primaryColumns[0] 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 { if err != nil {
return nil, err return nil, err
} }
@@ -189,7 +200,8 @@ func ConvertColumn(db, table string, in []*model.Column) (*Table, error) {
} }
for key, columns := range keyMap { for key, columns := range keyMap {
for _, item := range columns { 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 { if err != nil {
return nil, err return nil, err
} }

View File

@@ -79,6 +79,7 @@ func TestConvertColumn(t *testing.T) {
for _, item := range table.Fields { for _, item := range table.Fields {
if item.Name.Source() == "mobile" { if item.Name.Source() == "mobile" {
assert.True(t, item.IsUniqueKey) 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,184 @@
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
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
}
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" "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 goos := runtime.GOOS
var cmd *exec.Cmd var cmd *exec.Cmd
switch goos { switch goos {
@@ -28,6 +28,9 @@ func Run(arg string, dir string) (string, error) {
} }
stdout := new(bytes.Buffer) stdout := new(bytes.Buffer)
stderr := new(bytes.Buffer) stderr := new(bytes.Buffer)
if len(in) > 0 {
cmd.Stdin = in[0]
}
cmd.Stdout = stdout cmd.Stdout = stdout
cmd.Stderr = stderr cmd.Stderr = stderr
err := cmd.Run() err := cmd.Run()

View File

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

View File

@@ -7,6 +7,7 @@ import (
"github.com/tal-tech/go-zero/core/errorx" "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/api/gogen"
"github.com/tal-tech/go-zero/tools/goctl/docker" "github.com/tal-tech/go-zero/tools/goctl/docker"
"github.com/tal-tech/go-zero/tools/goctl/kube"
modelgen "github.com/tal-tech/go-zero/tools/goctl/model/sql/gen" modelgen "github.com/tal-tech/go-zero/tools/goctl/model/sql/gen"
rpcgen "github.com/tal-tech/go-zero/tools/goctl/rpc/generator" rpcgen "github.com/tal-tech/go-zero/tools/goctl/rpc/generator"
"github.com/tal-tech/go-zero/tools/goctl/util" "github.com/tal-tech/go-zero/tools/goctl/util"
@@ -29,6 +30,9 @@ func GenTemplates(ctx *cli.Context) error {
func() error { func() error {
return docker.GenTemplates(ctx) return docker.GenTemplates(ctx)
}, },
func() error {
return kube.GenTemplates(ctx)
},
); err != nil { ); err != nil {
return err return err
} }

View File

@@ -80,3 +80,30 @@ func FindGoModPath(dir string) (string, bool) {
} }
return "", false 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,12 @@ func Untitle(s string) string {
return strings.ToLower(s[:1]) + s[1:] 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" "unicode"
) )
type ( type String struct {
String struct { source string
source string }
}
)
func From(data string) String { func From(data string) String {
return String{source: data} return String{source: data}
@@ -30,8 +28,12 @@ func (s String) Lower() string {
return strings.ToLower(s.source) return strings.ToLower(s.source)
} }
func (s String) Upper() string { func (s String) ReplaceAll(old, new string) string {
return strings.ToUpper(s.source) return strings.ReplaceAll(s.source, old, new)
}
func (s String) Source() string {
return s.source
} }
func (s String) Title() string { 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 // return original string if rune is not letter at index 0
func (s String) UnTitle() string { func (s String) Untitle() string {
if s.IsEmptyOrSpace() { if s.IsEmptyOrSpace() {
return s.source return s.source
} }
@@ -75,6 +77,10 @@ func (s String) UnTitle() string {
return string(unicode.ToLower(r)) + s.source[1:] return string(unicode.ToLower(r)) + s.source[1:]
} }
func (s String) Upper() string {
return strings.ToUpper(s.source)
}
// it will not ignore spaces // it will not ignore spaces
func (s String) splitBy(fn func(r rune) bool, remove bool) []string { func (s String) splitBy(fn func(r rune) bool, remove bool) []string {
if s.IsEmptyOrSpace() { if s.IsEmptyOrSpace() {
@@ -100,11 +106,3 @@ func (s String) splitBy(fn func(r rune) bool, remove bool) []string {
} }
return list 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) { func TestWithUnaryClientInterceptors(t *testing.T) {
opts := WithUnaryClientInterceptors() opts := WithUnaryClientInterceptors()
assert.NotNil(t, opts) assert.NotNil(t, opts)
} }

View File

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