mirror of
https://github.com/zeromicro/go-zero.git
synced 2026-05-11 16:59:59 +08:00
Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
acd48f0abb | ||
|
|
f919bc6713 | ||
|
|
a0030b8f45 | ||
|
|
a5f0cce1b1 | ||
|
|
4d13dda605 | ||
|
|
b56cc8e459 | ||
|
|
c435811479 | ||
|
|
c686c93fb5 | ||
|
|
da8f76e6bd | ||
|
|
99596a4149 | ||
|
|
ec2a9f2c57 | ||
|
|
fd73ced6dc | ||
|
|
5071736ab4 | ||
|
|
0d7f1d23b4 | ||
|
|
84ab11ac09 | ||
|
|
67804a6bb2 | ||
|
|
65ee877236 | ||
|
|
b060867009 | ||
|
|
4d53045c6b | ||
|
|
cecd4b1b75 | ||
|
|
7cd0463953 | ||
|
|
7a82cf80ce | ||
|
|
f997aee3ba | ||
|
|
88ec89bdbd | ||
|
|
7d1b43780a | ||
|
|
4b5c2de376 | ||
|
|
e5c560e8ba | ||
|
|
bed494d904 | ||
|
|
2dfecda465 | ||
|
|
3ebb1e0221 | ||
|
|
348184904c | ||
|
|
7a27fa50a1 | ||
|
|
8d4951c990 | ||
|
|
6e57f6c527 | ||
|
|
b9ac51b6c3 | ||
|
|
702e8d79ce | ||
|
|
95a9dabf8b | ||
|
|
bae66c49c2 |
@@ -74,27 +74,29 @@ func (rw *RollingWindow) span() int {
|
||||
|
||||
func (rw *RollingWindow) updateOffset() {
|
||||
span := rw.span()
|
||||
if span > 0 {
|
||||
offset := rw.offset
|
||||
// reset expired buckets
|
||||
start := offset + 1
|
||||
steps := start + span
|
||||
var remainder int
|
||||
if steps > rw.size {
|
||||
remainder = steps - rw.size
|
||||
steps = rw.size
|
||||
}
|
||||
for i := start; i < steps; i++ {
|
||||
rw.win.resetBucket(i)
|
||||
offset = i
|
||||
}
|
||||
for i := 0; i < remainder; i++ {
|
||||
rw.win.resetBucket(i)
|
||||
offset = i
|
||||
}
|
||||
rw.offset = offset
|
||||
rw.lastTime = timex.Now()
|
||||
if span <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
offset := rw.offset
|
||||
start := offset + 1
|
||||
steps := start + span
|
||||
var remainder int
|
||||
if steps > rw.size {
|
||||
remainder = steps - rw.size
|
||||
steps = rw.size
|
||||
}
|
||||
|
||||
// reset expired buckets
|
||||
for i := start; i < steps; i++ {
|
||||
rw.win.resetBucket(i)
|
||||
}
|
||||
for i := 0; i < remainder; i++ {
|
||||
rw.win.resetBucket(i)
|
||||
}
|
||||
|
||||
rw.offset = (offset + span) % rw.size
|
||||
rw.lastTime = timex.Now()
|
||||
}
|
||||
|
||||
type Bucket struct {
|
||||
@@ -118,9 +120,9 @@ type window struct {
|
||||
}
|
||||
|
||||
func newWindow(size int) *window {
|
||||
var buckets []*Bucket
|
||||
buckets := make([]*Bucket, size)
|
||||
for i := 0; i < size; i++ {
|
||||
buckets = append(buckets, new(Bucket))
|
||||
buckets[i] = new(Bucket)
|
||||
}
|
||||
return &window{
|
||||
buckets: buckets,
|
||||
@@ -134,12 +136,12 @@ func (w *window) add(offset int, v float64) {
|
||||
|
||||
func (w *window) reduce(start, count int, fn func(b *Bucket)) {
|
||||
for i := 0; i < count; i++ {
|
||||
fn(w.buckets[(start+i)%len(w.buckets)])
|
||||
fn(w.buckets[(start+i)%w.size])
|
||||
}
|
||||
}
|
||||
|
||||
func (w *window) resetBucket(offset int) {
|
||||
w.buckets[offset].reset()
|
||||
w.buckets[offset%w.size].reset()
|
||||
}
|
||||
|
||||
func IgnoreCurrentBucket() RollingWindowOption {
|
||||
|
||||
@@ -21,6 +21,7 @@ var mock tracespec.Trace = new(mockTrace)
|
||||
|
||||
func TestTraceLog(t *testing.T) {
|
||||
var buf mockWriter
|
||||
atomic.StoreUint32(&initialized, 1)
|
||||
ctx := context.WithValue(context.Background(), tracespec.TracingKey, mock)
|
||||
WithContext(ctx).(*traceLogger).write(&buf, levelInfo, testlog)
|
||||
assert.True(t, strings.Contains(buf.String(), mockTraceId))
|
||||
|
||||
@@ -153,58 +153,57 @@ func doParseKeyAndOptions(field reflect.StructField, value string) (string, *fie
|
||||
key := strings.TrimSpace(segments[0])
|
||||
options := segments[1:]
|
||||
|
||||
if len(options) > 0 {
|
||||
var fieldOpts fieldOptions
|
||||
|
||||
for _, segment := range options {
|
||||
option := strings.TrimSpace(segment)
|
||||
switch {
|
||||
case option == stringOption:
|
||||
fieldOpts.FromString = true
|
||||
case strings.HasPrefix(option, optionalOption):
|
||||
segs := strings.Split(option, equalToken)
|
||||
switch len(segs) {
|
||||
case 1:
|
||||
fieldOpts.Optional = true
|
||||
case 2:
|
||||
fieldOpts.Optional = true
|
||||
fieldOpts.OptionalDep = segs[1]
|
||||
default:
|
||||
return "", nil, fmt.Errorf("field %s has wrong optional", field.Name)
|
||||
}
|
||||
case option == optionalOption:
|
||||
fieldOpts.Optional = true
|
||||
case strings.HasPrefix(option, optionsOption):
|
||||
segs := strings.Split(option, equalToken)
|
||||
if len(segs) != 2 {
|
||||
return "", nil, fmt.Errorf("field %s has wrong options", field.Name)
|
||||
} else {
|
||||
fieldOpts.Options = strings.Split(segs[1], optionSeparator)
|
||||
}
|
||||
case strings.HasPrefix(option, defaultOption):
|
||||
segs := strings.Split(option, equalToken)
|
||||
if len(segs) != 2 {
|
||||
return "", nil, fmt.Errorf("field %s has wrong default option", field.Name)
|
||||
} else {
|
||||
fieldOpts.Default = strings.TrimSpace(segs[1])
|
||||
}
|
||||
case strings.HasPrefix(option, rangeOption):
|
||||
segs := strings.Split(option, equalToken)
|
||||
if len(segs) != 2 {
|
||||
return "", nil, fmt.Errorf("field %s has wrong range", field.Name)
|
||||
}
|
||||
if nr, err := parseNumberRange(segs[1]); err != nil {
|
||||
return "", nil, err
|
||||
} else {
|
||||
fieldOpts.Range = nr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return key, &fieldOpts, nil
|
||||
if len(options) == 0 {
|
||||
return key, nil, nil
|
||||
}
|
||||
|
||||
return key, nil, nil
|
||||
var fieldOpts fieldOptions
|
||||
for _, segment := range options {
|
||||
option := strings.TrimSpace(segment)
|
||||
switch {
|
||||
case option == stringOption:
|
||||
fieldOpts.FromString = true
|
||||
case strings.HasPrefix(option, optionalOption):
|
||||
segs := strings.Split(option, equalToken)
|
||||
switch len(segs) {
|
||||
case 1:
|
||||
fieldOpts.Optional = true
|
||||
case 2:
|
||||
fieldOpts.Optional = true
|
||||
fieldOpts.OptionalDep = segs[1]
|
||||
default:
|
||||
return "", nil, fmt.Errorf("field %s has wrong optional", field.Name)
|
||||
}
|
||||
case option == optionalOption:
|
||||
fieldOpts.Optional = true
|
||||
case strings.HasPrefix(option, optionsOption):
|
||||
segs := strings.Split(option, equalToken)
|
||||
if len(segs) != 2 {
|
||||
return "", nil, fmt.Errorf("field %s has wrong options", field.Name)
|
||||
} else {
|
||||
fieldOpts.Options = strings.Split(segs[1], optionSeparator)
|
||||
}
|
||||
case strings.HasPrefix(option, defaultOption):
|
||||
segs := strings.Split(option, equalToken)
|
||||
if len(segs) != 2 {
|
||||
return "", nil, fmt.Errorf("field %s has wrong default option", field.Name)
|
||||
} else {
|
||||
fieldOpts.Default = strings.TrimSpace(segs[1])
|
||||
}
|
||||
case strings.HasPrefix(option, rangeOption):
|
||||
segs := strings.Split(option, equalToken)
|
||||
if len(segs) != 2 {
|
||||
return "", nil, fmt.Errorf("field %s has wrong range", field.Name)
|
||||
}
|
||||
if nr, err := parseNumberRange(segs[1]); err != nil {
|
||||
return "", nil, err
|
||||
} else {
|
||||
fieldOpts.Range = nr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return key, &fieldOpts, nil
|
||||
}
|
||||
|
||||
func implicitValueRequiredStruct(tag string, tp reflect.Type) (bool, error) {
|
||||
|
||||
@@ -556,7 +556,7 @@ func TestRedis_SortedSet(t *testing.T) {
|
||||
val, err = client.Zscore("key", "value1")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, int64(5), val)
|
||||
val, err = NewRedis(client.Addr, "").Zadds("key")
|
||||
_, err = NewRedis(client.Addr, "").Zadds("key")
|
||||
assert.NotNil(t, err)
|
||||
val, err = client.Zadds("key", Pair{
|
||||
Key: "value2",
|
||||
@@ -567,9 +567,9 @@ func TestRedis_SortedSet(t *testing.T) {
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, int64(2), val)
|
||||
pairs, err := NewRedis(client.Addr, "").ZRevRangeWithScores("key", 1, 3)
|
||||
_, err = NewRedis(client.Addr, "").ZRevRangeWithScores("key", 1, 3)
|
||||
assert.NotNil(t, err)
|
||||
pairs, err = client.ZRevRangeWithScores("key", 1, 3)
|
||||
pairs, err := client.ZRevRangeWithScores("key", 1, 3)
|
||||
assert.Nil(t, err)
|
||||
assert.EqualValues(t, []Pair{
|
||||
{
|
||||
|
||||
@@ -1,33 +1,29 @@
|
||||
type (
|
||||
addReq struct {
|
||||
book string `form:"book"`
|
||||
price int64 `form:"price"`
|
||||
}
|
||||
|
||||
addResp struct {
|
||||
ok bool `json:"ok"`
|
||||
}
|
||||
addReq {
|
||||
book string `form:"book"`
|
||||
price int64 `form:"price"`
|
||||
}
|
||||
|
||||
addResp {
|
||||
ok bool `json:"ok"`
|
||||
}
|
||||
)
|
||||
|
||||
type (
|
||||
checkReq struct {
|
||||
book string `form:"book"`
|
||||
}
|
||||
|
||||
checkResp struct {
|
||||
found bool `json:"found"`
|
||||
price int64 `json:"price"`
|
||||
}
|
||||
checkReq {
|
||||
book string `form:"book"`
|
||||
}
|
||||
|
||||
checkResp {
|
||||
found bool `json:"found"`
|
||||
price int64 `json:"price"`
|
||||
}
|
||||
)
|
||||
|
||||
service bookstore-api {
|
||||
@server(
|
||||
handler: AddHandler
|
||||
)
|
||||
get /add (addReq) returns (addResp)
|
||||
|
||||
@server(
|
||||
handler: CheckHandler
|
||||
)
|
||||
get /check (checkReq) returns (checkResp)
|
||||
@handler AddHandler
|
||||
get /add (addReq) returns (addResp)
|
||||
|
||||
@handler CheckHandler
|
||||
get /check (checkReq) returns (checkResp)
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/tal-tech/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func addHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
func AddHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.AddReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/tal-tech/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func checkHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
func CheckHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.CheckReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
|
||||
@@ -10,16 +10,18 @@ import (
|
||||
)
|
||||
|
||||
func RegisterHandlers(engine *rest.Server, serverCtx *svc.ServiceContext) {
|
||||
engine.AddRoutes([]rest.Route{
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/add",
|
||||
Handler: addHandler(serverCtx),
|
||||
engine.AddRoutes(
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/add",
|
||||
Handler: AddHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/check",
|
||||
Handler: CheckHandler(serverCtx),
|
||||
},
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/check",
|
||||
Handler: checkHandler(serverCtx),
|
||||
},
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ func (l *CheckLogic) Check(req types.CheckReq) (*types.CheckResp, error) {
|
||||
Book: req.Book,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
logx.Error(err)
|
||||
return &types.CheckResp{}, err
|
||||
}
|
||||
|
||||
return &types.CheckResp{
|
||||
|
||||
@@ -8,4 +8,5 @@ require (
|
||||
github.com/tal-tech/go-zero v1.0.27
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381
|
||||
google.golang.org/grpc v1.29.1
|
||||
google.golang.org/protobuf v1.25.0
|
||||
)
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
|
||||
"bookstore/rpc/add/add"
|
||||
"bookstore/rpc/add/internal/config"
|
||||
add "bookstore/rpc/add/internal/pb"
|
||||
"bookstore/rpc/add/internal/server"
|
||||
"bookstore/rpc/add/internal/svc"
|
||||
|
||||
|
||||
305
example/bookstore/rpc/add/add/add.pb.go
Normal file
305
example/bookstore/rpc/add/add/add.pb.go
Normal 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",
|
||||
}
|
||||
@@ -8,7 +8,7 @@ package adder
|
||||
import (
|
||||
"context"
|
||||
|
||||
add "bookstore/rpc/add/internal/pb"
|
||||
"bookstore/rpc/add/add"
|
||||
|
||||
"github.com/tal-tech/go-zero/zrpc"
|
||||
)
|
||||
@@ -33,6 +33,6 @@ func NewAdder(cli zrpc.Client) Adder {
|
||||
}
|
||||
|
||||
func (m *defaultAdder) Add(ctx context.Context, in *AddReq) (*AddResp, error) {
|
||||
adder := add.NewAdderClient(m.cli.Conn())
|
||||
return adder.Add(ctx, in)
|
||||
client := add.NewAdderClient(m.cli.Conn())
|
||||
return client.Add(ctx, in)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -8,6 +8,5 @@ import (
|
||||
type Config struct {
|
||||
zrpc.RpcServerConf
|
||||
DataSource string
|
||||
Table string
|
||||
Cache cache.CacheConf
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package logic
|
||||
import (
|
||||
"context"
|
||||
|
||||
add "bookstore/rpc/add/internal/pb"
|
||||
add "bookstore/rpc/add/adder"
|
||||
"bookstore/rpc/add/internal/svc"
|
||||
"bookstore/rpc/model"
|
||||
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
@@ -6,8 +6,8 @@ package server
|
||||
import (
|
||||
"context"
|
||||
|
||||
"bookstore/rpc/add/add"
|
||||
"bookstore/rpc/add/internal/logic"
|
||||
add "bookstore/rpc/add/internal/pb"
|
||||
"bookstore/rpc/add/internal/svc"
|
||||
)
|
||||
|
||||
|
||||
@@ -9,12 +9,12 @@ import (
|
||||
|
||||
type ServiceContext struct {
|
||||
c config.Config
|
||||
Model *model.BookModel
|
||||
Model model.BookModel
|
||||
}
|
||||
|
||||
func NewServiceContext(c config.Config) *ServiceContext {
|
||||
return &ServiceContext{
|
||||
c: c,
|
||||
Model: model.NewBookModel(sqlx.NewMysql(c.DataSource), c.Cache, c.Table),
|
||||
c: c,
|
||||
Model: model.NewBookModel(sqlx.NewMysql(c.DataSource), c.Cache),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
|
||||
"bookstore/rpc/check/check"
|
||||
"bookstore/rpc/check/internal/config"
|
||||
check "bookstore/rpc/check/internal/pb"
|
||||
"bookstore/rpc/check/internal/server"
|
||||
"bookstore/rpc/check/internal/svc"
|
||||
|
||||
|
||||
306
example/bookstore/rpc/check/check/check.pb.go
Normal file
306
example/bookstore/rpc/check/check/check.pb.go
Normal 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",
|
||||
}
|
||||
@@ -8,7 +8,7 @@ package checker
|
||||
import (
|
||||
"context"
|
||||
|
||||
check "bookstore/rpc/check/internal/pb"
|
||||
"bookstore/rpc/check/check"
|
||||
|
||||
"github.com/tal-tech/go-zero/zrpc"
|
||||
)
|
||||
@@ -33,6 +33,6 @@ func NewChecker(cli zrpc.Client) Checker {
|
||||
}
|
||||
|
||||
func (m *defaultChecker) Check(ctx context.Context, in *CheckReq) (*CheckResp, error) {
|
||||
checker := check.NewCheckerClient(m.cli.Conn())
|
||||
return checker.Check(ctx, in)
|
||||
client := check.NewCheckerClient(m.cli.Conn())
|
||||
return client.Check(ctx, in)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -8,6 +8,5 @@ import (
|
||||
type Config struct {
|
||||
zrpc.RpcServerConf
|
||||
DataSource string
|
||||
Table string
|
||||
Cache cache.CacheConf
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package logic
|
||||
import (
|
||||
"context"
|
||||
|
||||
check "bookstore/rpc/check/internal/pb"
|
||||
check "bookstore/rpc/check/checker"
|
||||
"bookstore/rpc/check/internal/svc"
|
||||
|
||||
"github.com/tal-tech/go-zero/core/logx"
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
@@ -6,8 +6,8 @@ package server
|
||||
import (
|
||||
"context"
|
||||
|
||||
"bookstore/rpc/check/check"
|
||||
"bookstore/rpc/check/internal/logic"
|
||||
check "bookstore/rpc/check/internal/pb"
|
||||
"bookstore/rpc/check/internal/svc"
|
||||
)
|
||||
|
||||
|
||||
@@ -9,12 +9,12 @@ import (
|
||||
|
||||
type ServiceContext struct {
|
||||
c config.Config
|
||||
Model *model.BookModel
|
||||
Model model.BookModel
|
||||
}
|
||||
|
||||
func NewServiceContext(c config.Config) *ServiceContext {
|
||||
return &ServiceContext{
|
||||
c: c,
|
||||
Model: model.NewBookModel(sqlx.NewMysql(c.DataSource), c.Cache, c.Table),
|
||||
c: c,
|
||||
Model: model.NewBookModel(sqlx.NewMysql(c.DataSource), c.Cache),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,11 +18,18 @@ var (
|
||||
bookRowsExpectAutoSet = strings.Join(stringx.Remove(bookFieldNames, "create_time", "update_time"), ",")
|
||||
bookRowsWithPlaceHolder = strings.Join(stringx.Remove(bookFieldNames, "book", "create_time", "update_time"), "=?,") + "=?"
|
||||
|
||||
bookPrefix = "cache#Book#book#"
|
||||
cacheBookPrefix = "cache#Book#book#"
|
||||
)
|
||||
|
||||
type (
|
||||
BookModel struct {
|
||||
BookModel interface {
|
||||
Insert(data Book) (sql.Result, error)
|
||||
FindOne(book string) (*Book, error)
|
||||
Update(data Book) error
|
||||
Delete(book string) error
|
||||
}
|
||||
|
||||
defaultBookModel struct {
|
||||
sqlc.CachedConn
|
||||
table string
|
||||
}
|
||||
@@ -33,23 +40,25 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
func NewBookModel(conn sqlx.SqlConn, c cache.CacheConf, table string) *BookModel {
|
||||
return &BookModel{
|
||||
func NewBookModel(conn sqlx.SqlConn, c cache.CacheConf) BookModel {
|
||||
return &defaultBookModel{
|
||||
CachedConn: sqlc.NewConn(conn, c),
|
||||
table: table,
|
||||
table: "book",
|
||||
}
|
||||
}
|
||||
|
||||
func (m *BookModel) Insert(data Book) (sql.Result, error) {
|
||||
query := `insert into ` + m.table + ` (` + bookRowsExpectAutoSet + `) values (?, ?)`
|
||||
return m.ExecNoCache(query, data.Book, data.Price)
|
||||
func (m *defaultBookModel) Insert(data Book) (sql.Result, error) {
|
||||
query := fmt.Sprintf("insert into %s (%s) values (?, ?)", m.table, bookRowsExpectAutoSet)
|
||||
ret, err := m.ExecNoCache(query, data.Book, data.Price)
|
||||
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (m *BookModel) FindOne(book string) (*Book, error) {
|
||||
bookKey := fmt.Sprintf("%s%v", bookPrefix, book)
|
||||
func (m *defaultBookModel) FindOne(book string) (*Book, error) {
|
||||
bookKey := fmt.Sprintf("%s%v", cacheBookPrefix, book)
|
||||
var resp Book
|
||||
err := m.QueryRow(&resp, bookKey, func(conn sqlx.SqlConn, v interface{}) error {
|
||||
query := `select ` + bookRows + ` from ` + m.table + ` where book = ? limit 1`
|
||||
query := fmt.Sprintf("select %s from %s where book = ? limit 1", bookRows, m.table)
|
||||
return conn.QueryRow(v, query, book)
|
||||
})
|
||||
switch err {
|
||||
@@ -62,20 +71,30 @@ func (m *BookModel) FindOne(book string) (*Book, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *BookModel) Update(data Book) error {
|
||||
bookKey := fmt.Sprintf("%s%v", bookPrefix, data.Book)
|
||||
func (m *defaultBookModel) Update(data Book) error {
|
||||
bookKey := fmt.Sprintf("%s%v", cacheBookPrefix, data.Book)
|
||||
_, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := `update ` + m.table + ` set ` + bookRowsWithPlaceHolder + ` where book = ?`
|
||||
query := fmt.Sprintf("update %s set %s where book = ?", m.table, bookRowsWithPlaceHolder)
|
||||
return conn.Exec(query, data.Price, data.Book)
|
||||
}, bookKey)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *BookModel) Delete(book string) error {
|
||||
bookKey := fmt.Sprintf("%s%v", bookPrefix, book)
|
||||
func (m *defaultBookModel) Delete(book string) error {
|
||||
|
||||
bookKey := fmt.Sprintf("%s%v", cacheBookPrefix, book)
|
||||
_, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := `delete from ` + m.table + ` where book = ?`
|
||||
query := fmt.Sprintf("delete from %s where book = ?", m.table)
|
||||
return conn.Exec(query, book)
|
||||
}, bookKey)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *defaultBookModel) formatPrimary(primary interface{}) string {
|
||||
return fmt.Sprintf("%s%v", cacheBookPrefix, primary)
|
||||
}
|
||||
|
||||
func (m *defaultBookModel) queryPrimary(conn sqlx.SqlConn, v, primary interface{}) error {
|
||||
query := fmt.Sprintf("select %s from %s where book = ? limit 1", bookRows, m.table)
|
||||
return conn.QueryRow(v, query, primary)
|
||||
}
|
||||
|
||||
0
example/bookstore/rpc/model/vars.go
Executable file → Normal file
0
example/bookstore/rpc/model/vars.go
Executable file → Normal file
@@ -41,6 +41,7 @@ func main() {
|
||||
var allowed, denied int32
|
||||
var wait sync.WaitGroup
|
||||
for i := 0; i < *threads; i++ {
|
||||
i := i
|
||||
wait.Add(1)
|
||||
go func() {
|
||||
for {
|
||||
|
||||
@@ -37,6 +37,7 @@ github.com/coreos/go-systemd/v22 v22.0.0 h1:XJIw/+VlJ+87J+doOxznsAWIdmWuViOVhkQa
|
||||
github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -49,6 +50,7 @@ github.com/dsymonds/gotoc v0.0.0-20160928043926-5aebcfc91819 h1:9778zj477h/VauD8
|
||||
github.com/dsymonds/gotoc v0.0.0-20160928043926-5aebcfc91819/go.mod h1:MvzMVHq8BH2Ji/o8TGDocVA70byvLrAgFTxkEnmjO4Y=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4 h1:qk/FSDDxo05wdJH28W+p5yivv7LuLYLRXPPD8KQCtZs=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/emicklei/proto v1.9.0 h1:l0QiNT6Qs7Yj0Mb4X6dnWBQer4ebei2BFcgQLbGqUDc=
|
||||
github.com/emicklei/proto v1.9.0/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
@@ -131,6 +133,7 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334 h1:VHgatEHNcBFEB7inlalqfNqw65aNkM1lGX2yt3NmbS8=
|
||||
github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
|
||||
github.com/iancoleman/strcase v0.1.2 h1:gnomlvw9tnV3ITTAxzKSgTF+8kFWcU/f+TgttpXGz1U=
|
||||
github.com/iancoleman/strcase v0.1.2/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
||||
@@ -220,6 +223,7 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
|
||||
@@ -252,6 +256,7 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6/go.mod h1
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA=
|
||||
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
|
||||
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
|
||||
7
go.mod
7
go.mod
@@ -1,6 +1,6 @@
|
||||
module github.com/tal-tech/go-zero
|
||||
|
||||
go 1.13
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/ClickHouse/clickhouse-go v1.4.3
|
||||
@@ -11,6 +11,7 @@ require (
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/emicklei/proto v1.9.0
|
||||
github.com/fatih/color v1.9.0 // indirect
|
||||
github.com/fatih/structtag v1.2.0
|
||||
github.com/frankban/quicktest v1.7.2 // indirect
|
||||
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8
|
||||
github.com/go-redis/redis v6.15.7+incompatible
|
||||
@@ -55,10 +56,10 @@ require (
|
||||
golang.org/x/tools v0.0.0-20200410132612-ae9902aceb98 // indirect
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f // indirect
|
||||
google.golang.org/grpc v1.29.1
|
||||
google.golang.org/protobuf v1.25.0
|
||||
google.golang.org/protobuf v1.25.0 // indirect
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.28
|
||||
gopkg.in/h2non/gock.v1 v1.0.15
|
||||
gopkg.in/yaml.v2 v2.3.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
honnef.co/go/tools v0.0.1-2020.1.4 // indirect
|
||||
sigs.k8s.io/yaml v1.2.0 // indirect
|
||||
)
|
||||
|
||||
6
go.sum
6
go.sum
@@ -63,6 +63,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
|
||||
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
|
||||
github.com/frankban/quicktest v1.7.2 h1:2QxQoC1TS09S7fhCPsrvqYdvP1H5M1P1ih5ABm3BTYk=
|
||||
github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
@@ -450,8 +452,8 @@ gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||
|
||||
@@ -129,7 +129,7 @@ go get -u github.com/tal-tech/go-zero
|
||||
the .api files also can be generate by goctl, like below:
|
||||
|
||||
```shell
|
||||
goctl api -o greet.api
|
||||
goctl api -o greet.api
|
||||
```
|
||||
|
||||
3. generate the go server side code
|
||||
@@ -174,7 +174,7 @@ goctl api -o greet.api
|
||||
you can check it by curl:
|
||||
|
||||
```shell
|
||||
curl -i http://localhost:8888/greet/from/you
|
||||
curl -i http://localhost:8888/from/you
|
||||
```
|
||||
|
||||
the response looks like:
|
||||
|
||||
@@ -120,7 +120,7 @@ GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/tal-tech/
|
||||
默认侦听在 8888 端口(可以在配置文件里修改),可以通过 curl 请求:
|
||||
|
||||
```shell
|
||||
curl -i http://localhost:8888/greet/from/you
|
||||
curl -i http://localhost:8888/from/you
|
||||
```
|
||||
|
||||
返回如下:
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
multipartFormData = "multipart/form-data"
|
||||
formKey = "form"
|
||||
pathKey = "path"
|
||||
emptyJson = "{}"
|
||||
@@ -39,12 +38,12 @@ func Parse(r *http.Request, v interface{}) error {
|
||||
|
||||
// Parses the form request.
|
||||
func ParseForm(r *http.Request, v interface{}) error {
|
||||
if strings.Contains(r.Header.Get(ContentType), multipartFormData) {
|
||||
if err := r.ParseMultipartForm(maxMemory); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := r.ParseMultipartForm(maxMemory); err != nil {
|
||||
if err != http.ErrNotMultipart {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ func (pr *patRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
allow, ok := pr.methodNotAllowed(r.Method, reqPath)
|
||||
allows, ok := pr.methodsAllowed(r.Method, reqPath)
|
||||
if !ok {
|
||||
pr.handleNotFound(w, r)
|
||||
return
|
||||
@@ -73,7 +73,7 @@ func (pr *patRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if pr.notAllowed != nil {
|
||||
pr.notAllowed.ServeHTTP(w, r)
|
||||
} else {
|
||||
w.Header().Set(allowHeader, allow)
|
||||
w.Header().Set(allowHeader, allows)
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
}
|
||||
}
|
||||
@@ -94,7 +94,7 @@ func (pr *patRouter) handleNotFound(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func (pr *patRouter) methodNotAllowed(method, path string) (string, bool) {
|
||||
func (pr *patRouter) methodsAllowed(method, path string) (string, bool) {
|
||||
var allows []string
|
||||
|
||||
for treeMethod, tree := range pr.trees {
|
||||
|
||||
@@ -2,13 +2,13 @@ version := $(shell /bin/date "+%Y-%m-%d %H:%M")
|
||||
|
||||
build:
|
||||
go build -ldflags="-s -w" -ldflags="-X 'main.BuildTime=$(version)'" goctl.go
|
||||
command -v upx &> /dev/null && upx goctl
|
||||
$(if $(shell command -v upx), upx goctl)
|
||||
mac:
|
||||
GOOS=darwin go build -ldflags="-s -w" -ldflags="-X 'main.BuildTime=$(version)'" -o goctl-darwin goctl.go
|
||||
command -v upx &> /dev/null && upx goctl-darwin
|
||||
$(if $(shell command -v upx), upx goctl-darwin)
|
||||
win:
|
||||
GOOS=windows go build -ldflags="-s -w" -ldflags="-X 'main.BuildTime=$(version)'" -o goctl.exe goctl.go
|
||||
command -v upx &> /dev/null && upx goctl.exe
|
||||
$(if $(shell command -v upx), upx goctl.exe)
|
||||
linux:
|
||||
GOOS=linux go build -ldflags="-s -w" -ldflags="-X 'main.BuildTime=$(version)'" -o goctl-linux goctl.go
|
||||
command -v upx &> /dev/null && upx goctl-linux
|
||||
$(if $(shell command -v upx), upx goctl-linux)
|
||||
|
||||
@@ -28,10 +28,10 @@ type response struct {
|
||||
}
|
||||
|
||||
service {{.serviceName}} {
|
||||
@handler // TODO: set handler name and delete this comment
|
||||
@handler GetUser // TODO: set handler name and delete this comment
|
||||
get /users/id/:userId(request) returns(response)
|
||||
|
||||
@handler // TODO: set handler name and delete this comment
|
||||
@handler CreateUser // TODO: set handler name and delete this comment
|
||||
post /users/create(request)
|
||||
}
|
||||
`
|
||||
|
||||
@@ -12,13 +12,13 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/logrusorgru/aurora"
|
||||
"github.com/urfave/cli"
|
||||
|
||||
"github.com/tal-tech/go-zero/core/logx"
|
||||
apiformat "github.com/tal-tech/go-zero/tools/goctl/api/format"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
|
||||
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/config"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
const tmpFile = "%s-%d"
|
||||
@@ -28,6 +28,8 @@ var tmpDir = path.Join(os.TempDir(), "goctl")
|
||||
func GoCommand(c *cli.Context) error {
|
||||
apiFile := c.String("api")
|
||||
dir := c.String("dir")
|
||||
namingStyle := c.String("style")
|
||||
|
||||
if len(apiFile) == 0 {
|
||||
return errors.New("missing -api")
|
||||
}
|
||||
@@ -35,10 +37,10 @@ func GoCommand(c *cli.Context) error {
|
||||
return errors.New("missing -dir")
|
||||
}
|
||||
|
||||
return DoGenProject(apiFile, dir)
|
||||
return DoGenProject(apiFile, dir, namingStyle)
|
||||
}
|
||||
|
||||
func DoGenProject(apiFile, dir string) error {
|
||||
func DoGenProject(apiFile, dir, style string) error {
|
||||
p, err := parser.NewParser(apiFile)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -48,15 +50,21 @@ func DoGenProject(apiFile, dir string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
cfg, err := config.NewConfig(style)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logx.Must(util.MkdirIfNotExist(dir))
|
||||
logx.Must(genEtc(dir, api))
|
||||
logx.Must(genConfig(dir, api))
|
||||
logx.Must(genMain(dir, api))
|
||||
logx.Must(genServiceContext(dir, api))
|
||||
logx.Must(genTypes(dir, api))
|
||||
logx.Must(genHandlers(dir, api))
|
||||
logx.Must(genRoutes(dir, api))
|
||||
logx.Must(genLogic(dir, api))
|
||||
logx.Must(genEtc(dir, cfg, api))
|
||||
logx.Must(genConfig(dir, cfg, api))
|
||||
logx.Must(genMain(dir, cfg, api))
|
||||
logx.Must(genServiceContext(dir, cfg, api))
|
||||
logx.Must(genTypes(dir, cfg, api))
|
||||
logx.Must(genRoutes(dir, cfg, api))
|
||||
logx.Must(genHandlers(dir, cfg, api))
|
||||
logx.Must(genLogic(dir, cfg, api))
|
||||
logx.Must(genMiddleware(dir, cfg, api))
|
||||
|
||||
if err := backupAndSweep(apiFile); err != nil {
|
||||
return err
|
||||
|
||||
@@ -25,7 +25,7 @@ info(
|
||||
// TODO: test
|
||||
// {
|
||||
type Request struct { // TODO: test
|
||||
// TOOD
|
||||
// TODO
|
||||
Name string ` + "`" + `path:"name,options=you|me"` + "`" + ` // }
|
||||
} // TODO: test
|
||||
|
||||
@@ -534,6 +534,7 @@ func TestHasImportApi(t *testing.T) {
|
||||
}
|
||||
}
|
||||
assert.True(t, hasInline)
|
||||
|
||||
validate(t, filename)
|
||||
}
|
||||
|
||||
@@ -558,15 +559,30 @@ func TestNestTypeApi(t *testing.T) {
|
||||
err := ioutil.WriteFile(filename, []byte(nestTypeApi), os.ModePerm)
|
||||
assert.Nil(t, err)
|
||||
defer os.Remove(filename)
|
||||
|
||||
_, err = parser.NewParser(filename)
|
||||
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestCamelStyle(t *testing.T) {
|
||||
filename := "greet.api"
|
||||
err := ioutil.WriteFile(filename, []byte(testApiTemplate), os.ModePerm)
|
||||
assert.Nil(t, err)
|
||||
defer os.Remove(filename)
|
||||
_, err = parser.NewParser(filename)
|
||||
assert.Nil(t, err)
|
||||
|
||||
validateWithCamel(t, filename, "GoZero")
|
||||
}
|
||||
|
||||
func validate(t *testing.T, api string) {
|
||||
validateWithCamel(t, api, "gozero")
|
||||
}
|
||||
|
||||
func validateWithCamel(t *testing.T, api, camel string) {
|
||||
dir := "_go"
|
||||
os.RemoveAll(dir)
|
||||
err := DoGenProject(api, dir)
|
||||
err := DoGenProject(api, dir, camel)
|
||||
defer os.RemoveAll(dir)
|
||||
assert.Nil(t, err)
|
||||
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
||||
|
||||
@@ -8,12 +8,14 @@ import (
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/config"
|
||||
ctlutil "github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/format"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/vars"
|
||||
)
|
||||
|
||||
const (
|
||||
configFile = "config.go"
|
||||
configFile = "config"
|
||||
configTemplate = `package config
|
||||
|
||||
import {{.authImport}}
|
||||
@@ -31,8 +33,13 @@ type Config struct {
|
||||
`
|
||||
)
|
||||
|
||||
func genConfig(dir string, api *spec.ApiSpec) error {
|
||||
fp, created, err := util.MaybeCreateFile(dir, configDir, configFile)
|
||||
func genConfig(dir string, cfg *config.Config, api *spec.ApiSpec) error {
|
||||
filename, err := format.FileNamingFormat(cfg.NamingFormat, configFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fp, created, err := util.MaybeCreateFile(dir, configDir, filename+".go")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -8,7 +8,9 @@ import (
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/config"
|
||||
ctlutil "github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/format"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -20,8 +22,13 @@ Port: {{.port}}
|
||||
`
|
||||
)
|
||||
|
||||
func genEtc(dir string, api *spec.ApiSpec) error {
|
||||
fp, created, err := util.MaybeCreateFile(dir, etcDir, fmt.Sprintf("%s.yaml", api.Service.Name))
|
||||
func genEtc(dir string, cfg *config.Config, api *spec.ApiSpec) error {
|
||||
filename, err := format.FileNamingFormat(cfg.NamingFormat, api.Service.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fp, created, err := util.MaybeCreateFile(dir, etcDir, fmt.Sprintf("%s.yaml", filename))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -2,14 +2,18 @@ package gogen
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
"text/template"
|
||||
"unicode"
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
|
||||
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/config"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/format"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/vars"
|
||||
)
|
||||
|
||||
@@ -50,13 +54,8 @@ type Handler struct {
|
||||
HasRequest bool
|
||||
}
|
||||
|
||||
func genHandler(dir string, group spec.Group, route spec.Route) error {
|
||||
handler, ok := apiutil.GetAnnotationValue(route.Annotations, "server", "handler")
|
||||
if !ok {
|
||||
return fmt.Errorf("missing handler annotation for %q", route.Path)
|
||||
}
|
||||
|
||||
handler = getHandlerName(handler)
|
||||
func genHandler(dir string, cfg *config.Config, group spec.Group, route spec.Route) error {
|
||||
handler := getHandlerName(route)
|
||||
if getHandlerFolderPath(group, route) != handlerDir {
|
||||
handler = strings.Title(handler)
|
||||
}
|
||||
@@ -65,27 +64,25 @@ func genHandler(dir string, group spec.Group, route spec.Route) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return doGenToFile(dir, handler, group, route, Handler{
|
||||
return doGenToFile(dir, handler, cfg, group, route, Handler{
|
||||
ImportPackages: genHandlerImports(group, route, parentPkg),
|
||||
HandlerName: handler,
|
||||
RequestType: util.Title(route.RequestType.Name),
|
||||
LogicType: strings.TrimSuffix(strings.Title(handler), "Handler") + "Logic",
|
||||
LogicType: strings.Title(getLogicName(route)),
|
||||
Call: strings.Title(strings.TrimSuffix(handler, "Handler")),
|
||||
HasResp: len(route.ResponseType.Name) > 0,
|
||||
HasRequest: len(route.RequestType.Name) > 0,
|
||||
})
|
||||
}
|
||||
|
||||
func doGenToFile(dir, handler string, group spec.Group, route spec.Route, handleObj Handler) error {
|
||||
if getHandlerFolderPath(group, route) != handlerDir {
|
||||
handler = strings.Title(handler)
|
||||
}
|
||||
filename := strings.ToLower(handler)
|
||||
if strings.HasSuffix(filename, "handler") {
|
||||
filename = filename + ".go"
|
||||
} else {
|
||||
filename = filename + "handler.go"
|
||||
func doGenToFile(dir, handler string, cfg *config.Config, group spec.Group,
|
||||
route spec.Route, handleObj Handler) error {
|
||||
filename, err := format.FileNamingFormat(cfg.NamingFormat, handler)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
filename = filename + ".go"
|
||||
fp, created, err := apiutil.MaybeCreateFile(dir, getHandlerFolderPath(group, route), filename)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -111,10 +108,10 @@ func doGenToFile(dir, handler string, group spec.Group, route spec.Route, handle
|
||||
return err
|
||||
}
|
||||
|
||||
func genHandlers(dir string, api *spec.ApiSpec) error {
|
||||
func genHandlers(dir string, cfg *config.Config, api *spec.ApiSpec) error {
|
||||
for _, group := range api.Service.Groups {
|
||||
for _, route := range group.Routes {
|
||||
if err := genHandler(dir, group, route); err != nil {
|
||||
if err := genHandler(dir, cfg, group, route); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -136,14 +133,23 @@ func genHandlerImports(group spec.Group, route spec.Route, parentPkg string) str
|
||||
return strings.Join(imports, "\n\t")
|
||||
}
|
||||
|
||||
func getHandlerBaseName(handler string) string {
|
||||
handlerName := util.Untitle(handler)
|
||||
if strings.HasSuffix(handlerName, "handler") {
|
||||
handlerName = strings.ReplaceAll(handlerName, "handler", "")
|
||||
} else if strings.HasSuffix(handlerName, "Handler") {
|
||||
handlerName = strings.ReplaceAll(handlerName, "Handler", "")
|
||||
func getHandlerBaseName(route spec.Route) (string, error) {
|
||||
handler, ok := apiutil.GetAnnotationValue(route.Annotations, "server", "handler")
|
||||
if !ok {
|
||||
return "", fmt.Errorf("missing handler annotation for %q", route.Path)
|
||||
}
|
||||
return handlerName
|
||||
|
||||
for _, char := range handler {
|
||||
if !unicode.IsDigit(char) && !unicode.IsLetter(char) {
|
||||
return "", errors.New(fmt.Sprintf("route [%s] handler [%s] invalid, handler name should only contains letter or digit",
|
||||
route.Path, handler))
|
||||
}
|
||||
}
|
||||
|
||||
handler = strings.TrimSpace(handler)
|
||||
handler = strings.TrimSuffix(handler, "handler")
|
||||
handler = strings.TrimSuffix(handler, "Handler")
|
||||
return handler, nil
|
||||
}
|
||||
|
||||
func getHandlerFolderPath(group spec.Group, route spec.Route) string {
|
||||
@@ -159,6 +165,20 @@ func getHandlerFolderPath(group spec.Group, route spec.Route) string {
|
||||
return path.Join(handlerDir, folder)
|
||||
}
|
||||
|
||||
func getHandlerName(handler string) string {
|
||||
return getHandlerBaseName(handler) + "Handler"
|
||||
func getHandlerName(route spec.Route) string {
|
||||
handler, err := getHandlerBaseName(route)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return handler + "Handler"
|
||||
}
|
||||
|
||||
func getLogicName(route spec.Route) string {
|
||||
handler, err := getHandlerBaseName(route)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return handler + "Logic"
|
||||
}
|
||||
|
||||
@@ -9,7 +9,9 @@ import (
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/config"
|
||||
ctlutil "github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/format"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/vars"
|
||||
)
|
||||
|
||||
@@ -40,10 +42,10 @@ func (l *{{.logic}}) {{.function}}({{.request}}) {{.responseType}} {
|
||||
}
|
||||
`
|
||||
|
||||
func genLogic(dir string, api *spec.ApiSpec) error {
|
||||
func genLogic(dir string, cfg *config.Config, api *spec.ApiSpec) error {
|
||||
for _, g := range api.Service.Groups {
|
||||
for _, r := range g.Routes {
|
||||
err := genLogicByRoute(dir, g, r)
|
||||
err := genLogicByRoute(dir, cfg, g, r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -52,16 +54,14 @@ func genLogic(dir string, api *spec.ApiSpec) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func genLogicByRoute(dir string, group spec.Group, route spec.Route) error {
|
||||
handler, ok := util.GetAnnotationValue(route.Annotations, "server", "handler")
|
||||
if !ok {
|
||||
return fmt.Errorf("missing handler annotation for %q", route.Path)
|
||||
func genLogicByRoute(dir string, cfg *config.Config, group spec.Group, route spec.Route) error {
|
||||
logic := getLogicName(route)
|
||||
goFile, err := format.FileNamingFormat(cfg.NamingFormat, logic)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
handler = strings.TrimSuffix(handler, "handler")
|
||||
handler = strings.TrimSuffix(handler, "Handler")
|
||||
filename := strings.ToLower(handler)
|
||||
goFile := filename + "logic.go"
|
||||
goFile = goFile + ".go"
|
||||
fp, created, err := util.MaybeCreateFile(dir, getLogicFolderPath(group, route), goFile)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -102,8 +102,8 @@ func genLogicByRoute(dir string, group spec.Group, route spec.Route) error {
|
||||
buffer := new(bytes.Buffer)
|
||||
err = t.Execute(fp, map[string]string{
|
||||
"imports": imports,
|
||||
"logic": strings.Title(handler) + "Logic",
|
||||
"function": strings.Title(strings.TrimSuffix(handler, "Handler")),
|
||||
"logic": strings.Title(logic),
|
||||
"function": strings.Title(strings.TrimSuffix(logic, "Logic")),
|
||||
"responseType": responseString,
|
||||
"returnString": returnString,
|
||||
"request": requestString,
|
||||
|
||||
@@ -8,7 +8,9 @@ import (
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/config"
|
||||
ctlutil "github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/format"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/vars"
|
||||
)
|
||||
|
||||
@@ -40,12 +42,17 @@ func main() {
|
||||
}
|
||||
`
|
||||
|
||||
func genMain(dir string, api *spec.ApiSpec) error {
|
||||
func genMain(dir string, cfg *config.Config, api *spec.ApiSpec) error {
|
||||
name := strings.ToLower(api.Service.Name)
|
||||
if strings.HasSuffix(name, "-api") {
|
||||
name = strings.ReplaceAll(name, "-api", "")
|
||||
}
|
||||
goFile := name + ".go"
|
||||
filename, err := format.FileNamingFormat(cfg.NamingFormat, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
goFile := filename + ".go"
|
||||
fp, created, err := util.MaybeCreateFile(dir, "", goFile)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -5,7 +5,10 @@ import (
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/config"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/format"
|
||||
)
|
||||
|
||||
var middlewareImplementCode = `
|
||||
@@ -30,9 +33,16 @@ func (m *{{.name}})Handle(next http.HandlerFunc) http.HandlerFunc {
|
||||
}
|
||||
`
|
||||
|
||||
func genMiddleware(dir string, middlewares []string) error {
|
||||
func genMiddleware(dir string, cfg *config.Config, api *spec.ApiSpec) error {
|
||||
var middlewares = getMiddleware(api)
|
||||
for _, item := range middlewares {
|
||||
filename := strings.TrimSuffix(strings.ToLower(item), "middleware") + "middleware" + ".go"
|
||||
middlewareFilename := strings.TrimSuffix(strings.ToLower(item), "middleware") + "_middleware"
|
||||
formatName, err := format.FileNamingFormat(cfg.NamingFormat, middlewareFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
filename := formatName + ".go"
|
||||
fp, created, err := util.MaybeCreateFile(dir, middlewareDir, filename)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -12,12 +12,14 @@ import (
|
||||
"github.com/tal-tech/go-zero/core/collection"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
|
||||
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/config"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/format"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/vars"
|
||||
)
|
||||
|
||||
const (
|
||||
routesFilename = "routes.go"
|
||||
routesFilename = "routes"
|
||||
routesTemplate = `// Code generated by goctl. DO NOT EDIT.
|
||||
package handler
|
||||
|
||||
@@ -62,7 +64,7 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
func genRoutes(dir string, api *spec.ApiSpec) error {
|
||||
func genRoutes(dir string, cfg *config.Config, api *spec.ApiSpec) error {
|
||||
var builder strings.Builder
|
||||
groups, err := getRoutes(api)
|
||||
if err != nil {
|
||||
@@ -121,10 +123,16 @@ func genRoutes(dir string, api *spec.ApiSpec) error {
|
||||
return err
|
||||
}
|
||||
|
||||
filename := path.Join(dir, handlerDir, routesFilename)
|
||||
routeFilename, err := format.FileNamingFormat(cfg.NamingFormat, routesFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
routeFilename = routeFilename + ".go"
|
||||
|
||||
filename := path.Join(dir, handlerDir, routeFilename)
|
||||
os.Remove(filename)
|
||||
|
||||
fp, created, err := apiutil.MaybeCreateFile(dir, handlerDir, routesFilename)
|
||||
fp, created, err := apiutil.MaybeCreateFile(dir, handlerDir, routeFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -176,11 +184,8 @@ func getRoutes(api *spec.ApiSpec) ([]group, error) {
|
||||
for _, g := range api.Service.Groups {
|
||||
var groupedRoutes group
|
||||
for _, r := range g.Routes {
|
||||
handler, ok := apiutil.GetAnnotationValue(r.Annotations, "server", "handler")
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("missing handler annotation for route %q", r.Path)
|
||||
}
|
||||
handler = getHandlerBaseName(handler) + "Handler(serverCtx)"
|
||||
handler := getHandlerName(r)
|
||||
handler = handler + "(serverCtx)"
|
||||
folder, ok := apiutil.GetAnnotationValue(r.Annotations, "server", groupProperty)
|
||||
if ok {
|
||||
handler = toPrefix(folder) + "." + strings.ToUpper(handler[:1]) + handler[1:]
|
||||
|
||||
@@ -8,12 +8,14 @@ import (
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/config"
|
||||
ctlutil "github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/format"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/vars"
|
||||
)
|
||||
|
||||
const (
|
||||
contextFilename = "servicecontext.go"
|
||||
contextFilename = "service_context"
|
||||
contextTemplate = `package svc
|
||||
|
||||
import (
|
||||
@@ -35,8 +37,13 @@ func NewServiceContext(c {{.config}}) *ServiceContext {
|
||||
`
|
||||
)
|
||||
|
||||
func genServiceContext(dir string, api *spec.ApiSpec) error {
|
||||
fp, created, err := util.MaybeCreateFile(dir, contextDir, contextFilename)
|
||||
func genServiceContext(dir string, cfg *config.Config, api *spec.ApiSpec) error {
|
||||
filename, err := format.FileNamingFormat(cfg.NamingFormat, contextFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fp, created, err := util.MaybeCreateFile(dir, contextDir, filename+".go")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -64,10 +71,6 @@ func genServiceContext(dir string, api *spec.ApiSpec) error {
|
||||
var middlewareStr string
|
||||
var middlewareAssignment string
|
||||
var middlewares = getMiddleware(api)
|
||||
err = genMiddleware(dir, middlewares)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, item := range middlewares {
|
||||
middlewareStr += fmt.Sprintf("%s rest.Middleware\n", item)
|
||||
|
||||
@@ -12,11 +12,13 @@ import (
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
|
||||
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/config"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/format"
|
||||
)
|
||||
|
||||
const (
|
||||
typesFile = "types.go"
|
||||
typesFile = "types"
|
||||
typesTemplate = `// Code generated by goctl. DO NOT EDIT.
|
||||
package types{{if .containsTime}}
|
||||
import (
|
||||
@@ -43,19 +45,25 @@ func BuildTypes(types []spec.Type) (string, error) {
|
||||
return builder.String(), nil
|
||||
}
|
||||
|
||||
func genTypes(dir string, api *spec.ApiSpec) error {
|
||||
func genTypes(dir string, cfg *config.Config, api *spec.ApiSpec) error {
|
||||
val, err := BuildTypes(api.Types)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
filename := path.Join(dir, typesDir, typesFile)
|
||||
os.Remove(filename)
|
||||
|
||||
fp, created, err := apiutil.MaybeCreateFile(dir, typesDir, typesFile)
|
||||
typeFilename, err := format.FileNamingFormat(cfg.NamingFormat, typesFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
typeFilename = typeFilename + ".go"
|
||||
filename := path.Join(dir, typesDir, typeFilename)
|
||||
os.Remove(filename)
|
||||
|
||||
fp, created, err := apiutil.MaybeCreateFile(dir, typesDir, typeFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !created {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -38,11 +38,12 @@ func RevertTemplate(name string) error {
|
||||
return util.CreateTemplate(category, name, content)
|
||||
}
|
||||
|
||||
func Update(category string) error {
|
||||
func Update() error {
|
||||
err := Clean()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return util.InitTemplates(category, templates)
|
||||
}
|
||||
|
||||
@@ -50,6 +51,6 @@ func Clean() error {
|
||||
return util.Clean(category)
|
||||
}
|
||||
|
||||
func GetCategory() string {
|
||||
func Category() string {
|
||||
return category
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ func TestUpdate(t *testing.T) {
|
||||
|
||||
assert.Equal(t, string(data), modifyData)
|
||||
|
||||
assert.Nil(t, Update(category))
|
||||
assert.Nil(t, Update())
|
||||
|
||||
data, err = ioutil.ReadFile(file)
|
||||
assert.Nil(t, err)
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"text/template"
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/gogen"
|
||||
conf "github.com/tal-tech/go-zero/tools/goctl/config"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
@@ -60,6 +61,6 @@ func NewService(c *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = gogen.DoGenProject(apiFilePath, abs)
|
||||
err = gogen.DoGenProject(apiFilePath, abs, conf.DefaultFormat)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -2,30 +2,15 @@ package spec
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/tal-tech/go-zero/core/stringx"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
)
|
||||
|
||||
const (
|
||||
TagKey = "tag"
|
||||
NameKey = "name"
|
||||
OptionKey = "option"
|
||||
BodyTag = "json"
|
||||
)
|
||||
const bodyTagKey = "json"
|
||||
|
||||
var (
|
||||
TagRe = regexp.MustCompile(`(?P<tag>\w+):"(?P<name>[^,"]+)[,]?(?P<option>[^"]*)"`)
|
||||
TagSubNames = TagRe.SubexpNames()
|
||||
definedTags = []string{TagKey, NameKey, OptionKey}
|
||||
)
|
||||
|
||||
type Attribute struct {
|
||||
Key string
|
||||
value string
|
||||
}
|
||||
var definedKeys = []string{"json", "form", "path"}
|
||||
|
||||
func (s Service) Routes() []Route {
|
||||
var result []Route
|
||||
@@ -35,81 +20,62 @@ func (s Service) Routes() []Route {
|
||||
return result
|
||||
}
|
||||
|
||||
func (m Member) IsOptional() bool {
|
||||
var option string
|
||||
|
||||
matches := TagRe.FindStringSubmatch(m.Tag)
|
||||
for i := range matches {
|
||||
name := TagSubNames[i]
|
||||
if name == OptionKey {
|
||||
option = matches[i]
|
||||
}
|
||||
func (m Member) Tags() []*Tag {
|
||||
tags, err := Parse(m.Tag)
|
||||
if err != nil {
|
||||
panic(m.Tag + ", " + err.Error())
|
||||
}
|
||||
|
||||
if len(option) == 0 {
|
||||
return tags.Tags()
|
||||
}
|
||||
|
||||
func (m Member) IsOptional() bool {
|
||||
if !m.IsBodyMember() {
|
||||
return false
|
||||
}
|
||||
|
||||
fields := strings.Split(option, ",")
|
||||
for _, field := range fields {
|
||||
if field == "optional" || strings.HasPrefix(field, "default=") {
|
||||
return true
|
||||
tag := m.Tags()
|
||||
for _, item := range tag {
|
||||
if item.Key == bodyTagKey {
|
||||
if stringx.Contains(item.Options, "optional") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (m Member) IsOmitempty() bool {
|
||||
var option string
|
||||
|
||||
matches := TagRe.FindStringSubmatch(m.Tag)
|
||||
for i := range matches {
|
||||
name := TagSubNames[i]
|
||||
if name == OptionKey {
|
||||
option = matches[i]
|
||||
}
|
||||
}
|
||||
|
||||
if len(option) == 0 {
|
||||
if !m.IsBodyMember() {
|
||||
return false
|
||||
}
|
||||
|
||||
fields := strings.Split(option, ",")
|
||||
for _, field := range fields {
|
||||
if field == "omitempty" {
|
||||
return true
|
||||
tag := m.Tags()
|
||||
for _, item := range tag {
|
||||
if item.Key == bodyTagKey {
|
||||
if stringx.Contains(item.Options, "omitempty") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (m Member) GetAttributes() []Attribute {
|
||||
matches := TagRe.FindStringSubmatch(m.Tag)
|
||||
var result []Attribute
|
||||
for i := range matches {
|
||||
name := TagSubNames[i]
|
||||
if stringx.Contains(definedTags, name) {
|
||||
result = append(result, Attribute{
|
||||
Key: name,
|
||||
value: matches[i],
|
||||
})
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (m Member) GetPropertyName() (string, error) {
|
||||
attrs := m.GetAttributes()
|
||||
for _, attr := range attrs {
|
||||
if attr.Key == NameKey && len(attr.value) > 0 {
|
||||
if attr.value == "-" {
|
||||
tags := m.Tags()
|
||||
if len(tags) == 0 {
|
||||
return "", errors.New("json property name not exist, member: " + m.Name)
|
||||
}
|
||||
|
||||
for _, tag := range tags {
|
||||
if stringx.Contains(definedKeys, tag.Key) {
|
||||
if tag.Name == "-" {
|
||||
return util.Untitle(m.Name), nil
|
||||
}
|
||||
return attr.value, nil
|
||||
return tag.Name, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", errors.New("json property name not exist, member: " + m.Name)
|
||||
}
|
||||
|
||||
@@ -121,9 +87,10 @@ func (m Member) IsBodyMember() bool {
|
||||
if m.IsInline {
|
||||
return true
|
||||
}
|
||||
attrs := m.GetAttributes()
|
||||
for _, attr := range attrs {
|
||||
if attr.value == BodyTag {
|
||||
|
||||
tags := m.Tags()
|
||||
for _, tag := range tags {
|
||||
if tag.Key == bodyTagKey {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
67
tools/goctl/api/spec/tags.go
Normal file
67
tools/goctl/api/spec/tags.go
Normal 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
|
||||
}
|
||||
122
tools/goctl/config/config.go
Normal file
122
tools/goctl/config/config.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
const (
|
||||
configFile = "config.yaml"
|
||||
configFolder = "config"
|
||||
DefaultFormat = "gozero"
|
||||
)
|
||||
|
||||
const defaultYaml = `# namingFormat is used to define the naming format of the generated file name.
|
||||
# just like time formatting, you can specify the formatting style through the
|
||||
# two format characters go, and zero. for example: snake format you can
|
||||
# define as go_zero, camel case format you can it is defined as goZero,
|
||||
# and even split characters can be specified, such as go#zero. in theory,
|
||||
# any combination can be used, but the prerequisite must meet the naming conventions
|
||||
# of each operating system file name. if you want to independently control the file
|
||||
# naming style of the api, rpc, and model layers, you can set it through apiNamingFormat,
|
||||
# rpcNamingFormat, modelNamingFormat, and independent control is not enabled by default.
|
||||
# for more information, please see #{apiNamingFormat},#{rpcNamingFormat},#{modelNamingFormat}
|
||||
# Note: namingFormat is based on snake or camel string
|
||||
namingFormat: gozero
|
||||
`
|
||||
|
||||
type Config struct {
|
||||
// NamingFormat is used to define the naming format of the generated file name.
|
||||
// just like time formatting, you can specify the formatting style through the
|
||||
// two format characters go, and zero. for example: snake format you can
|
||||
// define as go_zero, camel case format you can it is defined as goZero,
|
||||
// and even split characters can be specified, such as go#zero. in theory,
|
||||
// any combination can be used, but the prerequisite must meet the naming conventions
|
||||
// of each operating system file name.
|
||||
// Note: NamingFormat is based on snake or camel string
|
||||
NamingFormat string `yaml:"namingFormat"`
|
||||
}
|
||||
|
||||
func NewConfig(format string) (*Config, error) {
|
||||
if len(format) == 0 {
|
||||
format = DefaultFormat
|
||||
}
|
||||
cfg := &Config{NamingFormat: format}
|
||||
err := validate(cfg)
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
func InitOrGetConfig() (*Config, error) {
|
||||
var (
|
||||
defaultConfig Config
|
||||
)
|
||||
err := yaml.Unmarshal([]byte(defaultYaml), &defaultConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
goctlHome, err := util.GetGoctlHome()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
configDir := filepath.Join(goctlHome, configFolder)
|
||||
configFilename := filepath.Join(configDir, configFile)
|
||||
if util.FileExists(configFilename) {
|
||||
data, err := ioutil.ReadFile(configFilename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = yaml.Unmarshal(data, &defaultConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = validate(&defaultConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &defaultConfig, nil
|
||||
}
|
||||
|
||||
err = util.MkdirIfNotExist(configDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
f, err := os.Create(configFilename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = f.Close()
|
||||
}()
|
||||
|
||||
_, err = f.WriteString(defaultYaml)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = validate(&defaultConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &defaultConfig, nil
|
||||
}
|
||||
|
||||
func validate(cfg *Config) error {
|
||||
if len(strings.TrimSpace(cfg.NamingFormat)) == 0 {
|
||||
return errors.New("missing namingFormat")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
50
tools/goctl/config/readme.md
Normal file
50
tools/goctl/config/readme.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# 配置项管理
|
||||
|
||||
| 名称 | 是否可选 | 说明 |
|
||||
|-------------------|----------|-----------------------------------------------|
|
||||
| namingFormat | YES | 文件名称格式化符 |
|
||||
|
||||
# naming-format
|
||||
`namingFormat`可以用于对生成代码的文件名称进行格式化,和日期格式化符(yyyy-MM-dd)类似,在代码生成时可以根据这些配置项的格式化符进行格式化。
|
||||
|
||||
## 格式化符(gozero)
|
||||
格式化符有`go`,`zero`组成,如常见的三种格式化风格你可以这样编写:
|
||||
* lower: `gozero`
|
||||
* camel: `goZero`
|
||||
* snake: `go_zero`
|
||||
|
||||
常见格式化符生成示例
|
||||
源字符:welcome_to_go_zero
|
||||
|
||||
| 格式化符 | 格式化结果 | 说明 |
|
||||
|------------|-----------------------|---------------------------|
|
||||
| gozero | welcometogozero | 小写 |
|
||||
| goZero | welcomeToGoZero | 驼峰 |
|
||||
| go_zero | welcome_to_go_zero | snake |
|
||||
| Go#zero | Welcome#to#go#zero | #号分割Title类型 |
|
||||
| GOZERO | WELCOMETOGOZERO | 大写 |
|
||||
| \_go#zero_ | \_welcome#to#go#zero_ | 下划线做前后缀,并且#分割 |
|
||||
|
||||
错误格式化符示例
|
||||
* go
|
||||
* gOZero
|
||||
* zero
|
||||
* goZEro
|
||||
* goZERo
|
||||
* goZeRo
|
||||
* tal
|
||||
|
||||
# 使用方法
|
||||
目前可通过在生成api、rpc、model时通过`--style`参数指定format格式,如:
|
||||
```shell script
|
||||
goctl api go test.api -dir . -style gozero
|
||||
```
|
||||
```shell script
|
||||
goctl rpc proto -src test.proto -dir . -style go_zero
|
||||
```
|
||||
```shell script
|
||||
goctl model mysql datasource -url="" -table="*" -dir ./snake -style GoZero
|
||||
```
|
||||
|
||||
# 默认值
|
||||
当不指定-style时默认值为`gozero`
|
||||
@@ -43,8 +43,8 @@ func GenConfigCommand(c *cli.Context) error {
|
||||
return errors.New("abs failed: " + c.String("path"))
|
||||
}
|
||||
|
||||
goModPath, hasFound := util.FindGoModPath(path)
|
||||
if !hasFound {
|
||||
goModPath, found := util.FindGoModPath(path)
|
||||
if !found {
|
||||
return errors.New("go mod not initial")
|
||||
}
|
||||
|
||||
|
||||
@@ -2,33 +2,72 @@ package docker
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/logrusorgru/aurora"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
ctlutil "github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
const (
|
||||
etcDir = "etc"
|
||||
yamlEtx = ".yaml"
|
||||
dockerfileName = "Dockerfile"
|
||||
etcDir = "etc"
|
||||
yamlEtx = ".yaml"
|
||||
cstOffset = 60 * 60 * 8 // 8 hours offset for Chinese Standard Time
|
||||
)
|
||||
|
||||
func DockerCommand(c *cli.Context) error {
|
||||
type Docker struct {
|
||||
Chinese bool
|
||||
GoRelPath string
|
||||
GoFile string
|
||||
ExeFile string
|
||||
HasPort bool
|
||||
Port int
|
||||
Argument string
|
||||
}
|
||||
|
||||
func DockerCommand(c *cli.Context) (err error) {
|
||||
defer func() {
|
||||
if err == nil {
|
||||
fmt.Println(aurora.Green("Done."))
|
||||
}
|
||||
}()
|
||||
|
||||
goFile := c.String("go")
|
||||
if len(goFile) == 0 {
|
||||
return errors.New("-go can't be empty")
|
||||
}
|
||||
|
||||
if !util.FileExists(goFile) {
|
||||
return fmt.Errorf("file %q not found", goFile)
|
||||
}
|
||||
|
||||
port := c.Int("port")
|
||||
if _, err := os.Stat(etcDir); os.IsNotExist(err) {
|
||||
return generateDockerfile(goFile, port)
|
||||
}
|
||||
|
||||
cfg, err := findConfig(goFile, etcDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return generateDockerfile(goFile, "-f", "etc/"+cfg)
|
||||
if err := generateDockerfile(goFile, port, "-f", "etc/"+cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
projDir, ok := util.FindProjectPath(goFile)
|
||||
if ok {
|
||||
fmt.Printf("Hint: run \"docker build ...\" command in dir %q\n", projDir)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func findConfig(file, dir string) (string, error) {
|
||||
@@ -60,18 +99,22 @@ func findConfig(file, dir string) (string, error) {
|
||||
return files[0], nil
|
||||
}
|
||||
|
||||
func generateDockerfile(goFile string, args ...string) error {
|
||||
func generateDockerfile(goFile string, port int, args ...string) error {
|
||||
projPath, err := getFilePath(filepath.Dir(goFile))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pos := strings.IndexByte(projPath, '/')
|
||||
if pos >= 0 {
|
||||
projPath = projPath[pos+1:]
|
||||
if len(projPath) == 0 {
|
||||
projPath = "."
|
||||
} else {
|
||||
pos := strings.IndexByte(projPath, os.PathSeparator)
|
||||
if pos >= 0 {
|
||||
projPath = projPath[pos+1:]
|
||||
}
|
||||
}
|
||||
|
||||
out, err := util.CreateIfNotExist("Dockerfile")
|
||||
out, err := util.CreateIfNotExist(dockerfileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -87,12 +130,16 @@ func generateDockerfile(goFile string, args ...string) error {
|
||||
builder.WriteString(`, "` + arg + `"`)
|
||||
}
|
||||
|
||||
_, offset := time.Now().Zone()
|
||||
t := template.Must(template.New("dockerfile").Parse(text))
|
||||
return t.Execute(out, map[string]string{
|
||||
"goRelPath": projPath,
|
||||
"goFile": goFile,
|
||||
"exeFile": util.FileNameWithoutExt(filepath.Base(goFile)),
|
||||
"argument": builder.String(),
|
||||
return t.Execute(out, Docker{
|
||||
Chinese: offset == cstOffset,
|
||||
GoRelPath: projPath,
|
||||
GoFile: goFile,
|
||||
ExeFile: util.FileNameWithoutExt(filepath.Base(goFile)),
|
||||
HasPort: port > 0,
|
||||
Port: port,
|
||||
Argument: builder.String(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -14,30 +14,59 @@ LABEL stage=gobuilder
|
||||
|
||||
ENV CGO_ENABLED 0
|
||||
ENV GOOS linux
|
||||
ENV GOPROXY https://goproxy.cn,direct
|
||||
|
||||
{{if .Chinese}}ENV GOPROXY https://goproxy.cn,direct
|
||||
{{end}}
|
||||
WORKDIR /build/zero
|
||||
|
||||
ADD go.mod .
|
||||
ADD go.sum .
|
||||
RUN go mod download
|
||||
COPY . .
|
||||
COPY {{.goRelPath}}/etc /app/etc
|
||||
RUN go build -ldflags="-s -w" -o /app/{{.exeFile}} {{.goRelPath}}/{{.goFile}}
|
||||
{{if .Argument}}COPY {{.GoRelPath}}/etc /app/etc
|
||||
{{end}}RUN go build -ldflags="-s -w" -o /app/{{.ExeFile}} {{.GoRelPath}}/{{.GoFile}}
|
||||
|
||||
|
||||
FROM alpine
|
||||
|
||||
RUN apk update --no-cache
|
||||
RUN apk add --no-cache ca-certificates
|
||||
RUN apk add --no-cache tzdata
|
||||
RUN apk update --no-cache && apk add --no-cache ca-certificates tzdata
|
||||
ENV TZ Asia/Shanghai
|
||||
|
||||
WORKDIR /app
|
||||
COPY --from=builder /app/{{.exeFile}} /app/{{.exeFile}}
|
||||
COPY --from=builder /app/etc /app/etc
|
||||
|
||||
CMD ["./{{.exeFile}}"{{.argument}}]
|
||||
COPY --from=builder /app/{{.ExeFile}} /app/{{.ExeFile}}{{if .Argument}}
|
||||
COPY --from=builder /app/etc /app/etc{{end}}
|
||||
{{if .HasPort}}
|
||||
EXPOSE {{.Port}}
|
||||
{{end}}
|
||||
CMD ["./{{.ExeFile}}"{{.Argument}}]
|
||||
`
|
||||
)
|
||||
|
||||
func Clean() error {
|
||||
return util.Clean(category)
|
||||
}
|
||||
|
||||
func GenTemplates(_ *cli.Context) error {
|
||||
return initTemplate()
|
||||
}
|
||||
|
||||
func Category() string {
|
||||
return category
|
||||
}
|
||||
|
||||
func RevertTemplate(name string) error {
|
||||
return util.CreateTemplate(category, name, dockerTemplate)
|
||||
}
|
||||
|
||||
func Update() error {
|
||||
err := Clean()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return initTemplate()
|
||||
}
|
||||
|
||||
func initTemplate() error {
|
||||
return util.InitTemplates(category, map[string]string{
|
||||
dockerTemplateFile: dockerTemplate,
|
||||
})
|
||||
|
||||
@@ -18,14 +18,16 @@ import (
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/validate"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/configgen"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/docker"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/kube"
|
||||
model "github.com/tal-tech/go-zero/tools/goctl/model/sql/command"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/plugin"
|
||||
rpc "github.com/tal-tech/go-zero/tools/goctl/rpc/cli"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/tpl"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
BuildVersion = "20201108"
|
||||
BuildVersion = "1.1.1"
|
||||
commands = []cli.Command{
|
||||
{
|
||||
Name: "api",
|
||||
@@ -52,14 +54,12 @@ var (
|
||||
Usage: "the format target dir",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "iu",
|
||||
Usage: "ignore update",
|
||||
Required: false,
|
||||
Name: "iu",
|
||||
Usage: "ignore update",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "stdin",
|
||||
Usage: "use stdin to input api doc content, press \"ctrl + d\" to send EOF",
|
||||
Required: false,
|
||||
Name: "stdin",
|
||||
Usage: "use stdin to input api doc content, press \"ctrl + d\" to send EOF",
|
||||
},
|
||||
},
|
||||
Action: format.GoFormatApi,
|
||||
@@ -98,6 +98,10 @@ var (
|
||||
Name: "api",
|
||||
Usage: "the api file",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "style",
|
||||
Usage: "the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]",
|
||||
},
|
||||
},
|
||||
Action: gogen.GoCommand,
|
||||
},
|
||||
@@ -129,19 +133,16 @@ var (
|
||||
Usage: "the api file",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "webapi",
|
||||
Usage: "the web api file path",
|
||||
Required: false,
|
||||
Name: "webapi",
|
||||
Usage: "the web api file path",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "caller",
|
||||
Usage: "the web api caller",
|
||||
Required: false,
|
||||
Name: "caller",
|
||||
Usage: "the web api caller",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "unwrap",
|
||||
Usage: "unwrap the webapi caller for import",
|
||||
Required: false,
|
||||
Name: "unwrap",
|
||||
Usage: "unwrap the webapi caller for import",
|
||||
},
|
||||
},
|
||||
Action: tsgen.TsCommand,
|
||||
@@ -180,6 +181,29 @@ var (
|
||||
},
|
||||
Action: ktgen.KtCommand,
|
||||
},
|
||||
{
|
||||
Name: "plugin",
|
||||
Usage: "custom file generator",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "plugin, p",
|
||||
Usage: "the plugin file",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "dir",
|
||||
Usage: "the target directory",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "api",
|
||||
Usage: "the api file",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "style",
|
||||
Usage: "the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]",
|
||||
},
|
||||
},
|
||||
Action: plugin.PluginCommand,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -190,9 +214,101 @@ var (
|
||||
Name: "go",
|
||||
Usage: "the file that contains main function",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "port",
|
||||
Usage: "the port to expose, default none",
|
||||
Value: 0,
|
||||
},
|
||||
},
|
||||
Action: docker.DockerCommand,
|
||||
},
|
||||
{
|
||||
Name: "kube",
|
||||
Usage: "generate kubernetes files",
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "deploy",
|
||||
Usage: "generate deployment yaml file",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "name",
|
||||
Usage: "the name of deployment",
|
||||
Required: true,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "namespace",
|
||||
Usage: "the namespace of deployment",
|
||||
Required: true,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "image",
|
||||
Usage: "the docker image of deployment",
|
||||
Required: true,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "secret",
|
||||
Usage: "the secret to image pull from registry",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "requestCpu",
|
||||
Usage: "the request cpu to deploy",
|
||||
Value: 500,
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "requestMem",
|
||||
Usage: "the request memory to deploy",
|
||||
Value: 512,
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "limitCpu",
|
||||
Usage: "the limit cpu to deploy",
|
||||
Value: 1000,
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "limitMem",
|
||||
Usage: "the limit memory to deploy",
|
||||
Value: 1024,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "o",
|
||||
Usage: "the output yaml file",
|
||||
Required: true,
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "replicas",
|
||||
Usage: "the number of replicas to deploy",
|
||||
Value: 3,
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "revisions",
|
||||
Usage: "the number of revision history to limit",
|
||||
Value: 5,
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "port",
|
||||
Usage: "the port of the deployment to listen on pod",
|
||||
Required: true,
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "nodePort",
|
||||
Usage: "the nodePort of the deployment to expose",
|
||||
Value: 0,
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "minReplicas",
|
||||
Usage: "the min replicas to deploy",
|
||||
Value: 3,
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "maxReplicas",
|
||||
Usage: "the max replicas of deploy",
|
||||
Value: 10,
|
||||
},
|
||||
},
|
||||
Action: kube.DeploymentCommand,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "rpc",
|
||||
Usage: "generate rpc code",
|
||||
@@ -203,7 +319,7 @@ var (
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "style",
|
||||
Usage: "the file naming style, lower|camel|snake,default is lower",
|
||||
Usage: "the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "idea",
|
||||
@@ -241,7 +357,7 @@ var (
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "style",
|
||||
Usage: "the file naming style, lower|camel|snake,default is lower",
|
||||
Usage: "the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "idea",
|
||||
@@ -274,7 +390,7 @@ var (
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "style",
|
||||
Usage: "the file naming style, lower|camel|snake,default is lower",
|
||||
Usage: "the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "cache, c",
|
||||
@@ -309,7 +425,7 @@ var (
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "style",
|
||||
Usage: "the file naming style, lower|camel|snake, default is lower",
|
||||
Usage: "the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "idea",
|
||||
@@ -353,7 +469,7 @@ var (
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "category,c",
|
||||
Usage: "the category of template, enum [api,rpc,model]",
|
||||
Usage: "the category of template, enum [api,rpc,model,docker,kube]",
|
||||
},
|
||||
},
|
||||
Action: tpl.UpdateTemplates,
|
||||
@@ -364,7 +480,7 @@ var (
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "category,c",
|
||||
Usage: "the category of template, enum [api,rpc,model]",
|
||||
Usage: "the category of template, enum [api,rpc,model,docker,kube]",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "name,n",
|
||||
|
||||
@@ -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}}
|
||||
`
|
||||
@@ -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
|
||||
`
|
||||
@@ -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
|
||||
}
|
||||
117
tools/goctl/kube/deployment.go
Normal file
117
tools/goctl/kube/deployment.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package kube
|
||||
|
||||
var deploymentTemplate = `apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{.Name}}
|
||||
namespace: {{.Namespace}}
|
||||
labels:
|
||||
app: {{.Name}}
|
||||
spec:
|
||||
replicas: {{.Replicas}}
|
||||
revisionHistoryLimit: {{.Revisions}}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{.Name}}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{.Name}}
|
||||
spec:
|
||||
containers:
|
||||
- name: {{.Name}}
|
||||
image: {{.Image}}
|
||||
lifecycle:
|
||||
preStop:
|
||||
exec:
|
||||
command: ["sh","-c","sleep 5"]
|
||||
ports:
|
||||
- containerPort: {{.Port}}
|
||||
readinessProbe:
|
||||
tcpSocket:
|
||||
port: {{.Port}}
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
port: {{.Port}}
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 20
|
||||
resources:
|
||||
requests:
|
||||
cpu: {{.RequestCpu}}m
|
||||
memory: {{.RequestMem}}Mi
|
||||
limits:
|
||||
cpu: {{.LimitCpu}}m
|
||||
memory: {{.LimitMem}}Mi
|
||||
volumeMounts:
|
||||
- name: timezone
|
||||
mountPath: /etc/localtime
|
||||
{{if .Secret}}imagePullSecrets:
|
||||
- name: {{.Secret}}
|
||||
{{end}}volumes:
|
||||
- name: timezone
|
||||
hostPath:
|
||||
path: /usr/share/zoneinfo/Asia/Shanghai
|
||||
|
||||
---
|
||||
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{.Name}}-svc
|
||||
namespace: {{.Namespace}}
|
||||
spec:
|
||||
ports:
|
||||
{{if .UseNodePort}}- nodePort: {{.NodePort}}
|
||||
port: {{.Port}}
|
||||
protocol: TCP
|
||||
targetPort: {{.Port}}
|
||||
type: NodePort{{else}}- port: {{.Port}}{{end}}
|
||||
selector:
|
||||
app: {{.Name}}
|
||||
|
||||
---
|
||||
|
||||
apiVersion: autoscaling/v2beta1
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{.Name}}-hpa-c
|
||||
namespace: {{.Namespace}}
|
||||
labels:
|
||||
app: {{.Name}}-hpa-c
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: {{.Name}}
|
||||
minReplicas: {{.MinReplicas}}
|
||||
maxReplicas: {{.MaxReplicas}}
|
||||
metrics:
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
targetAverageUtilization: 80
|
||||
|
||||
---
|
||||
|
||||
apiVersion: autoscaling/v2beta1
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{.Name}}-hpa-m
|
||||
namespace: {{.Namespace}}
|
||||
labels:
|
||||
app: {{.Name}}-hpa-m
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: {{.Name}}
|
||||
minReplicas: {{.MinReplicas}}
|
||||
maxReplicas: {{.MaxReplicas}}
|
||||
metrics:
|
||||
- type: Resource
|
||||
resource:
|
||||
name: memory
|
||||
targetAverageUtilization: 80
|
||||
`
|
||||
39
tools/goctl/kube/job.go
Normal file
39
tools/goctl/kube/job.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package kube
|
||||
|
||||
var jobTmeplate = `apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: {{.Name}}
|
||||
namespace: {{.Namespace}}
|
||||
spec:
|
||||
successfulJobsHistoryLimit: {{.SuccessfulJobsHistoryLimit}}
|
||||
schedule: "{{.Schedule}}"
|
||||
jobTemplate:
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: {{.Name}}
|
||||
image: # todo image url
|
||||
resources:
|
||||
requests:
|
||||
cpu: {{.RequestCpu}}m
|
||||
memory: {{.RequestMem}}Mi
|
||||
limits:
|
||||
cpu: {{.LimitCpu}}m
|
||||
memory: {{.LimitMem}}Mi
|
||||
command:
|
||||
- ./{{.ServiceName}}
|
||||
- -f
|
||||
- ./{{.Name}}.yaml
|
||||
volumeMounts:
|
||||
- name: timezone
|
||||
mountPath: /etc/localtime
|
||||
imagePullSecrets:
|
||||
- name: # registry secret, if no, remove this
|
||||
restartPolicy: OnFailure
|
||||
volumes:
|
||||
- name: timezone
|
||||
hostPath:
|
||||
path: /usr/share/zoneinfo/Asia/Shanghai
|
||||
`
|
||||
112
tools/goctl/kube/kube.go
Normal file
112
tools/goctl/kube/kube.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package kube
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"text/template"
|
||||
|
||||
"github.com/logrusorgru/aurora"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
const (
|
||||
category = "kube"
|
||||
deployTemplateFile = "deployment.tpl"
|
||||
jobTemplateFile = "job.tpl"
|
||||
basePort = 30000
|
||||
portLimit = 32767
|
||||
)
|
||||
|
||||
type Deployment struct {
|
||||
Name string
|
||||
Namespace string
|
||||
Image string
|
||||
Secret string
|
||||
Replicas int
|
||||
Revisions int
|
||||
Port int
|
||||
NodePort int
|
||||
UseNodePort bool
|
||||
RequestCpu int
|
||||
RequestMem int
|
||||
LimitCpu int
|
||||
LimitMem int
|
||||
MinReplicas int
|
||||
MaxReplicas int
|
||||
}
|
||||
|
||||
func DeploymentCommand(c *cli.Context) error {
|
||||
nodePort := c.Int("nodePort")
|
||||
// 0 to disable the nodePort type
|
||||
if nodePort != 0 && (nodePort < basePort || nodePort > portLimit) {
|
||||
return errors.New("nodePort should be between 30000 and 32767")
|
||||
}
|
||||
|
||||
text, err := util.LoadTemplate(category, deployTemplateFile, deploymentTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out, err := util.CreateIfNotExist(c.String("o"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
t := template.Must(template.New("deploymentTemplate").Parse(text))
|
||||
err = t.Execute(out, Deployment{
|
||||
Name: c.String("name"),
|
||||
Namespace: c.String("namespace"),
|
||||
Image: c.String("image"),
|
||||
Secret: c.String("secret"),
|
||||
Replicas: c.Int("replicas"),
|
||||
Revisions: c.Int("revisions"),
|
||||
Port: c.Int("port"),
|
||||
NodePort: nodePort,
|
||||
UseNodePort: nodePort > 0,
|
||||
RequestCpu: c.Int("requestCpu"),
|
||||
RequestMem: c.Int("requestMem"),
|
||||
LimitCpu: c.Int("limitCpu"),
|
||||
LimitMem: c.Int("limitMem"),
|
||||
MinReplicas: c.Int("minReplicas"),
|
||||
MaxReplicas: c.Int("maxReplicas"),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(aurora.Green("Done."))
|
||||
return nil
|
||||
}
|
||||
|
||||
func Category() string {
|
||||
return category
|
||||
}
|
||||
|
||||
func Clean() error {
|
||||
return util.Clean(category)
|
||||
}
|
||||
|
||||
func GenTemplates(_ *cli.Context) error {
|
||||
return util.InitTemplates(category, map[string]string{
|
||||
deployTemplateFile: deploymentTemplate,
|
||||
jobTemplateFile: jobTmeplate,
|
||||
})
|
||||
}
|
||||
|
||||
func RevertTemplate(name string) error {
|
||||
return util.CreateTemplate(category, name, deploymentTemplate)
|
||||
}
|
||||
|
||||
func Update() error {
|
||||
err := Clean()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return util.InitTemplates(category, map[string]string{
|
||||
deployTemplateFile: deploymentTemplate,
|
||||
jobTemplateFile: jobTmeplate,
|
||||
})
|
||||
}
|
||||
@@ -7,7 +7,7 @@ goctl model 为go-zero下的工具模块中的组件之一,目前支持识别m
|
||||
* 通过ddl生成
|
||||
|
||||
```shell script
|
||||
goctl model mysql ddl -src="./*.sql" -dir="./sql/model" -c=true
|
||||
goctl model mysql ddl -src="./*.sql" -dir="./sql/model" -c
|
||||
```
|
||||
|
||||
执行上述命令后即可快速生成CURD代码。
|
||||
@@ -29,156 +29,191 @@ goctl model 为go-zero下的工具模块中的组件之一,目前支持识别m
|
||||
```go
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/tal-tech/go-zero/core/stores/cache"
|
||||
"github.com/tal-tech/go-zero/core/stores/sqlc"
|
||||
"github.com/tal-tech/go-zero/core/stores/sqlx"
|
||||
"github.com/tal-tech/go-zero/core/stringx"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/model/sql/builderx"
|
||||
)
|
||||
|
||||
var (
|
||||
userFieldNames = builderx.FieldNames(&User{})
|
||||
userRows = strings.Join(userFieldNames, ",")
|
||||
userRowsExpectAutoSet = strings.Join(stringx.Remove(userFieldNames, "id", "create_time", "update_time"), ",")
|
||||
userRowsWithPlaceHolder = strings.Join(stringx.Remove(userFieldNames, "id", "create_time", "update_time"), "=?,") + "=?"
|
||||
|
||||
cacheUserPrefix = "cache#User#user#"
|
||||
cacheUserNamePrefix = "cache#User#name#"
|
||||
cacheUserMobilePrefix = "cache#User#mobile#"
|
||||
cacheUserIdPrefix = "cache#User#id#"
|
||||
)
|
||||
|
||||
type (
|
||||
UserModel interface {
|
||||
Insert(data User) (sql.Result, error)
|
||||
FindOne(id int64) (*User, error)
|
||||
FindOneByUser(user string) (*User, error)
|
||||
FindOneByName(name string) (*User, error)
|
||||
FindOneByMobile(mobile string) (*User, error)
|
||||
Update(data User) error
|
||||
Delete(id int64) error
|
||||
}
|
||||
|
||||
defaultUserModel struct {
|
||||
sqlc.CachedConn
|
||||
table string
|
||||
}
|
||||
|
||||
User struct {
|
||||
Id int64 `db:"id"`
|
||||
User string `db:"user"` // 用户
|
||||
Name string `db:"name"` // 用户名称
|
||||
Password string `db:"password"` // 用户密码
|
||||
Mobile string `db:"mobile"` // 手机号
|
||||
Gender string `db:"gender"` // 男|女|未公开
|
||||
Nickname sql.NullString `db:"nickname"` // 用户昵称
|
||||
CreateTime sql.NullTime `db:"create_time"`
|
||||
UpdateTime time.Time `db:"update_time"`
|
||||
}
|
||||
)
|
||||
|
||||
func NewUserModel(conn sqlx.SqlConn, c cache.CacheConf) UserModel {
|
||||
return &defaultUserModel{
|
||||
CachedConn: sqlc.NewConn(conn, c),
|
||||
table: "user",
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultUserModel) Insert(data User) (sql.Result, error) {
|
||||
userKey := fmt.Sprintf("%s%v", cacheUserPrefix, data.User)
|
||||
userNameKey := fmt.Sprintf("%s%v", cacheUserNamePrefix, data.Name)
|
||||
userMobileKey := fmt.Sprintf("%s%v", cacheUserMobilePrefix, data.Mobile)
|
||||
ret, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?)", m.table, userRowsExpectAutoSet)
|
||||
return conn.Exec(query, data.User, data.Name, data.Password, data.Mobile, data.Gender, data.Nickname)
|
||||
}, userMobileKey, userKey, userNameKey)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (m *defaultUserModel) FindOne(id int64) (*User, error) {
|
||||
userIdKey := fmt.Sprintf("%s%v", cacheUserIdPrefix, id)
|
||||
var resp User
|
||||
err := m.QueryRow(&resp, userIdKey, func(conn sqlx.SqlConn, v interface{}) error {
|
||||
query := fmt.Sprintf("select %s from %s where id = ? limit 1", userRows, m.table)
|
||||
return conn.QueryRow(v, query, id)
|
||||
})
|
||||
switch err {
|
||||
case nil:
|
||||
return &resp, nil
|
||||
case sqlc.ErrNotFound:
|
||||
return nil, ErrNotFound
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultUserModel) FindOneByUser(user string) (*User, error) {
|
||||
userKey := fmt.Sprintf("%s%v", cacheUserPrefix, user)
|
||||
var resp User
|
||||
err := m.QueryRowIndex(&resp, userKey, m.formatPrimary, func(conn sqlx.SqlConn, v interface{}) (i interface{}, e error) {
|
||||
query := fmt.Sprintf("select %s from %s where user = ? limit 1", userRows, m.table)
|
||||
if err := conn.QueryRow(&resp, query, user); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp.Id, nil
|
||||
}, m.queryPrimary)
|
||||
switch err {
|
||||
case nil:
|
||||
return &resp, nil
|
||||
case sqlc.ErrNotFound:
|
||||
return nil, ErrNotFound
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultUserModel) FindOneByName(name string) (*User, error) {
|
||||
userNameKey := fmt.Sprintf("%s%v", cacheUserNamePrefix, name)
|
||||
var resp User
|
||||
err := m.QueryRowIndex(&resp, userNameKey, m.formatPrimary, func(conn sqlx.SqlConn, v interface{}) (i interface{}, e error) {
|
||||
query := fmt.Sprintf("select %s from %s where name = ? limit 1", userRows, m.table)
|
||||
if err := conn.QueryRow(&resp, query, name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp.Id, nil
|
||||
}, m.queryPrimary)
|
||||
switch err {
|
||||
case nil:
|
||||
return &resp, nil
|
||||
case sqlc.ErrNotFound:
|
||||
return nil, ErrNotFound
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultUserModel) FindOneByMobile(mobile string) (*User, error) {
|
||||
userMobileKey := fmt.Sprintf("%s%v", cacheUserMobilePrefix, mobile)
|
||||
var resp User
|
||||
err := m.QueryRowIndex(&resp, userMobileKey, m.formatPrimary, func(conn sqlx.SqlConn, v interface{}) (i interface{}, e error) {
|
||||
query := fmt.Sprintf("select %s from %s where mobile = ? limit 1", userRows, m.table)
|
||||
if err := conn.QueryRow(&resp, query, mobile); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp.Id, nil
|
||||
}, m.queryPrimary)
|
||||
switch err {
|
||||
case nil:
|
||||
return &resp, nil
|
||||
case sqlc.ErrNotFound:
|
||||
return nil, ErrNotFound
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultUserModel) Update(data User) error {
|
||||
userIdKey := fmt.Sprintf("%s%v", cacheUserIdPrefix, data.Id)
|
||||
_, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("update %s set %s where id = ?", m.table, userRowsWithPlaceHolder)
|
||||
return conn.Exec(query, data.User, data.Name, data.Password, data.Mobile, data.Gender, data.Nickname, data.Id)
|
||||
}, userIdKey)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *defaultUserModel) Delete(id int64) error {
|
||||
data, err := m.FindOne(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
userIdKey := fmt.Sprintf("%s%v", cacheUserIdPrefix, id)
|
||||
userKey := fmt.Sprintf("%s%v", cacheUserPrefix, data.User)
|
||||
userNameKey := fmt.Sprintf("%s%v", cacheUserNamePrefix, data.Name)
|
||||
userMobileKey := fmt.Sprintf("%s%v", cacheUserMobilePrefix, data.Mobile)
|
||||
_, err = m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("delete from %s where id = ?", m.table)
|
||||
return conn.Exec(query, id)
|
||||
}, userIdKey, userKey, userNameKey, userMobileKey)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *defaultUserModel) formatPrimary(primary interface{}) string {
|
||||
return fmt.Sprintf("%s%v", cacheUserIdPrefix, primary)
|
||||
}
|
||||
|
||||
func (m *defaultUserModel) queryPrimary(conn sqlx.SqlConn, v, primary interface{}) error {
|
||||
query := fmt.Sprintf("select %s from %s where id = ? limit 1", userRows, m.table)
|
||||
return conn.QueryRow(v, query, primary)
|
||||
}
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/tal-tech/go-zero/core/stores/cache"
|
||||
"github.com/tal-tech/go-zero/core/stores/sqlc"
|
||||
"github.com/tal-tech/go-zero/core/stores/sqlx"
|
||||
"github.com/tal-tech/go-zero/core/stringx"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/model/sql/builderx"
|
||||
)
|
||||
|
||||
var (
|
||||
userFieldNames = builderx.FieldNames(&User{})
|
||||
userRows = strings.Join(userFieldNames, ",")
|
||||
userRowsExpectAutoSet = strings.Join(stringx.Remove(userFieldNames, "id", "create_time", "update_time"), ",")
|
||||
userRowsWithPlaceHolder = strings.Join(stringx.Remove(userFieldNames, "id", "create_time", "update_time"), "=?,") + "=?"
|
||||
|
||||
cacheUserIdPrefix = "cache#User#id#"
|
||||
cacheUserNamePrefix = "cache#User#name#"
|
||||
cacheUserMobilePrefix = "cache#User#mobile#"
|
||||
)
|
||||
|
||||
type (
|
||||
UserModel struct {
|
||||
sqlc.CachedConn
|
||||
table string
|
||||
}
|
||||
|
||||
User struct {
|
||||
Id int64 `db:"id"`
|
||||
Name string `db:"name"` // 用户名称
|
||||
Password string `db:"password"` // 用户密码
|
||||
Mobile string `db:"mobile"` // 手机号
|
||||
Gender string `db:"gender"` // 男|女|未公开
|
||||
Nickname string `db:"nickname"` // 用户昵称
|
||||
CreateTime time.Time `db:"create_time"`
|
||||
UpdateTime time.Time `db:"update_time"`
|
||||
}
|
||||
)
|
||||
|
||||
func NewUserModel(conn sqlx.SqlConn, c cache.CacheConf) *UserModel {
|
||||
return &UserModel{
|
||||
CachedConn: sqlc.NewConn(conn, c),
|
||||
table: "user",
|
||||
}
|
||||
}
|
||||
|
||||
func (m *UserModel) Insert(data User) (sql.Result, error) {
|
||||
userNameKey := fmt.Sprintf("%s%v", cacheUserNamePrefix, data.Name)
|
||||
userMobileKey := fmt.Sprintf("%s%v", cacheUserMobilePrefix, data.Mobile)
|
||||
ret, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?)", m.table, userRowsExpectAutoSet)
|
||||
return conn.Exec(query, data.Name, data.Password, data.Mobile, data.Gender, data.Nickname)
|
||||
}, userNameKey, userMobileKey)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (m *UserModel) FindOne(id int64) (*User, error) {
|
||||
userIdKey := fmt.Sprintf("%s%v", cacheUserIdPrefix, id)
|
||||
var resp User
|
||||
err := m.QueryRow(&resp, userIdKey, func(conn sqlx.SqlConn, v interface{}) error {
|
||||
query := fmt.Sprintf("select %s from %s where id = ? limit 1", userRows, m.table)
|
||||
return conn.QueryRow(v, query, id)
|
||||
})
|
||||
switch err {
|
||||
case nil:
|
||||
return &resp, nil
|
||||
case sqlc.ErrNotFound:
|
||||
return nil, ErrNotFound
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *UserModel) FindOneByName(name string) (*User, error) {
|
||||
userNameKey := fmt.Sprintf("%s%v", cacheUserNamePrefix, name)
|
||||
var resp User
|
||||
err := m.QueryRowIndex(&resp, userNameKey, m.formatPrimary, func(conn sqlx.SqlConn, v interface{}) (i interface{}, e error) {
|
||||
query := fmt.Sprintf("select %s from %s where name = ? limit 1", userRows, m.table)
|
||||
if err := conn.QueryRow(&resp, query, name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp.Id, nil
|
||||
}, m.queryPrimary)
|
||||
switch err {
|
||||
case nil:
|
||||
return &resp, nil
|
||||
case sqlc.ErrNotFound:
|
||||
return nil, ErrNotFound
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *UserModel) FindOneByMobile(mobile string) (*User, error) {
|
||||
userMobileKey := fmt.Sprintf("%s%v", cacheUserMobilePrefix, mobile)
|
||||
var resp User
|
||||
err := m.QueryRowIndex(&resp, userMobileKey, m.formatPrimary, func(conn sqlx.SqlConn, v interface{}) (i interface{}, e error) {
|
||||
query := fmt.Sprintf("select %s from %s where mobile = ? limit 1", userRows, m.table)
|
||||
if err := conn.QueryRow(&resp, query, mobile); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp.Id, nil
|
||||
}, m.queryPrimary)
|
||||
switch err {
|
||||
case nil:
|
||||
return &resp, nil
|
||||
case sqlc.ErrNotFound:
|
||||
return nil, ErrNotFound
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *UserModel) Update(data User) error {
|
||||
userIdKey := fmt.Sprintf("%s%v", cacheUserIdPrefix, data.Id)
|
||||
_, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("update %s set %s where id = ?", m.table, userRowsWithPlaceHolder)
|
||||
return conn.Exec(query, data.Name, data.Password, data.Mobile, data.Gender, data.Nickname, data.Id)
|
||||
}, userIdKey)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *UserModel) Delete(id int64) error {
|
||||
data, err := m.FindOne(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
userMobileKey := fmt.Sprintf("%s%v", cacheUserMobilePrefix, data.Mobile)
|
||||
userIdKey := fmt.Sprintf("%s%v", cacheUserIdPrefix, id)
|
||||
userNameKey := fmt.Sprintf("%s%v", cacheUserNamePrefix, data.Name)
|
||||
_, err = m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("delete from %s where id = ?", m.table)
|
||||
return conn.Exec(query, id)
|
||||
}, userMobileKey, userIdKey, userNameKey)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *UserModel) formatPrimary(primary interface{}) string {
|
||||
return fmt.Sprintf("%s%v", cacheUserIdPrefix, primary)
|
||||
}
|
||||
|
||||
func (m *UserModel) queryPrimary(conn sqlx.SqlConn, v, primary interface{}) error {
|
||||
query := fmt.Sprintf("select %s from %s where id = ? limit 1", userRows, m.table)
|
||||
return conn.QueryRow(v, query, primary)
|
||||
}
|
||||
```
|
||||
|
||||
## 用法
|
||||
@@ -211,25 +246,24 @@ OPTIONS:
|
||||
* ddl
|
||||
|
||||
```shell script
|
||||
goctl model mysql -src={patterns} -dir={dir} -cache=true
|
||||
goctl model mysql -src={patterns} -dir={dir} -cache
|
||||
```
|
||||
|
||||
help
|
||||
|
||||
```
|
||||
NAME:
|
||||
goctl model mysql ddl - generate mysql model from ddl
|
||||
|
||||
USAGE:
|
||||
goctl model mysql ddl [command options] [arguments...]
|
||||
|
||||
OPTIONS:
|
||||
--src value, -s value the path or path globbing patterns of the ddl
|
||||
--dir value, -d value the target dir
|
||||
--style value the file naming style, lower|camel|underline,default is lower
|
||||
--cache, -c generate code with cache [optional]
|
||||
--idea for idea plugin [optional]
|
||||
|
||||
goctl model mysql ddl - generate mysql model from ddl
|
||||
|
||||
USAGE:
|
||||
goctl model mysql ddl [command options] [arguments...]
|
||||
|
||||
OPTIONS:
|
||||
--src value, -s value the path or path globbing patterns of the ddl
|
||||
--dir value, -d value the target dir
|
||||
--style value the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]
|
||||
--cache, -c generate code with cache [optional]
|
||||
--idea for idea plugin [optional]
|
||||
```
|
||||
|
||||
* datasource
|
||||
@@ -242,18 +276,19 @@ OPTIONS:
|
||||
|
||||
```
|
||||
NAME:
|
||||
goctl model mysql datasource - generate model from datasource
|
||||
goctl model mysql datasource - generate model from datasource
|
||||
|
||||
USAGE:
|
||||
goctl model mysql datasource [command options] [arguments...]
|
||||
|
||||
OPTIONS:
|
||||
--url value the data source of database,like "root:password@tcp(127.0.0.1:3306)/database
|
||||
--table value, -t value the table or table globbing patterns in the database
|
||||
--cache, -c generate code with cache [optional]
|
||||
--dir value, -d value the target dir
|
||||
--style value the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]
|
||||
--idea for idea plugin [optional]
|
||||
|
||||
USAGE:
|
||||
goctl model mysql datasource [command options] [arguments...]
|
||||
|
||||
OPTIONS:
|
||||
--url value the data source of database,like "root:password@tcp(127.0.0.1:3306)/database
|
||||
--table value, -t value the table or table globbing patterns in the database
|
||||
--cache, -c generate code with cache [optional]
|
||||
--dir value, -d value the target dir
|
||||
--style value the file naming style, lower|camel|snake, default is lower
|
||||
--idea for idea plugin [optional]
|
||||
|
||||
```
|
||||
|
||||
@@ -281,13 +316,13 @@ OPTIONS:
|
||||
* ddl
|
||||
|
||||
```shell script
|
||||
goctl model -src={patterns} -dir={dir} -cache=false
|
||||
goctl model -src={patterns} -dir={dir}
|
||||
```
|
||||
|
||||
* datasource
|
||||
|
||||
```shell script
|
||||
goctl model mysql datasource -url={datasource} -table={patterns} -dir={dir} -cache=false
|
||||
goctl model mysql datasource -url={datasource} -table={patterns} -dir={dir}
|
||||
```
|
||||
|
||||
生成代码仅基本的CURD结构。
|
||||
@@ -312,3 +347,33 @@ OPTIONS:
|
||||
|
||||
目前,我认为除了基本的CURD外,其他的代码均属于<i>业务型</i>代码,这个我觉得开发人员根据业务需要进行编写更好。
|
||||
|
||||
# 类型转换规则
|
||||
| mysql dataType | golang dataType | golang dataType(if null&&default null) |
|
||||
|----------------|-----------------|----------------------------------------|
|
||||
| bool | int64 | sql.NullInt64 |
|
||||
| boolean | int64 | sql.NullInt64 |
|
||||
| tinyint | int64 | sql.NullInt64 |
|
||||
| smallint | int64 | sql.NullInt64 |
|
||||
| mediumint | int64 | sql.NullInt64 |
|
||||
| int | int64 | sql.NullInt64 |
|
||||
| integer | int64 | sql.NullInt64 |
|
||||
| bigint | int64 | sql.NullInt64 |
|
||||
| float | float64 | sql.NullFloat64 |
|
||||
| double | float64 | sql.NullFloat64 |
|
||||
| decimal | float64 | sql.NullFloat64 |
|
||||
| date | time.Time | sql.NullTime |
|
||||
| datetime | time.Time | sql.NullTime |
|
||||
| timestamp | time.Time | sql.NullTime |
|
||||
| time | string | sql.NullString |
|
||||
| year | time.Time | sql.NullInt64 |
|
||||
| char | string | sql.NullString |
|
||||
| varchar | string | sql.NullString |
|
||||
| binary | string | sql.NullString |
|
||||
| varbinary | string | sql.NullString |
|
||||
| tinytext | string | sql.NullString |
|
||||
| text | string | sql.NullString |
|
||||
| mediumtext | string | sql.NullString |
|
||||
| longtext | string | sql.NullString |
|
||||
| enum | string | sql.NullString |
|
||||
| set | string | sql.NullString |
|
||||
| json | string | sql.NullString |
|
||||
@@ -2,7 +2,6 @@ package command
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -10,6 +9,7 @@ import (
|
||||
"github.com/go-sql-driver/mysql"
|
||||
"github.com/tal-tech/go-zero/core/logx"
|
||||
"github.com/tal-tech/go-zero/core/stores/sqlx"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/config"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/model/sql/gen"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/model/sql/model"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/model/sql/util"
|
||||
@@ -24,9 +24,9 @@ const (
|
||||
flagDir = "dir"
|
||||
flagCache = "cache"
|
||||
flagIdea = "idea"
|
||||
flagStyle = "style"
|
||||
flagUrl = "url"
|
||||
flagTable = "table"
|
||||
flagStyle = "style"
|
||||
)
|
||||
|
||||
func MysqlDDL(ctx *cli.Context) error {
|
||||
@@ -34,8 +34,12 @@ func MysqlDDL(ctx *cli.Context) error {
|
||||
dir := ctx.String(flagDir)
|
||||
cache := ctx.Bool(flagCache)
|
||||
idea := ctx.Bool(flagIdea)
|
||||
namingStyle := strings.TrimSpace(ctx.String(flagStyle))
|
||||
return fromDDl(src, dir, namingStyle, cache, idea)
|
||||
style := ctx.String(flagStyle)
|
||||
cfg, err := config.NewConfig(style)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return fromDDl(src, dir, cfg, cache, idea)
|
||||
}
|
||||
|
||||
func MyDataSource(ctx *cli.Context) error {
|
||||
@@ -43,26 +47,23 @@ func MyDataSource(ctx *cli.Context) error {
|
||||
dir := strings.TrimSpace(ctx.String(flagDir))
|
||||
cache := ctx.Bool(flagCache)
|
||||
idea := ctx.Bool(flagIdea)
|
||||
namingStyle := strings.TrimSpace(ctx.String(flagStyle))
|
||||
style := ctx.String(flagStyle)
|
||||
pattern := strings.TrimSpace(ctx.String(flagTable))
|
||||
return fromDataSource(url, pattern, dir, namingStyle, cache, idea)
|
||||
cfg, err := config.NewConfig(style)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return fromDataSource(url, pattern, dir, cfg, cache, idea)
|
||||
}
|
||||
|
||||
func fromDDl(src, dir, namingStyle string, cache, idea bool) error {
|
||||
func fromDDl(src, dir string, cfg *config.Config, cache, idea bool) error {
|
||||
log := console.NewConsole(idea)
|
||||
src = strings.TrimSpace(src)
|
||||
if len(src) == 0 {
|
||||
return errors.New("expected path or path globbing patterns, but nothing found")
|
||||
}
|
||||
|
||||
switch namingStyle {
|
||||
case gen.NamingLower, gen.NamingCamel, gen.NamingSnake:
|
||||
case "":
|
||||
namingStyle = gen.NamingLower
|
||||
default:
|
||||
return fmt.Errorf("unexpected naming style: %s", namingStyle)
|
||||
}
|
||||
|
||||
files, err := util.MatchFiles(src)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -81,7 +82,7 @@ func fromDDl(src, dir, namingStyle string, cache, idea bool) error {
|
||||
|
||||
source = append(source, string(data))
|
||||
}
|
||||
generator, err := gen.NewDefaultGenerator(dir, namingStyle, gen.WithConsoleOption(log))
|
||||
generator, err := gen.NewDefaultGenerator(dir, cfg, gen.WithConsoleOption(log))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -90,7 +91,7 @@ func fromDDl(src, dir, namingStyle string, cache, idea bool) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func fromDataSource(url, pattern, dir, namingStyle string, cache, idea bool) error {
|
||||
func fromDataSource(url, pattern, dir string, cfg *config.Config, cache, idea bool) error {
|
||||
log := console.NewConsole(idea)
|
||||
if len(url) == 0 {
|
||||
log.Error("%v", "expected data source of mysql, but nothing found")
|
||||
@@ -102,25 +103,17 @@ func fromDataSource(url, pattern, dir, namingStyle string, cache, idea bool) err
|
||||
return nil
|
||||
}
|
||||
|
||||
switch namingStyle {
|
||||
case gen.NamingLower, gen.NamingCamel, gen.NamingSnake:
|
||||
case "":
|
||||
namingStyle = gen.NamingLower
|
||||
default:
|
||||
return fmt.Errorf("unexpected naming style: %s", namingStyle)
|
||||
}
|
||||
|
||||
cfg, err := mysql.ParseDSN(url)
|
||||
dsn, err := mysql.ParseDSN(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logx.Disable()
|
||||
databaseSource := strings.TrimSuffix(url, "/"+cfg.DBName) + "/information_schema"
|
||||
databaseSource := strings.TrimSuffix(url, "/"+dsn.DBName) + "/information_schema"
|
||||
db := sqlx.NewMysql(databaseSource)
|
||||
im := model.NewInformationSchemaModel(db)
|
||||
|
||||
tables, err := im.GetAllTables(cfg.DBName)
|
||||
tables, err := im.GetAllTables(dsn.DBName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -135,7 +128,7 @@ func fromDataSource(url, pattern, dir, namingStyle string, cache, idea bool) err
|
||||
if !match {
|
||||
continue
|
||||
}
|
||||
columns, err := im.FindByTableName(cfg.DBName, item)
|
||||
columns, err := im.FindByTableName(dsn.DBName, item)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -146,11 +139,11 @@ func fromDataSource(url, pattern, dir, namingStyle string, cache, idea bool) err
|
||||
return errors.New("no tables matched")
|
||||
}
|
||||
|
||||
generator, err := gen.NewDefaultGenerator(dir, namingStyle, gen.WithConsoleOption(log))
|
||||
generator, err := gen.NewDefaultGenerator(dir, cfg, gen.WithConsoleOption(log))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = generator.StartFromInformationSchema(cfg.DBName, matchTables, cache)
|
||||
err = generator.StartFromInformationSchema(dsn.DBName, matchTables, cache)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -7,19 +7,22 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/model/sql/gen"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/config"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
)
|
||||
|
||||
var sql = "-- 用户表 --\nCREATE TABLE `user` (\n `id` bigint(10) NOT NULL AUTO_INCREMENT,\n `name` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户名称',\n `password` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户密码',\n `mobile` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '手机号',\n `gender` char(5) COLLATE utf8mb4_general_ci NOT NULL COMMENT '男|女|未公开',\n `nickname` varchar(255) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '用户昵称',\n `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,\n `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n PRIMARY KEY (`id`),\n UNIQUE KEY `name_index` (`name`),\n UNIQUE KEY `mobile_index` (`mobile`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;\n\n"
|
||||
var cfg = &config.Config{
|
||||
NamingFormat: "gozero",
|
||||
}
|
||||
|
||||
func TestFromDDl(t *testing.T) {
|
||||
err := fromDDl("./user.sql", t.TempDir(), gen.NamingCamel, true, false)
|
||||
err := fromDDl("./user.sql", t.TempDir(), cfg, true, false)
|
||||
assert.Equal(t, errNotMatched, err)
|
||||
|
||||
// case dir is not exists
|
||||
unknownDir := filepath.Join(t.TempDir(), "test", "user.sql")
|
||||
err = fromDDl(unknownDir, t.TempDir(), gen.NamingCamel, true, false)
|
||||
err = fromDDl(unknownDir, t.TempDir(), cfg, true, false)
|
||||
assert.True(t, func() bool {
|
||||
switch err.(type) {
|
||||
case *os.PathError:
|
||||
@@ -30,18 +33,11 @@ func TestFromDDl(t *testing.T) {
|
||||
}())
|
||||
|
||||
// case empty src
|
||||
err = fromDDl("", t.TempDir(), gen.NamingCamel, true, false)
|
||||
err = fromDDl("", t.TempDir(), cfg, true, false)
|
||||
if err != nil {
|
||||
assert.Equal(t, "expected path or path globbing patterns, but nothing found", err.Error())
|
||||
}
|
||||
|
||||
// case unknown naming style
|
||||
tmp := filepath.Join(t.TempDir(), "user.sql")
|
||||
err = fromDDl(tmp, t.TempDir(), "lower1", true, false)
|
||||
if err != nil {
|
||||
assert.Equal(t, "unexpected naming style: lower1", err.Error())
|
||||
}
|
||||
|
||||
tempDir := filepath.Join(t.TempDir(), "test")
|
||||
err = util.MkdirIfNotExist(tempDir)
|
||||
if err != nil {
|
||||
@@ -67,7 +63,7 @@ func TestFromDDl(t *testing.T) {
|
||||
_, err = os.Stat(user2Sql)
|
||||
assert.Nil(t, err)
|
||||
|
||||
err = fromDDl(filepath.Join(tempDir, "user*.sql"), tempDir, gen.NamingLower, true, false)
|
||||
err = fromDDl(filepath.Join(tempDir, "user*.sql"), tempDir, cfg, true, false)
|
||||
assert.Nil(t, err)
|
||||
|
||||
_, err = os.Stat(filepath.Join(tempDir, "usermodel.go"))
|
||||
|
||||
@@ -41,12 +41,34 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
func ConvertDataType(dataBaseType string) (goDataType string, err error) {
|
||||
func ConvertDataType(dataBaseType string, isDefaultNull bool) (string, error) {
|
||||
tp, ok := commonMysqlDataTypeMap[strings.ToLower(dataBaseType)]
|
||||
if !ok {
|
||||
err = fmt.Errorf("unexpected database type: %s", dataBaseType)
|
||||
return
|
||||
return "", fmt.Errorf("unexpected database type: %s", dataBaseType)
|
||||
}
|
||||
|
||||
return mayConvertNullType(tp, isDefaultNull), nil
|
||||
}
|
||||
|
||||
func mayConvertNullType(goDataType string, isDefaultNull bool) string {
|
||||
if !isDefaultNull {
|
||||
return goDataType
|
||||
}
|
||||
|
||||
switch goDataType {
|
||||
case "int64":
|
||||
return "sql.NullInt64"
|
||||
case "int32":
|
||||
return "sql.NullInt32"
|
||||
case "float64":
|
||||
return "sql.NullFloat64"
|
||||
case "bool":
|
||||
return "sql.NullBool"
|
||||
case "string":
|
||||
return "sql.NullString"
|
||||
case "time.Time":
|
||||
return "sql.NullTime"
|
||||
default:
|
||||
return goDataType
|
||||
}
|
||||
goDataType = tp
|
||||
return
|
||||
}
|
||||
|
||||
@@ -7,14 +7,22 @@ import (
|
||||
)
|
||||
|
||||
func TestConvertDataType(t *testing.T) {
|
||||
v, err := ConvertDataType("tinyint")
|
||||
v, err := ConvertDataType("tinyint", false)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "int64", v)
|
||||
|
||||
v, err = ConvertDataType("timestamp")
|
||||
v, err = ConvertDataType("tinyint", true)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "sql.NullInt64", v)
|
||||
|
||||
v, err = ConvertDataType("timestamp", false)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "time.Time", v)
|
||||
|
||||
_, err = ConvertDataType("float32")
|
||||
v, err = ConvertDataType("timestamp", true)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "sql.NullTime", v)
|
||||
|
||||
_, err = ConvertDataType("float32", false)
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# generate model with cache from ddl
|
||||
fromDDL:
|
||||
goctl model mysql ddl -src="./sql/*.sql" -dir="./sql/model/user" -c
|
||||
goctl model mysql ddl -src="./sql/*.sql" -dir="./sql/model/user" -cache
|
||||
|
||||
|
||||
# generate model with cache from data source
|
||||
@@ -12,4 +12,4 @@ datasource=127.0.0.1:3306
|
||||
database=gozero
|
||||
|
||||
fromDataSource:
|
||||
goctl model mysql datasource -url="$(user):$(password)@tcp($(datasource))/$(database)" -table="*" -dir ./model/cache -c -style camel
|
||||
goctl model mysql datasource -url="$(user):$(password)@tcp($(datasource))/$(database)" -table="*" -dir ./model/cache -c -style gozero
|
||||
@@ -1,6 +1,7 @@
|
||||
-- 用户表 --
|
||||
CREATE TABLE `user` (
|
||||
`id` bigint(10) NOT NULL AUTO_INCREMENT,
|
||||
`user` varchar(50) NOT NULL DEFAULT '' COMMENT '用户',
|
||||
`name` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户名称',
|
||||
`password` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户密码',
|
||||
`mobile` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '手机号',
|
||||
@@ -10,6 +11,16 @@ CREATE TABLE `user` (
|
||||
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `name_index` (`name`),
|
||||
UNIQUE KEY `user_index` (`user`),
|
||||
UNIQUE KEY `mobile_index` (`mobile`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE `student` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(255) COLLATE utf8mb4_bin NOT NULL DEFAULT '',
|
||||
`age` tinyint DEFAULT NULL,
|
||||
`score` float(10,0) DEFAULT NULL,
|
||||
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`update_time` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
@@ -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;
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/stringx"
|
||||
)
|
||||
|
||||
func genDelete(table Table, withCache bool) (string, error) {
|
||||
func genDelete(table Table, withCache bool) (string, string, error) {
|
||||
keySet := collection.NewSet()
|
||||
keyVariableSet := collection.NewSet()
|
||||
for fieldName, key := range table.CacheKey {
|
||||
@@ -24,7 +24,7 @@ func genDelete(table Table, withCache bool) (string, error) {
|
||||
camel := table.Name.ToCamel()
|
||||
text, err := util.LoadTemplate(category, deleteTemplateFile, template.Delete)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
output, err := util.With("delete").
|
||||
@@ -33,15 +33,30 @@ func genDelete(table Table, withCache bool) (string, error) {
|
||||
"upperStartCamelObject": camel,
|
||||
"withCache": withCache,
|
||||
"containsIndexCache": table.ContainsUniqueKey,
|
||||
"lowerStartCamelPrimaryKey": stringx.From(table.PrimaryKey.Name.ToCamel()).UnTitle(),
|
||||
"lowerStartCamelPrimaryKey": stringx.From(table.PrimaryKey.Name.ToCamel()).Untitle(),
|
||||
"dataType": table.PrimaryKey.DataType,
|
||||
"keys": strings.Join(keySet.KeysStr(), "\n"),
|
||||
"originalPrimaryKey": table.PrimaryKey.Name.Source(),
|
||||
"keyValues": strings.Join(keyVariableSet.KeysStr(), ", "),
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return output.String(), nil
|
||||
// interface method
|
||||
text, err = util.LoadTemplate(category, deleteMethodTemplateFile, template.DeleteMethod)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
deleteMethodOut, err := util.With("deleteMethod").
|
||||
Parse(text).
|
||||
Execute(map[string]interface{}{
|
||||
"lowerStartCamelPrimaryKey": stringx.From(table.PrimaryKey.Name.ToCamel()).Untitle(),
|
||||
"dataType": table.PrimaryKey.DataType,
|
||||
})
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
return output.String(), deleteMethodOut.String(), nil
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@ import (
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/stringx"
|
||||
)
|
||||
|
||||
func genFindOne(table Table, withCache bool) (string, error) {
|
||||
func genFindOne(table Table, withCache bool) (string, string, error) {
|
||||
camel := table.Name.ToCamel()
|
||||
text, err := util.LoadTemplate(category, findOneTemplateFile, template.FindOne)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
output, err := util.With("findOne").
|
||||
@@ -18,16 +18,31 @@ func genFindOne(table Table, withCache bool) (string, error) {
|
||||
Execute(map[string]interface{}{
|
||||
"withCache": withCache,
|
||||
"upperStartCamelObject": camel,
|
||||
"lowerStartCamelObject": stringx.From(camel).UnTitle(),
|
||||
"lowerStartCamelObject": stringx.From(camel).Untitle(),
|
||||
"originalPrimaryKey": table.PrimaryKey.Name.Source(),
|
||||
"lowerStartCamelPrimaryKey": stringx.From(table.PrimaryKey.Name.ToCamel()).UnTitle(),
|
||||
"lowerStartCamelPrimaryKey": stringx.From(table.PrimaryKey.Name.ToCamel()).Untitle(),
|
||||
"dataType": table.PrimaryKey.DataType,
|
||||
"cacheKey": table.CacheKey[table.PrimaryKey.Name.Source()].KeyExpression,
|
||||
"cacheKeyVariable": table.CacheKey[table.PrimaryKey.Name.Source()].Variable,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return output.String(), nil
|
||||
text, err = util.LoadTemplate(category, findOneMethodTemplateFile, template.FindOneMethod)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
findOneMethod, err := util.With("findOneMethod").
|
||||
Parse(text).
|
||||
Execute(map[string]interface{}{
|
||||
"upperStartCamelObject": camel,
|
||||
"lowerStartCamelPrimaryKey": stringx.From(table.PrimaryKey.Name.ToCamel()).Untitle(),
|
||||
"dataType": table.PrimaryKey.DataType,
|
||||
})
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
return output.String(), findOneMethod.String(), nil
|
||||
}
|
||||
|
||||
@@ -9,10 +9,16 @@ import (
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/stringx"
|
||||
)
|
||||
|
||||
func genFindOneByField(table Table, withCache bool) (string, string, error) {
|
||||
type findOneCode struct {
|
||||
findOneMethod string
|
||||
findOneInterfaceMethod string
|
||||
cacheExtra string
|
||||
}
|
||||
|
||||
func genFindOneByField(table Table, withCache bool) (*findOneCode, error) {
|
||||
text, err := util.LoadTemplate(category, findOneByFieldTemplateFile, template.FindOneByField)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t := util.With("findOneByField").Parse(text)
|
||||
@@ -26,39 +32,71 @@ func genFindOneByField(table Table, withCache bool) (string, string, error) {
|
||||
output, err := t.Execute(map[string]interface{}{
|
||||
"upperStartCamelObject": camelTableName,
|
||||
"upperField": camelFieldName,
|
||||
"in": fmt.Sprintf("%s %s", stringx.From(camelFieldName).UnTitle(), field.DataType),
|
||||
"in": fmt.Sprintf("%s %s", stringx.From(camelFieldName).Untitle(), field.DataType),
|
||||
"withCache": withCache,
|
||||
"cacheKey": table.CacheKey[field.Name.Source()].KeyExpression,
|
||||
"cacheKeyVariable": table.CacheKey[field.Name.Source()].Variable,
|
||||
"lowerStartCamelObject": stringx.From(camelTableName).UnTitle(),
|
||||
"lowerStartCamelField": stringx.From(camelFieldName).UnTitle(),
|
||||
"lowerStartCamelObject": stringx.From(camelTableName).Untitle(),
|
||||
"lowerStartCamelField": stringx.From(camelFieldName).Untitle(),
|
||||
"upperStartCamelPrimaryKey": table.PrimaryKey.Name.ToCamel(),
|
||||
"originalField": field.Name.Source(),
|
||||
})
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
list = append(list, output.String())
|
||||
}
|
||||
|
||||
text, err = util.LoadTemplate(category, findOneByFieldMethodTemplateFile, template.FindOneByFieldMethod)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t = util.With("findOneByFieldMethod").Parse(text)
|
||||
var listMethod []string
|
||||
for _, field := range table.Fields {
|
||||
if field.IsPrimaryKey || !field.IsUniqueKey {
|
||||
continue
|
||||
}
|
||||
camelFieldName := field.Name.ToCamel()
|
||||
output, err := t.Execute(map[string]interface{}{
|
||||
"upperStartCamelObject": camelTableName,
|
||||
"upperField": camelFieldName,
|
||||
"in": fmt.Sprintf("%s %s", stringx.From(camelFieldName).Untitle(), field.DataType),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
listMethod = append(listMethod, output.String())
|
||||
}
|
||||
|
||||
if withCache {
|
||||
text, err := util.LoadTemplate(category, findOneByFieldExtraMethodTemplateFile, template.FindOneByFieldExtraMethod)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out, err := util.With("findOneByFieldExtraMethod").Parse(text).Execute(map[string]interface{}{
|
||||
"upperStartCamelObject": camelTableName,
|
||||
"primaryKeyLeft": table.CacheKey[table.PrimaryKey.Name.Source()].Left,
|
||||
"lowerStartCamelObject": stringx.From(camelTableName).UnTitle(),
|
||||
"lowerStartCamelObject": stringx.From(camelTableName).Untitle(),
|
||||
"originalPrimaryField": table.PrimaryKey.Name.Source(),
|
||||
})
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return strings.Join(list, "\n"), out.String(), nil
|
||||
return &findOneCode{
|
||||
findOneMethod: strings.Join(list, util.NL),
|
||||
findOneInterfaceMethod: strings.Join(listMethod, util.NL),
|
||||
cacheExtra: out.String(),
|
||||
}, nil
|
||||
}
|
||||
return strings.Join(list, "\n"), "", nil
|
||||
|
||||
return &findOneCode{
|
||||
findOneMethod: strings.Join(list, util.NL),
|
||||
findOneInterfaceMethod: strings.Join(listMethod, util.NL),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -7,11 +7,14 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/config"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/model/sql/model"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/model/sql/parser"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/model/sql/template"
|
||||
modelutil "github.com/tal-tech/go-zero/tools/goctl/model/sql/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/console"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/format"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/stringx"
|
||||
)
|
||||
|
||||
@@ -28,13 +31,13 @@ type (
|
||||
//source string
|
||||
dir string
|
||||
console.Console
|
||||
pkg string
|
||||
namingStyle string
|
||||
pkg string
|
||||
cfg *config.Config
|
||||
}
|
||||
Option func(generator *defaultGenerator)
|
||||
)
|
||||
|
||||
func NewDefaultGenerator(dir, namingStyle string, opt ...Option) (*defaultGenerator, error) {
|
||||
func NewDefaultGenerator(dir string, cfg *config.Config, opt ...Option) (*defaultGenerator, error) {
|
||||
if dir == "" {
|
||||
dir = pwd
|
||||
}
|
||||
@@ -50,7 +53,7 @@ func NewDefaultGenerator(dir, namingStyle string, opt ...Option) (*defaultGenera
|
||||
return nil, err
|
||||
}
|
||||
|
||||
generator := &defaultGenerator{dir: dir, namingStyle: namingStyle, pkg: pkg}
|
||||
generator := &defaultGenerator{dir: dir, cfg: cfg, pkg: pkg}
|
||||
var optionList []Option
|
||||
optionList = append(optionList, newDefaultOption())
|
||||
optionList = append(optionList, opt...)
|
||||
@@ -114,13 +117,12 @@ func (g *defaultGenerator) createFile(modelList map[string]string) error {
|
||||
|
||||
for tableName, code := range modelList {
|
||||
tn := stringx.From(tableName)
|
||||
name := fmt.Sprintf("%smodel.go", strings.ToLower(tn.ToCamel()))
|
||||
switch g.namingStyle {
|
||||
case NamingCamel:
|
||||
name = fmt.Sprintf("%sModel.go", tn.ToCamel())
|
||||
case NamingSnake:
|
||||
name = fmt.Sprintf("%s_model.go", tn.ToSnake())
|
||||
modelFilename, err := format.FileNamingFormat(g.cfg.NamingFormat, fmt.Sprintf("%s_model", tn.Source()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := modelFilename + ".go"
|
||||
filename := filepath.Join(dirAbs, name)
|
||||
if util.FileExists(filename) {
|
||||
g.Warning("%s already exists, ignored.", name)
|
||||
@@ -132,10 +134,12 @@ func (g *defaultGenerator) createFile(modelList map[string]string) error {
|
||||
}
|
||||
}
|
||||
// generate error file
|
||||
filename := filepath.Join(dirAbs, "vars.go")
|
||||
if g.namingStyle == NamingCamel {
|
||||
filename = filepath.Join(dirAbs, "Vars.go")
|
||||
varFilename, err := format.FileNamingFormat(g.cfg.NamingFormat, "vars")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
filename := filepath.Join(dirAbs, varFilename+".go")
|
||||
text, err := util.LoadTemplate(category, errTemplateFile, template.Error)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -219,39 +223,41 @@ func (g *defaultGenerator) genModel(in parser.Table, withCache bool) (string, er
|
||||
return "", err
|
||||
}
|
||||
|
||||
typesCode, err := genTypes(table, withCache)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
newCode, err := genNew(table, withCache)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
insertCode, err := genInsert(table, withCache)
|
||||
insertCode, insertCodeMethod, err := genInsert(table, withCache)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var findCode = make([]string, 0)
|
||||
findOneCode, err := genFindOne(table, withCache)
|
||||
findOneCode, findOneCodeMethod, err := genFindOne(table, withCache)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
findOneByFieldCode, extraMethod, err := genFindOneByField(table, withCache)
|
||||
ret, err := genFindOneByField(table, withCache)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
findCode = append(findCode, findOneCode, findOneByFieldCode)
|
||||
updateCode, err := genUpdate(table, withCache)
|
||||
findCode = append(findCode, findOneCode, ret.findOneMethod)
|
||||
updateCode, updateCodeMethod, err := genUpdate(table, withCache)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
deleteCode, err := genDelete(table, withCache)
|
||||
deleteCode, deleteCodeMethod, err := genDelete(table, withCache)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var list []string
|
||||
list = append(list, insertCodeMethod, findOneCodeMethod, ret.findOneInterfaceMethod, updateCodeMethod, deleteCodeMethod)
|
||||
typesCode, err := genTypes(table, strings.Join(modelutil.TrimStringSlice(list), util.NL), withCache)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
newCode, err := genNew(table, withCache)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -266,7 +272,7 @@ func (g *defaultGenerator) genModel(in parser.Table, withCache bool) (string, er
|
||||
"find": strings.Join(findCode, "\n"),
|
||||
"update": updateCode,
|
||||
"delete": deleteCode,
|
||||
"extraMethod": extraMethod,
|
||||
"extraMethod": ret.cacheExtra,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tal-tech/go-zero/core/logx"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/config"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -22,7 +23,9 @@ func TestCacheModel(t *testing.T) {
|
||||
defer func() {
|
||||
_ = os.RemoveAll(dir)
|
||||
}()
|
||||
g, err := NewDefaultGenerator(cacheDir, NamingCamel)
|
||||
g, err := NewDefaultGenerator(cacheDir, &config.Config{
|
||||
NamingFormat: "GoZero",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
err = g.StartFromDDL(source, true)
|
||||
@@ -31,7 +34,9 @@ func TestCacheModel(t *testing.T) {
|
||||
_, err := os.Stat(filepath.Join(cacheDir, "TestUserInfoModel.go"))
|
||||
return err == nil
|
||||
}())
|
||||
g, err = NewDefaultGenerator(noCacheDir, NamingLower)
|
||||
g, err = NewDefaultGenerator(noCacheDir, &config.Config{
|
||||
NamingFormat: "gozero",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
err = g.StartFromDDL(source, false)
|
||||
@@ -51,7 +56,9 @@ func TestNamingModel(t *testing.T) {
|
||||
defer func() {
|
||||
_ = os.RemoveAll(dir)
|
||||
}()
|
||||
g, err := NewDefaultGenerator(camelDir, NamingCamel)
|
||||
g, err := NewDefaultGenerator(camelDir, &config.Config{
|
||||
NamingFormat: "GoZero",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
err = g.StartFromDDL(source, true)
|
||||
@@ -60,7 +67,9 @@ func TestNamingModel(t *testing.T) {
|
||||
_, err := os.Stat(filepath.Join(camelDir, "TestUserInfoModel.go"))
|
||||
return err == nil
|
||||
}())
|
||||
g, err = NewDefaultGenerator(snakeDir, NamingSnake)
|
||||
g, err = NewDefaultGenerator(snakeDir, &config.Config{
|
||||
NamingFormat: "go_zero",
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
err = g.StartFromDDL(source, true)
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/stringx"
|
||||
)
|
||||
|
||||
func genInsert(table Table, withCache bool) (string, error) {
|
||||
func genInsert(table Table, withCache bool) (string, string, error) {
|
||||
keySet := collection.NewSet()
|
||||
keyVariableSet := collection.NewSet()
|
||||
for fieldName, key := range table.CacheKey {
|
||||
@@ -36,7 +36,7 @@ func genInsert(table Table, withCache bool) (string, error) {
|
||||
camel := table.Name.ToCamel()
|
||||
text, err := util.LoadTemplate(category, insertTemplateFile, template.Insert)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
output, err := util.With("insert").
|
||||
@@ -45,15 +45,30 @@ func genInsert(table Table, withCache bool) (string, error) {
|
||||
"withCache": withCache,
|
||||
"containsIndexCache": table.ContainsUniqueKey,
|
||||
"upperStartCamelObject": camel,
|
||||
"lowerStartCamelObject": stringx.From(camel).UnTitle(),
|
||||
"lowerStartCamelObject": stringx.From(camel).Untitle(),
|
||||
"expression": strings.Join(expressions, ", "),
|
||||
"expressionValues": strings.Join(expressionValues, ", "),
|
||||
"keys": strings.Join(keySet.KeysStr(), "\n"),
|
||||
"keyValues": strings.Join(keyVariableSet.KeysStr(), ", "),
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return output.String(), nil
|
||||
// interface method
|
||||
text, err = util.LoadTemplate(category, insertTemplateMethodFile, template.InsertMethod)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
insertMethodOutput, err := util.With("insertMethod").
|
||||
Parse(text).
|
||||
Execute(map[string]interface{}{
|
||||
"upperStartCamelObject": camel,
|
||||
})
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return output.String(), insertMethodOutput.String(), nil
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package gen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/model/sql/parser"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/stringx"
|
||||
@@ -27,14 +28,20 @@ func genCacheKeys(table parser.Table) (map[string]Key, error) {
|
||||
fields := table.Fields
|
||||
m := make(map[string]Key)
|
||||
camelTableName := table.Name.ToCamel()
|
||||
lowerStartCamelTableName := stringx.From(camelTableName).UnTitle()
|
||||
lowerStartCamelTableName := stringx.From(camelTableName).Untitle()
|
||||
for _, field := range fields {
|
||||
if field.IsUniqueKey || field.IsPrimaryKey {
|
||||
camelFieldName := field.Name.ToCamel()
|
||||
lowerStartCamelFieldName := stringx.From(camelFieldName).UnTitle()
|
||||
lowerStartCamelFieldName := stringx.From(camelFieldName).Untitle()
|
||||
left := fmt.Sprintf("cache%s%sPrefix", camelTableName, camelFieldName)
|
||||
if strings.ToLower(camelFieldName) == strings.ToLower(camelTableName) {
|
||||
left = fmt.Sprintf("cache%sPrefix", camelTableName)
|
||||
}
|
||||
right := fmt.Sprintf("cache#%s#%s#", camelTableName, lowerStartCamelFieldName)
|
||||
variable := fmt.Sprintf("%s%sKey", lowerStartCamelTableName, camelFieldName)
|
||||
if strings.ToLower(lowerStartCamelTableName) == strings.ToLower(camelFieldName) {
|
||||
variable = fmt.Sprintf("%sKey", lowerStartCamelTableName)
|
||||
}
|
||||
m[field.Name.Source()] = Key{
|
||||
VarExpression: fmt.Sprintf(`%s = "%s"`, left, right),
|
||||
Left: left,
|
||||
|
||||
@@ -62,11 +62,11 @@ func TestGenCacheKeys(t *testing.T) {
|
||||
|
||||
for fieldName, key := range m {
|
||||
name := stringx.From(fieldName)
|
||||
assert.Equal(t, fmt.Sprintf(`cacheUser%sPrefix = "cache#User#%s#"`, name.ToCamel(), name.UnTitle()), key.VarExpression)
|
||||
assert.Equal(t, fmt.Sprintf(`cacheUser%sPrefix = "cache#User#%s#"`, name.ToCamel(), name.Untitle()), key.VarExpression)
|
||||
assert.Equal(t, fmt.Sprintf(`cacheUser%sPrefix`, name.ToCamel()), key.Left)
|
||||
assert.Equal(t, fmt.Sprintf(`cache#User#%s#`, name.UnTitle()), key.Right)
|
||||
assert.Equal(t, fmt.Sprintf(`cache#User#%s#`, name.Untitle()), key.Right)
|
||||
assert.Equal(t, fmt.Sprintf(`user%sKey`, name.ToCamel()), key.Variable)
|
||||
assert.Equal(t, `user`+name.ToCamel()+`Key := fmt.Sprintf("%s%v", cacheUser`+name.ToCamel()+`Prefix,`+name.UnTitle()+`)`, key.KeyExpression)
|
||||
assert.Equal(t, `user`+name.ToCamel()+`Key := fmt.Sprintf("%s%v", cacheUser`+name.ToCamel()+`Prefix,`+name.Untitle()+`)`, key.KeyExpression)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,31 +11,40 @@ import (
|
||||
const (
|
||||
category = "model"
|
||||
deleteTemplateFile = "delete.tpl"
|
||||
deleteMethodTemplateFile = "interface-delete.tpl"
|
||||
fieldTemplateFile = "filed.tpl"
|
||||
findOneTemplateFile = "find-one.tpl"
|
||||
findOneMethodTemplateFile = "interface-find-one.tpl"
|
||||
findOneByFieldTemplateFile = "find-one-by-field.tpl"
|
||||
findOneByFieldMethodTemplateFile = "interface-find-one-by-field.tpl"
|
||||
findOneByFieldExtraMethodTemplateFile = "find-one-by-filed-extra-method.tpl"
|
||||
importsTemplateFile = "import.tpl"
|
||||
importsWithNoCacheTemplateFile = "import-no-cache.tpl"
|
||||
insertTemplateFile = "insert.tpl"
|
||||
insertTemplateMethodFile = "interface-insert.tpl"
|
||||
modelTemplateFile = "model.tpl"
|
||||
modelNewTemplateFile = "model-new.tpl"
|
||||
tagTemplateFile = "tag.tpl"
|
||||
typesTemplateFile = "types.tpl"
|
||||
updateTemplateFile = "update.tpl"
|
||||
updateMethodTemplateFile = "interface-update.tpl"
|
||||
varTemplateFile = "var.tpl"
|
||||
errTemplateFile = "err.tpl"
|
||||
)
|
||||
|
||||
var templates = map[string]string{
|
||||
deleteTemplateFile: template.Delete,
|
||||
deleteMethodTemplateFile: template.DeleteMethod,
|
||||
fieldTemplateFile: template.Field,
|
||||
findOneTemplateFile: template.FindOne,
|
||||
findOneMethodTemplateFile: template.FindOneMethod,
|
||||
findOneByFieldTemplateFile: template.FindOneByField,
|
||||
findOneByFieldMethodTemplateFile: template.FindOneByFieldMethod,
|
||||
findOneByFieldExtraMethodTemplateFile: template.FindOneByFieldExtraMethod,
|
||||
importsTemplateFile: template.Imports,
|
||||
importsWithNoCacheTemplateFile: template.ImportsNoCache,
|
||||
insertTemplateFile: template.Insert,
|
||||
insertTemplateMethodFile: template.InsertMethod,
|
||||
modelTemplateFile: template.Model,
|
||||
modelNewTemplateFile: template.New,
|
||||
tagTemplateFile: template.Tag,
|
||||
@@ -45,6 +54,14 @@ var templates = map[string]string{
|
||||
errTemplateFile: template.Error,
|
||||
}
|
||||
|
||||
func Category() string {
|
||||
return category
|
||||
}
|
||||
|
||||
func Clean() error {
|
||||
return util.Clean(category)
|
||||
}
|
||||
|
||||
func GenTemplates(_ *cli.Context) error {
|
||||
return util.InitTemplates(category, templates)
|
||||
}
|
||||
@@ -57,18 +74,10 @@ func RevertTemplate(name string) error {
|
||||
return util.CreateTemplate(category, name, content)
|
||||
}
|
||||
|
||||
func Clean() error {
|
||||
return util.Clean(category)
|
||||
}
|
||||
|
||||
func Update(category string) error {
|
||||
func Update() error {
|
||||
err := Clean()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return util.InitTemplates(category, templates)
|
||||
}
|
||||
|
||||
func GetCategory() string {
|
||||
return category
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ func TestUpdate(t *testing.T) {
|
||||
|
||||
assert.Equal(t, string(data), modifyData)
|
||||
|
||||
assert.Nil(t, Update(category))
|
||||
assert.Nil(t, Update())
|
||||
|
||||
data, err = ioutil.ReadFile(file)
|
||||
assert.Nil(t, err)
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
)
|
||||
|
||||
func genTypes(table Table, withCache bool) (string, error) {
|
||||
func genTypes(table Table, methods string, withCache bool) (string, error) {
|
||||
fields := table.Fields
|
||||
fieldsString, err := genFields(fields)
|
||||
if err != nil {
|
||||
@@ -21,6 +21,7 @@ func genTypes(table Table, withCache bool) (string, error) {
|
||||
Parse(text).
|
||||
Execute(map[string]interface{}{
|
||||
"withCache": withCache,
|
||||
"method": methods,
|
||||
"upperStartCamelObject": table.Name.ToCamel(),
|
||||
"fields": fieldsString,
|
||||
})
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/stringx"
|
||||
)
|
||||
|
||||
func genUpdate(table Table, withCache bool) (string, error) {
|
||||
func genUpdate(table Table, withCache bool) (string, string, error) {
|
||||
expressionValues := make([]string, 0)
|
||||
for _, filed := range table.Fields {
|
||||
camel := filed.Name.ToCamel()
|
||||
@@ -24,7 +24,7 @@ func genUpdate(table Table, withCache bool) (string, error) {
|
||||
camelTableName := table.Name.ToCamel()
|
||||
text, err := util.LoadTemplate(category, updateTemplateFile, template.Update)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
output, err := util.With("update").
|
||||
@@ -34,13 +34,28 @@ func genUpdate(table Table, withCache bool) (string, error) {
|
||||
"upperStartCamelObject": camelTableName,
|
||||
"primaryCacheKey": table.CacheKey[table.PrimaryKey.Name.Source()].DataKeyExpression,
|
||||
"primaryKeyVariable": table.CacheKey[table.PrimaryKey.Name.Source()].Variable,
|
||||
"lowerStartCamelObject": stringx.From(camelTableName).UnTitle(),
|
||||
"lowerStartCamelObject": stringx.From(camelTableName).Untitle(),
|
||||
"originalPrimaryKey": table.PrimaryKey.Name.Source(),
|
||||
"expressionValues": strings.Join(expressionValues, ", "),
|
||||
})
|
||||
if err != nil {
|
||||
return "", nil
|
||||
return "", "", nil
|
||||
}
|
||||
|
||||
return output.String(), nil
|
||||
// update interface method
|
||||
text, err = util.LoadTemplate(category, updateMethodTemplateFile, template.UpdateMethod)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
updateMethodOutput, err := util.With("updateMethod").
|
||||
Parse(text).
|
||||
Execute(map[string]interface{}{
|
||||
"upperStartCamelObject": camelTableName,
|
||||
})
|
||||
if err != nil {
|
||||
return "", "", nil
|
||||
}
|
||||
|
||||
return output.String(), updateMethodOutput.String(), nil
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ func genVars(table Table, withCache bool) (string, error) {
|
||||
Parse(text).
|
||||
GoFmt(true).
|
||||
Execute(map[string]interface{}{
|
||||
"lowerStartCamelObject": stringx.From(camel).UnTitle(),
|
||||
"lowerStartCamelObject": stringx.From(camel).Untitle(),
|
||||
"upperStartCamelObject": camel,
|
||||
"cacheKeys": strings.Join(keys, "\n"),
|
||||
"autoIncrement": table.PrimaryKey.AutoIncrement,
|
||||
|
||||
@@ -9,11 +9,13 @@ type (
|
||||
conn sqlx.SqlConn
|
||||
}
|
||||
Column struct {
|
||||
Name string `db:"COLUMN_NAME"`
|
||||
DataType string `db:"DATA_TYPE"`
|
||||
Key string `db:"COLUMN_KEY"`
|
||||
Extra string `db:"EXTRA"`
|
||||
Comment string `db:"COLUMN_COMMENT"`
|
||||
Name string `db:"COLUMN_NAME"`
|
||||
DataType string `db:"DATA_TYPE"`
|
||||
Key string `db:"COLUMN_KEY"`
|
||||
Extra string `db:"EXTRA"`
|
||||
Comment string `db:"COLUMN_COMMENT"`
|
||||
ColumnDefault interface{} `db:"COLUMN_DEFAULT"`
|
||||
IsNullAble string `db:"IS_NULLABLE"`
|
||||
}
|
||||
)
|
||||
|
||||
@@ -33,7 +35,7 @@ func (m *InformationSchemaModel) GetAllTables(database string) ([]string, error)
|
||||
}
|
||||
|
||||
func (m *InformationSchemaModel) FindByTableName(db, table string) ([]*Column, error) {
|
||||
querySql := `select COLUMN_NAME,DATA_TYPE,COLUMN_KEY,EXTRA,COLUMN_COMMENT from COLUMNS where TABLE_SCHEMA = ? and TABLE_NAME = ?`
|
||||
querySql := `select COLUMN_NAME,COLUMN_DEFAULT,IS_NULLABLE,DATA_TYPE,COLUMN_KEY,EXTRA,COLUMN_COMMENT from COLUMNS where TABLE_SCHEMA = ? and TABLE_NAME = ?`
|
||||
var reply []*Column
|
||||
err := m.conn.QueryRows(&reply, querySql, db, table)
|
||||
return reply, err
|
||||
|
||||
@@ -112,7 +112,17 @@ func Parse(ddl string) (*Table, error) {
|
||||
if column.Type.Comment != nil {
|
||||
comment = string(column.Type.Comment.Val)
|
||||
}
|
||||
dataType, err := converter.ConvertDataType(column.Type.Type)
|
||||
var isDefaultNull = true
|
||||
if column.Type.NotNull {
|
||||
isDefaultNull = false
|
||||
} else {
|
||||
if column.Type.Default == nil {
|
||||
isDefaultNull = false
|
||||
} else if string(column.Type.Default.Val) != "null" {
|
||||
isDefaultNull = false
|
||||
}
|
||||
}
|
||||
dataType, err := converter.ConvertDataType(column.Type.Type, isDefaultNull)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -170,7 +180,8 @@ func ConvertColumn(db, table string, in []*model.Column) (*Table, error) {
|
||||
}
|
||||
|
||||
primaryColumn := primaryColumns[0]
|
||||
primaryFt, err := converter.ConvertDataType(primaryColumn.DataType)
|
||||
isDefaultNull := primaryColumn.ColumnDefault == nil && primaryColumn.IsNullAble == "YES"
|
||||
primaryFt, err := converter.ConvertDataType(primaryColumn.DataType, isDefaultNull)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -189,7 +200,8 @@ func ConvertColumn(db, table string, in []*model.Column) (*Table, error) {
|
||||
}
|
||||
for key, columns := range keyMap {
|
||||
for _, item := range columns {
|
||||
dt, err := converter.ConvertDataType(item.DataType)
|
||||
isColumnDefaultNull := item.ColumnDefault == nil && item.IsNullAble == "YES"
|
||||
dt, err := converter.ConvertDataType(item.DataType, isColumnDefaultNull)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -76,6 +76,10 @@ func TestConvertColumn(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, table.PrimaryKey.AutoIncrement && table.PrimaryKey.IsPrimaryKey)
|
||||
assert.Equal(t, "id", table.PrimaryKey.Name.Source())
|
||||
assert.Equal(t, "mobile", table.Fields[1].Name.Source())
|
||||
assert.True(t, table.Fields[1].IsUniqueKey)
|
||||
for _, item := range table.Fields {
|
||||
if item.Name.Source() == "mobile" {
|
||||
assert.True(t, item.IsUniqueKey)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package template
|
||||
|
||||
var Delete = `
|
||||
func (m *{{.upperStartCamelObject}}Model) Delete({{.lowerStartCamelPrimaryKey}} {{.dataType}}) error {
|
||||
func (m *default{{.upperStartCamelObject}}Model) Delete({{.lowerStartCamelPrimaryKey}} {{.dataType}}) error {
|
||||
{{if .withCache}}{{if .containsIndexCache}}data, err:=m.FindOne({{.lowerStartCamelPrimaryKey}})
|
||||
if err!=nil{
|
||||
return err
|
||||
@@ -16,3 +16,5 @@ func (m *{{.upperStartCamelObject}}Model) Delete({{.lowerStartCamelPrimaryKey}}
|
||||
return err
|
||||
}
|
||||
`
|
||||
|
||||
var DeleteMethod = `Delete({{.lowerStartCamelPrimaryKey}} {{.dataType}}) error`
|
||||
|
||||
@@ -2,7 +2,7 @@ package template
|
||||
|
||||
// 通过id查询
|
||||
var FindOne = `
|
||||
func (m *{{.upperStartCamelObject}}Model) FindOne({{.lowerStartCamelPrimaryKey}} {{.dataType}}) (*{{.upperStartCamelObject}}, error) {
|
||||
func (m *default{{.upperStartCamelObject}}Model) FindOne({{.lowerStartCamelPrimaryKey}} {{.dataType}}) (*{{.upperStartCamelObject}}, error) {
|
||||
{{if .withCache}}{{.cacheKey}}
|
||||
var resp {{.upperStartCamelObject}}
|
||||
err := m.QueryRow(&resp, {{.cacheKeyVariable}}, func(conn sqlx.SqlConn, v interface{}) error {
|
||||
@@ -32,7 +32,7 @@ func (m *{{.upperStartCamelObject}}Model) FindOne({{.lowerStartCamelPrimaryKey}}
|
||||
|
||||
// 通过指定字段查询
|
||||
var FindOneByField = `
|
||||
func (m *{{.upperStartCamelObject}}Model) FindOneBy{{.upperField}}({{.in}}) (*{{.upperStartCamelObject}}, error) {
|
||||
func (m *default{{.upperStartCamelObject}}Model) FindOneBy{{.upperField}}({{.in}}) (*{{.upperStartCamelObject}}, error) {
|
||||
{{if .withCache}}{{.cacheKey}}
|
||||
var resp {{.upperStartCamelObject}}
|
||||
err := m.QueryRowIndex(&resp, {{.cacheKeyVariable}}, m.formatPrimary, func(conn sqlx.SqlConn, v interface{}) (i interface{}, e error) {
|
||||
@@ -64,12 +64,15 @@ func (m *{{.upperStartCamelObject}}Model) FindOneBy{{.upperField}}({{.in}}) (*{{
|
||||
}{{end}}
|
||||
`
|
||||
var FindOneByFieldExtraMethod = `
|
||||
func (m *{{.upperStartCamelObject}}Model) formatPrimary(primary interface{}) string {
|
||||
func (m *default{{.upperStartCamelObject}}Model) formatPrimary(primary interface{}) string {
|
||||
return fmt.Sprintf("%s%v", {{.primaryKeyLeft}}, primary)
|
||||
}
|
||||
|
||||
func (m *{{.upperStartCamelObject}}Model) queryPrimary(conn sqlx.SqlConn, v, primary interface{}) error {
|
||||
func (m *default{{.upperStartCamelObject}}Model) queryPrimary(conn sqlx.SqlConn, v, primary interface{}) error {
|
||||
query := fmt.Sprintf("select %s from %s where {{.originalPrimaryField}} = ? limit 1", {{.lowerStartCamelObject}}Rows, m.table )
|
||||
return conn.QueryRow(v, query, primary)
|
||||
}
|
||||
`
|
||||
|
||||
var FindOneMethod = `FindOne({{.lowerStartCamelPrimaryKey}} {{.dataType}}) (*{{.upperStartCamelObject}}, error)`
|
||||
var FindOneByFieldMethod = `FindOneBy{{.upperField}}({{.in}}) (*{{.upperStartCamelObject}}, error) `
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package template
|
||||
|
||||
var Insert = `
|
||||
func (m *{{.upperStartCamelObject}}Model) Insert(data {{.upperStartCamelObject}}) (sql.Result,error) {
|
||||
func (m *default{{.upperStartCamelObject}}Model) Insert(data {{.upperStartCamelObject}}) (sql.Result,error) {
|
||||
{{if .withCache}}{{if .containsIndexCache}}{{.keys}}
|
||||
ret, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("insert into %s (%s) values ({{.expression}})", m.table, {{.lowerStartCamelObject}}RowsExpectAutoSet)
|
||||
@@ -13,3 +13,5 @@ func (m *{{.upperStartCamelObject}}Model) Insert(data {{.upperStartCamelObject}}
|
||||
return ret,err
|
||||
}
|
||||
`
|
||||
|
||||
var InsertMethod = `Insert(data {{.upperStartCamelObject}}) (sql.Result,error)`
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package template
|
||||
|
||||
var New = `
|
||||
func New{{.upperStartCamelObject}}Model(conn sqlx.SqlConn{{if .withCache}}, c cache.CacheConf{{end}}) *{{.upperStartCamelObject}}Model {
|
||||
return &{{.upperStartCamelObject}}Model{
|
||||
func New{{.upperStartCamelObject}}Model(conn sqlx.SqlConn{{if .withCache}}, c cache.CacheConf{{end}}) {{.upperStartCamelObject}}Model {
|
||||
return &default{{.upperStartCamelObject}}Model{
|
||||
{{if .withCache}}CachedConn: sqlc.NewConn(conn, c){{else}}conn:conn{{end}},
|
||||
table: "{{.table}}",
|
||||
}
|
||||
|
||||
@@ -2,7 +2,11 @@ package template
|
||||
|
||||
var Types = `
|
||||
type (
|
||||
{{.upperStartCamelObject}}Model struct {
|
||||
{{.upperStartCamelObject}}Model interface{
|
||||
{{.method}}
|
||||
}
|
||||
|
||||
default{{.upperStartCamelObject}}Model struct {
|
||||
{{if .withCache}}sqlc.CachedConn{{else}}conn sqlx.SqlConn{{end}}
|
||||
table string
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package template
|
||||
|
||||
var Update = `
|
||||
func (m *{{.upperStartCamelObject}}Model) Update(data {{.upperStartCamelObject}}) error {
|
||||
func (m *default{{.upperStartCamelObject}}Model) Update(data {{.upperStartCamelObject}}) error {
|
||||
{{if .withCache}}{{.primaryCacheKey}}
|
||||
_, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("update %s set %s where {{.originalPrimaryKey}} = ?", m.table, {{.lowerStartCamelObject}}RowsWithPlaceHolder)
|
||||
@@ -11,3 +11,5 @@ func (m *{{.upperStartCamelObject}}Model) Update(data {{.upperStartCamelObject}}
|
||||
return err
|
||||
}
|
||||
`
|
||||
|
||||
var UpdateMethod = `Update(data {{.upperStartCamelObject}}) error`
|
||||
|
||||
12
tools/goctl/model/sql/util/slice.go
Normal file
12
tools/goctl/model/sql/util/slice.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package util
|
||||
|
||||
func TrimStringSlice(list []string) []string {
|
||||
var out []string
|
||||
for _, item := range list {
|
||||
if len(item) == 0 {
|
||||
continue
|
||||
}
|
||||
out = append(out, item)
|
||||
}
|
||||
return out
|
||||
}
|
||||
19
tools/goctl/plugin/demo/goctlplugin.go
Normal file
19
tools/goctl/plugin/demo/goctlplugin.go
Normal 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.")
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user