mirror of
https://github.com/zeromicro/go-zero.git
synced 2026-05-12 01:10:00 +08:00
Compare commits
64 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8428a7f65 | ||
|
|
a5e1d0d0dc | ||
|
|
8270c7deed | ||
|
|
9f4a882a1b | ||
|
|
cb7b7cb72e | ||
|
|
603c93aa4a | ||
|
|
cb8d9d413a | ||
|
|
ff7443c6a7 | ||
|
|
b812e74d6f | ||
|
|
089cdaa75f | ||
|
|
476026e393 | ||
|
|
75952308f9 | ||
|
|
df0550d6dc | ||
|
|
e481b63b21 | ||
|
|
e47079f0f4 | ||
|
|
9b2a279948 | ||
|
|
db87fd3239 | ||
|
|
598fda0c97 | ||
|
|
b0e335e7b0 | ||
|
|
efdf475da4 | ||
|
|
22a1315136 | ||
|
|
5b22823018 | ||
|
|
9ccb997ed8 | ||
|
|
01c92a6bc5 | ||
|
|
c9a2a60e28 | ||
|
|
b0739d63c0 | ||
|
|
c22f84cb5f | ||
|
|
60450bab02 | ||
|
|
3e8cec5c78 | ||
|
|
74ee163761 | ||
|
|
ea4f680052 | ||
|
|
58cdba2c5d | ||
|
|
a2fbc14c70 | ||
|
|
158df8c270 | ||
|
|
30ec236a87 | ||
|
|
ac3653b3f9 | ||
|
|
8520db4fd9 | ||
|
|
14141fed62 | ||
|
|
5d86cc2f20 | ||
|
|
8a6e4b7580 | ||
|
|
453f949638 | ||
|
|
75a330184d | ||
|
|
546fcd8bab | ||
|
|
3022f93b6d | ||
|
|
8ffc392c66 | ||
|
|
ae7d85dadf | ||
|
|
e89268ac37 | ||
|
|
aaa3623404 | ||
|
|
8998f16054 | ||
|
|
94417be018 | ||
|
|
f300408fc0 | ||
|
|
aaa39e17a3 | ||
|
|
73906f996d | ||
|
|
73417f54db | ||
|
|
491213afb8 | ||
|
|
edf743cd72 | ||
|
|
78a88be787 | ||
|
|
9f6a574f97 | ||
|
|
ea01cc78f0 | ||
|
|
a87978568a | ||
|
|
14cecb9b31 | ||
|
|
0ce54100a4 | ||
|
|
d28ac35ff7 | ||
|
|
a5962f677f |
102
CONTRIBUTING.md
Normal file
102
CONTRIBUTING.md
Normal file
@@ -0,0 +1,102 @@
|
||||
# Contributing
|
||||
|
||||
Welcome to go-zero!
|
||||
|
||||
- [Before you get started](#before-you-get-started)
|
||||
- [Code of Conduct](#code-of-conduct)
|
||||
- [Community Expectations](#community-expectations)
|
||||
- [Getting started](#getting-started)
|
||||
- [Your First Contribution](#your-first-contribution)
|
||||
- [Find something to work on](#find-something-to-work-on)
|
||||
- [Find a good first topic](#find-a-good-first-topic)
|
||||
- [Work on an Issue](#work-on-an-issue)
|
||||
- [File an Issue](#file-an-issue)
|
||||
- [Contributor Workflow](#contributor-workflow)
|
||||
- [Creating Pull Requests](#creating-pull-requests)
|
||||
- [Code Review](#code-review)
|
||||
- [Testing](#testing)
|
||||
|
||||
# Before you get started
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Please make sure to read and observe our [Code of Conduct](/code-of-conduct.md).
|
||||
|
||||
## Community Expectations
|
||||
|
||||
go-zero is a community project driven by its community which strives to promote a healthy, friendly and productive environment.
|
||||
go-zero is a web and rpc framework written in Go. It's born to ensure the stability of the busy sites with resilient design. Builtin goctl greatly improves the development productivity.
|
||||
|
||||
# Getting started
|
||||
|
||||
- Fork the repository on GitHub.
|
||||
- Make your changes on your fork repository.
|
||||
- Submit a PR.
|
||||
|
||||
|
||||
# Your First Contribution
|
||||
|
||||
We will help you to contribute in different areas like filing issues, developing features, fixing critical bugs and
|
||||
getting your work reviewed and merged.
|
||||
|
||||
If you have questions about the development process,
|
||||
feel free to [file an issue](https://github.com/tal-tech/go-zero/issues/new/choose).
|
||||
|
||||
## Find something to work on
|
||||
|
||||
We are always in need of help, be it fixing documentation, reporting bugs or writing some code.
|
||||
Look at places where you feel best coding practices aren't followed, code refactoring is needed or tests are missing.
|
||||
Here is how you get started.
|
||||
|
||||
### Find a good first topic
|
||||
|
||||
[go-zero](https://github.com/tal-tech/go-zero) has beginner-friendly issues that provide a good first issue.
|
||||
For example, [go-zero](https://github.com/tal-tech/go-zero) has
|
||||
[help wanted](https://github.com/tal-tech/go-zero/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) and
|
||||
[good first issue](https://github.com/tal-tech/go-zero/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)
|
||||
labels for issues that should not need deep knowledge of the system.
|
||||
We can help new contributors who wish to work on such issues.
|
||||
|
||||
Another good way to contribute is to find a documentation improvement, such as a missing/broken link.
|
||||
Please see [Contributing](#contributing) below for the workflow.
|
||||
|
||||
#### Work on an issue
|
||||
|
||||
When you are willing to take on an issue, just reply on the issue. The maintainer will assign it to you.
|
||||
|
||||
### File an Issue
|
||||
|
||||
While we encourage everyone to contribute code, it is also appreciated when someone reports an issue.
|
||||
|
||||
Please follow the prompted submission guidelines while opening an issue.
|
||||
|
||||
# Contributor Workflow
|
||||
|
||||
Please do not ever hesitate to ask a question or send a pull request.
|
||||
|
||||
This is a rough outline of what a contributor's workflow looks like:
|
||||
|
||||
- Create a topic branch from where to base the contribution. This is usually master.
|
||||
- Make commits of logical units.
|
||||
- Push changes in a topic branch to a personal fork of the repository.
|
||||
- Submit a pull request to [go-zero](https://github.com/tal-tech/go-zero).
|
||||
|
||||
## Creating Pull Requests
|
||||
|
||||
Pull requests are often called simply "PR".
|
||||
go-zero generally follows the standard [github pull request](https://help.github.com/articles/about-pull-requests/) process.
|
||||
To submit a proposed change, please develop the code/fix and add new test cases.
|
||||
After that, run these local verifications before submitting pull request to predict the pass or
|
||||
fail of continuous integration.
|
||||
|
||||
* Format the code with `gofmt`
|
||||
* Run the test with data race enabled `go test -race ./…`
|
||||
|
||||
## Code Review
|
||||
|
||||
To make it easier for your PR to receive reviews, consider the reviewers will need you to:
|
||||
|
||||
* follow [good coding guidelines](https://github.com/golang/go/wiki/CodeReviewComments).
|
||||
* write [good commit messages](https://chris.beams.io/posts/git-commit/).
|
||||
* break large changes into a logical series of smaller patches which individually make easily understandable changes, and in aggregate solve a broader issue.
|
||||
|
||||
21
ROADMAP.md
Normal file
21
ROADMAP.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# go-zero Roadmap
|
||||
|
||||
This document defines a high level roadmap for go-zero development and upcoming releases.
|
||||
Community and contributor involvement is vital for successfully implementing all desired items for each release.
|
||||
We hope that the items listed below will inspire further engagement from the community to keep go-zero progressing and shipping exciting and valuable features.
|
||||
|
||||
## 2021 Q2
|
||||
- Support TLS in redis connections
|
||||
- Support service discovery through K8S watch api
|
||||
- Log full sql statements for easier sql problem solving
|
||||
|
||||
## 2021 Q3
|
||||
- Support `goctl mock` command to start a mocking server with given `.api` file
|
||||
- Adapt builtin tracing mechanism to opentracing solutions
|
||||
- Support `goctl model pg` to support PostgreSQL code generation
|
||||
|
||||
## 2021 Q4
|
||||
- Support `goctl doctor` command to report potential issues for given service
|
||||
- Support `context` in redis related methods for timeout and tracing
|
||||
- Support `context` in sql related methods for timeout and tracing
|
||||
- Support `context` in mongodb related methods for timeout and tracing
|
||||
76
code-of-conduct.md
Normal file
76
code-of-conduct.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to make participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all project spaces, and it also applies when
|
||||
an individual is representing the project or its community in public spaces.
|
||||
Examples of representing a project or community include using an official
|
||||
project e-mail address, posting via an official social media account, or acting
|
||||
as an appointed representative at an online or offline event. Representation of
|
||||
a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at [INSERT EMAIL ADDRESS]. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
https://www.contributor-covenant.org/faq
|
||||
@@ -94,7 +94,7 @@ func (b *googleBreaker) markFailure() {
|
||||
b.stat.Add(0)
|
||||
}
|
||||
|
||||
func (b *googleBreaker) history() (accepts int64, total int64) {
|
||||
func (b *googleBreaker) history() (accepts, total int64) {
|
||||
b.stat.Reduce(func(b *collection.Bucket) {
|
||||
accepts += int64(b.Sum)
|
||||
total += b.Count
|
||||
|
||||
@@ -106,9 +106,7 @@ func (s *Set) KeysInt() []int {
|
||||
var keys []int
|
||||
|
||||
for key := range s.data {
|
||||
if intKey, ok := key.(int); !ok {
|
||||
continue
|
||||
} else {
|
||||
if intKey, ok := key.(int); ok {
|
||||
keys = append(keys, intKey)
|
||||
}
|
||||
}
|
||||
@@ -121,9 +119,7 @@ func (s *Set) KeysInt64() []int64 {
|
||||
var keys []int64
|
||||
|
||||
for key := range s.data {
|
||||
if intKey, ok := key.(int64); !ok {
|
||||
continue
|
||||
} else {
|
||||
if intKey, ok := key.(int64); ok {
|
||||
keys = append(keys, intKey)
|
||||
}
|
||||
}
|
||||
@@ -136,9 +132,7 @@ func (s *Set) KeysUint() []uint {
|
||||
var keys []uint
|
||||
|
||||
for key := range s.data {
|
||||
if intKey, ok := key.(uint); !ok {
|
||||
continue
|
||||
} else {
|
||||
if intKey, ok := key.(uint); ok {
|
||||
keys = append(keys, intKey)
|
||||
}
|
||||
}
|
||||
@@ -151,9 +145,7 @@ func (s *Set) KeysUint64() []uint64 {
|
||||
var keys []uint64
|
||||
|
||||
for key := range s.data {
|
||||
if intKey, ok := key.(uint64); !ok {
|
||||
continue
|
||||
} else {
|
||||
if intKey, ok := key.(uint64); ok {
|
||||
keys = append(keys, intKey)
|
||||
}
|
||||
}
|
||||
@@ -166,9 +158,7 @@ func (s *Set) KeysStr() []string {
|
||||
var keys []string
|
||||
|
||||
for key := range s.data {
|
||||
if strKey, ok := key.(string); !ok {
|
||||
continue
|
||||
} else {
|
||||
if strKey, ok := key.(string); ok {
|
||||
keys = append(keys, strKey)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ func (tw *TimingWheel) drainAll(fn func(key, value interface{})) {
|
||||
}
|
||||
}
|
||||
|
||||
func (tw *TimingWheel) getPositionAndCircle(d time.Duration) (pos int, circle int) {
|
||||
func (tw *TimingWheel) getPositionAndCircle(d time.Duration) (pos, circle int) {
|
||||
steps := int(d / tw.interval)
|
||||
pos = (tw.tickedPos + steps) % tw.numSlots
|
||||
circle = (steps - 1) / tw.numSlots
|
||||
|
||||
@@ -5,7 +5,7 @@ package internal
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.etcd.io/etcd/clientv3"
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
|
||||
@@ -6,10 +6,11 @@ package internal
|
||||
|
||||
import (
|
||||
context "context"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
clientv3 "go.etcd.io/etcd/clientv3"
|
||||
grpc "google.golang.org/grpc"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
grpc "google.golang.org/grpc"
|
||||
)
|
||||
|
||||
// MockEtcdClient is a mock of EtcdClient interface
|
||||
|
||||
@@ -2,5 +2,5 @@ package internal
|
||||
|
||||
// Listener interface wraps the OnUpdate method.
|
||||
type Listener interface {
|
||||
OnUpdate(keys []string, values []string, newKey string)
|
||||
OnUpdate(keys, values []string, newKey string)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
"github.com/tal-tech/go-zero/core/logx"
|
||||
"github.com/tal-tech/go-zero/core/syncx"
|
||||
"github.com/tal-tech/go-zero/core/threading"
|
||||
"go.etcd.io/etcd/clientv3"
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -260,26 +260,34 @@ func (c *cluster) reload(cli EtcdClient) {
|
||||
}
|
||||
|
||||
func (c *cluster) watch(cli EtcdClient, key string) {
|
||||
for {
|
||||
if c.watchStream(cli, key) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cluster) watchStream(cli EtcdClient, key string) bool {
|
||||
rch := cli.Watch(clientv3.WithRequireLeader(c.context(cli)), makeKeyPrefix(key), clientv3.WithPrefix())
|
||||
for {
|
||||
select {
|
||||
case wresp, ok := <-rch:
|
||||
if !ok {
|
||||
logx.Error("etcd monitor chan has been closed")
|
||||
return
|
||||
return false
|
||||
}
|
||||
if wresp.Canceled {
|
||||
logx.Error("etcd monitor chan has been canceled")
|
||||
return
|
||||
logx.Errorf("etcd monitor chan has been canceled, error: %v", wresp.Err())
|
||||
return false
|
||||
}
|
||||
if wresp.Err() != nil {
|
||||
logx.Error(fmt.Sprintf("etcd monitor chan error: %v", wresp.Err()))
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
c.handleWatchEvents(key, wresp.Events)
|
||||
case <-c.done:
|
||||
return
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,11 @@ import (
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tal-tech/go-zero/core/contextx"
|
||||
"github.com/tal-tech/go-zero/core/lang"
|
||||
"github.com/tal-tech/go-zero/core/logx"
|
||||
"github.com/tal-tech/go-zero/core/stringx"
|
||||
"go.etcd.io/etcd/clientv3"
|
||||
"go.etcd.io/etcd/mvcc/mvccpb"
|
||||
"go.etcd.io/etcd/api/v3/mvccpb"
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
)
|
||||
|
||||
var mockLock sync.Mutex
|
||||
@@ -202,11 +203,13 @@ func TestClusterWatch_RespFailures(t *testing.T) {
|
||||
restore := setMockClient(cli)
|
||||
defer restore()
|
||||
ch := make(chan clientv3.WatchResponse)
|
||||
cli.EXPECT().Watch(gomock.Any(), "any/", gomock.Any()).Return(ch)
|
||||
cli.EXPECT().Watch(gomock.Any(), "any/", gomock.Any()).Return(ch).AnyTimes()
|
||||
cli.EXPECT().Ctx().Return(context.Background()).AnyTimes()
|
||||
c := new(cluster)
|
||||
c.done = make(chan lang.PlaceholderType)
|
||||
go func() {
|
||||
ch <- resp
|
||||
close(c.done)
|
||||
}()
|
||||
c.watch(cli, "any")
|
||||
})
|
||||
@@ -220,11 +223,13 @@ func TestClusterWatch_CloseChan(t *testing.T) {
|
||||
restore := setMockClient(cli)
|
||||
defer restore()
|
||||
ch := make(chan clientv3.WatchResponse)
|
||||
cli.EXPECT().Watch(gomock.Any(), "any/", gomock.Any()).Return(ch)
|
||||
cli.EXPECT().Watch(gomock.Any(), "any/", gomock.Any()).Return(ch).AnyTimes()
|
||||
cli.EXPECT().Ctx().Return(context.Background()).AnyTimes()
|
||||
c := new(cluster)
|
||||
c.done = make(chan lang.PlaceholderType)
|
||||
go func() {
|
||||
close(ch)
|
||||
close(c.done)
|
||||
}()
|
||||
c.watch(cli, "any")
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"github.com/tal-tech/go-zero/core/proc"
|
||||
"github.com/tal-tech/go-zero/core/syncx"
|
||||
"github.com/tal-tech/go-zero/core/threading"
|
||||
"go.etcd.io/etcd/clientv3"
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"github.com/tal-tech/go-zero/core/discov/internal"
|
||||
"github.com/tal-tech/go-zero/core/lang"
|
||||
"github.com/tal-tech/go-zero/core/logx"
|
||||
"go.etcd.io/etcd/clientv3"
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -49,6 +49,11 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
// Concat returns a concatenated Stream.
|
||||
func Concat(s Stream, others ...Stream) Stream {
|
||||
return s.Concat(others...)
|
||||
}
|
||||
|
||||
// From constructs a Stream from the given GenerateFunc.
|
||||
func From(generate GenerateFunc) Stream {
|
||||
source := make(chan interface{})
|
||||
@@ -79,16 +84,42 @@ func Range(source <-chan interface{}) Stream {
|
||||
}
|
||||
}
|
||||
|
||||
// AllMach returns whether all elements of this stream match the provided predicate.
|
||||
// May not evaluate the predicate on all elements if not necessary for determining the result.
|
||||
// If the stream is empty then true is returned and the predicate is not evaluated.
|
||||
func (s Stream) AllMach(predicate func(item interface{}) bool) bool {
|
||||
for item := range s.source {
|
||||
if !predicate(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// AnyMach returns whether any elements of this stream match the provided predicate.
|
||||
// May not evaluate the predicate on all elements if not necessary for determining the result.
|
||||
// If the stream is empty then false is returned and the predicate is not evaluated.
|
||||
func (s Stream) AnyMach(predicate func(item interface{}) bool) bool {
|
||||
for item := range s.source {
|
||||
if predicate(item) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Buffer buffers the items into a queue with size n.
|
||||
// It can balance the producer and the consumer if their processing throughput don't match.
|
||||
func (p Stream) Buffer(n int) Stream {
|
||||
func (s Stream) Buffer(n int) Stream {
|
||||
if n < 0 {
|
||||
n = 0
|
||||
}
|
||||
|
||||
source := make(chan interface{}, n)
|
||||
go func() {
|
||||
for item := range p.source {
|
||||
for item := range s.source {
|
||||
source <- item
|
||||
}
|
||||
close(source)
|
||||
@@ -97,23 +128,51 @@ func (p Stream) Buffer(n int) Stream {
|
||||
return Range(source)
|
||||
}
|
||||
|
||||
// Concat returns a Stream that concatenated other streams
|
||||
func (s Stream) Concat(others ...Stream) Stream {
|
||||
source := make(chan interface{})
|
||||
|
||||
go func() {
|
||||
group := threading.NewRoutineGroup()
|
||||
group.Run(func() {
|
||||
for item := range s.source {
|
||||
source <- item
|
||||
}
|
||||
})
|
||||
|
||||
for _, each := range others {
|
||||
each := each
|
||||
group.Run(func() {
|
||||
for item := range each.source {
|
||||
source <- item
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
group.Wait()
|
||||
close(source)
|
||||
}()
|
||||
|
||||
return Range(source)
|
||||
}
|
||||
|
||||
// Count counts the number of elements in the result.
|
||||
func (p Stream) Count() (count int) {
|
||||
for range p.source {
|
||||
func (s Stream) Count() (count int) {
|
||||
for range s.source {
|
||||
count++
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Distinct removes the duplicated items base on the given KeyFunc.
|
||||
func (p Stream) Distinct(fn KeyFunc) Stream {
|
||||
func (s Stream) Distinct(fn KeyFunc) Stream {
|
||||
source := make(chan interface{})
|
||||
|
||||
threading.GoSafe(func() {
|
||||
defer close(source)
|
||||
|
||||
keys := make(map[interface{}]lang.PlaceholderType)
|
||||
for item := range p.source {
|
||||
for item := range s.source {
|
||||
key := fn(item)
|
||||
if _, ok := keys[key]; !ok {
|
||||
source <- item
|
||||
@@ -126,14 +185,14 @@ func (p Stream) Distinct(fn KeyFunc) Stream {
|
||||
}
|
||||
|
||||
// Done waits all upstreaming operations to be done.
|
||||
func (p Stream) Done() {
|
||||
for range p.source {
|
||||
func (s Stream) Done() {
|
||||
for range s.source {
|
||||
}
|
||||
}
|
||||
|
||||
// Filter filters the items by the given FilterFunc.
|
||||
func (p Stream) Filter(fn FilterFunc, opts ...Option) Stream {
|
||||
return p.Walk(func(item interface{}, pipe chan<- interface{}) {
|
||||
func (s Stream) Filter(fn FilterFunc, opts ...Option) Stream {
|
||||
return s.Walk(func(item interface{}, pipe chan<- interface{}) {
|
||||
if fn(item) {
|
||||
pipe <- item
|
||||
}
|
||||
@@ -141,21 +200,21 @@ func (p Stream) Filter(fn FilterFunc, opts ...Option) Stream {
|
||||
}
|
||||
|
||||
// ForAll handles the streaming elements from the source and no later streams.
|
||||
func (p Stream) ForAll(fn ForAllFunc) {
|
||||
fn(p.source)
|
||||
func (s Stream) ForAll(fn ForAllFunc) {
|
||||
fn(s.source)
|
||||
}
|
||||
|
||||
// ForEach seals the Stream with the ForEachFunc on each item, no successive operations.
|
||||
func (p Stream) ForEach(fn ForEachFunc) {
|
||||
for item := range p.source {
|
||||
func (s Stream) ForEach(fn ForEachFunc) {
|
||||
for item := range s.source {
|
||||
fn(item)
|
||||
}
|
||||
}
|
||||
|
||||
// Group groups the elements into different groups based on their keys.
|
||||
func (p Stream) Group(fn KeyFunc) Stream {
|
||||
func (s Stream) Group(fn KeyFunc) Stream {
|
||||
groups := make(map[interface{}][]interface{})
|
||||
for item := range p.source {
|
||||
for item := range s.source {
|
||||
key := fn(item)
|
||||
groups[key] = append(groups[key], item)
|
||||
}
|
||||
@@ -172,7 +231,7 @@ func (p Stream) Group(fn KeyFunc) Stream {
|
||||
}
|
||||
|
||||
// Head returns the first n elements in p.
|
||||
func (p Stream) Head(n int64) Stream {
|
||||
func (s Stream) Head(n int64) Stream {
|
||||
if n < 1 {
|
||||
panic("n must be greater than 0")
|
||||
}
|
||||
@@ -180,7 +239,7 @@ func (p Stream) Head(n int64) Stream {
|
||||
source := make(chan interface{})
|
||||
|
||||
go func() {
|
||||
for item := range p.source {
|
||||
for item := range s.source {
|
||||
n--
|
||||
if n >= 0 {
|
||||
source <- item
|
||||
@@ -201,16 +260,16 @@ func (p Stream) Head(n int64) Stream {
|
||||
}
|
||||
|
||||
// Map converts each item to another corresponding item, which means it's a 1:1 model.
|
||||
func (p Stream) Map(fn MapFunc, opts ...Option) Stream {
|
||||
return p.Walk(func(item interface{}, pipe chan<- interface{}) {
|
||||
func (s Stream) Map(fn MapFunc, opts ...Option) Stream {
|
||||
return s.Walk(func(item interface{}, pipe chan<- interface{}) {
|
||||
pipe <- fn(item)
|
||||
}, opts...)
|
||||
}
|
||||
|
||||
// Merge merges all the items into a slice and generates a new stream.
|
||||
func (p Stream) Merge() Stream {
|
||||
func (s Stream) Merge() Stream {
|
||||
var items []interface{}
|
||||
for item := range p.source {
|
||||
for item := range s.source {
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
@@ -222,21 +281,21 @@ func (p Stream) Merge() Stream {
|
||||
}
|
||||
|
||||
// Parallel applies the given ParallelFunc to each item concurrently with given number of workers.
|
||||
func (p Stream) Parallel(fn ParallelFunc, opts ...Option) {
|
||||
p.Walk(func(item interface{}, pipe chan<- interface{}) {
|
||||
func (s Stream) Parallel(fn ParallelFunc, opts ...Option) {
|
||||
s.Walk(func(item interface{}, pipe chan<- interface{}) {
|
||||
fn(item)
|
||||
}, opts...).Done()
|
||||
}
|
||||
|
||||
// Reduce is a utility method to let the caller deal with the underlying channel.
|
||||
func (p Stream) Reduce(fn ReduceFunc) (interface{}, error) {
|
||||
return fn(p.source)
|
||||
func (s Stream) Reduce(fn ReduceFunc) (interface{}, error) {
|
||||
return fn(s.source)
|
||||
}
|
||||
|
||||
// Reverse reverses the elements in the stream.
|
||||
func (p Stream) Reverse() Stream {
|
||||
func (s Stream) Reverse() Stream {
|
||||
var items []interface{}
|
||||
for item := range p.source {
|
||||
for item := range s.source {
|
||||
items = append(items, item)
|
||||
}
|
||||
// reverse, official method
|
||||
@@ -248,10 +307,36 @@ func (p Stream) Reverse() Stream {
|
||||
return Just(items...)
|
||||
}
|
||||
|
||||
// Skip returns a Stream that skips size elements.
|
||||
func (s Stream) Skip(n int64) Stream {
|
||||
if n < 0 {
|
||||
panic("n must not be negative")
|
||||
}
|
||||
if n == 0 {
|
||||
return s
|
||||
}
|
||||
|
||||
source := make(chan interface{})
|
||||
|
||||
go func() {
|
||||
for item := range s.source {
|
||||
n--
|
||||
if n >= 0 {
|
||||
continue
|
||||
} else {
|
||||
source <- item
|
||||
}
|
||||
}
|
||||
close(source)
|
||||
}()
|
||||
|
||||
return Range(source)
|
||||
}
|
||||
|
||||
// Sort sorts the items from the underlying source.
|
||||
func (p Stream) Sort(less LessFunc) Stream {
|
||||
func (s Stream) Sort(less LessFunc) Stream {
|
||||
var items []interface{}
|
||||
for item := range p.source {
|
||||
for item := range s.source {
|
||||
items = append(items, item)
|
||||
}
|
||||
sort.Slice(items, func(i, j int) bool {
|
||||
@@ -263,7 +348,7 @@ func (p Stream) Sort(less LessFunc) Stream {
|
||||
|
||||
// Split splits the elements into chunk with size up to n,
|
||||
// might be less than n on tailing elements.
|
||||
func (p Stream) Split(n int) Stream {
|
||||
func (s Stream) Split(n int) Stream {
|
||||
if n < 1 {
|
||||
panic("n should be greater than 0")
|
||||
}
|
||||
@@ -271,7 +356,7 @@ func (p Stream) Split(n int) Stream {
|
||||
source := make(chan interface{})
|
||||
go func() {
|
||||
var chunk []interface{}
|
||||
for item := range p.source {
|
||||
for item := range s.source {
|
||||
chunk = append(chunk, item)
|
||||
if len(chunk) == n {
|
||||
source <- chunk
|
||||
@@ -288,7 +373,7 @@ func (p Stream) Split(n int) Stream {
|
||||
}
|
||||
|
||||
// Tail returns the last n elements in p.
|
||||
func (p Stream) Tail(n int64) Stream {
|
||||
func (s Stream) Tail(n int64) Stream {
|
||||
if n < 1 {
|
||||
panic("n should be greater than 0")
|
||||
}
|
||||
@@ -297,7 +382,7 @@ func (p Stream) Tail(n int64) Stream {
|
||||
|
||||
go func() {
|
||||
ring := collection.NewRing(int(n))
|
||||
for item := range p.source {
|
||||
for item := range s.source {
|
||||
ring.Add(item)
|
||||
}
|
||||
for _, item := range ring.Take() {
|
||||
@@ -310,16 +395,16 @@ func (p Stream) Tail(n int64) Stream {
|
||||
}
|
||||
|
||||
// Walk lets the callers handle each item, the caller may write zero, one or more items base on the given item.
|
||||
func (p Stream) Walk(fn WalkFunc, opts ...Option) Stream {
|
||||
func (s Stream) Walk(fn WalkFunc, opts ...Option) Stream {
|
||||
option := buildOptions(opts...)
|
||||
if option.unlimitedWorkers {
|
||||
return p.walkUnlimited(fn, option)
|
||||
return s.walkUnlimited(fn, option)
|
||||
}
|
||||
|
||||
return p.walkLimited(fn, option)
|
||||
return s.walkLimited(fn, option)
|
||||
}
|
||||
|
||||
func (p Stream) walkLimited(fn WalkFunc, option *rxOptions) Stream {
|
||||
func (s Stream) walkLimited(fn WalkFunc, option *rxOptions) Stream {
|
||||
pipe := make(chan interface{}, option.workers)
|
||||
|
||||
go func() {
|
||||
@@ -328,7 +413,7 @@ func (p Stream) walkLimited(fn WalkFunc, option *rxOptions) Stream {
|
||||
|
||||
for {
|
||||
pool <- lang.Placeholder
|
||||
item, ok := <-p.source
|
||||
item, ok := <-s.source
|
||||
if !ok {
|
||||
<-pool
|
||||
break
|
||||
@@ -353,14 +438,14 @@ func (p Stream) walkLimited(fn WalkFunc, option *rxOptions) Stream {
|
||||
return Range(pipe)
|
||||
}
|
||||
|
||||
func (p Stream) walkUnlimited(fn WalkFunc, option *rxOptions) Stream {
|
||||
func (s Stream) walkUnlimited(fn WalkFunc, option *rxOptions) Stream {
|
||||
pipe := make(chan interface{}, defaultWorkers)
|
||||
|
||||
go func() {
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for {
|
||||
item, ok := <-p.source
|
||||
item, ok := <-s.source
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
|
||||
@@ -3,7 +3,10 @@ package fx
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sort"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
@@ -330,6 +333,29 @@ func TestWalk(t *testing.T) {
|
||||
assert.Equal(t, 9, result)
|
||||
}
|
||||
|
||||
func BenchmarkParallelMapReduce(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
mapper := func(v interface{}) interface{} {
|
||||
return v.(int64) * v.(int64)
|
||||
}
|
||||
reducer := func(input <-chan interface{}) (interface{}, error) {
|
||||
var result int64
|
||||
for v := range input {
|
||||
result += v.(int64)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
b.ResetTimer()
|
||||
From(func(input chan<- interface{}) {
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
input <- int64(rand.Int())
|
||||
}
|
||||
})
|
||||
}).Map(mapper).Reduce(reducer)
|
||||
}
|
||||
|
||||
func BenchmarkMapReduce(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
@@ -343,12 +369,103 @@ func BenchmarkMapReduce(b *testing.B) {
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
b.ResetTimer()
|
||||
From(func(input chan<- interface{}) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
input <- int64(rand.Int())
|
||||
}
|
||||
}).Map(mapper).Reduce(reducer)
|
||||
}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
From(func(input chan<- interface{}) {
|
||||
for j := 0; j < 2; j++ {
|
||||
input <- int64(j)
|
||||
}
|
||||
}).Map(mapper).Reduce(reducer)
|
||||
func equal(t *testing.T, stream Stream, data []interface{}) {
|
||||
items := make([]interface{}, 0)
|
||||
for item := range stream.source {
|
||||
items = append(items, item)
|
||||
}
|
||||
if !reflect.DeepEqual(items, data) {
|
||||
t.Errorf(" %v, want %v", items, data)
|
||||
}
|
||||
}
|
||||
|
||||
func assetEqual(t *testing.T, except, data interface{}) {
|
||||
if !reflect.DeepEqual(except, data) {
|
||||
t.Errorf(" %v, want %v", data, except)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStream_AnyMach(t *testing.T) {
|
||||
assetEqual(t, false, Just(1, 2, 3).AnyMach(func(item interface{}) bool {
|
||||
return 4 == item.(int)
|
||||
}))
|
||||
assetEqual(t, false, Just(1, 2, 3).AnyMach(func(item interface{}) bool {
|
||||
return 0 == item.(int)
|
||||
}))
|
||||
assetEqual(t, true, Just(1, 2, 3).AnyMach(func(item interface{}) bool {
|
||||
return 2 == item.(int)
|
||||
}))
|
||||
assetEqual(t, true, Just(1, 2, 3).AnyMach(func(item interface{}) bool {
|
||||
return 2 == item.(int)
|
||||
}))
|
||||
}
|
||||
|
||||
func TestStream_AllMach(t *testing.T) {
|
||||
assetEqual(
|
||||
t, true, Just(1, 2, 3).AllMach(func(item interface{}) bool {
|
||||
return true
|
||||
}),
|
||||
)
|
||||
assetEqual(
|
||||
t, false, Just(1, 2, 3).AllMach(func(item interface{}) bool {
|
||||
return false
|
||||
}),
|
||||
)
|
||||
assetEqual(
|
||||
t, false, Just(1, 2, 3).AllMach(func(item interface{}) bool {
|
||||
return item.(int) == 1
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
func TestConcat(t *testing.T) {
|
||||
a1 := []interface{}{1, 2, 3}
|
||||
a2 := []interface{}{4, 5, 6}
|
||||
s1 := Just(a1...)
|
||||
s2 := Just(a2...)
|
||||
stream := Concat(s1, s2)
|
||||
var items []interface{}
|
||||
for item := range stream.source {
|
||||
items = append(items, item)
|
||||
}
|
||||
sort.Slice(items, func(i, j int) bool {
|
||||
return items[i].(int) < items[j].(int)
|
||||
})
|
||||
ints := make([]interface{}, 0)
|
||||
ints = append(ints, a1...)
|
||||
ints = append(ints, a2...)
|
||||
assetEqual(t, ints, items)
|
||||
}
|
||||
|
||||
func TestStream_Skip(t *testing.T) {
|
||||
assetEqual(t, 3, Just(1, 2, 3, 4).Skip(1).Count())
|
||||
assetEqual(t, 1, Just(1, 2, 3, 4).Skip(3).Count())
|
||||
assetEqual(t, 4, Just(1, 2, 3, 4).Skip(0).Count())
|
||||
equal(t, Just(1, 2, 3, 4).Skip(3), []interface{}{4})
|
||||
assert.Panics(t, func() {
|
||||
Just(1, 2, 3, 4).Skip(-1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStream_Concat(t *testing.T) {
|
||||
stream := Just(1).Concat(Just(2), Just(3))
|
||||
var items []interface{}
|
||||
for item := range stream.source {
|
||||
items = append(items, item)
|
||||
}
|
||||
sort.Slice(items, func(i, j int) bool {
|
||||
return items[i].(int) < items[j].(int)
|
||||
})
|
||||
assetEqual(t, []interface{}{1, 2, 3}, items)
|
||||
|
||||
just := Just(1)
|
||||
equal(t, just.Concat(just), []interface{}{1})
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ func (h *ConsistentHash) AddWithReplicas(node interface{}, replicas int) {
|
||||
h.ring[hash] = append(h.ring[hash], node)
|
||||
}
|
||||
|
||||
sort.Slice(h.keys, func(i int, j int) bool {
|
||||
sort.Slice(h.keys, func(i, j int) bool {
|
||||
return h.keys[i] < h.keys[j]
|
||||
})
|
||||
}
|
||||
|
||||
@@ -112,5 +112,5 @@ func (t mockTrace) Follow(ctx context.Context, serviceName, operationName string
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (t mockTrace) Visit(fn func(key string, val string) bool) {
|
||||
func (t mockTrace) Visit(fn func(key, val string) bool) {
|
||||
}
|
||||
|
||||
@@ -457,6 +457,10 @@ func (u *Unmarshaler) fillSlice(fieldType reflect.Type, value reflect.Value, map
|
||||
} else {
|
||||
conv.Index(i).Set(target.Elem())
|
||||
}
|
||||
case reflect.Slice:
|
||||
if err := u.fillSlice(dereffedBaseType, conv.Index(i), ithValue); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if err := u.fillSliceValue(conv, i, dereffedBaseKind, ithValue); err != nil {
|
||||
return err
|
||||
@@ -492,18 +496,31 @@ func (u *Unmarshaler) fillSliceFromString(fieldType reflect.Type, value reflect.
|
||||
}
|
||||
|
||||
func (u *Unmarshaler) fillSliceValue(slice reflect.Value, index int, baseKind reflect.Kind, value interface{}) error {
|
||||
ithVal := slice.Index(index)
|
||||
switch v := value.(type) {
|
||||
case json.Number:
|
||||
return setValue(baseKind, slice.Index(index), v.String())
|
||||
return setValue(baseKind, ithVal, v.String())
|
||||
default:
|
||||
// don't need to consider the difference between int, int8, int16, int32, int64,
|
||||
// uint, uint8, uint16, uint32, uint64, because they're handled as json.Number.
|
||||
if slice.Index(index).Kind() != reflect.TypeOf(value).Kind() {
|
||||
return errTypeMismatch
|
||||
}
|
||||
if ithVal.Kind() == reflect.Ptr {
|
||||
baseType := Deref(ithVal.Type())
|
||||
if baseType.Kind() != reflect.TypeOf(value).Kind() {
|
||||
return errTypeMismatch
|
||||
}
|
||||
|
||||
slice.Index(index).Set(reflect.ValueOf(value))
|
||||
return nil
|
||||
target := reflect.New(baseType).Elem()
|
||||
target.Set(reflect.ValueOf(value))
|
||||
ithVal.Set(target.Addr())
|
||||
return nil
|
||||
} else {
|
||||
if ithVal.Kind() != reflect.TypeOf(value).Kind() {
|
||||
return errTypeMismatch
|
||||
}
|
||||
|
||||
ithVal.Set(reflect.ValueOf(value))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package mapping
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -2480,3 +2481,40 @@ func BenchmarkUnmarshal(b *testing.B) {
|
||||
UnmarshalKey(data, &an)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalJsonReaderMultiArray(t *testing.T) {
|
||||
payload := `{"a": "133", "b": [["add", "cccd"], ["eeee"]]}`
|
||||
var res struct {
|
||||
A string `json:"a"`
|
||||
B [][]string `json:"b"`
|
||||
}
|
||||
reader := strings.NewReader(payload)
|
||||
err := UnmarshalJsonReader(reader, &res)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(res.B))
|
||||
}
|
||||
|
||||
func TestUnmarshalJsonReaderPtrMultiArray(t *testing.T) {
|
||||
payload := `{"a": "133", "b": [["add", "cccd"], ["eeee"]]}`
|
||||
var res struct {
|
||||
A string `json:"a"`
|
||||
B [][]*string `json:"b"`
|
||||
}
|
||||
reader := strings.NewReader(payload)
|
||||
err := UnmarshalJsonReader(reader, &res)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(res.B))
|
||||
assert.Equal(t, 2, len(res.B[0]))
|
||||
}
|
||||
|
||||
func TestUnmarshalJsonReaderPtrArray(t *testing.T) {
|
||||
payload := `{"a": "133", "b": ["add", "cccd", "eeee"]}`
|
||||
var res struct {
|
||||
A string `json:"a"`
|
||||
B []*string `json:"b"`
|
||||
}
|
||||
reader := strings.NewReader(payload)
|
||||
err := UnmarshalJsonReader(reader, &res)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 3, len(res.B))
|
||||
}
|
||||
|
||||
@@ -286,7 +286,7 @@ func parseNumberRange(str string) (*numberRange, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func parseOption(fieldOpts *fieldOptions, fieldName string, option string) error {
|
||||
func parseOption(fieldOpts *fieldOptions, fieldName, option string) error {
|
||||
switch {
|
||||
case option == stringOption:
|
||||
fieldOpts.FromString = true
|
||||
|
||||
@@ -136,14 +136,16 @@ func MapReduceWithSource(source <-chan interface{}, mapper MapperFunc, reducer R
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
drain(collector)
|
||||
|
||||
if r := recover(); r != nil {
|
||||
cancel(fmt.Errorf("%v", r))
|
||||
} else {
|
||||
finish()
|
||||
}
|
||||
}()
|
||||
|
||||
reducer(collector, writer, cancel)
|
||||
drain(collector)
|
||||
}()
|
||||
|
||||
go executeMappers(func(item interface{}, w Writer) {
|
||||
@@ -165,7 +167,6 @@ func MapReduceWithSource(source <-chan interface{}, mapper MapperFunc, reducer R
|
||||
func MapReduceVoid(generate GenerateFunc, mapper MapperFunc, reducer VoidReducerFunc, opts ...Option) error {
|
||||
_, err := MapReduce(generate, mapper, func(input <-chan interface{}, writer Writer, cancel func(error)) {
|
||||
reducer(input, cancel)
|
||||
drain(input)
|
||||
// We need to write a placeholder to let MapReduce to continue on reducer done,
|
||||
// otherwise, all goroutines are waiting. The placeholder will be discarded by MapReduce.
|
||||
writer.Write(lang.Placeholder)
|
||||
|
||||
@@ -71,7 +71,7 @@ func NewQueue(producerFactory ProducerFactory, consumerFactory ConsumerFactory)
|
||||
return q
|
||||
}
|
||||
|
||||
// AddListener adds a litener to q.
|
||||
// AddListener adds a listener to q.
|
||||
func (q *Queue) AddListener(listener Listener) {
|
||||
q.listeners = append(q.listeners, listener)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package search
|
||||
|
||||
import "errors"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
colon = ':'
|
||||
@@ -8,16 +11,16 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrDupItem means adding duplicated item.
|
||||
ErrDupItem = errors.New("duplicated item")
|
||||
// ErrDupSlash means item is started with more than one slash.
|
||||
ErrDupSlash = errors.New("duplicated slash")
|
||||
// ErrEmptyItem means adding empty item.
|
||||
ErrEmptyItem = errors.New("empty item")
|
||||
// ErrInvalidState means search tree is in an invalid state.
|
||||
ErrInvalidState = errors.New("search tree is in an invalid state")
|
||||
// ErrNotFromRoot means path is not starting with slash.
|
||||
ErrNotFromRoot = errors.New("path should start with /")
|
||||
// errDupItem means adding duplicated item.
|
||||
errDupItem = errors.New("duplicated item")
|
||||
// errDupSlash means item is started with more than one slash.
|
||||
errDupSlash = errors.New("duplicated slash")
|
||||
// errEmptyItem means adding empty item.
|
||||
errEmptyItem = errors.New("empty item")
|
||||
// errInvalidState means search tree is in an invalid state.
|
||||
errInvalidState = errors.New("search tree is in an invalid state")
|
||||
// errNotFromRoot means path is not starting with slash.
|
||||
errNotFromRoot = errors.New("path should start with /")
|
||||
|
||||
// NotFound is used to hold the not found result.
|
||||
NotFound Result
|
||||
@@ -58,14 +61,22 @@ func NewTree() *Tree {
|
||||
// Add adds item to associate with route.
|
||||
func (t *Tree) Add(route string, item interface{}) error {
|
||||
if len(route) == 0 || route[0] != slash {
|
||||
return ErrNotFromRoot
|
||||
return errNotFromRoot
|
||||
}
|
||||
|
||||
if item == nil {
|
||||
return ErrEmptyItem
|
||||
return errEmptyItem
|
||||
}
|
||||
|
||||
return add(t.root, route[1:], item)
|
||||
err := add(t.root, route[1:], item)
|
||||
switch err {
|
||||
case errDupItem:
|
||||
return duplicatedItem(route)
|
||||
case errDupSlash:
|
||||
return duplicatedSlash(route)
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Search searches item that associates with given route.
|
||||
@@ -86,22 +97,22 @@ func (t *Tree) next(n *node, route string, result *Result) bool {
|
||||
}
|
||||
|
||||
for i := range route {
|
||||
if route[i] == slash {
|
||||
token := route[:i]
|
||||
return n.forEach(func(k string, v *node) bool {
|
||||
if r := match(k, token); r.found {
|
||||
if t.next(v, route[i+1:], result) {
|
||||
if r.named {
|
||||
addParam(result, r.key, r.value)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
if route[i] != slash {
|
||||
continue
|
||||
}
|
||||
|
||||
token := route[:i]
|
||||
return n.forEach(func(k string, v *node) bool {
|
||||
r := match(k, token)
|
||||
if !r.found || !t.next(v, route[i+1:], result) {
|
||||
return false
|
||||
}
|
||||
if r.named {
|
||||
addParam(result, r.key, r.value)
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
return n.forEach(func(k string, v *node) bool {
|
||||
@@ -141,7 +152,7 @@ func (nd *node) getChildren(route string) map[string]*node {
|
||||
func add(nd *node, route string, item interface{}) error {
|
||||
if len(route) == 0 {
|
||||
if nd.item != nil {
|
||||
return ErrDupItem
|
||||
return errDupItem
|
||||
}
|
||||
|
||||
nd.item = item
|
||||
@@ -149,31 +160,33 @@ func add(nd *node, route string, item interface{}) error {
|
||||
}
|
||||
|
||||
if route[0] == slash {
|
||||
return ErrDupSlash
|
||||
return errDupSlash
|
||||
}
|
||||
|
||||
for i := range route {
|
||||
if route[i] == slash {
|
||||
token := route[:i]
|
||||
children := nd.getChildren(token)
|
||||
if child, ok := children[token]; ok {
|
||||
if child != nil {
|
||||
return add(child, route[i+1:], item)
|
||||
}
|
||||
if route[i] != slash {
|
||||
continue
|
||||
}
|
||||
|
||||
return ErrInvalidState
|
||||
token := route[:i]
|
||||
children := nd.getChildren(token)
|
||||
if child, ok := children[token]; ok {
|
||||
if child != nil {
|
||||
return add(child, route[i+1:], item)
|
||||
}
|
||||
|
||||
child := newNode(nil)
|
||||
children[token] = child
|
||||
return add(child, route[i+1:], item)
|
||||
return errInvalidState
|
||||
}
|
||||
|
||||
child := newNode(nil)
|
||||
children[token] = child
|
||||
return add(child, route[i+1:], item)
|
||||
}
|
||||
|
||||
children := nd.getChildren(route)
|
||||
if child, ok := children[route]; ok {
|
||||
if child.item != nil {
|
||||
return ErrDupItem
|
||||
return errDupItem
|
||||
}
|
||||
|
||||
child.item = item
|
||||
@@ -192,6 +205,14 @@ func addParam(result *Result, k, v string) {
|
||||
result.Params[k] = v
|
||||
}
|
||||
|
||||
func duplicatedItem(item string) error {
|
||||
return fmt.Errorf("duplicated item for %s", item)
|
||||
}
|
||||
|
||||
func duplicatedSlash(item string) error {
|
||||
return fmt.Errorf("duplicated slash for %s", item)
|
||||
}
|
||||
|
||||
func match(pat, token string) innerResult {
|
||||
if pat[0] == colon {
|
||||
return innerResult{
|
||||
|
||||
@@ -151,9 +151,9 @@ func TestAddDuplicate(t *testing.T) {
|
||||
err := tree.Add("/a/b", 1)
|
||||
assert.Nil(t, err)
|
||||
err = tree.Add("/a/b", 2)
|
||||
assert.Equal(t, ErrDupItem, err)
|
||||
assert.Error(t, errDupItem, err)
|
||||
err = tree.Add("/a/b/", 2)
|
||||
assert.Equal(t, ErrDupItem, err)
|
||||
assert.Error(t, errDupItem, err)
|
||||
}
|
||||
|
||||
func TestPlain(t *testing.T) {
|
||||
@@ -169,19 +169,19 @@ func TestPlain(t *testing.T) {
|
||||
func TestSearchWithDoubleSlashes(t *testing.T) {
|
||||
tree := NewTree()
|
||||
err := tree.Add("//a", 1)
|
||||
assert.Error(t, ErrDupSlash, err)
|
||||
assert.Error(t, errDupSlash, err)
|
||||
}
|
||||
|
||||
func TestSearchInvalidRoute(t *testing.T) {
|
||||
tree := NewTree()
|
||||
err := tree.Add("", 1)
|
||||
assert.Equal(t, ErrNotFromRoot, err)
|
||||
assert.Equal(t, errNotFromRoot, err)
|
||||
err = tree.Add("bad", 1)
|
||||
assert.Equal(t, ErrNotFromRoot, err)
|
||||
assert.Equal(t, errNotFromRoot, err)
|
||||
}
|
||||
|
||||
func TestSearchInvalidItem(t *testing.T) {
|
||||
tree := NewTree()
|
||||
err := tree.Add("/", nil)
|
||||
assert.Equal(t, ErrEmptyItem, err)
|
||||
assert.Equal(t, errEmptyItem, err)
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ var (
|
||||
cores uint64
|
||||
)
|
||||
|
||||
// if /proc not present, ignore the cpu calcuation, like wsl linux
|
||||
// if /proc not present, ignore the cpu calculation, like wsl linux
|
||||
func init() {
|
||||
cpus, err := perCpuUsage()
|
||||
if err != nil {
|
||||
|
||||
2
core/stores/cache/cachenode.go
vendored
2
core/stores/cache/cachenode.go
vendored
@@ -205,7 +205,7 @@ func (c cacheNode) doTake(v interface{}, key string, query func(v interface{}) e
|
||||
return jsonx.Unmarshal(val.([]byte), v)
|
||||
}
|
||||
|
||||
func (c cacheNode) processCache(key string, data string, v interface{}) error {
|
||||
func (c cacheNode) processCache(key, data string, v interface{}) error {
|
||||
err := jsonx.Unmarshal([]byte(data), v)
|
||||
if err == nil {
|
||||
return nil
|
||||
|
||||
@@ -17,7 +17,7 @@ type (
|
||||
// Store interface represents a KV store.
|
||||
Store interface {
|
||||
Del(keys ...string) (int, error)
|
||||
Eval(script string, key string, args ...interface{}) (interface{}, error)
|
||||
Eval(script, key string, args ...interface{}) (interface{}, error)
|
||||
Exists(key string) (bool, error)
|
||||
Expire(key string, seconds int) error
|
||||
Expireat(key string, expireTime int64) error
|
||||
@@ -39,7 +39,7 @@ type (
|
||||
Llen(key string) (int, error)
|
||||
Lpop(key string) (string, error)
|
||||
Lpush(key string, values ...interface{}) (int, error)
|
||||
Lrange(key string, start int, stop int) ([]string, error)
|
||||
Lrange(key string, start, stop int) ([]string, error)
|
||||
Lrem(key string, count int, value string) (int, error)
|
||||
Persist(key string) (bool, error)
|
||||
Pfadd(key string, values ...interface{}) (bool, error)
|
||||
@@ -47,7 +47,7 @@ type (
|
||||
Rpush(key string, values ...interface{}) (int, error)
|
||||
Sadd(key string, values ...interface{}) (int, error)
|
||||
Scard(key string) (int64, error)
|
||||
Set(key string, value string) error
|
||||
Set(key, value string) error
|
||||
Setex(key, value string, seconds int) error
|
||||
Setnx(key, value string) (bool, error)
|
||||
SetnxEx(key, value string, seconds int) (bool, error)
|
||||
@@ -74,7 +74,7 @@ type (
|
||||
Zrevrange(key string, start, stop int64) ([]string, error)
|
||||
ZrevrangebyscoreWithScores(key string, start, stop int64) ([]redis.Pair, error)
|
||||
ZrevrangebyscoreWithScoresAndLimit(key string, start, stop int64, page, size int) ([]redis.Pair, error)
|
||||
Zscore(key string, value string) (int64, error)
|
||||
Zscore(key, value string) (int64, error)
|
||||
Zrevrank(key, field string) (int64, error)
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ func (cs clusterStore) Del(keys ...string) (int, error) {
|
||||
return val, be.Err()
|
||||
}
|
||||
|
||||
func (cs clusterStore) Eval(script string, key string, args ...interface{}) (interface{}, error) {
|
||||
func (cs clusterStore) Eval(script, key string, args ...interface{}) (interface{}, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -321,7 +321,7 @@ func (cs clusterStore) Lpush(key string, values ...interface{}) (int, error) {
|
||||
return node.Lpush(key, values...)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Lrange(key string, start int, stop int) ([]string, error) {
|
||||
func (cs clusterStore) Lrange(key string, start, stop int) ([]string, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -393,7 +393,7 @@ func (cs clusterStore) Scard(key string) (int64, error) {
|
||||
return node.Scard(key)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Set(key string, value string) error {
|
||||
func (cs clusterStore) Set(key, value string) error {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -648,7 +648,7 @@ func (cs clusterStore) Zrevrank(key, field string) (int64, error) {
|
||||
return node.Zrevrank(key, field)
|
||||
}
|
||||
|
||||
func (cs clusterStore) Zscore(key string, value string) (int64, error) {
|
||||
func (cs clusterStore) Zscore(key, value string) (int64, error) {
|
||||
node, err := cs.getRedis(key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
||||
@@ -24,11 +24,11 @@ type (
|
||||
CachedCollection interface {
|
||||
Count(query interface{}) (int, error)
|
||||
DelCache(keys ...string) error
|
||||
FindAllNoCache(v interface{}, query interface{}, opts ...QueryOption) error
|
||||
FindAllNoCache(v, query interface{}, opts ...QueryOption) error
|
||||
FindOne(v interface{}, key string, query interface{}) error
|
||||
FindOneNoCache(v interface{}, query interface{}) error
|
||||
FindOneNoCache(v, query interface{}) error
|
||||
FindOneId(v interface{}, key string, id interface{}) error
|
||||
FindOneIdNoCache(v interface{}, id interface{}) error
|
||||
FindOneIdNoCache(v, id interface{}) error
|
||||
GetCache(key string, v interface{}) error
|
||||
Insert(docs ...interface{}) error
|
||||
Pipe(pipeline interface{}) mongo.Pipe
|
||||
@@ -68,7 +68,7 @@ func (c *cachedCollection) DelCache(keys ...string) error {
|
||||
return c.cache.Del(keys...)
|
||||
}
|
||||
|
||||
func (c *cachedCollection) FindAllNoCache(v interface{}, query interface{}, opts ...QueryOption) error {
|
||||
func (c *cachedCollection) FindAllNoCache(v, query interface{}, opts ...QueryOption) error {
|
||||
q := c.collection.Find(query)
|
||||
for _, opt := range opts {
|
||||
q = opt(q)
|
||||
@@ -83,7 +83,7 @@ func (c *cachedCollection) FindOne(v interface{}, key string, query interface{})
|
||||
})
|
||||
}
|
||||
|
||||
func (c *cachedCollection) FindOneNoCache(v interface{}, query interface{}) error {
|
||||
func (c *cachedCollection) FindOneNoCache(v, query interface{}) error {
|
||||
q := c.collection.Find(query)
|
||||
return q.One(v)
|
||||
}
|
||||
@@ -95,7 +95,7 @@ func (c *cachedCollection) FindOneId(v interface{}, key string, id interface{})
|
||||
})
|
||||
}
|
||||
|
||||
func (c *cachedCollection) FindOneIdNoCache(v interface{}, id interface{}) error {
|
||||
func (c *cachedCollection) FindOneIdNoCache(v, id interface{}) error {
|
||||
q := c.collection.FindId(id)
|
||||
return q.One(v)
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ func (mm *Model) GetCollection(session *mgo.Session) CachedCollection {
|
||||
}
|
||||
|
||||
// FindAllNoCache finds all records without cache.
|
||||
func (mm *Model) FindAllNoCache(v interface{}, query interface{}, opts ...QueryOption) error {
|
||||
func (mm *Model) FindAllNoCache(v, query interface{}, opts ...QueryOption) error {
|
||||
return mm.execute(func(c CachedCollection) error {
|
||||
return c.FindAllNoCache(v, query, opts...)
|
||||
})
|
||||
@@ -89,7 +89,7 @@ func (mm *Model) FindOne(v interface{}, key string, query interface{}) error {
|
||||
}
|
||||
|
||||
// FindOneNoCache unmarshals a record into v with query, without cache.
|
||||
func (mm *Model) FindOneNoCache(v interface{}, query interface{}) error {
|
||||
func (mm *Model) FindOneNoCache(v, query interface{}) error {
|
||||
return mm.execute(func(c CachedCollection) error {
|
||||
return c.FindOneNoCache(v, query)
|
||||
})
|
||||
@@ -103,7 +103,7 @@ func (mm *Model) FindOneId(v interface{}, key string, id interface{}) error {
|
||||
}
|
||||
|
||||
// FindOneIdNoCache unmarshals a record into v with query, without cache.
|
||||
func (mm *Model) FindOneIdNoCache(v interface{}, id interface{}) error {
|
||||
func (mm *Model) FindOneIdNoCache(v, id interface{}) error {
|
||||
return mm.execute(func(c CachedCollection) error {
|
||||
return c.FindOneIdNoCache(v, id)
|
||||
})
|
||||
|
||||
@@ -180,7 +180,7 @@ func (s *Redis) BitOpXor(destKey string, keys ...string) (val int64, err error)
|
||||
}
|
||||
|
||||
// BitPos is redis bitpos command implementation.
|
||||
func (s *Redis) BitPos(key string, bit int64, start, end int64) (val int64, err error) {
|
||||
func (s *Redis) BitPos(key string, bit, start, end int64) (val int64, err error) {
|
||||
err = s.brk.DoWithAcceptable(func() error {
|
||||
conn, err := getRedis(s)
|
||||
if err != nil {
|
||||
@@ -346,7 +346,7 @@ func (s *Redis) GeoAdd(key string, geoLocation ...*GeoLocation) (val int64, err
|
||||
}
|
||||
|
||||
// GeoDist is the implementation of redis geodist command.
|
||||
func (s *Redis) GeoDist(key string, member1, member2, unit string) (val float64, err error) {
|
||||
func (s *Redis) GeoDist(key, member1, member2, unit string) (val float64, err error) {
|
||||
err = s.brk.DoWithAcceptable(func() error {
|
||||
conn, err := getRedis(s)
|
||||
if err != nil {
|
||||
@@ -795,7 +795,7 @@ func (s *Redis) Lpush(key string, values ...interface{}) (val int, err error) {
|
||||
}
|
||||
|
||||
// Lrange is the implementation of redis lrange command.
|
||||
func (s *Redis) Lrange(key string, start int, stop int) (val []string, err error) {
|
||||
func (s *Redis) Lrange(key string, start, stop int) (val []string, err error) {
|
||||
err = s.brk.DoWithAcceptable(func() error {
|
||||
conn, err := getRedis(s)
|
||||
if err != nil {
|
||||
@@ -1074,7 +1074,7 @@ func (s *Redis) ScriptLoad(script string) (string, error) {
|
||||
}
|
||||
|
||||
// Set is the implementation of redis set command.
|
||||
func (s *Redis) Set(key string, value string) error {
|
||||
func (s *Redis) Set(key, value string) error {
|
||||
return s.brk.DoWithAcceptable(func() error {
|
||||
conn, err := getRedis(s)
|
||||
if err != nil {
|
||||
@@ -1282,6 +1282,41 @@ func (s *Redis) Sdiffstore(destination string, keys ...string) (val int, err err
|
||||
return
|
||||
}
|
||||
|
||||
// Sinter is the implementation of redis sinter command.
|
||||
func (s *Redis) Sinter(keys ...string) (val []string, err error) {
|
||||
err = s.brk.DoWithAcceptable(func() error {
|
||||
conn, err := getRedis(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
val, err = conn.SInter(keys...).Result()
|
||||
return err
|
||||
}, acceptable)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Sinterstore is the implementation of redis sinterstore command.
|
||||
func (s *Redis) Sinterstore(destination string, keys ...string) (val int, err error) {
|
||||
err = s.brk.DoWithAcceptable(func() error {
|
||||
conn, err := getRedis(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v, err := conn.SInterStore(destination, keys...).Result()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
val = int(v)
|
||||
return nil
|
||||
}, acceptable)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Ttl is the implementation of redis ttl command.
|
||||
func (s *Redis) Ttl(key string) (val int, err error) {
|
||||
err = s.brk.DoWithAcceptable(func() error {
|
||||
@@ -1412,7 +1447,7 @@ func (s *Redis) Zincrby(key string, increment int64, field string) (val int64, e
|
||||
}
|
||||
|
||||
// Zscore is the implementation of redis zscore command.
|
||||
func (s *Redis) Zscore(key string, value string) (val int64, err error) {
|
||||
func (s *Redis) Zscore(key, value string) (val int64, err error) {
|
||||
err = s.brk.DoWithAcceptable(func() error {
|
||||
conn, err := getRedis(s)
|
||||
if err != nil {
|
||||
@@ -1684,7 +1719,7 @@ func (s *Redis) ZrevrangebyscoreWithScoresAndLimit(key string, start, stop int64
|
||||
}
|
||||
|
||||
// Zrevrank is the implementation of redis zrevrank command.
|
||||
func (s *Redis) Zrevrank(key string, field string) (val int64, err error) {
|
||||
func (s *Redis) Zrevrank(key, field string) (val int64, err error) {
|
||||
err = s.brk.DoWithAcceptable(func() error {
|
||||
conn, err := getRedis(s)
|
||||
if err != nil {
|
||||
|
||||
@@ -638,6 +638,16 @@ func TestRedis_Set(t *testing.T) {
|
||||
num, err = client.Sdiffstore("key4", "key1", "key2")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 1, num)
|
||||
_, err = New(client.Addr, badType()).Sinter("key1", "key2")
|
||||
assert.NotNil(t, err)
|
||||
vals, err = client.Sinter("key1", "key2")
|
||||
assert.Nil(t, err)
|
||||
assert.ElementsMatch(t, []string{"2", "3", "4"}, vals)
|
||||
_, err = New(client.Addr, badType()).Sinterstore("key4", "key1", "key2")
|
||||
assert.NotNil(t, err)
|
||||
num, err = client.Sinterstore("key4", "key1", "key2")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 3, num)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,8 @@ type (
|
||||
}
|
||||
|
||||
statement struct {
|
||||
stmt *sql.Stmt
|
||||
query string
|
||||
stmt *sql.Stmt
|
||||
}
|
||||
|
||||
stmtConn interface {
|
||||
@@ -111,7 +112,8 @@ func (db *commonSqlConn) Prepare(query string) (stmt StmtSession, err error) {
|
||||
}
|
||||
|
||||
stmt = statement{
|
||||
stmt: st,
|
||||
query: query,
|
||||
stmt: st,
|
||||
}
|
||||
return nil
|
||||
}, db.acceptable)
|
||||
@@ -181,29 +183,29 @@ func (s statement) Close() error {
|
||||
}
|
||||
|
||||
func (s statement) Exec(args ...interface{}) (sql.Result, error) {
|
||||
return execStmt(s.stmt, args...)
|
||||
return execStmt(s.stmt, s.query, args...)
|
||||
}
|
||||
|
||||
func (s statement) QueryRow(v interface{}, args ...interface{}) error {
|
||||
return queryStmt(s.stmt, func(rows *sql.Rows) error {
|
||||
return unmarshalRow(v, rows, true)
|
||||
}, args...)
|
||||
}, s.query, args...)
|
||||
}
|
||||
|
||||
func (s statement) QueryRowPartial(v interface{}, args ...interface{}) error {
|
||||
return queryStmt(s.stmt, func(rows *sql.Rows) error {
|
||||
return unmarshalRow(v, rows, false)
|
||||
}, args...)
|
||||
}, s.query, args...)
|
||||
}
|
||||
|
||||
func (s statement) QueryRows(v interface{}, args ...interface{}) error {
|
||||
return queryStmt(s.stmt, func(rows *sql.Rows) error {
|
||||
return unmarshalRows(v, rows, true)
|
||||
}, args...)
|
||||
}, s.query, args...)
|
||||
}
|
||||
|
||||
func (s statement) QueryRowsPartial(v interface{}, args ...interface{}) error {
|
||||
return queryStmt(s.stmt, func(rows *sql.Rows) error {
|
||||
return unmarshalRows(v, rows, false)
|
||||
}, args...)
|
||||
}, s.query, args...)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package sqlx
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/tal-tech/go-zero/core/logx"
|
||||
@@ -12,10 +11,14 @@ import (
|
||||
const slowThreshold = time.Millisecond * 500
|
||||
|
||||
func exec(conn sessionConn, q string, args ...interface{}) (sql.Result, error) {
|
||||
stmt, err := format(q, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
startTime := timex.Now()
|
||||
result, err := conn.Exec(q, args...)
|
||||
duration := timex.Since(startTime)
|
||||
stmt := formatForPrint(q, args)
|
||||
if duration > slowThreshold {
|
||||
logx.WithDuration(duration).Slowf("[SQL] exec: slowcall - %s", stmt)
|
||||
} else {
|
||||
@@ -28,11 +31,15 @@ func exec(conn sessionConn, q string, args ...interface{}) (sql.Result, error) {
|
||||
return result, err
|
||||
}
|
||||
|
||||
func execStmt(conn stmtConn, args ...interface{}) (sql.Result, error) {
|
||||
func execStmt(conn stmtConn, q string, args ...interface{}) (sql.Result, error) {
|
||||
stmt, err := format(q, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
startTime := timex.Now()
|
||||
result, err := conn.Exec(args...)
|
||||
duration := timex.Since(startTime)
|
||||
stmt := fmt.Sprint(args...)
|
||||
if duration > slowThreshold {
|
||||
logx.WithDuration(duration).Slowf("[SQL] execStmt: slowcall - %s", stmt)
|
||||
} else {
|
||||
@@ -46,10 +53,14 @@ func execStmt(conn stmtConn, args ...interface{}) (sql.Result, error) {
|
||||
}
|
||||
|
||||
func query(conn sessionConn, scanner func(*sql.Rows) error, q string, args ...interface{}) error {
|
||||
stmt, err := format(q, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
startTime := timex.Now()
|
||||
rows, err := conn.Query(q, args...)
|
||||
duration := timex.Since(startTime)
|
||||
stmt := fmt.Sprint(args...)
|
||||
if duration > slowThreshold {
|
||||
logx.WithDuration(duration).Slowf("[SQL] query: slowcall - %s", stmt)
|
||||
} else {
|
||||
@@ -64,8 +75,12 @@ func query(conn sessionConn, scanner func(*sql.Rows) error, q string, args ...in
|
||||
return scanner(rows)
|
||||
}
|
||||
|
||||
func queryStmt(conn stmtConn, scanner func(*sql.Rows) error, args ...interface{}) error {
|
||||
stmt := fmt.Sprint(args...)
|
||||
func queryStmt(conn stmtConn, scanner func(*sql.Rows) error, q string, args ...interface{}) error {
|
||||
stmt, err := format(q, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
startTime := timex.Now()
|
||||
rows, err := conn.Query(args...)
|
||||
duration := timex.Since(startTime)
|
||||
|
||||
@@ -14,6 +14,7 @@ var errMockedPlaceholder = errors.New("placeholder")
|
||||
func TestStmt_exec(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
query string
|
||||
args []interface{}
|
||||
delay bool
|
||||
hasError bool
|
||||
@@ -23,18 +24,28 @@ func TestStmt_exec(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "normal",
|
||||
query: "select user from users where id=?",
|
||||
args: []interface{}{1},
|
||||
lastInsertId: 1,
|
||||
rowsAffected: 2,
|
||||
},
|
||||
{
|
||||
name: "exec error",
|
||||
query: "select user from users where id=?",
|
||||
args: []interface{}{1},
|
||||
hasError: true,
|
||||
err: errors.New("exec"),
|
||||
},
|
||||
{
|
||||
name: "exec more args error",
|
||||
query: "select user from users where id=? and name=?",
|
||||
args: []interface{}{1},
|
||||
hasError: true,
|
||||
err: errors.New("exec"),
|
||||
},
|
||||
{
|
||||
name: "slowcall",
|
||||
query: "select user from users where id=?",
|
||||
args: []interface{}{1},
|
||||
delay: true,
|
||||
lastInsertId: 1,
|
||||
@@ -51,7 +62,7 @@ func TestStmt_exec(t *testing.T) {
|
||||
rowsAffected: test.rowsAffected,
|
||||
err: test.err,
|
||||
delay: test.delay,
|
||||
}, "select user from users where id=?", args...)
|
||||
}, test.query, args...)
|
||||
},
|
||||
func(args ...interface{}) (sql.Result, error) {
|
||||
return execStmt(&mockedStmtConn{
|
||||
@@ -59,7 +70,7 @@ func TestStmt_exec(t *testing.T) {
|
||||
rowsAffected: test.rowsAffected,
|
||||
err: test.err,
|
||||
delay: test.delay,
|
||||
}, args...)
|
||||
}, test.query, args...)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -89,23 +100,34 @@ func TestStmt_exec(t *testing.T) {
|
||||
func TestStmt_query(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
query string
|
||||
args []interface{}
|
||||
delay bool
|
||||
hasError bool
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "normal",
|
||||
args: []interface{}{1},
|
||||
name: "normal",
|
||||
query: "select user from users where id=?",
|
||||
args: []interface{}{1},
|
||||
},
|
||||
{
|
||||
name: "query error",
|
||||
query: "select user from users where id=?",
|
||||
args: []interface{}{1},
|
||||
hasError: true,
|
||||
err: errors.New("exec"),
|
||||
},
|
||||
{
|
||||
name: "query more args error",
|
||||
query: "select user from users where id=? and name=?",
|
||||
args: []interface{}{1},
|
||||
hasError: true,
|
||||
err: errors.New("exec"),
|
||||
},
|
||||
{
|
||||
name: "slowcall",
|
||||
query: "select user from users where id=?",
|
||||
args: []interface{}{1},
|
||||
delay: true,
|
||||
},
|
||||
@@ -120,7 +142,7 @@ func TestStmt_query(t *testing.T) {
|
||||
delay: test.delay,
|
||||
}, func(rows *sql.Rows) error {
|
||||
return nil
|
||||
}, "select user from users where id=?", args...)
|
||||
}, test.query, args...)
|
||||
},
|
||||
func(args ...interface{}) error {
|
||||
return queryStmt(&mockedStmtConn{
|
||||
@@ -128,7 +150,7 @@ func TestStmt_query(t *testing.T) {
|
||||
delay: test.delay,
|
||||
}, func(rows *sql.Rows) error {
|
||||
return nil
|
||||
}, args...)
|
||||
}, test.query, args...)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -143,7 +165,7 @@ func TestStmt_query(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(t, errMockedPlaceholder, err)
|
||||
assert.NotNil(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,8 @@ func (t txSession) Prepare(q string) (StmtSession, error) {
|
||||
}
|
||||
|
||||
return statement{
|
||||
stmt: stmt,
|
||||
query: q,
|
||||
stmt: stmt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package sqlx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/tal-tech/go-zero/core/logx"
|
||||
@@ -45,24 +46,6 @@ func escape(input string) string {
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func formatForPrint(query string, args ...interface{}) string {
|
||||
if len(args) == 0 {
|
||||
return query
|
||||
}
|
||||
|
||||
var vals []string
|
||||
for _, arg := range args {
|
||||
vals = append(vals, fmt.Sprintf("%q", mapping.Repr(arg)))
|
||||
}
|
||||
|
||||
var b strings.Builder
|
||||
b.WriteByte('[')
|
||||
b.WriteString(strings.Join(vals, ", "))
|
||||
b.WriteByte(']')
|
||||
|
||||
return strings.Join([]string{query, b.String()}, " ")
|
||||
}
|
||||
|
||||
func format(query string, args ...interface{}) (string, error) {
|
||||
numArgs := len(args)
|
||||
if numArgs == 0 {
|
||||
@@ -70,38 +53,52 @@ func format(query string, args ...interface{}) (string, error) {
|
||||
}
|
||||
|
||||
var b strings.Builder
|
||||
argIndex := 0
|
||||
var argIndex int
|
||||
bytes := len(query)
|
||||
|
||||
for _, ch := range query {
|
||||
if ch == '?' {
|
||||
for i := 0; i < bytes; i++ {
|
||||
ch := query[i]
|
||||
switch ch {
|
||||
case '?':
|
||||
if argIndex >= numArgs {
|
||||
return "", fmt.Errorf("error: %d ? in sql, but less arguments provided", argIndex)
|
||||
}
|
||||
|
||||
arg := args[argIndex]
|
||||
writeValue(&b, args[argIndex])
|
||||
argIndex++
|
||||
|
||||
switch v := arg.(type) {
|
||||
case bool:
|
||||
if v {
|
||||
b.WriteByte('1')
|
||||
} else {
|
||||
b.WriteByte('0')
|
||||
case '$':
|
||||
var j int
|
||||
for j = i + 1; j < bytes; j++ {
|
||||
char := query[j]
|
||||
if char < '0' || '9' < char {
|
||||
break
|
||||
}
|
||||
case string:
|
||||
b.WriteByte('\'')
|
||||
b.WriteString(escape(v))
|
||||
b.WriteByte('\'')
|
||||
default:
|
||||
b.WriteString(mapping.Repr(v))
|
||||
}
|
||||
} else {
|
||||
b.WriteRune(ch)
|
||||
if j > i+1 {
|
||||
index, err := strconv.Atoi(query[i+1 : j])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// index starts from 1 for pg
|
||||
if index > argIndex {
|
||||
argIndex = index
|
||||
}
|
||||
index--
|
||||
if index < 0 || numArgs <= index {
|
||||
return "", fmt.Errorf("error: wrong index %d in sql", index)
|
||||
}
|
||||
|
||||
writeValue(&b, args[index])
|
||||
i = j - 1
|
||||
}
|
||||
default:
|
||||
b.WriteByte(ch)
|
||||
}
|
||||
}
|
||||
|
||||
if argIndex < numArgs {
|
||||
return "", fmt.Errorf("error: %d ? in sql, but more arguments provided", argIndex)
|
||||
return "", fmt.Errorf("error: %d arguments provided, not matching sql", argIndex)
|
||||
}
|
||||
|
||||
return b.String(), nil
|
||||
@@ -117,3 +114,20 @@ func logSqlError(stmt string, err error) {
|
||||
logx.Errorf("stmt: %s, error: %s", stmt, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func writeValue(buf *strings.Builder, arg interface{}) {
|
||||
switch v := arg.(type) {
|
||||
case bool:
|
||||
if v {
|
||||
buf.WriteByte('1')
|
||||
} else {
|
||||
buf.WriteByte('0')
|
||||
}
|
||||
case string:
|
||||
buf.WriteByte('\'')
|
||||
buf.WriteString(escape(v))
|
||||
buf.WriteByte('\'')
|
||||
default:
|
||||
buf.WriteString(mapping.Repr(v))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,30 +29,63 @@ func TestDesensitize_WithoutAccount(t *testing.T) {
|
||||
assert.True(t, strings.Contains(datasource, "tcp(111.222.333.44:3306)"))
|
||||
}
|
||||
|
||||
func TestFormatForPrint(t *testing.T) {
|
||||
func TestFormat(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
query string
|
||||
args []interface{}
|
||||
expect string
|
||||
hasErr bool
|
||||
}{
|
||||
{
|
||||
name: "no args",
|
||||
query: "select user, name from table where id=?",
|
||||
expect: `select user, name from table where id=?`,
|
||||
name: "mysql normal",
|
||||
query: "select name, age from users where bool=? and phone=?",
|
||||
args: []interface{}{true, "133"},
|
||||
expect: "select name, age from users where bool=1 and phone='133'",
|
||||
},
|
||||
{
|
||||
name: "one arg",
|
||||
query: "select user, name from table where id=?",
|
||||
args: []interface{}{"kevin"},
|
||||
expect: `select user, name from table where id=? ["kevin"]`,
|
||||
name: "mysql normal",
|
||||
query: "select name, age from users where bool=? and phone=?",
|
||||
args: []interface{}{false, "133"},
|
||||
expect: "select name, age from users where bool=0 and phone='133'",
|
||||
},
|
||||
{
|
||||
name: "pg normal",
|
||||
query: "select name, age from users where bool=$1 and phone=$2",
|
||||
args: []interface{}{true, "133"},
|
||||
expect: "select name, age from users where bool=1 and phone='133'",
|
||||
},
|
||||
{
|
||||
name: "pg normal reverse",
|
||||
query: "select name, age from users where bool=$2 and phone=$1",
|
||||
args: []interface{}{"133", false},
|
||||
expect: "select name, age from users where bool=0 and phone='133'",
|
||||
},
|
||||
{
|
||||
name: "pg error not number",
|
||||
query: "select name, age from users where bool=$a and phone=$1",
|
||||
args: []interface{}{"133", false},
|
||||
hasErr: true,
|
||||
},
|
||||
{
|
||||
name: "pg error more args",
|
||||
query: "select name, age from users where bool=$2 and phone=$1 and nickname=$3",
|
||||
args: []interface{}{"133", false},
|
||||
hasErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
actual := formatForPrint(test.query, test.args...)
|
||||
assert.Equal(t, test.expect, actual)
|
||||
t.Parallel()
|
||||
|
||||
actual, err := format(test.query, test.args...)
|
||||
if test.hasErr {
|
||||
assert.NotNil(t, err)
|
||||
} else {
|
||||
assert.Equal(t, test.expect, actual)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ func Reverse(s string) string {
|
||||
}
|
||||
|
||||
// Substr returns runes between start and stop [start, stop) regardless of the chars are ascii or utf8.
|
||||
func Substr(str string, start int, stop int) (string, error) {
|
||||
func Substr(str string, start, stop int) (string, error) {
|
||||
rs := []rune(str)
|
||||
length := len(rs)
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ func NewManagedResource(generate func() interface{}, equals func(a, b interface{
|
||||
}
|
||||
}
|
||||
|
||||
// MarkBroken marks the resouce broken.
|
||||
// MarkBroken marks the resource broken.
|
||||
func (mr *ManagedResource) MarkBroken(resource interface{}) {
|
||||
mr.lock.Lock()
|
||||
defer mr.lock.Unlock()
|
||||
|
||||
@@ -2,7 +2,7 @@ package syncx
|
||||
|
||||
import "sync"
|
||||
|
||||
// Once returns a func that guanartees fn can only called once.
|
||||
// Once returns a func that guarantees fn can only called once.
|
||||
func Once(fn func()) func() {
|
||||
once := new(sync.Once)
|
||||
return func() {
|
||||
|
||||
@@ -2,7 +2,7 @@ package syncx
|
||||
|
||||
import "sync/atomic"
|
||||
|
||||
// A OnceGuard is used to make sure a resouce can be taken once.
|
||||
// A OnceGuard is used to make sure a resource can be taken once.
|
||||
type OnceGuard struct {
|
||||
done uint32
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ type (
|
||||
|
||||
// A Pool is used to pool resources.
|
||||
// The difference between sync.Pool is that:
|
||||
// 1. the limit of the resouces
|
||||
// 1. the limit of the resources
|
||||
// 2. max age of the resources can be set
|
||||
// 3. the method to destroy resources can be customized
|
||||
Pool struct {
|
||||
@@ -56,7 +56,7 @@ func NewPool(n int, create func() interface{}, destroy func(interface{}), opts .
|
||||
return pool
|
||||
}
|
||||
|
||||
// Get gets a resouce.
|
||||
// Get gets a resource.
|
||||
func (p *Pool) Get() interface{} {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
// ErrUseOfCleaned is an error that indicates using a cleaned resource.
|
||||
var ErrUseOfCleaned = errors.New("using a cleaned resource")
|
||||
|
||||
// A RefResource is used to reference counting a resouce.
|
||||
// A RefResource is used to reference counting a resource.
|
||||
type RefResource struct {
|
||||
lock sync.Mutex
|
||||
ref int32
|
||||
|
||||
42
go.mod
42
go.mod
@@ -16,48 +16,36 @@ require (
|
||||
github.com/go-redis/redis v6.15.7+incompatible
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/go-xorm/builder v0.3.4
|
||||
github.com/gogo/protobuf v1.3.1 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
|
||||
github.com/golang/mock v1.4.3
|
||||
github.com/golang/protobuf v1.4.2
|
||||
github.com/google/uuid v1.1.1
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.14.3 // indirect
|
||||
github.com/golang/protobuf v1.5.2
|
||||
github.com/google/uuid v1.1.2
|
||||
github.com/iancoleman/strcase v0.1.2
|
||||
github.com/justinas/alice v1.2.0
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
||||
github.com/kr/pretty v0.2.0 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/lib/pq v1.3.0
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible
|
||||
github.com/mattn/go-colorable v0.1.6 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.4
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/onsi/ginkgo v1.7.0 // indirect
|
||||
github.com/onsi/gomega v1.5.0 // indirect
|
||||
github.com/pierrec/lz4 v2.5.1+incompatible // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/prometheus/client_golang v1.5.1
|
||||
github.com/prometheus/client_golang v1.11.0
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0
|
||||
github.com/stretchr/testify v1.5.1
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6 // indirect
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/urfave/cli v1.22.5
|
||||
github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2
|
||||
github.com/zeromicro/antlr v0.0.1 // indirect
|
||||
go.etcd.io/etcd v0.0.0-20200402134248-51bdeb39e698
|
||||
github.com/zeromicro/antlr v0.0.1
|
||||
github.com/zeromicro/ddl-parser v0.0.0-20210712021150-63520aca7348 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.0
|
||||
go.etcd.io/etcd/client/v3 v3.5.0
|
||||
go.uber.org/automaxprocs v1.3.0
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381
|
||||
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1 // indirect
|
||||
golang.org/x/text v0.3.3 // indirect
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0
|
||||
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 // indirect
|
||||
golang.org/x/net v0.0.0-20210716203947-853a461950ff
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
|
||||
google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f // indirect
|
||||
google.golang.org/grpc v1.39.0
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.28
|
||||
gopkg.in/h2non/gock.v1 v1.0.15
|
||||
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
|
||||
)
|
||||
|
||||
308
go.sum
308
go.sum
@@ -1,30 +1,28 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/ClickHouse/clickhouse-go v1.4.3 h1:iAFMa2UrQdR5bHJ2/yaSLffZkxpcOYQMCUuKeNXGdqc=
|
||||
github.com/ClickHouse/clickhouse-go v1.4.3/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
|
||||
github.com/DATA-DOG/go-sqlmock v1.4.1 h1:ThlnYciV1iM/V0OSF/dtkqWb6xo5qITT1TJBG1MRDJM=
|
||||
github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk=
|
||||
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
|
||||
github.com/alicebob/miniredis/v2 v2.14.1 h1:GjlbSeoJ24bzdLRs13HoMEeaRZx9kg5nHoRW7QV/nCs=
|
||||
github.com/alicebob/miniredis/v2 v2.14.1/go.mod h1:uS970Sw5Gs9/iK3yBg0l9Uj9s25wXxSpQUE9EaJ/Blg=
|
||||
github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
|
||||
github.com/antlr/antlr4 v0.0.0-20210105212045-464bcbc32de2 h1:rL2miklL5rhxUaZO7hntBcy/VHaiyuPQ4EJoy/NMwaM=
|
||||
github.com/antlr/antlr4 v0.0.0-20210105212045-464bcbc32de2/go.mod h1:T7PbCXFs94rrTttyxjbyT5+/1V8T2TYDejxUfHJjw1Y=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521184019-c5ad59b459ec h1:EEyRvzmpEUZ+I8WmD5cw/vY8EqhambkOqy5iFr0908A=
|
||||
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521184019-c5ad59b459ec/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bkaradzic/go-lz4 v1.0.0 h1:RXc4wYsyz985CkXXeX04y4VnZFGG8Rd43pRaHsOXAKk=
|
||||
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
@@ -35,31 +33,31 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
|
||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 h1:F1EaeKL/ta07PY/k9Os/UFtwERei2/XzGemhpGnBKNg=
|
||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||
github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd/v22 v22.0.0 h1:XJIw/+VlJ+87J+doOxznsAWIdmWuViOVhkQamW5YV28=
|
||||
github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4 h1:qk/FSDDxo05wdJH28W+p5yivv7LuLYLRXPPD8KQCtZs=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/dustin/go-humanize v1.0.0/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=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
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=
|
||||
@@ -73,137 +71,111 @@ github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7a
|
||||
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-redis/redis v6.15.7+incompatible h1:3skhDh95XQMpnqeqNftPkQD9jL9e5e36z/1SUm6dy1U=
|
||||
github.com/go-redis/redis v6.15.7+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-xorm/builder v0.3.4 h1:FxkeGB4Cggdw3tPwutLCpfjng2jugfkg6LDMrd/KsoY=
|
||||
github.com/go-xorm/builder v0.3.4/go.mod h1:KxkQkNN1DpPKTedxXyTQcmH+rXfvk4LZ9SOOBoZBAxw=
|
||||
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y=
|
||||
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
|
||||
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 h1:z53tR0945TRRQO/fLEVPI6SMv7ZflF0TEaTAoU7tOzg=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
|
||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.14.3 h1:OCJlWkOUoTnl0neNGlf4fUm3TmbEtguw7vR+nGtnDjY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.14.3/go.mod h1:6CwZWGDSPRJidgKAtJVvND6soZe6fT7iteq8wDPdhb0=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
|
||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
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=
|
||||
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo=
|
||||
github.com/justinas/alice v1.2.0/go.mod h1:fN5HRH/reO/zrUflLfTN43t3vXvKzvZIENsNEe7i7qA=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
|
||||
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4=
|
||||
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
||||
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
|
||||
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
@@ -213,7 +185,6 @@ github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi
|
||||
github.com/pierrec/lz4 v2.5.1+incompatible h1:Yq0up0149Hh5Ekhm/91lgkZuD1ZDnXNM26bycpTzYBM=
|
||||
github.com/pierrec/lz4 v2.5.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
@@ -221,125 +192,119 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.5.1 h1:bdHYieyGlH+6OLEk2YQha8THib30KP0/yD0YH9m6xcA=
|
||||
github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ=
|
||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U=
|
||||
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8=
|
||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/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/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4=
|
||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6 h1:lYIiVDtZnyTWlNwiAxLj0bbpTcx1BWCFhXjfsvmPdNc=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
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=
|
||||
github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2 h1:zzrxE1FKn5ryBNl9eKOeqQ58Y/Qpo3Q9QNxKHX5uzzQ=
|
||||
github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2/go.mod h1:hzfGeIUDq/j97IG+FhNqkowIyEcD88LrW6fyU3K3WqY=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb h1:ZkM6LRnq40pR1Ox0hTHlnpkcOTuFIDQpZ1IN8rKKhX0=
|
||||
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
|
||||
github.com/zeromicro/antlr v0.0.0-20210508120604-8d7a7786f5c4 h1:wt86gT5lsN+xWmij6lFCrDIqoxeOnqM2MxiO7cNm+Lo=
|
||||
github.com/zeromicro/antlr v0.0.0-20210508120604-8d7a7786f5c4/go.mod h1:nfpjEwFR6Q4xGDJMcZnCL9tEfQRgszMwu3rDz2Z+p5M=
|
||||
github.com/zeromicro/antlr v0.0.1 h1:CQpIn/dc0pUjgGQ81y98s/NGOm2Hfru2NNio2I9mQgk=
|
||||
github.com/zeromicro/antlr v0.0.1/go.mod h1:nfpjEwFR6Q4xGDJMcZnCL9tEfQRgszMwu3rDz2Z+p5M=
|
||||
go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
|
||||
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||
go.etcd.io/etcd v0.0.0-20200402134248-51bdeb39e698 h1:jWtjCJX1qxhHISBMLRztWwR+EXkI7MJAF2HjHAE/x/I=
|
||||
go.etcd.io/etcd v0.0.0-20200402134248-51bdeb39e698/go.mod h1:YoUyTScD3Vcv2RBm3eGVOq7i1ULiz3OuXoQFWOirmAM=
|
||||
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
github.com/zeromicro/ddl-parser v0.0.0-20210710132903-bc9dbb9789b1 h1:zItUIfobEHTYD9X0fAt9QWEWIFWDa8CypF+Z62zIR+M=
|
||||
github.com/zeromicro/ddl-parser v0.0.0-20210710132903-bc9dbb9789b1/go.mod h1:ISU/8NuPyEpl9pa17Py9TBPetMjtsiHrb9f5XGiYbo8=
|
||||
github.com/zeromicro/ddl-parser v0.0.0-20210712021150-63520aca7348 h1:OhxL9tn28gDeJVzreIUiE5oVxZCjL3tBJ0XBNw8p5R8=
|
||||
github.com/zeromicro/ddl-parser v0.0.0-20210712021150-63520aca7348/go.mod h1:ISU/8NuPyEpl9pa17Py9TBPetMjtsiHrb9f5XGiYbo8=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0 h1:GsV3S+OfZEOCNXdtNkBSR7kgLobAa/SO6tCxRa0GAYw=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.0 h1:2aQv6F436YnN7I4VbI8PPYrBhu+SmrTaADcf8Mi/6PU=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||
go.etcd.io/etcd/client/v3 v3.5.0 h1:62Eh0XOro+rDwkrypAGDfgmNh5Joq+z+W9HZdlXMzek=
|
||||
go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/automaxprocs v1.3.0 h1:II28aZoGdaglS5vVNnspf28lnZpXScxtIozx1lAjdb0=
|
||||
go.uber.org/automaxprocs v1.3.0/go.mod h1:9CWT6lKIep8U41DDaPiH6eFscnTyjfTANNQNx6LrIcA=
|
||||
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo=
|
||||
go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210716203947-853a461950ff h1:j2EK/QoxYNBsXI4R7fQkkRUk8y6wnOBI+6hgPdP/6Ds=
|
||||
golang.org/x/net v0.0.0-20210716203947-853a461950ff/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -347,80 +312,94 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1 h1:sIky/MyNRSHTrdxfsiUSS4WIAMvInbeXljJz+jDjeYE=
|
||||
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200410132612-ae9902aceb98 h1:ibc1eDGW5ajwA4qzFTj0WHlD9eofMe1gAre+A0a3Vhs=
|
||||
golang.org/x/tools v0.0.0-20200410132612-ae9902aceb98/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f h1:ohwtWcCwB/fZUxh/vjazHorYmBnua3NmY3CAjwC7mEA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced h1:c5geK1iMU3cDKtFrCVQIcjR3W+JOZMuhIyICMCTbtus=
|
||||
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
|
||||
google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f h1:YORWxaStkWBnWgELOHTmDrqNlFXuVGEbhwbB5iK94bQ=
|
||||
google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.39.0 h1:Klz8I9kdtkIN6EpHHUOMLCYhTn/2WAe5a0s1hcBkdTI=
|
||||
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
@@ -428,30 +407,23 @@ gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/h2non/gock.v1 v1.0.15 h1:SzLqcIlb/fDfg7UvukMpNcWsu7sI5tWwL+KCATZqks0=
|
||||
gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
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/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=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
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=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
|
||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||
|
||||
38
readme-cn.md
38
readme-cn.md
@@ -26,7 +26,7 @@ go-zero 包含极简的 API 定义和生成工具 goctl,可以根据定义的
|
||||
* 自动校验客户端请求参数合法性
|
||||
* 大量微服务治理和并发工具包
|
||||
|
||||
<img src="https://gitee.com/kevwan/static/raw/master/doc/images/architecture.png" alt="架构图" width="1500" />
|
||||

|
||||
|
||||
## 1. go-zero 框架背景
|
||||
|
||||
@@ -78,7 +78,7 @@ go-zero 是一个集成了各种工程实践的包含 web 和 rpc 框架,有
|
||||
|
||||
如下图,我们从多个层面保障了整体服务的高可用:
|
||||
|
||||

|
||||

|
||||
|
||||
觉得不错的话,别忘 **star** 👏
|
||||
|
||||
@@ -151,7 +151,7 @@ GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/tal-tech/
|
||||
|
||||
## 6. Benchmark
|
||||
|
||||

|
||||

|
||||
|
||||
[测试代码见这里](https://github.com/smallnest/go-web-framework-benchmark)
|
||||
|
||||
@@ -159,19 +159,10 @@ GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/tal-tech/
|
||||
|
||||
* API 文档
|
||||
|
||||
[https://go-zero.dev/zh-hans/](https://zeromicro.github.io/go-zero)
|
||||
|
||||
* 常见问题
|
||||
|
||||
* 因为 `etcd` 和 `grpc` 兼容性问题,请使用 `grpc@v1.29.1`
|
||||
|
||||
`google.golang.org/grpc v1.29.1`
|
||||
|
||||
* 因为 `protobuf` 兼容性问题,请使用 `protocol-gen@v1.3.2`
|
||||
|
||||
`go get -u github.com/golang/protobuf/protoc-gen-go@v1.3.2`
|
||||
[https://go-zero.dev/cn/](https://go-zero.dev/cn/)
|
||||
|
||||
* awesome 系列(更多文章见『微服务实践』公众号)
|
||||
|
||||
* [快速构建高并发微服务](https://github.com/tal-tech/zero-doc/blob/main/doc/shorturl.md)
|
||||
* [快速构建高并发微服务 - 多 RPC 版](https://github.com/tal-tech/zero-doc/blob/main/docs/zero/bookstore.md)
|
||||
* [goctl 使用帮助](https://github.com/tal-tech/zero-doc/blob/main/doc/goctl.md)
|
||||
@@ -208,6 +199,23 @@ go-zero 已被许多公司用于生产部署,接入场景如在线教育、电
|
||||
>17. 三七游戏
|
||||
>18. 成都创道夫科技有限公司
|
||||
>19. 联想Lenovo
|
||||
>20. 云犀
|
||||
>21. 高盈国际
|
||||
>22. 北京中科生活服务有限公司
|
||||
>23. Indochat 印尼艾希英
|
||||
>24. 数赞
|
||||
>25. 量冠科技
|
||||
>26. 杭州又拍云科技有限公司
|
||||
>27. 深圳市点购电子商务控股股份有限公司
|
||||
>28. 深圳市宁克沃德科技有限公司
|
||||
>29. 桂林优利特医疗电子有限公司
|
||||
>30. 成都智橙互动科技有限公司
|
||||
>31. 深圳市班班科技有限公司
|
||||
>32. 飞视(苏州)数字技术有限公司
|
||||
>33. 上海鲸思智能科技有限公司
|
||||
>34. 南宁宸升计算机科技有限公司
|
||||
>35. 秦皇岛2084team
|
||||
>36. 天翼云股份有限公司
|
||||
|
||||
如果贵公司也已使用 go-zero,欢迎在 [登记地址](https://github.com/tal-tech/go-zero/issues/602) 登记,仅仅为了推广,不做其它用途。
|
||||
|
||||
@@ -215,7 +223,7 @@ go-zero 已被许多公司用于生产部署,接入场景如在线教育、电
|
||||
|
||||
`go-zero` 相关文章和视频都会在 `微服务实践` 公众号整理呈现,欢迎扫码关注 👏
|
||||
|
||||
<img src="https://gitee.com/kevwan/static/raw/master/images/wechat-micro.jpg" alt="wechat" width="300" />
|
||||
<img src="https://raw.githubusercontent.com/tal-tech/zero-doc/main/doc/images/wechat-micro.jpg" alt="wechat" width="300" />
|
||||
|
||||
## 10. 微信交流群
|
||||
|
||||
|
||||
19
readme.md
19
readme.md
@@ -97,7 +97,7 @@ go get -u github.com/tal-tech/go-zero
|
||||
|
||||
[Rapid development of microservice systems](https://github.com/tal-tech/zero-doc/blob/main/doc/shorturl-en.md)
|
||||
|
||||
[Rapid development of microservice systems - multiple RPCs](https://github.com/tal-tech/zero-doc/blob/main/doc/bookstore-en.md)
|
||||
[Rapid development of microservice systems - multiple RPCs](https://github.com/tal-tech/zero-doc/blob/main/docs/zero/bookstore-en.md)
|
||||
|
||||
1. install goctl
|
||||
|
||||
@@ -200,31 +200,20 @@ go get -u github.com/tal-tech/go-zero
|
||||
|
||||
## 7. Benchmark
|
||||
|
||||
Document: [https://go-zero.dev/en/](https://go-zero.dev/en/)
|
||||
|
||||

|
||||
|
||||
[Checkout the test code](https://github.com/smallnest/go-web-framework-benchmark)
|
||||
|
||||
## 8. Documents (adding)
|
||||
|
||||
* [Documents](https://go-zero.dev/en/)
|
||||
* [Rapid development of microservice systems](https://github.com/tal-tech/zero-doc/blob/main/doc/shorturl-en.md)
|
||||
* [Rapid development of microservice systems - multiple RPCs](https://github.com/tal-tech/zero-doc/blob/main/docs/zero/bookstore-en.md)
|
||||
* [Examples](https://github.com/zeromicro/zero-examples)
|
||||
|
||||
## 9. Important notes
|
||||
## 9. Chat group
|
||||
|
||||
* Use grpc 1.29.1, because etcd lib doesn’t support latter versions.
|
||||
|
||||
`google.golang.org/grpc v1.29.1`
|
||||
|
||||
* For protobuf compatibility, use `protocol-gen@v1.3.2`.
|
||||
|
||||
` go get -u github.com/golang/protobuf/protoc-gen-go@v1.3.2`
|
||||
|
||||
## 10. Chat group
|
||||
|
||||
Join the chat via https://join.slack.com/t/go-zeroworkspace/shared_invite/zt-m39xssxc-kgIqERa7aVsujKNj~XuPKg
|
||||
Join the chat via https://join.slack.com/t/go-zero/shared_invite/zt-thyennhc-_fNXFpeUJcGE_tQNZFpsdA
|
||||
|
||||
## Give a Star! ⭐
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@ type mockedRouter struct{}
|
||||
func (m mockedRouter) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
||||
}
|
||||
|
||||
func (m mockedRouter) Handle(method string, path string, handler http.Handler) error {
|
||||
func (m mockedRouter) Handle(method, path string, handler http.Handler) error {
|
||||
return errors.New("foo")
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
const (
|
||||
formKey = "form"
|
||||
pathKey = "path"
|
||||
headerKey = "header"
|
||||
emptyJson = "{}"
|
||||
maxMemory = 32 << 20 // 32MB
|
||||
maxBodyLen = 8 << 20 // 8MB
|
||||
@@ -20,8 +21,9 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
formUnmarshaler = mapping.NewUnmarshaler(formKey, mapping.WithStringValues())
|
||||
pathUnmarshaler = mapping.NewUnmarshaler(pathKey, mapping.WithStringValues())
|
||||
formUnmarshaler = mapping.NewUnmarshaler(formKey, mapping.WithStringValues())
|
||||
pathUnmarshaler = mapping.NewUnmarshaler(pathKey, mapping.WithStringValues())
|
||||
headerUnmarshaler = mapping.NewUnmarshaler(headerKey, mapping.WithStringValues())
|
||||
)
|
||||
|
||||
// Parse parses the request.
|
||||
@@ -34,9 +36,28 @@ func Parse(r *http.Request, v interface{}) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ParseHeaders(r, v); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ParseJsonBody(r, v)
|
||||
}
|
||||
|
||||
// ParseHeaders parses the headers request.
|
||||
func ParseHeaders(r *http.Request, v interface{}) error {
|
||||
m := map[string]interface{}{}
|
||||
for k, v := range r.Header {
|
||||
k = strings.ToLower(k)
|
||||
if len(v) == 1 {
|
||||
m[k] = v[0]
|
||||
} else {
|
||||
m[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return headerUnmarshaler.Unmarshal(m, v)
|
||||
}
|
||||
|
||||
// ParseForm parses the form request.
|
||||
func ParseForm(r *http.Request, v interface{}) error {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
|
||||
@@ -201,3 +201,26 @@ func BenchmarkParseAuto(b *testing.B) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseHeaders(t *testing.T) {
|
||||
v := struct {
|
||||
Name string `header:"name"`
|
||||
Percent string `header:"percent"`
|
||||
Addrs []string `header:"addrs"`
|
||||
}{}
|
||||
request, err := http.NewRequest("POST", "http://hello.com/", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
request.Header.Set("name", "chenquan")
|
||||
request.Header.Set("percent", "1")
|
||||
request.Header.Add("addrs", "addr1")
|
||||
request.Header.Add("addrs", "addr2")
|
||||
err = ParseHeaders(request, &v)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, "chenquan", v.Name)
|
||||
assert.Equal(t, "1", v.Percent)
|
||||
assert.Equal(t, []string{"addr1", "addr2"}, v.Addrs)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import "net/http"
|
||||
// Router interface represents a http router that handles http requests.
|
||||
type Router interface {
|
||||
http.Handler
|
||||
Handle(method string, path string, handler http.Handler) error
|
||||
Handle(method, path string, handler http.Handler) error
|
||||
SetNotFoundHandler(handler http.Handler)
|
||||
SetNotAllowedHandler(handler http.Handler)
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ func StartHttps(host string, port int, certFile, keyFile string, handler http.Ha
|
||||
})
|
||||
}
|
||||
|
||||
func start(host string, port int, handler http.Handler, run func(srv *http.Server) error) error {
|
||||
func start(host string, port int, handler http.Handler, run func(srv *http.Server) error) (err error) {
|
||||
server := &http.Server{
|
||||
Addr: fmt.Sprintf("%s:%d", host, port),
|
||||
Handler: handler,
|
||||
@@ -31,7 +31,11 @@ func start(host string, port int, handler http.Handler, run func(srv *http.Serve
|
||||
waitForCalled := proc.AddWrapUpListener(func() {
|
||||
server.Shutdown(context.Background())
|
||||
})
|
||||
defer waitForCalled()
|
||||
defer func() {
|
||||
if err == http.ErrServerClosed {
|
||||
waitForCalled()
|
||||
}
|
||||
}()
|
||||
|
||||
return run(server)
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ const (
|
||||
`
|
||||
)
|
||||
|
||||
func genDoc(api *spec.ApiSpec, dir string, filename string) error {
|
||||
func genDoc(api *spec.ApiSpec, dir, filename string) error {
|
||||
fp, _, err := util.MaybeCreateFile(dir, "", filename)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -86,12 +86,17 @@ func ApiFormatByPath(apiFilePath string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
result, err := apiFormat(string(data))
|
||||
abs, err := filepath.Abs(apiFilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = parser.ParseContent(result)
|
||||
result, err := apiFormat(string(data), abs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = parser.ParseContent(result, abs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -99,8 +104,8 @@ func ApiFormatByPath(apiFilePath string) error {
|
||||
return ioutil.WriteFile(apiFilePath, []byte(result), os.ModePerm)
|
||||
}
|
||||
|
||||
func apiFormat(data string) (string, error) {
|
||||
_, err := parser.ParseContent(data)
|
||||
func apiFormat(data string, filename ...string) (string, error) {
|
||||
_, err := parser.ParseContent(data, filename...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -30,7 +30,11 @@ func GoCommand(c *cli.Context) error {
|
||||
apiFile := c.String("api")
|
||||
dir := c.String("dir")
|
||||
namingStyle := c.String("style")
|
||||
home := c.String("home")
|
||||
|
||||
if len(home) > 0 {
|
||||
util.RegisterGoctlHome(home)
|
||||
}
|
||||
if len(apiFile) == 0 {
|
||||
return errors.New("missing -api")
|
||||
}
|
||||
@@ -54,14 +58,19 @@ func DoGenProject(apiFile, dir, style string) error {
|
||||
}
|
||||
|
||||
logx.Must(util.MkdirIfNotExist(dir))
|
||||
rootPkg, err := getParentPackage(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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(genMain(dir, rootPkg, cfg, api))
|
||||
logx.Must(genServiceContext(dir, rootPkg, 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(genRoutes(dir, rootPkg, cfg, api))
|
||||
logx.Must(genHandlers(dir, rootPkg, cfg, api))
|
||||
logx.Must(genLogic(dir, rootPkg, cfg, api))
|
||||
logx.Must(genMiddleware(dir, cfg, api))
|
||||
|
||||
if err := backupAndSweep(apiFile); err != nil {
|
||||
|
||||
@@ -49,18 +49,14 @@ type handlerInfo struct {
|
||||
HasRequest bool
|
||||
}
|
||||
|
||||
func genHandler(dir string, cfg *config.Config, group spec.Group, route spec.Route) error {
|
||||
func genHandler(dir, rootPkg string, cfg *config.Config, group spec.Group, route spec.Route) error {
|
||||
handler := getHandlerName(route)
|
||||
if getHandlerFolderPath(group, route) != handlerDir {
|
||||
handler = strings.Title(handler)
|
||||
}
|
||||
parentPkg, err := getParentPackage(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return doGenToFile(dir, handler, cfg, group, route, handlerInfo{
|
||||
ImportPackages: genHandlerImports(group, route, parentPkg),
|
||||
ImportPackages: genHandlerImports(group, route, rootPkg),
|
||||
HandlerName: handler,
|
||||
RequestType: util.Title(route.RequestTypeName()),
|
||||
LogicType: strings.Title(getLogicName(route)),
|
||||
@@ -89,10 +85,10 @@ func doGenToFile(dir, handler string, cfg *config.Config, group spec.Group,
|
||||
})
|
||||
}
|
||||
|
||||
func genHandlers(dir string, cfg *config.Config, api *spec.ApiSpec) error {
|
||||
func genHandlers(dir, rootPkg string, cfg *config.Config, api *spec.ApiSpec) error {
|
||||
for _, group := range api.Service.Groups {
|
||||
for _, route := range group.Routes {
|
||||
if err := genHandler(dir, cfg, group, route); err != nil {
|
||||
if err := genHandler(dir, rootPkg, cfg, group, route); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,10 +39,10 @@ func (l *{{.logic}}) {{.function}}({{.request}}) {{.responseType}} {
|
||||
}
|
||||
`
|
||||
|
||||
func genLogic(dir string, cfg *config.Config, api *spec.ApiSpec) error {
|
||||
func genLogic(dir, rootPkg string, cfg *config.Config, api *spec.ApiSpec) error {
|
||||
for _, g := range api.Service.Groups {
|
||||
for _, r := range g.Routes {
|
||||
err := genLogicByRoute(dir, cfg, g, r)
|
||||
err := genLogicByRoute(dir, rootPkg, cfg, g, r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -51,19 +51,14 @@ func genLogic(dir string, cfg *config.Config, api *spec.ApiSpec) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func genLogicByRoute(dir string, cfg *config.Config, group spec.Group, route spec.Route) error {
|
||||
func genLogicByRoute(dir, rootPkg 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
|
||||
}
|
||||
|
||||
parentPkg, err := getParentPackage(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
imports := genLogicImports(route, parentPkg)
|
||||
imports := genLogicImports(route, rootPkg)
|
||||
var responseString string
|
||||
var returnString string
|
||||
var requestString string
|
||||
|
||||
@@ -39,7 +39,7 @@ func main() {
|
||||
}
|
||||
`
|
||||
|
||||
func genMain(dir string, cfg *config.Config, api *spec.ApiSpec) error {
|
||||
func genMain(dir, rootPkg string, cfg *config.Config, api *spec.ApiSpec) error {
|
||||
name := strings.ToLower(api.Service.Name)
|
||||
if strings.HasSuffix(name, "-api") {
|
||||
name = strings.ReplaceAll(name, "-api", "")
|
||||
@@ -49,11 +49,6 @@ func genMain(dir string, cfg *config.Config, api *spec.ApiSpec) error {
|
||||
return err
|
||||
}
|
||||
|
||||
parentPkg, err := getParentPackage(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return genFile(fileGenConfig{
|
||||
dir: dir,
|
||||
subdir: "",
|
||||
@@ -63,7 +58,7 @@ func genMain(dir string, cfg *config.Config, api *spec.ApiSpec) error {
|
||||
templateFile: mainTemplateFile,
|
||||
builtinTemplate: mainTemplate,
|
||||
data: map[string]string{
|
||||
"importPackages": genMainImports(parentPkg),
|
||||
"importPackages": genMainImports(rootPkg),
|
||||
"serviceName": api.Service.Name,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -62,7 +62,7 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
func genRoutes(dir string, cfg *config.Config, api *spec.ApiSpec) error {
|
||||
func genRoutes(dir, rootPkg string, cfg *config.Config, api *spec.ApiSpec) error {
|
||||
var builder strings.Builder
|
||||
groups, err := getRoutes(api)
|
||||
if err != nil {
|
||||
@@ -116,11 +116,6 @@ func genRoutes(dir string, cfg *config.Config, api *spec.ApiSpec) error {
|
||||
}
|
||||
}
|
||||
|
||||
parentPkg, err := getParentPackage(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
routeFilename, err := format.FileNamingFormat(cfg.NamingFormat, routesFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -139,7 +134,7 @@ func genRoutes(dir string, cfg *config.Config, api *spec.ApiSpec) error {
|
||||
templateFile: "",
|
||||
builtinTemplate: routesTemplate,
|
||||
data: map[string]string{
|
||||
"importPackages": genRouteImports(parentPkg, api),
|
||||
"importPackages": genRouteImports(rootPkg, api),
|
||||
"routesAdditions": strings.TrimSpace(builder.String()),
|
||||
},
|
||||
})
|
||||
|
||||
@@ -33,7 +33,7 @@ func NewServiceContext(c {{.config}}) *ServiceContext {
|
||||
`
|
||||
)
|
||||
|
||||
func genServiceContext(dir string, cfg *config.Config, api *spec.ApiSpec) error {
|
||||
func genServiceContext(dir, rootPkg string, cfg *config.Config, api *spec.ApiSpec) error {
|
||||
filename, err := format.FileNamingFormat(cfg.NamingFormat, contextFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -45,11 +45,6 @@ func genServiceContext(dir string, cfg *config.Config, api *spec.ApiSpec) error
|
||||
auths = append(auths, fmt.Sprintf("%s config.AuthConfig", item))
|
||||
}
|
||||
|
||||
parentPkg, err := getParentPackage(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var middlewareStr string
|
||||
var middlewareAssignment string
|
||||
middlewares := getMiddleware(api)
|
||||
@@ -61,9 +56,9 @@ func genServiceContext(dir string, cfg *config.Config, api *spec.ApiSpec) error
|
||||
fmt.Sprintf("middleware.New%s().%s", strings.Title(name), "Handle"))
|
||||
}
|
||||
|
||||
configImport := "\"" + ctlutil.JoinPackages(parentPkg, configDir) + "\""
|
||||
configImport := "\"" + ctlutil.JoinPackages(rootPkg, configDir) + "\""
|
||||
if len(middlewareStr) > 0 {
|
||||
configImport += "\n\t\"" + ctlutil.JoinPackages(parentPkg, middlewareDir) + "\""
|
||||
configImport += "\n\t\"" + ctlutil.JoinPackages(rootPkg, middlewareDir) + "\""
|
||||
configImport += fmt.Sprintf("\n\t\"%s/rest\"", vars.ProjectOpenSourceURL)
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ func (v *ApiVisitor) VisitApi(ctx *api.ApiContext) interface{} {
|
||||
return &final
|
||||
}
|
||||
|
||||
func (v *ApiVisitor) acceptService(root *Api, final *Api) {
|
||||
func (v *ApiVisitor) acceptService(root, final *Api) {
|
||||
for _, service := range root.Service {
|
||||
if _, ok := final.serviceM[service.ServiceApi.Name.Text()]; !ok && len(final.serviceM) > 0 {
|
||||
v.panic(service.ServiceApi.Name, fmt.Sprintf("mutiple service declaration"))
|
||||
@@ -104,7 +104,7 @@ func (v *ApiVisitor) duplicateServerItemCheck(service *Service) {
|
||||
}
|
||||
}
|
||||
|
||||
func (v *ApiVisitor) acceptType(root *Api, final *Api) {
|
||||
func (v *ApiVisitor) acceptType(root, final *Api) {
|
||||
for _, tp := range root.Type {
|
||||
if _, ok := final.typeM[tp.NameExpr().Text()]; ok {
|
||||
v.panic(tp.NameExpr(), fmt.Sprintf("duplicate type '%s'", tp.NameExpr().Text()))
|
||||
@@ -115,7 +115,7 @@ func (v *ApiVisitor) acceptType(root *Api, final *Api) {
|
||||
}
|
||||
}
|
||||
|
||||
func (v *ApiVisitor) acceptInfo(root *Api, final *Api) {
|
||||
func (v *ApiVisitor) acceptInfo(root, final *Api) {
|
||||
if root.Info != nil {
|
||||
infoM := map[string]PlaceHolder{}
|
||||
if final.Info != nil {
|
||||
@@ -133,7 +133,7 @@ func (v *ApiVisitor) acceptInfo(root *Api, final *Api) {
|
||||
}
|
||||
}
|
||||
|
||||
func (v *ApiVisitor) acceptImport(root *Api, final *Api) {
|
||||
func (v *ApiVisitor) acceptImport(root, final *Api) {
|
||||
for _, imp := range root.Import {
|
||||
if _, ok := final.importM[imp.Value.Text()]; ok {
|
||||
v.panic(imp.Import, fmt.Sprintf("duplicate import '%s'", imp.Value.Text()))
|
||||
@@ -144,7 +144,7 @@ func (v *ApiVisitor) acceptImport(root *Api, final *Api) {
|
||||
}
|
||||
}
|
||||
|
||||
func (v *ApiVisitor) acceptSyntax(root *Api, final *Api) {
|
||||
func (v *ApiVisitor) acceptSyntax(root, final *Api) {
|
||||
if root.Syntax != nil {
|
||||
if final.Syntax != nil {
|
||||
v.panic(root.Syntax.Syntax, fmt.Sprintf("mutiple syntax declaration"))
|
||||
|
||||
@@ -18,6 +18,7 @@ type (
|
||||
debug bool
|
||||
log console.Console
|
||||
antlr.DefaultErrorListener
|
||||
src string
|
||||
}
|
||||
|
||||
// ParserOption defines an function with argument Parser
|
||||
@@ -70,6 +71,12 @@ func (p *Parser) Accept(fn func(p *api.ApiParserParser, visitor *ApiVisitor) int
|
||||
|
||||
// Parse is used to parse the api from the specified file name
|
||||
func (p *Parser) Parse(filename string) (*Api, error) {
|
||||
abs, err := filepath.Abs(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p.src = abs
|
||||
data, err := p.readContent(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -79,8 +86,19 @@ func (p *Parser) Parse(filename string) (*Api, error) {
|
||||
}
|
||||
|
||||
// ParseContent is used to parse the api from the specified content
|
||||
func (p *Parser) ParseContent(content string) (*Api, error) {
|
||||
return p.parse("", content)
|
||||
func (p *Parser) ParseContent(content string, filename ...string) (*Api, error) {
|
||||
var f string
|
||||
if len(filename) > 0 {
|
||||
f = filename[0]
|
||||
abs, err := filepath.Abs(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p.src = abs
|
||||
}
|
||||
|
||||
return p.parse(f, content)
|
||||
}
|
||||
|
||||
// parse is used to parse api from the content
|
||||
@@ -94,7 +112,8 @@ func (p *Parser) parse(filename, content string) (*Api, error) {
|
||||
var apiAstList []*Api
|
||||
apiAstList = append(apiAstList, root)
|
||||
for _, imp := range root.Import {
|
||||
path := imp.Value.Text()
|
||||
dir := filepath.Dir(p.src)
|
||||
path := filepath.Join(dir, imp.Value.Text())
|
||||
data, err := p.readContent(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -158,7 +177,7 @@ func (p *Parser) invoke(linePrefix, content string) (v *Api, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Parser) valid(mainApi *Api, nestedApi *Api) error {
|
||||
func (p *Parser) valid(mainApi, nestedApi *Api) error {
|
||||
err := p.nestedApiCheck(mainApi, nestedApi)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -218,7 +237,7 @@ func (p *Parser) valid(mainApi *Api, nestedApi *Api) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Parser) duplicateRouteCheck(nestedApi *Api, mainHandlerMap map[string]PlaceHolder, mainRouteMap map[string]PlaceHolder) error {
|
||||
func (p *Parser) duplicateRouteCheck(nestedApi *Api, mainHandlerMap, mainRouteMap map[string]PlaceHolder) error {
|
||||
for _, each := range nestedApi.Service {
|
||||
for _, r := range each.ServiceApi.ServiceRoute {
|
||||
handler := r.GetHandler()
|
||||
@@ -241,7 +260,7 @@ func (p *Parser) duplicateRouteCheck(nestedApi *Api, mainHandlerMap map[string]P
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Parser) nestedApiCheck(mainApi *Api, nestedApi *Api) error {
|
||||
func (p *Parser) nestedApiCheck(mainApi, nestedApi *Api) error {
|
||||
if len(nestedApi.Import) > 0 {
|
||||
importToken := nestedApi.Import[0].Import
|
||||
return fmt.Errorf("%s line %d:%d the nested api does not support import",
|
||||
@@ -415,12 +434,7 @@ func (p *Parser) checkType(linePrefix string, types map[string]TypeExpr, expr Da
|
||||
|
||||
func (p *Parser) readContent(filename string) (string, error) {
|
||||
filename = strings.ReplaceAll(filename, `"`, "")
|
||||
abs, err := filepath.Abs(filename)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadFile(abs)
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -114,8 +114,10 @@ func (v *ApiVisitor) VisitTypeLit(ctx *api.TypeLitContext) interface{} {
|
||||
return alias
|
||||
}
|
||||
|
||||
doc := v.getDoc(ctx)
|
||||
st, ok := typeLit.(*TypeStruct)
|
||||
if ok {
|
||||
st.DocExpr = doc
|
||||
return st
|
||||
}
|
||||
|
||||
|
||||
@@ -34,9 +34,9 @@ func Parse(filename string) (*spec.ApiSpec, error) {
|
||||
}
|
||||
|
||||
// ParseContent parses the api content
|
||||
func ParseContent(content string) (*spec.ApiSpec, error) {
|
||||
func ParseContent(content string, filename ...string) (*spec.ApiSpec, error) {
|
||||
astParser := ast.NewParser()
|
||||
ast, err := astParser.ParseContent(content)
|
||||
ast, err := astParser.ParseContent(content, filename...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -76,14 +76,22 @@ func (p parser) fillInfo() {
|
||||
|
||||
func (p parser) fillSyntax() {
|
||||
if p.ast.Syntax != nil {
|
||||
p.spec.Syntax = spec.ApiSyntax{Version: p.ast.Syntax.Version.Text()}
|
||||
p.spec.Syntax = spec.ApiSyntax{
|
||||
Version: p.ast.Syntax.Version.Text(),
|
||||
Doc: p.stringExprs(p.ast.Syntax.DocExpr),
|
||||
Comment: p.stringExprs([]ast.Expr{p.ast.Syntax.CommentExpr}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p parser) fillImport() {
|
||||
if len(p.ast.Import) > 0 {
|
||||
for _, item := range p.ast.Import {
|
||||
p.spec.Imports = append(p.spec.Imports, spec.Import{Value: item.Value.Text()})
|
||||
p.spec.Imports = append(p.spec.Imports, spec.Import{
|
||||
Value: item.Value.Text(),
|
||||
Doc: p.stringExprs(item.DocExpr),
|
||||
Comment: p.stringExprs([]ast.Expr{item.CommentExpr}),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -173,10 +181,14 @@ func (p parser) astTypeToSpec(in ast.DataType) spec.Type {
|
||||
case *ast.Literal:
|
||||
raw := v.Literal.Text()
|
||||
if api.IsBasicType(raw) {
|
||||
return spec.PrimitiveType{RawName: raw}
|
||||
return spec.PrimitiveType{
|
||||
RawName: raw,
|
||||
}
|
||||
}
|
||||
|
||||
return spec.DefineStruct{RawName: raw}
|
||||
return spec.DefineStruct{
|
||||
RawName: raw,
|
||||
}
|
||||
case *ast.Interface:
|
||||
return spec.InterfaceType{RawName: v.Literal.Text()}
|
||||
case *ast.Map:
|
||||
@@ -198,6 +210,9 @@ func (p parser) astTypeToSpec(in ast.DataType) spec.Type {
|
||||
func (p parser) stringExprs(docs []ast.Expr) []string {
|
||||
var result []string
|
||||
for _, item := range docs {
|
||||
if item == nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, item.Text())
|
||||
}
|
||||
return result
|
||||
@@ -222,9 +237,13 @@ func (p parser) fillService() error {
|
||||
AtServerAnnotation: spec.Annotation{},
|
||||
Method: astRoute.Route.Method.Text(),
|
||||
Path: astRoute.Route.Path.Text(),
|
||||
Doc: p.stringExprs(astRoute.Route.DocExpr),
|
||||
Comment: p.stringExprs([]ast.Expr{astRoute.Route.CommentExpr}),
|
||||
}
|
||||
if astRoute.AtHandler != nil {
|
||||
route.Handler = astRoute.AtHandler.Name.Text()
|
||||
route.HandlerDoc = append(route.HandlerDoc, p.stringExprs(astRoute.AtHandler.DocExpr)...)
|
||||
route.HandlerComment = append(route.HandlerComment, p.stringExprs([]ast.Expr{astRoute.AtHandler.CommentExpr})...)
|
||||
}
|
||||
|
||||
err := p.fillRouteAtServer(astRoute, &route)
|
||||
|
||||
28
tools/goctl/api/parser/parser_test.go
Normal file
28
tools/goctl/api/parser/parser_test.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
|
||||
)
|
||||
|
||||
var testApi = "// syntax doc\nsyntax = \"v1\" // syntax comment\n\n// type doc\ntype Request {\n\tName string `path:\"name,options=you|me\"`\n}\n\ntype Response {\n\tMessage string `json:\"message\"`\n}\n\n// service doc\nservice greet-api {\n\t// handler doc\n\t@handler GreetHandler // handler comment\n\tget /from/:name(Request) returns (Response);\n}"
|
||||
|
||||
func TestParseContent(t *testing.T) {
|
||||
sp, err := ParseContent(testApi)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, spec.Doc{`// syntax doc`}, sp.Syntax.Doc)
|
||||
assert.Equal(t, spec.Doc{`// syntax comment`}, sp.Syntax.Comment)
|
||||
for _, tp := range sp.Types {
|
||||
if tp.Name() == "Request" {
|
||||
assert.Equal(t, []string{`// type doc`}, tp.Documents())
|
||||
}
|
||||
}
|
||||
for _, e := range sp.Service.Routes() {
|
||||
if e.Handler == "GreetHandler" {
|
||||
assert.Equal(t, spec.Doc{"// handler doc"}, e.HandlerDoc)
|
||||
assert.Equal(t, spec.Doc{"// handler comment"}, e.HandlerComment)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,27 +5,87 @@ func (t PrimitiveType) Name() string {
|
||||
return t.RawName
|
||||
}
|
||||
|
||||
// Comments returns the comments of struct
|
||||
func (t PrimitiveType) Comments() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Documents returns the documents of struct
|
||||
func (t PrimitiveType) Documents() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Name returns a structure string, such as User
|
||||
func (t DefineStruct) Name() string {
|
||||
return t.RawName
|
||||
}
|
||||
|
||||
// Comments returns the comments of struct
|
||||
func (t DefineStruct) Comments() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Documents returns the documents of struct
|
||||
func (t DefineStruct) Documents() []string {
|
||||
return t.Docs
|
||||
}
|
||||
|
||||
// Name returns a map string, such as map[string]int
|
||||
func (t MapType) Name() string {
|
||||
return t.RawName
|
||||
}
|
||||
|
||||
// Comments returns the comments of struct
|
||||
func (t MapType) Comments() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Documents returns the documents of struct
|
||||
func (t MapType) Documents() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Name returns a slice string, such as []int
|
||||
func (t ArrayType) Name() string {
|
||||
return t.RawName
|
||||
}
|
||||
|
||||
// Comments returns the comments of struct
|
||||
func (t ArrayType) Comments() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Documents returns the documents of struct
|
||||
func (t ArrayType) Documents() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Name returns a pointer string, such as *User
|
||||
func (t PointerType) Name() string {
|
||||
return t.RawName
|
||||
}
|
||||
|
||||
// Comments returns the comments of struct
|
||||
func (t PointerType) Comments() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Documents returns the documents of struct
|
||||
func (t PointerType) Documents() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Name returns a interface string, Its fixed value is interface{}
|
||||
func (t InterfaceType) Name() string {
|
||||
return t.RawName
|
||||
}
|
||||
|
||||
// Comments returns the comments of struct
|
||||
func (t InterfaceType) Comments() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Documents returns the documents of struct
|
||||
func (t InterfaceType) Documents() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ type (
|
||||
// ApiSyntax describes the syntax grammar
|
||||
ApiSyntax struct {
|
||||
Version string
|
||||
Doc Doc
|
||||
Comment Doc
|
||||
}
|
||||
|
||||
// ApiSpec describes a api file
|
||||
@@ -25,7 +27,9 @@ type (
|
||||
|
||||
// Import describes api import
|
||||
Import struct {
|
||||
Value string
|
||||
Value string
|
||||
Doc Doc
|
||||
Comment Doc
|
||||
}
|
||||
|
||||
// Group defines a set of routing information
|
||||
@@ -71,6 +75,10 @@ type (
|
||||
Docs Doc
|
||||
Handler string
|
||||
AtDoc AtDoc
|
||||
HandlerDoc Doc
|
||||
HandlerComment Doc
|
||||
Doc Doc
|
||||
Comment Doc
|
||||
}
|
||||
|
||||
// Service describes api service
|
||||
@@ -82,6 +90,8 @@ type (
|
||||
// Type defines api type
|
||||
Type interface {
|
||||
Name() string
|
||||
Comments() []string
|
||||
Documents() []string
|
||||
}
|
||||
|
||||
// DefineStruct describes api structure
|
||||
|
||||
@@ -42,6 +42,12 @@ func DockerCommand(c *cli.Context) (err error) {
|
||||
}()
|
||||
|
||||
goFile := c.String("go")
|
||||
home := c.String("home")
|
||||
|
||||
if len(home) > 0 {
|
||||
util.RegisterGoctlHome(home)
|
||||
}
|
||||
|
||||
if len(goFile) == 0 {
|
||||
return errors.New("-go can't be empty")
|
||||
}
|
||||
|
||||
@@ -5,7 +5,10 @@ import (
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/logrusorgru/aurora"
|
||||
"github.com/tal-tech/go-zero/core/load"
|
||||
"github.com/tal-tech/go-zero/core/logx"
|
||||
"github.com/tal-tech/go-zero/core/stat"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/apigen"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/dartgen"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/api/docgen"
|
||||
@@ -29,7 +32,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
buildVersion = "1.1.6"
|
||||
buildVersion = "1.1.9-pre"
|
||||
commands = []cli.Command{
|
||||
{
|
||||
Name: "upgrade",
|
||||
@@ -114,6 +117,10 @@ var (
|
||||
Name: "style",
|
||||
Usage: "the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "home",
|
||||
Usage: "the goctl home path of the template",
|
||||
},
|
||||
},
|
||||
Action: gogen.GoCommand,
|
||||
},
|
||||
@@ -231,6 +238,10 @@ var (
|
||||
Usage: "the port to expose, default none",
|
||||
Value: 0,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "home",
|
||||
Usage: "the goctl home path of the template",
|
||||
},
|
||||
},
|
||||
Action: docker.DockerCommand,
|
||||
},
|
||||
@@ -316,6 +327,10 @@ var (
|
||||
Usage: "the max replicas of deploy",
|
||||
Value: 10,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "home",
|
||||
Usage: "the goctl home path of the template",
|
||||
},
|
||||
},
|
||||
Action: kube.DeploymentCommand,
|
||||
},
|
||||
@@ -337,6 +352,10 @@ var (
|
||||
Name: "idea",
|
||||
Usage: "whether the command execution environment is from idea plugin. [optional]",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "home",
|
||||
Usage: "the goctl home path of the template",
|
||||
},
|
||||
},
|
||||
Action: rpc.RPCNew,
|
||||
},
|
||||
@@ -363,6 +382,10 @@ var (
|
||||
Name: "proto_path, I",
|
||||
Usage: `native command of protoc, specify the directory in which to search for imports. [optional]`,
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "go_opt",
|
||||
Usage: `native command of protoc-gen-go, specify the mapping from proto to go, eg --go_opt=proto_import=go_package_import. [optional]`,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "dir, d",
|
||||
Usage: `the target path of the code`,
|
||||
@@ -375,6 +398,10 @@ var (
|
||||
Name: "idea",
|
||||
Usage: "whether the command execution environment is from idea plugin. [optional]",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "home",
|
||||
Usage: "the goctl home path of the template",
|
||||
},
|
||||
},
|
||||
Action: rpc.RPC,
|
||||
},
|
||||
@@ -412,6 +439,14 @@ var (
|
||||
Name: "idea",
|
||||
Usage: "for idea plugin [optional]",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "database, db",
|
||||
Usage: "the name of database [optional]",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "home",
|
||||
Usage: "the goctl home path of the template",
|
||||
},
|
||||
},
|
||||
Action: model.MysqlDDL,
|
||||
},
|
||||
@@ -421,7 +456,7 @@ var (
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "url",
|
||||
Usage: `the data source of database,like "root:password@tcp(127.0.0.1:3306)/database`,
|
||||
Usage: `the data source of database,like "root:password@tcp(127.0.0.1:3306)/database"`,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "table, t",
|
||||
@@ -443,8 +478,57 @@ var (
|
||||
Name: "idea",
|
||||
Usage: "for idea plugin [optional]",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "home",
|
||||
Usage: "the goctl home path of the template",
|
||||
},
|
||||
},
|
||||
Action: model.MyDataSource,
|
||||
Action: model.MySqlDataSource,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "pg",
|
||||
Usage: `generate postgresql model`,
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "datasource",
|
||||
Usage: `generate model from datasource`,
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "url",
|
||||
Usage: `the data source of database,like "postgres://root:password@127.0.0.1:54332/database?sslmode=disable"`,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "table, t",
|
||||
Usage: `the table or table globbing patterns in the database`,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "schema, s",
|
||||
Usage: `the table schema, default is [public]`,
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "cache, c",
|
||||
Usage: "generate code with cache [optional]",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "dir, d",
|
||||
Usage: "the target dir",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "style",
|
||||
Usage: "the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "idea",
|
||||
Usage: "for idea plugin [optional]",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "home",
|
||||
Usage: "the goctl home path of the template",
|
||||
},
|
||||
},
|
||||
Action: model.PostgreSqlDataSource,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -468,6 +552,10 @@ var (
|
||||
Name: "style",
|
||||
Usage: "the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "home",
|
||||
Usage: "the goctl home path of the template",
|
||||
},
|
||||
},
|
||||
Action: mongo.Action,
|
||||
},
|
||||
@@ -489,13 +577,25 @@ var (
|
||||
Usage: "template operation",
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "init",
|
||||
Usage: "initialize the all templates(force update)",
|
||||
Name: "init",
|
||||
Usage: "initialize the all templates(force update)",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "home",
|
||||
Usage: "the goctl home path of the template",
|
||||
},
|
||||
},
|
||||
Action: tpl.GenTemplates,
|
||||
},
|
||||
{
|
||||
Name: "clean",
|
||||
Usage: "clean the all cache templates",
|
||||
Name: "clean",
|
||||
Usage: "clean the all cache templates",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "home",
|
||||
Usage: "the goctl home path of the template",
|
||||
},
|
||||
},
|
||||
Action: tpl.CleanTemplates,
|
||||
},
|
||||
{
|
||||
@@ -506,6 +606,10 @@ var (
|
||||
Name: "category,c",
|
||||
Usage: "the category of template, enum [api,rpc,model,docker,kube]",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "home",
|
||||
Usage: "the goctl home path of the template",
|
||||
},
|
||||
},
|
||||
Action: tpl.UpdateTemplates,
|
||||
},
|
||||
@@ -521,6 +625,10 @@ var (
|
||||
Name: "name,n",
|
||||
Usage: "the target file name of template",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "home",
|
||||
Usage: "the goctl home path of the template",
|
||||
},
|
||||
},
|
||||
Action: tpl.RevertTemplates,
|
||||
},
|
||||
@@ -531,6 +639,8 @@ var (
|
||||
|
||||
func main() {
|
||||
logx.Disable()
|
||||
load.Disable()
|
||||
stat.DisableLog()
|
||||
|
||||
app := cli.NewApp()
|
||||
app.Usage = "a cli tool to generate code"
|
||||
@@ -538,6 +648,6 @@ func main() {
|
||||
app.Commands = commands
|
||||
// cli already print error messages
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
fmt.Println("error:", err)
|
||||
fmt.Println(aurora.Red("error: " + err.Error()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,8 +54,8 @@ type (
|
||||
|
||||
createRequest struct {
|
||||
innerType
|
||||
name string `form:"name"` // niha
|
||||
age int `form:"age,optional"` // nihaod
|
||||
name string `form:"name"`
|
||||
age int `form:"age,optional"`
|
||||
address []address `json:"address,optional"`
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,12 @@ type Deployment struct {
|
||||
// DeploymentCommand is used to generate the kubernetes deployment yaml files.
|
||||
func DeploymentCommand(c *cli.Context) error {
|
||||
nodePort := c.Int("nodePort")
|
||||
home := c.String("home")
|
||||
|
||||
if len(home) > 0 {
|
||||
util.RegisterGoctlHome(home)
|
||||
}
|
||||
|
||||
// 0 to disable the nodePort type
|
||||
if nodePort != 0 && (nodePort < basePort || nodePort > portLimit) {
|
||||
return errors.New("nodePort should be between 30000 and 32767")
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/config"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/model/mongo/generate"
|
||||
file "github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
@@ -16,6 +17,12 @@ func Action(ctx *cli.Context) error {
|
||||
c := ctx.Bool("cache")
|
||||
o := strings.TrimSpace(ctx.String("dir"))
|
||||
s := ctx.String("style")
|
||||
home := ctx.String("home")
|
||||
|
||||
if len(home) > 0 {
|
||||
file.RegisterGoctlHome(home)
|
||||
}
|
||||
|
||||
if len(tp) == 0 {
|
||||
return errors.New("missing type")
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"github.com/tal-tech/go-zero/core/stores/mongoc"
|
||||
)
|
||||
|
||||
{{if .Cache}}var prefix{{.Type}}CacheKey = "cache#{{.Type}}#"{{end}}
|
||||
{{if .Cache}}var prefix{{.Type}}CacheKey = "cache:{{.Type}}:"{{end}}
|
||||
|
||||
type {{.Type}}Model interface{
|
||||
Insert(ctx context.Context,data *{{.Type}}) error
|
||||
|
||||
@@ -264,6 +264,7 @@ OPTIONS:
|
||||
--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]
|
||||
--database, -db the name of database [optional]
|
||||
```
|
||||
|
||||
* datasource
|
||||
|
||||
@@ -3,6 +3,7 @@ package builderx
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/go-xorm/builder"
|
||||
)
|
||||
@@ -81,13 +82,18 @@ func FieldNames(in interface{}) []string {
|
||||
}
|
||||
|
||||
// RawFieldNames converts golang struct field into slice string
|
||||
func RawFieldNames(in interface{}) []string {
|
||||
func RawFieldNames(in interface{}, postgresSql ...bool) []string {
|
||||
out := make([]string, 0)
|
||||
v := reflect.ValueOf(in)
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
var pg bool
|
||||
if len(postgresSql) > 0 {
|
||||
pg = postgresSql[0]
|
||||
}
|
||||
|
||||
// we only accept structs
|
||||
if v.Kind() != reflect.Struct {
|
||||
panic(fmt.Errorf("ToMap only accepts structs; got %T", v))
|
||||
@@ -98,11 +104,32 @@ func RawFieldNames(in interface{}) []string {
|
||||
// gets us a StructField
|
||||
fi := typ.Field(i)
|
||||
if tagv := fi.Tag.Get(dbTag); tagv != "" {
|
||||
out = append(out, fmt.Sprintf("`%s`", tagv))
|
||||
if pg {
|
||||
out = append(out, fmt.Sprintf("%s", tagv))
|
||||
} else {
|
||||
out = append(out, fmt.Sprintf("`%s`", tagv))
|
||||
}
|
||||
} else {
|
||||
out = append(out, fmt.Sprintf(`"%s"`, fi.Name))
|
||||
if pg {
|
||||
out = append(out, fmt.Sprintf("%s", fi.Name))
|
||||
} else {
|
||||
out = append(out, fmt.Sprintf("`%s`", fi.Name))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func PostgreSqlJoin(elems []string) string {
|
||||
var b = new(strings.Builder)
|
||||
for index, e := range elems {
|
||||
b.WriteString(fmt.Sprintf("%s = $%d, ", e, index+1))
|
||||
}
|
||||
|
||||
if b.Len() == 0 {
|
||||
return b.String()
|
||||
}
|
||||
|
||||
return b.String()[0 : b.Len()-2]
|
||||
}
|
||||
|
||||
@@ -118,3 +118,8 @@ func TestBuildSqlLike(t *testing.T) {
|
||||
assert.Equal(t, sql, actualSQL)
|
||||
assert.Equal(t, args, actualArgs)
|
||||
}
|
||||
|
||||
func TestJoin(t *testing.T) {
|
||||
ret := PostgreSqlJoin([]string{"name", "age"})
|
||||
assert.Equal(t, "name = $1, age = $2", ret)
|
||||
}
|
||||
|
||||
@@ -2,29 +2,32 @@ package command
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/go-sql-driver/mysql"
|
||||
"github.com/tal-tech/go-zero/core/logx"
|
||||
"github.com/tal-tech/go-zero/core/stores/postgres"
|
||||
"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"
|
||||
file "github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/console"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
const (
|
||||
flagSrc = "src"
|
||||
flagDir = "dir"
|
||||
flagCache = "cache"
|
||||
flagIdea = "idea"
|
||||
flagURL = "url"
|
||||
flagTable = "table"
|
||||
flagStyle = "style"
|
||||
flagSrc = "src"
|
||||
flagDir = "dir"
|
||||
flagCache = "cache"
|
||||
flagIdea = "idea"
|
||||
flagURL = "url"
|
||||
flagTable = "table"
|
||||
flagStyle = "style"
|
||||
flagDatabase = "database"
|
||||
flagSchema = "schema"
|
||||
)
|
||||
|
||||
var errNotMatched = errors.New("sql not matched")
|
||||
@@ -36,31 +39,70 @@ func MysqlDDL(ctx *cli.Context) error {
|
||||
cache := ctx.Bool(flagCache)
|
||||
idea := ctx.Bool(flagIdea)
|
||||
style := ctx.String(flagStyle)
|
||||
database := ctx.String(flagDatabase)
|
||||
home := ctx.String("home")
|
||||
|
||||
if len(home) > 0 {
|
||||
file.RegisterGoctlHome(home)
|
||||
}
|
||||
cfg, err := config.NewConfig(style)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return fromDDl(src, dir, cfg, cache, idea)
|
||||
return fromDDl(src, dir, cfg, cache, idea, database)
|
||||
}
|
||||
|
||||
// MyDataSource generates model code from datasource
|
||||
func MyDataSource(ctx *cli.Context) error {
|
||||
// MySqlDataSource generates model code from datasource
|
||||
func MySqlDataSource(ctx *cli.Context) error {
|
||||
url := strings.TrimSpace(ctx.String(flagURL))
|
||||
dir := strings.TrimSpace(ctx.String(flagDir))
|
||||
cache := ctx.Bool(flagCache)
|
||||
idea := ctx.Bool(flagIdea)
|
||||
style := ctx.String(flagStyle)
|
||||
home := ctx.String("home")
|
||||
|
||||
if len(home) > 0 {
|
||||
file.RegisterGoctlHome(home)
|
||||
}
|
||||
|
||||
pattern := strings.TrimSpace(ctx.String(flagTable))
|
||||
cfg, err := config.NewConfig(style)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return fromDataSource(url, pattern, dir, cfg, cache, idea)
|
||||
return fromMysqlDataSource(url, pattern, dir, cfg, cache, idea)
|
||||
}
|
||||
|
||||
func fromDDl(src, dir string, cfg *config.Config, cache, idea bool) error {
|
||||
// PostgreSqlDataSource generates model code from datasource
|
||||
func PostgreSqlDataSource(ctx *cli.Context) error {
|
||||
url := strings.TrimSpace(ctx.String(flagURL))
|
||||
dir := strings.TrimSpace(ctx.String(flagDir))
|
||||
cache := ctx.Bool(flagCache)
|
||||
idea := ctx.Bool(flagIdea)
|
||||
style := ctx.String(flagStyle)
|
||||
schema := ctx.String(flagSchema)
|
||||
home := ctx.String("home")
|
||||
|
||||
if len(home) > 0 {
|
||||
file.RegisterGoctlHome(home)
|
||||
}
|
||||
|
||||
if len(schema) == 0 {
|
||||
schema = "public"
|
||||
}
|
||||
|
||||
pattern := strings.TrimSpace(ctx.String(flagTable))
|
||||
cfg, err := config.NewConfig(style)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return fromPostgreSqlDataSource(url, pattern, dir, schema, cfg, cache, idea)
|
||||
}
|
||||
|
||||
func fromDDl(src, dir string, cfg *config.Config, cache, idea bool, database string) error {
|
||||
log := console.NewConsole(idea)
|
||||
src = strings.TrimSpace(src)
|
||||
if len(src) == 0 {
|
||||
@@ -76,25 +118,22 @@ func fromDDl(src, dir string, cfg *config.Config, cache, idea bool) error {
|
||||
return errNotMatched
|
||||
}
|
||||
|
||||
var source []string
|
||||
for _, file := range files {
|
||||
data, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
source = append(source, string(data))
|
||||
}
|
||||
|
||||
generator, err := gen.NewDefaultGenerator(dir, cfg, gen.WithConsoleOption(log))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return generator.StartFromDDL(strings.Join(source, "\n"), cache)
|
||||
for _, file := range files {
|
||||
err = generator.StartFromDDL(file, cache, database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func fromDataSource(url, pattern, dir string, cfg *config.Config, cache, idea bool) error {
|
||||
func fromMysqlDataSource(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")
|
||||
@@ -156,3 +195,58 @@ func fromDataSource(url, pattern, dir string, cfg *config.Config, cache, idea bo
|
||||
|
||||
return generator.StartFromInformationSchema(matchTables, cache)
|
||||
}
|
||||
|
||||
func fromPostgreSqlDataSource(url, pattern, dir, schema string, cfg *config.Config, cache, idea bool) error {
|
||||
log := console.NewConsole(idea)
|
||||
if len(url) == 0 {
|
||||
log.Error("%v", "expected data source of postgresql, but nothing found")
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(pattern) == 0 {
|
||||
log.Error("%v", "expected table or table globbing patterns, but nothing found")
|
||||
return nil
|
||||
}
|
||||
db := postgres.New(url)
|
||||
im := model.NewPostgreSqlModel(db)
|
||||
|
||||
tables, err := im.GetAllTables(schema)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
matchTables := make(map[string]*model.Table)
|
||||
for _, item := range tables {
|
||||
match, err := filepath.Match(pattern, item)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !match {
|
||||
continue
|
||||
}
|
||||
|
||||
columnData, err := im.FindColumns(schema, item)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
table, err := columnData.Convert()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
matchTables[item] = table
|
||||
}
|
||||
|
||||
if len(matchTables) == 0 {
|
||||
return errors.New("no tables matched")
|
||||
}
|
||||
|
||||
generator, err := gen.NewDefaultGenerator(dir, cfg, gen.WithConsoleOption(log), gen.WithPostgreSql())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return generator.StartFromInformationSchema(matchTables, cache)
|
||||
}
|
||||
|
||||
@@ -24,12 +24,12 @@ func TestFromDDl(t *testing.T) {
|
||||
err := gen.Clean()
|
||||
assert.Nil(t, err)
|
||||
|
||||
err = fromDDl("./user.sql", t.TempDir(), cfg, true, false)
|
||||
err = fromDDl("./user.sql", t.TempDir(), cfg, true, false, "go_zero")
|
||||
assert.Equal(t, errNotMatched, err)
|
||||
|
||||
// case dir is not exists
|
||||
unknownDir := filepath.Join(t.TempDir(), "test", "user.sql")
|
||||
err = fromDDl(unknownDir, t.TempDir(), cfg, true, false)
|
||||
err = fromDDl(unknownDir, t.TempDir(), cfg, true, false, "go_zero")
|
||||
assert.True(t, func() bool {
|
||||
switch err.(type) {
|
||||
case *os.PathError:
|
||||
@@ -40,7 +40,7 @@ func TestFromDDl(t *testing.T) {
|
||||
}())
|
||||
|
||||
// case empty src
|
||||
err = fromDDl("", t.TempDir(), cfg, true, false)
|
||||
err = fromDDl("", t.TempDir(), cfg, true, false, "go_zero")
|
||||
if err != nil {
|
||||
assert.Equal(t, "expected path or path globbing patterns, but nothing found", err.Error())
|
||||
}
|
||||
@@ -70,7 +70,7 @@ func TestFromDDl(t *testing.T) {
|
||||
_, err = os.Stat(user2Sql)
|
||||
assert.Nil(t, err)
|
||||
|
||||
err = fromDDl(filepath.Join(tempDir, "user*.sql"), tempDir, cfg, true, false)
|
||||
err = fromDDl(filepath.Join(tempDir, "user*.sql"), tempDir, cfg, true, false, "go_zero")
|
||||
assert.Nil(t, err)
|
||||
|
||||
_, err = os.Stat(filepath.Join(tempDir, "usermodel.go"))
|
||||
|
||||
@@ -3,9 +3,57 @@ package converter
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/zeromicro/ddl-parser/parser"
|
||||
)
|
||||
|
||||
var commonMysqlDataTypeMap = map[string]string{
|
||||
var commonMysqlDataTypeMap = map[int]string{
|
||||
// For consistency, all integer types are converted to int64
|
||||
// number
|
||||
parser.Bool: "int64",
|
||||
parser.Boolean: "int64",
|
||||
parser.TinyInt: "int64",
|
||||
parser.SmallInt: "int64",
|
||||
parser.MediumInt: "int64",
|
||||
parser.Int: "int64",
|
||||
parser.MiddleInt: "int64",
|
||||
parser.Int1: "int64",
|
||||
parser.Int2: "int64",
|
||||
parser.Int3: "int64",
|
||||
parser.Int4: "int64",
|
||||
parser.Int8: "int64",
|
||||
parser.Integer: "int64",
|
||||
parser.BigInt: "int64",
|
||||
parser.Float: "float64",
|
||||
parser.Float4: "float64",
|
||||
parser.Float8: "float64",
|
||||
parser.Double: "float64",
|
||||
parser.Decimal: "float64",
|
||||
// date&time
|
||||
parser.Date: "time.Time",
|
||||
parser.DateTime: "time.Time",
|
||||
parser.Timestamp: "time.Time",
|
||||
parser.Time: "string",
|
||||
parser.Year: "int64",
|
||||
// string
|
||||
parser.Char: "string",
|
||||
parser.VarChar: "string",
|
||||
parser.Binary: "string",
|
||||
parser.VarBinary: "string",
|
||||
parser.TinyText: "string",
|
||||
parser.Text: "string",
|
||||
parser.MediumText: "string",
|
||||
parser.LongText: "string",
|
||||
parser.Enum: "string",
|
||||
parser.Set: "string",
|
||||
parser.Json: "string",
|
||||
parser.Blob: "string",
|
||||
parser.LongBlob: "string",
|
||||
parser.MediumBlob: "string",
|
||||
parser.TinyBlob: "string",
|
||||
}
|
||||
|
||||
var commonMysqlDataTypeMap2 = map[string]string{
|
||||
// For consistency, all integer types are converted to int64
|
||||
// number
|
||||
"bool": "int64",
|
||||
@@ -37,13 +85,27 @@ var commonMysqlDataTypeMap = map[string]string{
|
||||
"enum": "string",
|
||||
"set": "string",
|
||||
"json": "string",
|
||||
"blob": "string",
|
||||
"longblob": "string",
|
||||
"mediumblob": "string",
|
||||
"tinyblob": "string",
|
||||
}
|
||||
|
||||
// ConvertDataType converts mysql column type into golang type
|
||||
func ConvertDataType(dataBaseType string, isDefaultNull bool) (string, error) {
|
||||
tp, ok := commonMysqlDataTypeMap[strings.ToLower(dataBaseType)]
|
||||
func ConvertDataType(dataBaseType int, isDefaultNull bool) (string, error) {
|
||||
tp, ok := commonMysqlDataTypeMap[dataBaseType]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("unexpected database type: %s", dataBaseType)
|
||||
return "", fmt.Errorf("unsupported database type: %v", dataBaseType)
|
||||
}
|
||||
|
||||
return mayConvertNullType(tp, isDefaultNull), nil
|
||||
}
|
||||
|
||||
// ConvertStringDataType converts mysql column type into golang type
|
||||
func ConvertStringDataType(dataBaseType string, isDefaultNull bool) (string, error) {
|
||||
tp, ok := commonMysqlDataTypeMap2[strings.ToLower(dataBaseType)]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("unsupported database type: %s", dataBaseType)
|
||||
}
|
||||
|
||||
return mayConvertNullType(tp, isDefaultNull), nil
|
||||
|
||||
@@ -4,25 +4,23 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/zeromicro/ddl-parser/parser"
|
||||
)
|
||||
|
||||
func TestConvertDataType(t *testing.T) {
|
||||
v, err := ConvertDataType("tinyint", false)
|
||||
v, err := ConvertDataType(parser.TinyInt, false)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "int64", v)
|
||||
|
||||
v, err = ConvertDataType("tinyint", true)
|
||||
v, err = ConvertDataType(parser.TinyInt, true)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "sql.NullInt64", v)
|
||||
|
||||
v, err = ConvertDataType("timestamp", false)
|
||||
v, err = ConvertDataType(parser.Timestamp, false)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "time.Time", v)
|
||||
|
||||
v, err = ConvertDataType("timestamp", true)
|
||||
v, err = ConvertDataType(parser.Timestamp, true)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "sql.NullTime", v)
|
||||
|
||||
_, err = ConvertDataType("float32", false)
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
-- 用户表 --
|
||||
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 '手机号',
|
||||
`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 `name_index2` (`name`),
|
||||
UNIQUE KEY `user_index` (`user`),
|
||||
UNIQUE KEY `mobile_index` (`mobile`)
|
||||
CREATE TABLE `user`
|
||||
(
|
||||
`id` bigint(10) NOT NULL AUTO_INCREMENT,
|
||||
`user` varchar(50) NOT NULL DEFAULT '' COMMENT '用户',
|
||||
`name` varchar(255) COLLATE utf8mb4_general_ci NULL COMMENT '用户\t名称',
|
||||
`password` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户\n密码',
|
||||
`mobile` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '手机号',
|
||||
`gender` char(5) COLLATE utf8mb4_general_ci NOT NULL COMMENT '男|女|未公\r开',
|
||||
`nickname` varchar(255) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '用户昵称',
|
||||
`create_time` timestamp NULL,
|
||||
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `name_index` (`name`),
|
||||
UNIQUE KEY `name_index2` (`name`),
|
||||
UNIQUE KEY `user_index` (`user`),
|
||||
UNIQUE KEY `mobile_index` (`mobile`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE `student` (
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/stringx"
|
||||
)
|
||||
|
||||
func genDelete(table Table, withCache bool) (string, string, error) {
|
||||
func genDelete(table Table, withCache, postgreSql bool) (string, string, error) {
|
||||
keySet := collection.NewSet()
|
||||
keyVariableSet := collection.NewSet()
|
||||
keySet.AddStr(table.PrimaryCacheKey.KeyExpression)
|
||||
@@ -34,8 +34,9 @@ func genDelete(table Table, withCache bool) (string, string, error) {
|
||||
"lowerStartCamelPrimaryKey": stringx.From(table.PrimaryKey.Name.ToCamel()).Untitle(),
|
||||
"dataType": table.PrimaryKey.DataType,
|
||||
"keys": strings.Join(keySet.KeysStr(), "\n"),
|
||||
"originalPrimaryKey": wrapWithRawString(table.PrimaryKey.Name.Source()),
|
||||
"originalPrimaryKey": wrapWithRawString(table.PrimaryKey.Name.Source(), postgreSql),
|
||||
"keyValues": strings.Join(keyVariableSet.KeysStr(), ", "),
|
||||
"postgreSql": postgreSql,
|
||||
})
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/stringx"
|
||||
)
|
||||
|
||||
func genFindOne(table Table, withCache bool) (string, string, error) {
|
||||
func genFindOne(table Table, withCache, postgreSql bool) (string, string, error) {
|
||||
camel := table.Name.ToCamel()
|
||||
text, err := util.LoadTemplate(category, findOneTemplateFile, template.FindOne)
|
||||
if err != nil {
|
||||
@@ -19,11 +19,12 @@ func genFindOne(table Table, withCache bool) (string, string, error) {
|
||||
"withCache": withCache,
|
||||
"upperStartCamelObject": camel,
|
||||
"lowerStartCamelObject": stringx.From(camel).Untitle(),
|
||||
"originalPrimaryKey": wrapWithRawString(table.PrimaryKey.Name.Source()),
|
||||
"originalPrimaryKey": wrapWithRawString(table.PrimaryKey.Name.Source(), postgreSql),
|
||||
"lowerStartCamelPrimaryKey": stringx.From(table.PrimaryKey.Name.ToCamel()).Untitle(),
|
||||
"dataType": table.PrimaryKey.DataType,
|
||||
"cacheKey": table.PrimaryCacheKey.KeyExpression,
|
||||
"cacheKeyVariable": table.PrimaryCacheKey.KeyLeft,
|
||||
"postgreSql": postgreSql,
|
||||
})
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
|
||||
@@ -15,7 +15,7 @@ type findOneCode struct {
|
||||
cacheExtra string
|
||||
}
|
||||
|
||||
func genFindOneByField(table Table, withCache bool) (*findOneCode, error) {
|
||||
func genFindOneByField(table Table, withCache, postgreSql bool) (*findOneCode, error) {
|
||||
text, err := util.LoadTemplate(category, findOneByFieldTemplateFile, template.FindOneByField)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -25,7 +25,7 @@ func genFindOneByField(table Table, withCache bool) (*findOneCode, error) {
|
||||
var list []string
|
||||
camelTableName := table.Name.ToCamel()
|
||||
for _, key := range table.UniqueCacheKey {
|
||||
in, paramJoinString, originalFieldString := convertJoin(key)
|
||||
in, paramJoinString, originalFieldString := convertJoin(key, postgreSql)
|
||||
|
||||
output, err := t.Execute(map[string]interface{}{
|
||||
"upperStartCamelObject": camelTableName,
|
||||
@@ -38,6 +38,7 @@ func genFindOneByField(table Table, withCache bool) (*findOneCode, error) {
|
||||
"lowerStartCamelField": paramJoinString,
|
||||
"upperStartCamelPrimaryKey": table.PrimaryKey.Name.ToCamel(),
|
||||
"originalField": originalFieldString,
|
||||
"postgreSql": postgreSql,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -87,7 +88,8 @@ func genFindOneByField(table Table, withCache bool) (*findOneCode, error) {
|
||||
"upperStartCamelObject": camelTableName,
|
||||
"primaryKeyLeft": table.PrimaryCacheKey.VarLeft,
|
||||
"lowerStartCamelObject": stringx.From(camelTableName).Untitle(),
|
||||
"originalPrimaryField": wrapWithRawString(table.PrimaryKey.Name.Source()),
|
||||
"originalPrimaryField": wrapWithRawString(table.PrimaryKey.Name.Source(), postgreSql),
|
||||
"postgreSql": postgreSql,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -106,13 +108,17 @@ func genFindOneByField(table Table, withCache bool) (*findOneCode, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func convertJoin(key Key) (in, paramJoinString, originalFieldString string) {
|
||||
func convertJoin(key Key, postgreSql bool) (in, paramJoinString, originalFieldString string) {
|
||||
var inJoin, paramJoin, argJoin Join
|
||||
for _, f := range key.Fields {
|
||||
for index, f := range key.Fields {
|
||||
param := stringx.From(f.Name.ToCamel()).Untitle()
|
||||
inJoin = append(inJoin, fmt.Sprintf("%s %s", param, f.DataType))
|
||||
paramJoin = append(paramJoin, param)
|
||||
argJoin = append(argJoin, fmt.Sprintf("%s = ?", wrapWithRawString(f.Name.Source())))
|
||||
if postgreSql {
|
||||
argJoin = append(argJoin, fmt.Sprintf("%s = $%d", wrapWithRawString(f.Name.Source(), postgreSql), index+1))
|
||||
} else {
|
||||
argJoin = append(argJoin, fmt.Sprintf("%s = ?", wrapWithRawString(f.Name.Source(), postgreSql)))
|
||||
}
|
||||
}
|
||||
if len(inJoin) > 0 {
|
||||
in = inJoin.With(", ").Source()
|
||||
|
||||
@@ -29,8 +29,9 @@ type (
|
||||
// source string
|
||||
dir string
|
||||
console.Console
|
||||
pkg string
|
||||
cfg *config.Config
|
||||
pkg string
|
||||
cfg *config.Config
|
||||
isPostgreSql bool
|
||||
}
|
||||
|
||||
// Option defines a function with argument defaultGenerator
|
||||
@@ -84,14 +85,21 @@ func WithConsoleOption(c console.Console) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithPostgreSql marks defaultGenerator.isPostgreSql true
|
||||
func WithPostgreSql() Option {
|
||||
return func(generator *defaultGenerator) {
|
||||
generator.isPostgreSql = true
|
||||
}
|
||||
}
|
||||
|
||||
func newDefaultOption() Option {
|
||||
return func(generator *defaultGenerator) {
|
||||
generator.Console = console.NewColorConsole()
|
||||
}
|
||||
}
|
||||
|
||||
func (g *defaultGenerator) StartFromDDL(source string, withCache bool) error {
|
||||
modelList, err := g.genFromDDL(source, withCache)
|
||||
func (g *defaultGenerator) StartFromDDL(filename string, withCache bool, database string) error {
|
||||
modelList, err := g.genFromDDL(filename, withCache, database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -174,21 +182,20 @@ func (g *defaultGenerator) createFile(modelList map[string]string) error {
|
||||
}
|
||||
|
||||
// ret1: key-table name,value-code
|
||||
func (g *defaultGenerator) genFromDDL(source string, withCache bool) (map[string]string, error) {
|
||||
ddlList := g.split(source)
|
||||
func (g *defaultGenerator) genFromDDL(filename string, withCache bool, database string) (map[string]string, error) {
|
||||
m := make(map[string]string)
|
||||
for _, ddl := range ddlList {
|
||||
table, err := parser.Parse(ddl)
|
||||
tables, err := parser.Parse(filename, database)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, e := range tables {
|
||||
code, err := g.genModel(*e, withCache)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
code, err := g.genModel(*table, withCache)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m[table.Name.Source()] = code
|
||||
m[e.Name.Source()] = code
|
||||
}
|
||||
|
||||
return m, nil
|
||||
@@ -220,34 +227,34 @@ func (g *defaultGenerator) genModel(in parser.Table, withCache bool) (string, er
|
||||
table.UniqueCacheKey = uniqueKey
|
||||
table.ContainsUniqueCacheKey = len(uniqueKey) > 0
|
||||
|
||||
varsCode, err := genVars(table, withCache)
|
||||
varsCode, err := genVars(table, withCache, g.isPostgreSql)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
insertCode, insertCodeMethod, err := genInsert(table, withCache)
|
||||
insertCode, insertCodeMethod, err := genInsert(table, withCache, g.isPostgreSql)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
findCode := make([]string, 0)
|
||||
findOneCode, findOneCodeMethod, err := genFindOne(table, withCache)
|
||||
findOneCode, findOneCodeMethod, err := genFindOne(table, withCache, g.isPostgreSql)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
ret, err := genFindOneByField(table, withCache)
|
||||
ret, err := genFindOneByField(table, withCache, g.isPostgreSql)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
findCode = append(findCode, findOneCode, ret.findOneMethod)
|
||||
updateCode, updateCodeMethod, err := genUpdate(table, withCache)
|
||||
updateCode, updateCodeMethod, err := genUpdate(table, withCache, g.isPostgreSql)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
deleteCode, deleteCodeMethod, err := genDelete(table, withCache)
|
||||
deleteCode, deleteCodeMethod, err := genDelete(table, withCache, g.isPostgreSql)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -259,7 +266,7 @@ func (g *defaultGenerator) genModel(in parser.Table, withCache bool) (string, er
|
||||
return "", err
|
||||
}
|
||||
|
||||
newCode, err := genNew(table, withCache)
|
||||
newCode, err := genNew(table, withCache, g.isPostgreSql)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -310,7 +317,11 @@ func (g *defaultGenerator) executeModel(code *code) (*bytes.Buffer, error) {
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func wrapWithRawString(v string) string {
|
||||
func wrapWithRawString(v string, postgreSql bool) string {
|
||||
if postgreSql {
|
||||
return v
|
||||
}
|
||||
|
||||
if v == "`" {
|
||||
return v
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package gen
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -20,6 +21,11 @@ var source = "CREATE TABLE `test_user` (\n `id` bigint NOT NULL AUTO_INCREMENT,
|
||||
func TestCacheModel(t *testing.T) {
|
||||
logx.Disable()
|
||||
_ = Clean()
|
||||
|
||||
sqlFile := filepath.Join(t.TempDir(), "tmp.sql")
|
||||
err := ioutil.WriteFile(sqlFile, []byte(source), 0o777)
|
||||
assert.Nil(t, err)
|
||||
|
||||
dir := filepath.Join(t.TempDir(), "./testmodel")
|
||||
cacheDir := filepath.Join(dir, "cache")
|
||||
noCacheDir := filepath.Join(dir, "nocache")
|
||||
@@ -28,7 +34,7 @@ func TestCacheModel(t *testing.T) {
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
err = g.StartFromDDL(source, true)
|
||||
err = g.StartFromDDL(sqlFile, true, "go_zero")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, func() bool {
|
||||
_, err := os.Stat(filepath.Join(cacheDir, "TestUserModel.go"))
|
||||
@@ -39,7 +45,7 @@ func TestCacheModel(t *testing.T) {
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
err = g.StartFromDDL(source, false)
|
||||
err = g.StartFromDDL(sqlFile, false, "go_zero")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, func() bool {
|
||||
_, err := os.Stat(filepath.Join(noCacheDir, "testusermodel.go"))
|
||||
@@ -50,6 +56,11 @@ func TestCacheModel(t *testing.T) {
|
||||
func TestNamingModel(t *testing.T) {
|
||||
logx.Disable()
|
||||
_ = Clean()
|
||||
|
||||
sqlFile := filepath.Join(t.TempDir(), "tmp.sql")
|
||||
err := ioutil.WriteFile(sqlFile, []byte(source), 0o777)
|
||||
assert.Nil(t, err)
|
||||
|
||||
dir, _ := filepath.Abs("./testmodel")
|
||||
camelDir := filepath.Join(dir, "camel")
|
||||
snakeDir := filepath.Join(dir, "snake")
|
||||
@@ -61,7 +72,7 @@ func TestNamingModel(t *testing.T) {
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
err = g.StartFromDDL(source, true)
|
||||
err = g.StartFromDDL(sqlFile, true, "go_zero")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, func() bool {
|
||||
_, err := os.Stat(filepath.Join(camelDir, "TestUserModel.go"))
|
||||
@@ -72,7 +83,7 @@ func TestNamingModel(t *testing.T) {
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
err = g.StartFromDDL(source, true)
|
||||
err = g.StartFromDDL(sqlFile, true, "go_zero")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, func() bool {
|
||||
_, err := os.Stat(filepath.Join(snakeDir, "test_user_model.go"))
|
||||
@@ -81,10 +92,11 @@ func TestNamingModel(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWrapWithRawString(t *testing.T) {
|
||||
assert.Equal(t, "``", wrapWithRawString(""))
|
||||
assert.Equal(t, "``", wrapWithRawString("``"))
|
||||
assert.Equal(t, "`a`", wrapWithRawString("a"))
|
||||
assert.Equal(t, "` `", wrapWithRawString(" "))
|
||||
assert.Equal(t, "``", wrapWithRawString("", false))
|
||||
assert.Equal(t, "``", wrapWithRawString("``", false))
|
||||
assert.Equal(t, "`a`", wrapWithRawString("a", false))
|
||||
assert.Equal(t, "a", wrapWithRawString("a", true))
|
||||
assert.Equal(t, "` `", wrapWithRawString(" ", false))
|
||||
}
|
||||
|
||||
func TestFields(t *testing.T) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package gen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/tal-tech/go-zero/core/collection"
|
||||
@@ -9,7 +10,7 @@ import (
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/stringx"
|
||||
)
|
||||
|
||||
func genInsert(table Table, withCache bool) (string, string, error) {
|
||||
func genInsert(table Table, withCache, postgreSql bool) (string, string, error) {
|
||||
keySet := collection.NewSet()
|
||||
keyVariableSet := collection.NewSet()
|
||||
for _, key := range table.UniqueCacheKey {
|
||||
@@ -19,6 +20,7 @@ func genInsert(table Table, withCache bool) (string, string, error) {
|
||||
|
||||
expressions := make([]string, 0)
|
||||
expressionValues := make([]string, 0)
|
||||
var count int
|
||||
for _, field := range table.Fields {
|
||||
camel := field.Name.ToCamel()
|
||||
if camel == "CreateTime" || camel == "UpdateTime" {
|
||||
@@ -31,7 +33,12 @@ func genInsert(table Table, withCache bool) (string, string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
expressions = append(expressions, "?")
|
||||
count += 1
|
||||
if postgreSql {
|
||||
expressions = append(expressions, fmt.Sprintf("$%d", count))
|
||||
} else {
|
||||
expressions = append(expressions, "?")
|
||||
}
|
||||
expressionValues = append(expressionValues, "data."+camel)
|
||||
}
|
||||
|
||||
|
||||
@@ -13,9 +13,9 @@ import (
|
||||
type Key struct {
|
||||
// VarLeft describes the variable of cache key expression which likes cacheUserIdPrefix
|
||||
VarLeft string
|
||||
// VarRight describes the value of cache key expression which likes "cache#user#id#"
|
||||
// VarRight describes the value of cache key expression which likes "cache:user:id:"
|
||||
VarRight string
|
||||
// VarExpression describes the cache key expression which likes cacheUserIdPrefix = "cache#user#id#"
|
||||
// VarExpression describes the cache key expression which likes cacheUserIdPrefix = "cache:user:id:"
|
||||
VarExpression string
|
||||
// KeyLeft describes the variable of key definition expression which likes userKey
|
||||
KeyLeft string
|
||||
@@ -39,9 +39,9 @@ type Join []string
|
||||
func genCacheKeys(table parser.Table) (Key, []Key) {
|
||||
var primaryKey Key
|
||||
var uniqueKey []Key
|
||||
primaryKey = genCacheKey(table.Name, []*parser.Field{&table.PrimaryKey.Field})
|
||||
primaryKey = genCacheKey(table.Db, table.Name, []*parser.Field{&table.PrimaryKey.Field})
|
||||
for _, each := range table.UniqueIndex {
|
||||
uniqueKey = append(uniqueKey, genCacheKey(table.Name, each))
|
||||
uniqueKey = append(uniqueKey, genCacheKey(table.Db, table.Name, each))
|
||||
}
|
||||
sort.Slice(uniqueKey, func(i, j int) bool {
|
||||
return uniqueKey[i].VarLeft < uniqueKey[j].VarLeft
|
||||
@@ -50,7 +50,7 @@ func genCacheKeys(table parser.Table) (Key, []Key) {
|
||||
return primaryKey, uniqueKey
|
||||
}
|
||||
|
||||
func genCacheKey(table stringx.String, in []*parser.Field) Key {
|
||||
func genCacheKey(db stringx.String, table stringx.String, in []*parser.Field) Key {
|
||||
var (
|
||||
varLeftJoin, varRightJon, fieldNameJoin Join
|
||||
varLeft, varRight, varExpression string
|
||||
@@ -59,9 +59,9 @@ func genCacheKey(table stringx.String, in []*parser.Field) Key {
|
||||
keyLeft, keyRight, dataKeyRight, keyExpression, dataKeyExpression string
|
||||
)
|
||||
|
||||
varLeftJoin = append(varLeftJoin, "cache", table.Source())
|
||||
varRightJon = append(varRightJon, "cache", table.Source())
|
||||
keyLeftJoin = append(keyLeftJoin, table.Source())
|
||||
varLeftJoin = append(varLeftJoin, "cache", db.Source(), table.Source())
|
||||
varRightJon = append(varRightJon, "cache", db.Source(), table.Source())
|
||||
keyLeftJoin = append(keyLeftJoin, db.Source(), table.Source())
|
||||
|
||||
for _, each := range in {
|
||||
varLeftJoin = append(varLeftJoin, each.Name.Source())
|
||||
@@ -76,12 +76,12 @@ func genCacheKey(table stringx.String, in []*parser.Field) Key {
|
||||
keyLeftJoin = append(keyLeftJoin, "key")
|
||||
|
||||
varLeft = varLeftJoin.Camel().With("").Untitle()
|
||||
varRight = fmt.Sprintf(`"%s"`, varRightJon.Camel().Untitle().With("#").Source()+"#")
|
||||
varRight = fmt.Sprintf(`"%s"`, varRightJon.Camel().Untitle().With(":").Source()+":")
|
||||
varExpression = fmt.Sprintf(`%s = %s`, varLeft, varRight)
|
||||
|
||||
keyLeft = keyLeftJoin.Camel().With("").Untitle()
|
||||
keyRight = fmt.Sprintf(`fmt.Sprintf("%s%s", %s, %s)`, "%s", keyRightArgJoin.With("").Source(), varLeft, keyRightJoin.With(", ").Source())
|
||||
dataKeyRight = fmt.Sprintf(`fmt.Sprintf("%s%s", %s, %s)`, "%s", keyRightArgJoin.With("").Source(), varLeft, dataRightJoin.With(", ").Source())
|
||||
keyRight = fmt.Sprintf(`fmt.Sprintf("%s%s", %s, %s)`, "%s", keyRightArgJoin.With(":").Source(), varLeft, keyRightJoin.With(", ").Source())
|
||||
dataKeyRight = fmt.Sprintf(`fmt.Sprintf("%s%s", %s, %s)`, "%s", keyRightArgJoin.With(":").Source(), varLeft, dataRightJoin.With(", ").Source())
|
||||
keyExpression = fmt.Sprintf("%s := %s", keyLeft, keyRight)
|
||||
dataKeyExpression = fmt.Sprintf("%s := %s", keyLeft, dataKeyRight)
|
||||
|
||||
|
||||
@@ -11,35 +11,32 @@ import (
|
||||
|
||||
func TestGenCacheKeys(t *testing.T) {
|
||||
primaryField := &parser.Field{
|
||||
Name: stringx.From("id"),
|
||||
DataBaseType: "bigint",
|
||||
DataType: "int64",
|
||||
Comment: "自增id",
|
||||
SeqInIndex: 1,
|
||||
Name: stringx.From("id"),
|
||||
DataType: "int64",
|
||||
Comment: "自增id",
|
||||
SeqInIndex: 1,
|
||||
}
|
||||
mobileField := &parser.Field{
|
||||
Name: stringx.From("mobile"),
|
||||
DataBaseType: "varchar",
|
||||
DataType: "string",
|
||||
Comment: "手机号",
|
||||
SeqInIndex: 1,
|
||||
Name: stringx.From("mobile"),
|
||||
DataType: "string",
|
||||
Comment: "手机号",
|
||||
SeqInIndex: 1,
|
||||
}
|
||||
classField := &parser.Field{
|
||||
Name: stringx.From("class"),
|
||||
DataBaseType: "varchar",
|
||||
DataType: "string",
|
||||
Comment: "班级",
|
||||
SeqInIndex: 1,
|
||||
Name: stringx.From("class"),
|
||||
DataType: "string",
|
||||
Comment: "班级",
|
||||
SeqInIndex: 1,
|
||||
}
|
||||
nameField := &parser.Field{
|
||||
Name: stringx.From("name"),
|
||||
DataBaseType: "varchar",
|
||||
DataType: "string",
|
||||
Comment: "姓名",
|
||||
SeqInIndex: 2,
|
||||
Name: stringx.From("name"),
|
||||
DataType: "string",
|
||||
Comment: "姓名",
|
||||
SeqInIndex: 2,
|
||||
}
|
||||
primariCacheKey, uniqueCacheKey := genCacheKeys(parser.Table{
|
||||
Name: stringx.From("user"),
|
||||
Db: stringx.From("go_zero"),
|
||||
PrimaryKey: parser.Primary{
|
||||
Field: *primaryField,
|
||||
AutoIncrement: true,
|
||||
@@ -53,23 +50,20 @@ func TestGenCacheKeys(t *testing.T) {
|
||||
nameField,
|
||||
},
|
||||
},
|
||||
NormalIndex: nil,
|
||||
Fields: []*parser.Field{
|
||||
primaryField,
|
||||
mobileField,
|
||||
classField,
|
||||
nameField,
|
||||
{
|
||||
Name: stringx.From("createTime"),
|
||||
DataBaseType: "timestamp",
|
||||
DataType: "time.Time",
|
||||
Comment: "创建时间",
|
||||
Name: stringx.From("createTime"),
|
||||
DataType: "time.Time",
|
||||
Comment: "创建时间",
|
||||
},
|
||||
{
|
||||
Name: stringx.From("updateTime"),
|
||||
DataBaseType: "timestamp",
|
||||
DataType: "time.Time",
|
||||
Comment: "更新时间",
|
||||
Name: stringx.From("updateTime"),
|
||||
DataType: "time.Time",
|
||||
Comment: "更新时间",
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -77,14 +71,14 @@ func TestGenCacheKeys(t *testing.T) {
|
||||
t.Run("primaryCacheKey", func(t *testing.T) {
|
||||
assert.Equal(t, true, func() bool {
|
||||
return cacheKeyEqual(primariCacheKey, Key{
|
||||
VarLeft: "cacheUserIdPrefix",
|
||||
VarRight: `"cache#user#id#"`,
|
||||
VarExpression: `cacheUserIdPrefix = "cache#user#id#"`,
|
||||
KeyLeft: "userIdKey",
|
||||
KeyRight: `fmt.Sprintf("%s%v", cacheUserIdPrefix, id)`,
|
||||
DataKeyRight: `fmt.Sprintf("%s%v", cacheUserIdPrefix, data.Id)`,
|
||||
KeyExpression: `userIdKey := fmt.Sprintf("%s%v", cacheUserIdPrefix, id)`,
|
||||
DataKeyExpression: `userIdKey := fmt.Sprintf("%s%v", cacheUserIdPrefix, data.Id)`,
|
||||
VarLeft: "cacheGoZeroUserIdPrefix",
|
||||
VarRight: `"cache:goZero:user:id:"`,
|
||||
VarExpression: `cacheGoZeroUserIdPrefix = "cache:goZero:user:id:"`,
|
||||
KeyLeft: "goZeroUserIdKey",
|
||||
KeyRight: `fmt.Sprintf("%s%v", cacheGoZeroUserIdPrefix, id)`,
|
||||
DataKeyRight: `fmt.Sprintf("%s%v", cacheGoZeroUserIdPrefix, data.Id)`,
|
||||
KeyExpression: `goZeroUserIdKey := fmt.Sprintf("%s%v", cacheGoZeroUserIdPrefix, id)`,
|
||||
DataKeyExpression: `goZeroUserIdKey := fmt.Sprintf("%s%v", cacheGoZeroUserIdPrefix, data.Id)`,
|
||||
FieldNameJoin: []string{"id"},
|
||||
})
|
||||
}())
|
||||
@@ -94,25 +88,25 @@ func TestGenCacheKeys(t *testing.T) {
|
||||
assert.Equal(t, true, func() bool {
|
||||
expected := []Key{
|
||||
{
|
||||
VarLeft: "cacheUserClassNamePrefix",
|
||||
VarRight: `"cache#user#class#name#"`,
|
||||
VarExpression: `cacheUserClassNamePrefix = "cache#user#class#name#"`,
|
||||
KeyLeft: "userClassNameKey",
|
||||
KeyRight: `fmt.Sprintf("%s%v%v", cacheUserClassNamePrefix, class, name)`,
|
||||
DataKeyRight: `fmt.Sprintf("%s%v%v", cacheUserClassNamePrefix, data.Class, data.Name)`,
|
||||
KeyExpression: `userClassNameKey := fmt.Sprintf("%s%v%v", cacheUserClassNamePrefix, class, name)`,
|
||||
DataKeyExpression: `userClassNameKey := fmt.Sprintf("%s%v%v", cacheUserClassNamePrefix, data.Class, data.Name)`,
|
||||
VarLeft: "cacheGoZeroUserClassNamePrefix",
|
||||
VarRight: `"cache:goZero:user:class:name:"`,
|
||||
VarExpression: `cacheGoZeroUserClassNamePrefix = "cache:goZero:user:class:name:"`,
|
||||
KeyLeft: "goZeroUserClassNameKey",
|
||||
KeyRight: `fmt.Sprintf("%s%v:%v", cacheGoZeroUserClassNamePrefix, class, name)`,
|
||||
DataKeyRight: `fmt.Sprintf("%s%v:%v", cacheGoZeroUserClassNamePrefix, data.Class, data.Name)`,
|
||||
KeyExpression: `goZeroUserClassNameKey := fmt.Sprintf("%s%v:%v", cacheGoZeroUserClassNamePrefix, class, name)`,
|
||||
DataKeyExpression: `goZeroUserClassNameKey := fmt.Sprintf("%s%v:%v", cacheGoZeroUserClassNamePrefix, data.Class, data.Name)`,
|
||||
FieldNameJoin: []string{"class", "name"},
|
||||
},
|
||||
{
|
||||
VarLeft: "cacheUserMobilePrefix",
|
||||
VarRight: `"cache#user#mobile#"`,
|
||||
VarExpression: `cacheUserMobilePrefix = "cache#user#mobile#"`,
|
||||
KeyLeft: "userMobileKey",
|
||||
KeyRight: `fmt.Sprintf("%s%v", cacheUserMobilePrefix, mobile)`,
|
||||
DataKeyRight: `fmt.Sprintf("%s%v", cacheUserMobilePrefix, data.Mobile)`,
|
||||
KeyExpression: `userMobileKey := fmt.Sprintf("%s%v", cacheUserMobilePrefix, mobile)`,
|
||||
DataKeyExpression: `userMobileKey := fmt.Sprintf("%s%v", cacheUserMobilePrefix, data.Mobile)`,
|
||||
VarLeft: "cacheGoZeroUserMobilePrefix",
|
||||
VarRight: `"cache:goZero:user:mobile:"`,
|
||||
VarExpression: `cacheGoZeroUserMobilePrefix = "cache:goZero:user:mobile:"`,
|
||||
KeyLeft: "goZeroUserMobileKey",
|
||||
KeyRight: `fmt.Sprintf("%s%v", cacheGoZeroUserMobilePrefix, mobile)`,
|
||||
DataKeyRight: `fmt.Sprintf("%s%v", cacheGoZeroUserMobilePrefix, data.Mobile)`,
|
||||
KeyExpression: `goZeroUserMobileKey := fmt.Sprintf("%s%v", cacheGoZeroUserMobilePrefix, mobile)`,
|
||||
DataKeyExpression: `goZeroUserMobileKey := fmt.Sprintf("%s%v", cacheGoZeroUserMobilePrefix, data.Mobile)`,
|
||||
FieldNameJoin: []string{"mobile"},
|
||||
},
|
||||
}
|
||||
@@ -136,7 +130,7 @@ func TestGenCacheKeys(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func cacheKeyEqual(k1 Key, k2 Key) bool {
|
||||
func cacheKeyEqual(k1, k2 Key) bool {
|
||||
k1Join := k1.FieldNameJoin
|
||||
k2Join := k2.FieldNameJoin
|
||||
sort.Strings(k1Join)
|
||||
|
||||
@@ -1,20 +1,27 @@
|
||||
package gen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/model/sql/template"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
)
|
||||
|
||||
func genNew(table Table, withCache bool) (string, error) {
|
||||
func genNew(table Table, withCache, postgreSql bool) (string, error) {
|
||||
text, err := util.LoadTemplate(category, modelNewTemplateFile, template.New)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
t := fmt.Sprintf(`"%s"`, wrapWithRawString(table.Name.Source(), postgreSql))
|
||||
if postgreSql {
|
||||
t = "`" + fmt.Sprintf(`"%s"."%s"`, table.Db.Source(), table.Name.Source()) + "`"
|
||||
}
|
||||
|
||||
output, err := util.With("new").
|
||||
Parse(text).
|
||||
Execute(map[string]interface{}{
|
||||
"table": wrapWithRawString(table.Name.Source()),
|
||||
"table": t,
|
||||
"withCache": withCache,
|
||||
"upperStartCamelObject": table.Name.ToCamel(),
|
||||
})
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/stringx"
|
||||
)
|
||||
|
||||
func genUpdate(table Table, withCache bool) (string, string, error) {
|
||||
func genUpdate(table Table, withCache, postgreSql bool) (string, string, error) {
|
||||
expressionValues := make([]string, 0)
|
||||
for _, field := range table.Fields {
|
||||
camel := field.Name.ToCamel()
|
||||
@@ -50,8 +50,9 @@ func genUpdate(table Table, withCache bool) (string, string, error) {
|
||||
"primaryCacheKey": table.PrimaryCacheKey.DataKeyExpression,
|
||||
"primaryKeyVariable": table.PrimaryCacheKey.KeyLeft,
|
||||
"lowerStartCamelObject": stringx.From(camelTableName).Untitle(),
|
||||
"originalPrimaryKey": wrapWithRawString(table.PrimaryKey.Name.Source()),
|
||||
"originalPrimaryKey": wrapWithRawString(table.PrimaryKey.Name.Source(), postgreSql),
|
||||
"expressionValues": strings.Join(expressionValues, ", "),
|
||||
"postgreSql": postgreSql,
|
||||
})
|
||||
if err != nil {
|
||||
return "", "", nil
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/stringx"
|
||||
)
|
||||
|
||||
func genVars(table Table, withCache bool) (string, error) {
|
||||
func genVars(table Table, withCache, postgreSql bool) (string, error) {
|
||||
keys := make([]string, 0)
|
||||
keys = append(keys, table.PrimaryCacheKey.VarExpression)
|
||||
for _, v := range table.UniqueCacheKey {
|
||||
@@ -27,8 +27,9 @@ func genVars(table Table, withCache bool) (string, error) {
|
||||
"upperStartCamelObject": camel,
|
||||
"cacheKeys": strings.Join(keys, "\n"),
|
||||
"autoIncrement": table.PrimaryKey.AutoIncrement,
|
||||
"originalPrimaryKey": wrapWithRawString(table.PrimaryKey.Name.Source()),
|
||||
"originalPrimaryKey": wrapWithRawString(table.PrimaryKey.Name.Source(), postgreSql),
|
||||
"withCache": withCache,
|
||||
"postgreSql": postgreSql,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"sort"
|
||||
|
||||
"github.com/tal-tech/go-zero/core/stores/sqlx"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/model/sql/util"
|
||||
)
|
||||
|
||||
const indexPri = "PRIMARY"
|
||||
@@ -151,6 +152,7 @@ func (c *ColumnData) Convert() (*Table, error) {
|
||||
|
||||
m := make(map[string][]*Column)
|
||||
for _, each := range c.Columns {
|
||||
each.Comment = util.TrimNewLine(each.Comment)
|
||||
if each.Index != nil {
|
||||
m[each.Index.IndexName] = append(m[each.Index.IndexName], each)
|
||||
}
|
||||
|
||||
234
tools/goctl/model/sql/model/postgresqlmodel.go
Normal file
234
tools/goctl/model/sql/model/postgresqlmodel.go
Normal file
@@ -0,0 +1,234 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"strings"
|
||||
|
||||
"github.com/tal-tech/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
var (
|
||||
p2m = map[string]string{
|
||||
"int8": "bigint",
|
||||
"numeric": "bigint",
|
||||
"float8": "double",
|
||||
"float4": "float",
|
||||
"int2": "smallint",
|
||||
"int4": "integer",
|
||||
}
|
||||
)
|
||||
|
||||
// PostgreSqlModel gets table information from information_schema、pg_catalog
|
||||
type PostgreSqlModel struct {
|
||||
conn sqlx.SqlConn
|
||||
}
|
||||
|
||||
// PostgreColumn describes a column in table
|
||||
type PostgreColumn struct {
|
||||
Num sql.NullInt32 `db:"num"`
|
||||
Field sql.NullString `db:"field"`
|
||||
Type sql.NullString `db:"type"`
|
||||
NotNull sql.NullBool `db:"not_null"`
|
||||
Comment sql.NullString `db:"comment"`
|
||||
ColumnDefault sql.NullString `db:"column_default"`
|
||||
IdentityIncrement sql.NullInt32 `db:"identity_increment"`
|
||||
}
|
||||
|
||||
// PostgreIndex describes an index for a column
|
||||
type PostgreIndex struct {
|
||||
IndexName sql.NullString `db:"index_name"`
|
||||
IndexId sql.NullInt32 `db:"index_id"`
|
||||
IsUnique sql.NullBool `db:"is_unique"`
|
||||
IsPrimary sql.NullBool `db:"is_primary"`
|
||||
ColumnName sql.NullString `db:"column_name"`
|
||||
IndexSort sql.NullInt32 `db:"index_sort"`
|
||||
}
|
||||
|
||||
// NewPostgreSqlModel creates an instance and return
|
||||
func NewPostgreSqlModel(conn sqlx.SqlConn) *PostgreSqlModel {
|
||||
return &PostgreSqlModel{
|
||||
conn: conn,
|
||||
}
|
||||
}
|
||||
|
||||
// GetAllTables selects all tables from TABLE_SCHEMA
|
||||
func (m *PostgreSqlModel) GetAllTables(schema string) ([]string, error) {
|
||||
query := `select table_name from information_schema.tables where table_schema = $1`
|
||||
var tables []string
|
||||
err := m.conn.QueryRows(&tables, query, schema)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tables, nil
|
||||
}
|
||||
|
||||
// FindColumns return columns in specified database and table
|
||||
func (m *PostgreSqlModel) FindColumns(schema, table string) (*ColumnData, error) {
|
||||
querySql := `select t.num,t.field,t.type,t.not_null,t.comment, c.column_default, identity_increment
|
||||
from (
|
||||
SELECT a.attnum AS num,
|
||||
c.relname,
|
||||
a.attname AS field,
|
||||
t.typname AS type,
|
||||
a.atttypmod AS lengthvar,
|
||||
a.attnotnull AS not_null,
|
||||
b.description AS comment
|
||||
FROM pg_class c,
|
||||
pg_attribute a
|
||||
LEFT OUTER JOIN pg_description b ON a.attrelid = b.objoid AND a.attnum = b.objsubid,
|
||||
pg_type t
|
||||
WHERE c.relname = $1
|
||||
and a.attnum > 0
|
||||
and a.attrelid = c.oid
|
||||
and a.atttypid = t.oid
|
||||
ORDER BY a.attnum) AS t
|
||||
left join information_schema.columns AS c on t.relname = c.table_name
|
||||
and t.field = c.column_name and c.table_schema = $2`
|
||||
|
||||
var reply []*PostgreColumn
|
||||
err := m.conn.QueryRowsPartial(&reply, querySql, table, schema)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
list, err := m.getColumns(schema, table, reply)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var columnData ColumnData
|
||||
columnData.Db = schema
|
||||
columnData.Table = table
|
||||
columnData.Columns = list
|
||||
return &columnData, nil
|
||||
}
|
||||
|
||||
func (m *PostgreSqlModel) getColumns(schema, table string, in []*PostgreColumn) ([]*Column, error) {
|
||||
index, err := m.getIndex(schema, table)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var list []*Column
|
||||
for _, e := range in {
|
||||
var dft interface{}
|
||||
if len(e.ColumnDefault.String) > 0 {
|
||||
dft = e.ColumnDefault
|
||||
}
|
||||
|
||||
isNullAble := "YES"
|
||||
if e.NotNull.Bool {
|
||||
isNullAble = "NO"
|
||||
}
|
||||
|
||||
extra := "auto_increment"
|
||||
if e.IdentityIncrement.Int32 != 1 {
|
||||
extra = ""
|
||||
}
|
||||
|
||||
if len(index[e.Field.String]) > 0 {
|
||||
for _, i := range index[e.Field.String] {
|
||||
list = append(list, &Column{
|
||||
DbColumn: &DbColumn{
|
||||
Name: e.Field.String,
|
||||
DataType: m.convertPostgreSqlTypeIntoMysqlType(e.Type.String),
|
||||
Extra: extra,
|
||||
Comment: e.Comment.String,
|
||||
ColumnDefault: dft,
|
||||
IsNullAble: isNullAble,
|
||||
OrdinalPosition: int(e.Num.Int32),
|
||||
},
|
||||
Index: i,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
list = append(list, &Column{
|
||||
DbColumn: &DbColumn{
|
||||
Name: e.Field.String,
|
||||
DataType: m.convertPostgreSqlTypeIntoMysqlType(e.Type.String),
|
||||
Extra: extra,
|
||||
Comment: e.Comment.String,
|
||||
ColumnDefault: dft,
|
||||
IsNullAble: isNullAble,
|
||||
OrdinalPosition: int(e.Num.Int32),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func (m *PostgreSqlModel) convertPostgreSqlTypeIntoMysqlType(in string) string {
|
||||
r, ok := p2m[strings.ToLower(in)]
|
||||
if ok {
|
||||
return r
|
||||
}
|
||||
|
||||
return in
|
||||
}
|
||||
|
||||
func (m *PostgreSqlModel) getIndex(schema, table string) (map[string][]*DbIndex, error) {
|
||||
indexes, err := m.FindIndex(schema, table)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var index = make(map[string][]*DbIndex)
|
||||
for _, e := range indexes {
|
||||
if e.IsPrimary.Bool {
|
||||
index[e.ColumnName.String] = append(index[e.ColumnName.String], &DbIndex{
|
||||
IndexName: indexPri,
|
||||
SeqInIndex: int(e.IndexSort.Int32),
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
nonUnique := 0
|
||||
if !e.IsUnique.Bool {
|
||||
nonUnique = 1
|
||||
}
|
||||
|
||||
index[e.ColumnName.String] = append(index[e.ColumnName.String], &DbIndex{
|
||||
IndexName: e.IndexName.String,
|
||||
NonUnique: nonUnique,
|
||||
SeqInIndex: int(e.IndexSort.Int32),
|
||||
})
|
||||
}
|
||||
return index, nil
|
||||
}
|
||||
|
||||
// FindIndex finds index with given schema, table and column.
|
||||
func (m *PostgreSqlModel) FindIndex(schema, table string) ([]*PostgreIndex, error) {
|
||||
querySql := `select A.INDEXNAME AS index_name,
|
||||
C.INDEXRELID AS index_id,
|
||||
C.INDISUNIQUE AS is_unique,
|
||||
C.INDISPRIMARY AS is_primary,
|
||||
G.ATTNAME AS column_name,
|
||||
G.attnum AS index_sort
|
||||
from PG_AM B
|
||||
left join PG_CLASS F on
|
||||
B.OID = F.RELAM
|
||||
left join PG_STAT_ALL_INDEXES E on
|
||||
F.OID = E.INDEXRELID
|
||||
left join PG_INDEX C on
|
||||
E.INDEXRELID = C.INDEXRELID
|
||||
left outer join PG_DESCRIPTION D on
|
||||
C.INDEXRELID = D.OBJOID,
|
||||
PG_INDEXES A,
|
||||
pg_attribute G
|
||||
where A.SCHEMANAME = E.SCHEMANAME
|
||||
and A.TABLENAME = E.RELNAME
|
||||
and A.INDEXNAME = E.INDEXRELNAME
|
||||
and F.oid = G.attrelid
|
||||
and E.SCHEMANAME = $1
|
||||
and E.RELNAME = $2
|
||||
order by C.INDEXRELID,G.attnum`
|
||||
|
||||
var reply []*PostgreIndex
|
||||
err := m.conn.QueryRowsPartial(&reply, querySql, schema, table)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
errUnsupportDDL = errors.New("unexpected type")
|
||||
errTableBodyNotFound = errors.New("create table spec not found")
|
||||
errPrimaryKey = errors.New("unexpected join primary key")
|
||||
)
|
||||
@@ -2,15 +2,17 @@ package parser
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/tal-tech/go-zero/core/collection"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/model/sql/converter"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/model/sql/model"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/model/sql/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/console"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/stringx"
|
||||
"github.com/xwb1989/sqlparser"
|
||||
"github.com/zeromicro/ddl-parser/parser"
|
||||
)
|
||||
|
||||
const timeImport = "time.Time"
|
||||
@@ -19,9 +21,9 @@ type (
|
||||
// Table describes a mysql table
|
||||
Table struct {
|
||||
Name stringx.String
|
||||
Db stringx.String
|
||||
PrimaryKey Primary
|
||||
UniqueIndex map[string][]*Field
|
||||
NormalIndex map[string][]*Field
|
||||
Fields []*Field
|
||||
}
|
||||
|
||||
@@ -34,7 +36,6 @@ type (
|
||||
// Field describes a table field
|
||||
Field struct {
|
||||
Name stringx.String
|
||||
DataBaseType string
|
||||
DataType string
|
||||
Comment string
|
||||
SeqInIndex int
|
||||
@@ -46,73 +47,116 @@ type (
|
||||
)
|
||||
|
||||
// Parse parses ddl into golang structure
|
||||
func Parse(ddl string) (*Table, error) {
|
||||
stmt, err := sqlparser.ParseStrictDDL(ddl)
|
||||
func Parse(filename string, database string) ([]*Table, error) {
|
||||
p := parser.NewParser()
|
||||
tables, err := p.From(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ddlStmt, ok := stmt.(*sqlparser.DDL)
|
||||
if !ok {
|
||||
return nil, errUnsupportDDL
|
||||
indexNameGen := func(column ...string) string {
|
||||
return strings.Join(column, "_")
|
||||
}
|
||||
|
||||
action := ddlStmt.Action
|
||||
if action != sqlparser.CreateStr {
|
||||
return nil, fmt.Errorf("expected [CREATE] action,but found: %s", action)
|
||||
}
|
||||
prefix := filepath.Base(filename)
|
||||
var list []*Table
|
||||
for _, e := range tables {
|
||||
columns := e.Columns
|
||||
|
||||
tableName := ddlStmt.NewName.Name.String()
|
||||
tableSpec := ddlStmt.TableSpec
|
||||
if tableSpec == nil {
|
||||
return nil, errTableBodyNotFound
|
||||
}
|
||||
var (
|
||||
primaryColumnSet = collection.NewSet()
|
||||
|
||||
columns := tableSpec.Columns
|
||||
indexes := tableSpec.Indexes
|
||||
primaryColumn, uniqueKeyMap, normalKeyMap, err := convertIndexes(indexes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
primaryColumn string
|
||||
uniqueKeyMap = make(map[string][]string)
|
||||
normalKeyMap = make(map[string][]string)
|
||||
)
|
||||
|
||||
primaryKey, fieldM, err := convertColumns(columns, primaryColumn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, column := range columns {
|
||||
if column.Constraint != nil {
|
||||
if column.Constraint.Primary {
|
||||
primaryColumnSet.AddStr(column.Name)
|
||||
}
|
||||
|
||||
var fields []*Field
|
||||
for _, e := range fieldM {
|
||||
fields = append(fields, e)
|
||||
}
|
||||
if column.Constraint.Unique {
|
||||
indexName := indexNameGen(column.Name, "unique")
|
||||
uniqueKeyMap[indexName] = []string{column.Name}
|
||||
}
|
||||
|
||||
var (
|
||||
uniqueIndex = make(map[string][]*Field)
|
||||
normalIndex = make(map[string][]*Field)
|
||||
)
|
||||
|
||||
for indexName, each := range uniqueKeyMap {
|
||||
for _, columnName := range each {
|
||||
uniqueIndex[indexName] = append(uniqueIndex[indexName], fieldM[columnName])
|
||||
if column.Constraint.Key {
|
||||
indexName := indexNameGen(column.Name, "idx")
|
||||
uniqueKeyMap[indexName] = []string{column.Name}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for indexName, each := range normalKeyMap {
|
||||
for _, columnName := range each {
|
||||
normalIndex[indexName] = append(normalIndex[indexName], fieldM[columnName])
|
||||
for _, e := range e.Constraints {
|
||||
if len(e.ColumnPrimaryKey) > 1 {
|
||||
return nil, fmt.Errorf("%s: unexpected join primary key", prefix)
|
||||
}
|
||||
|
||||
if len(e.ColumnPrimaryKey) == 1 {
|
||||
primaryColumn = e.ColumnPrimaryKey[0]
|
||||
primaryColumnSet.AddStr(e.ColumnPrimaryKey[0])
|
||||
}
|
||||
|
||||
if len(e.ColumnUniqueKey) > 0 {
|
||||
list := append([]string(nil), e.ColumnUniqueKey...)
|
||||
list = append(list, "unique")
|
||||
indexName := indexNameGen(list...)
|
||||
uniqueKeyMap[indexName] = e.ColumnUniqueKey
|
||||
}
|
||||
}
|
||||
|
||||
if primaryColumnSet.Count() > 1 {
|
||||
return nil, fmt.Errorf("%s: unexpected join primary key", prefix)
|
||||
}
|
||||
|
||||
primaryKey, fieldM, err := convertColumns(columns, primaryColumn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var fields []*Field
|
||||
// sort
|
||||
for _, c := range columns {
|
||||
field, ok := fieldM[c.Name]
|
||||
if ok {
|
||||
fields = append(fields, field)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
uniqueIndex = make(map[string][]*Field)
|
||||
normalIndex = make(map[string][]*Field)
|
||||
)
|
||||
|
||||
for indexName, each := range uniqueKeyMap {
|
||||
for _, columnName := range each {
|
||||
uniqueIndex[indexName] = append(uniqueIndex[indexName], fieldM[columnName])
|
||||
}
|
||||
}
|
||||
|
||||
for indexName, each := range normalKeyMap {
|
||||
for _, columnName := range each {
|
||||
normalIndex[indexName] = append(normalIndex[indexName], fieldM[columnName])
|
||||
}
|
||||
}
|
||||
|
||||
checkDuplicateUniqueIndex(uniqueIndex, e.Name)
|
||||
|
||||
list = append(list, &Table{
|
||||
Name: stringx.From(e.Name),
|
||||
Db: stringx.From(database),
|
||||
PrimaryKey: primaryKey,
|
||||
UniqueIndex: uniqueIndex,
|
||||
Fields: fields,
|
||||
})
|
||||
}
|
||||
|
||||
checkDuplicateUniqueIndex(uniqueIndex, tableName, normalIndex)
|
||||
return &Table{
|
||||
Name: stringx.From(tableName),
|
||||
PrimaryKey: primaryKey,
|
||||
UniqueIndex: uniqueIndex,
|
||||
NormalIndex: normalIndex,
|
||||
Fields: fields,
|
||||
}, nil
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func checkDuplicateUniqueIndex(uniqueIndex map[string][]*Field, tableName string, normalIndex map[string][]*Field) {
|
||||
func checkDuplicateUniqueIndex(uniqueIndex map[string][]*Field, tableName string) {
|
||||
log := console.NewColorConsole()
|
||||
uniqueSet := collection.NewSet()
|
||||
for k, i := range uniqueIndex {
|
||||
@@ -130,26 +174,9 @@ func checkDuplicateUniqueIndex(uniqueIndex map[string][]*Field, tableName string
|
||||
|
||||
uniqueSet.AddStr(joinRet)
|
||||
}
|
||||
|
||||
normalIndexSet := collection.NewSet()
|
||||
for k, i := range normalIndex {
|
||||
var list []string
|
||||
for _, e := range i {
|
||||
list = append(list, e.Name.Source())
|
||||
}
|
||||
|
||||
joinRet := strings.Join(list, ",")
|
||||
if normalIndexSet.Contains(joinRet) {
|
||||
log.Warning("table %s: duplicate index %s", tableName, joinRet)
|
||||
delete(normalIndex, k)
|
||||
continue
|
||||
}
|
||||
|
||||
normalIndexSet.Add(joinRet)
|
||||
}
|
||||
}
|
||||
|
||||
func convertColumns(columns []*sqlparser.ColumnDefinition, primaryColumn string) (Primary, map[string]*Field, error) {
|
||||
func convertColumns(columns []*parser.Column, primaryColumn string) (Primary, map[string]*Field, error) {
|
||||
var (
|
||||
primaryKey Primary
|
||||
fieldM = make(map[string]*Field)
|
||||
@@ -160,37 +187,35 @@ func convertColumns(columns []*sqlparser.ColumnDefinition, primaryColumn string)
|
||||
continue
|
||||
}
|
||||
|
||||
var comment string
|
||||
if column.Type.Comment != nil {
|
||||
comment = string(column.Type.Comment.Val)
|
||||
}
|
||||
var (
|
||||
comment string
|
||||
isDefaultNull bool
|
||||
)
|
||||
|
||||
isDefaultNull := true
|
||||
if column.Type.NotNull {
|
||||
isDefaultNull = false
|
||||
} else {
|
||||
if column.Type.Default == nil {
|
||||
isDefaultNull = false
|
||||
} else if string(column.Type.Default.Val) != "null" {
|
||||
if column.Constraint != nil {
|
||||
comment = column.Constraint.Comment
|
||||
isDefaultNull = !column.Constraint.HasDefaultValue
|
||||
if column.Name == primaryColumn && column.Constraint.AutoIncrement {
|
||||
isDefaultNull = false
|
||||
}
|
||||
}
|
||||
|
||||
dataType, err := converter.ConvertDataType(column.Type.Type, isDefaultNull)
|
||||
dataType, err := converter.ConvertDataType(column.DataType.Type(), isDefaultNull)
|
||||
if err != nil {
|
||||
return Primary{}, nil, err
|
||||
}
|
||||
|
||||
var field Field
|
||||
field.Name = stringx.From(column.Name.String())
|
||||
field.DataBaseType = column.Type.Type
|
||||
field.Name = stringx.From(column.Name)
|
||||
field.DataType = dataType
|
||||
field.Comment = comment
|
||||
field.Comment = util.TrimNewLine(comment)
|
||||
|
||||
if field.Name.Source() == primaryColumn {
|
||||
primaryKey = Primary{
|
||||
Field: field,
|
||||
AutoIncrement: bool(column.Type.Autoincrement),
|
||||
Field: field,
|
||||
}
|
||||
if column.Constraint != nil {
|
||||
primaryKey.AutoIncrement = column.Constraint.AutoIncrement
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,60 +224,6 @@ func convertColumns(columns []*sqlparser.ColumnDefinition, primaryColumn string)
|
||||
return primaryKey, fieldM, nil
|
||||
}
|
||||
|
||||
func convertIndexes(indexes []*sqlparser.IndexDefinition) (string, map[string][]string, map[string][]string, error) {
|
||||
var primaryColumn string
|
||||
uniqueKeyMap := make(map[string][]string)
|
||||
normalKeyMap := make(map[string][]string)
|
||||
|
||||
isCreateTimeOrUpdateTime := func(name string) bool {
|
||||
camelColumnName := stringx.From(name).ToCamel()
|
||||
// by default, createTime|updateTime findOne is not used.
|
||||
return camelColumnName == "CreateTime" || camelColumnName == "UpdateTime"
|
||||
}
|
||||
|
||||
for _, index := range indexes {
|
||||
info := index.Info
|
||||
if info == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
indexName := index.Info.Name.String()
|
||||
if info.Primary {
|
||||
if len(index.Columns) > 1 {
|
||||
return "", nil, nil, errPrimaryKey
|
||||
}
|
||||
columnName := index.Columns[0].Column.String()
|
||||
if isCreateTimeOrUpdateTime(columnName) {
|
||||
continue
|
||||
}
|
||||
|
||||
primaryColumn = columnName
|
||||
continue
|
||||
} else if info.Unique {
|
||||
for _, each := range index.Columns {
|
||||
columnName := each.Column.String()
|
||||
if isCreateTimeOrUpdateTime(columnName) {
|
||||
break
|
||||
}
|
||||
|
||||
uniqueKeyMap[indexName] = append(uniqueKeyMap[indexName], columnName)
|
||||
}
|
||||
} else if info.Spatial {
|
||||
// do nothing
|
||||
} else {
|
||||
for _, each := range index.Columns {
|
||||
columnName := each.Column.String()
|
||||
if isCreateTimeOrUpdateTime(columnName) {
|
||||
break
|
||||
}
|
||||
|
||||
normalKeyMap[indexName] = append(normalKeyMap[indexName], each.Column.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
return primaryColumn, uniqueKeyMap, normalKeyMap, nil
|
||||
}
|
||||
|
||||
// ContainsTime returns true if contains golang type time.Time
|
||||
func (t *Table) ContainsTime() bool {
|
||||
for _, item := range t.Fields {
|
||||
@@ -266,15 +237,15 @@ func (t *Table) ContainsTime() bool {
|
||||
// ConvertDataType converts mysql data type into golang data type
|
||||
func ConvertDataType(table *model.Table) (*Table, error) {
|
||||
isPrimaryDefaultNull := table.PrimaryKey.ColumnDefault == nil && table.PrimaryKey.IsNullAble == "YES"
|
||||
primaryDataType, err := converter.ConvertDataType(table.PrimaryKey.DataType, isPrimaryDefaultNull)
|
||||
primaryDataType, err := converter.ConvertStringDataType(table.PrimaryKey.DataType, isPrimaryDefaultNull)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var reply Table
|
||||
reply.UniqueIndex = map[string][]*Field{}
|
||||
reply.NormalIndex = map[string][]*Field{}
|
||||
reply.Name = stringx.From(table.Table)
|
||||
reply.Db = stringx.From(table.Db)
|
||||
seqInIndex := 0
|
||||
if table.PrimaryKey.Index != nil {
|
||||
seqInIndex = table.PrimaryKey.Index.SeqInIndex
|
||||
@@ -283,7 +254,6 @@ func ConvertDataType(table *model.Table) (*Table, error) {
|
||||
reply.PrimaryKey = Primary{
|
||||
Field: Field{
|
||||
Name: stringx.From(table.PrimaryKey.Name),
|
||||
DataBaseType: table.PrimaryKey.DataType,
|
||||
DataType: primaryDataType,
|
||||
Comment: table.PrimaryKey.Comment,
|
||||
SeqInIndex: seqInIndex,
|
||||
@@ -339,29 +309,6 @@ func ConvertDataType(table *model.Table) (*Table, error) {
|
||||
reply.UniqueIndex[indexName] = list
|
||||
}
|
||||
|
||||
normalIndexSet := collection.NewSet()
|
||||
for indexName, each := range table.NormalIndex {
|
||||
var list []*Field
|
||||
var normalJoin []string
|
||||
for _, c := range each {
|
||||
list = append(list, fieldM[c.Name])
|
||||
normalJoin = append(normalJoin, c.Name)
|
||||
}
|
||||
|
||||
normalKey := strings.Join(normalJoin, ",")
|
||||
if normalIndexSet.Contains(normalKey) {
|
||||
log.Warning("table %s: duplicate index, %s", table.Table, normalKey)
|
||||
continue
|
||||
}
|
||||
|
||||
normalIndexSet.AddStr(normalKey)
|
||||
sort.Slice(list, func(i, j int) bool {
|
||||
return list[i].SeqInIndex < list[j].SeqInIndex
|
||||
})
|
||||
|
||||
reply.NormalIndex[indexName] = list
|
||||
}
|
||||
|
||||
return &reply, nil
|
||||
}
|
||||
|
||||
@@ -369,7 +316,7 @@ func getTableFields(table *model.Table) (map[string]*Field, error) {
|
||||
fieldM := make(map[string]*Field)
|
||||
for _, each := range table.Columns {
|
||||
isDefaultNull := each.ColumnDefault == nil && each.IsNullAble == "YES"
|
||||
dt, err := converter.ConvertDataType(each.DataType, isDefaultNull)
|
||||
dt, err := converter.ConvertStringDataType(each.DataType, isDefaultNull)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -380,7 +327,6 @@ func getTableFields(table *model.Table) (map[string]*Field, error) {
|
||||
|
||||
field := &Field{
|
||||
Name: stringx.From(each.Name),
|
||||
DataBaseType: each.DataType,
|
||||
DataType: dt,
|
||||
Comment: each.Comment,
|
||||
SeqInIndex: columnSeqInIndex,
|
||||
|
||||
@@ -1,86 +1,55 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/model/sql/model"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/stringx"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/model/sql/util"
|
||||
)
|
||||
|
||||
func TestParsePlainText(t *testing.T) {
|
||||
_, err := Parse("plain text")
|
||||
sqlFile := filepath.Join(t.TempDir(), "tmp.sql")
|
||||
err := ioutil.WriteFile(sqlFile, []byte("plain text"), 0o777)
|
||||
assert.Nil(t, err)
|
||||
|
||||
_, err = Parse(sqlFile, "go_zero")
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestParseSelect(t *testing.T) {
|
||||
_, err := Parse("select * from user")
|
||||
assert.Equal(t, errUnsupportDDL, err)
|
||||
sqlFile := filepath.Join(t.TempDir(), "tmp.sql")
|
||||
err := ioutil.WriteFile(sqlFile, []byte("select * from user"), 0o777)
|
||||
assert.Nil(t, err)
|
||||
|
||||
tables, err := Parse(sqlFile, "go_zero")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 0, len(tables))
|
||||
}
|
||||
|
||||
func TestParseCreateTable(t *testing.T) {
|
||||
table, err := Parse("CREATE TABLE `test_user` (\n `id` bigint NOT NULL AUTO_INCREMENT,\n `mobile` varchar(255) COLLATE utf8mb4_bin NOT NULL,\n `class` bigint NOT NULL,\n `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,\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 `mobile_unique` (`mobile`),\n UNIQUE KEY `class_name_unique` (`class`,`name`),\n KEY `create_index` (`create_time`),\n KEY `name_index` (`name`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;")
|
||||
sqlFile := filepath.Join(t.TempDir(), "tmp.sql")
|
||||
err := ioutil.WriteFile(sqlFile, []byte("CREATE TABLE `test_user` (\n `id` bigint NOT NULL AUTO_INCREMENT,\n `mobile` varchar(255) COLLATE utf8mb4_bin NOT NULL comment '手\\t机 号',\n `class` bigint NOT NULL comment '班级',\n `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL comment '姓\n 名',\n `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP comment '创建\\r时间',\n `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n PRIMARY KEY (`id`),\n UNIQUE KEY `mobile_unique` (`mobile`),\n UNIQUE KEY `class_name_unique` (`class`,`name`),\n KEY `create_index` (`create_time`),\n KEY `name_index` (`name`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;"), 0o777)
|
||||
assert.Nil(t, err)
|
||||
|
||||
tables, err := Parse(sqlFile, "go_zero")
|
||||
assert.Equal(t, 1, len(tables))
|
||||
table := tables[0]
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "test_user", table.Name.Source())
|
||||
assert.Equal(t, "id", table.PrimaryKey.Name.Source())
|
||||
assert.Equal(t, true, table.ContainsTime())
|
||||
assert.Equal(t, true, func() bool {
|
||||
mobileUniqueIndex, ok := table.UniqueIndex["mobile_unique"]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
classNameUniqueIndex, ok := table.UniqueIndex["class_name_unique"]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
equal := func(f1, f2 []*Field) bool {
|
||||
sort.Slice(f1, func(i, j int) bool {
|
||||
return f1[i].Name.Source() < f1[j].Name.Source()
|
||||
})
|
||||
sort.Slice(f2, func(i, j int) bool {
|
||||
return f2[i].Name.Source() < f2[j].Name.Source()
|
||||
})
|
||||
|
||||
if len(f2) != len(f2) {
|
||||
assert.Equal(t, 2, len(table.UniqueIndex))
|
||||
assert.True(t, func() bool {
|
||||
for _, e := range table.Fields {
|
||||
if e.Comment != util.TrimNewLine(e.Comment) {
|
||||
return false
|
||||
}
|
||||
|
||||
for index, f := range f1 {
|
||||
if f1[index].Name.Source() != f.Name.Source() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if !equal(mobileUniqueIndex, []*Field{
|
||||
{
|
||||
Name: stringx.From("mobile"),
|
||||
DataBaseType: "varchar",
|
||||
DataType: "string",
|
||||
SeqInIndex: 1,
|
||||
},
|
||||
}) {
|
||||
return false
|
||||
}
|
||||
|
||||
return equal(classNameUniqueIndex, []*Field{
|
||||
{
|
||||
Name: stringx.From("class"),
|
||||
DataBaseType: "bigint",
|
||||
DataType: "int64",
|
||||
SeqInIndex: 1,
|
||||
},
|
||||
{
|
||||
Name: stringx.From("name"),
|
||||
DataBaseType: "varchar",
|
||||
DataType: "string",
|
||||
SeqInIndex: 2,
|
||||
},
|
||||
})
|
||||
return true
|
||||
}())
|
||||
}
|
||||
|
||||
|
||||
@@ -10,9 +10,9 @@ func (m *default{{.upperStartCamelObject}}Model) Delete({{.lowerStartCamelPrimar
|
||||
|
||||
{{.keys}}
|
||||
_, err {{if .containsIndexCache}}={{else}}:={{end}} m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("delete from %s where {{.originalPrimaryKey}} = ?", m.table)
|
||||
query := fmt.Sprintf("delete from %s where {{.originalPrimaryKey}} = {{if .postgreSql}}$1{{else}}?{{end}}", m.table)
|
||||
return conn.Exec(query, {{.lowerStartCamelPrimaryKey}})
|
||||
}, {{.keyValues}}){{else}}query := fmt.Sprintf("delete from %s where {{.originalPrimaryKey}} = ?", m.table)
|
||||
}, {{.keyValues}}){{else}}query := fmt.Sprintf("delete from %s where {{.originalPrimaryKey}} = {{if .postgreSql}}$1{{else}}?{{end}}", m.table)
|
||||
_,err:=m.conn.Exec(query, {{.lowerStartCamelPrimaryKey}}){{end}}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ func (m *default{{.upperStartCamelObject}}Model) FindOne({{.lowerStartCamelPrima
|
||||
{{if .withCache}}{{.cacheKey}}
|
||||
var resp {{.upperStartCamelObject}}
|
||||
err := m.QueryRow(&resp, {{.cacheKeyVariable}}, func(conn sqlx.SqlConn, v interface{}) error {
|
||||
query := fmt.Sprintf("select %s from %s where {{.originalPrimaryKey}} = ? limit 1", {{.lowerStartCamelObject}}Rows, m.table)
|
||||
query := fmt.Sprintf("select %s from %s where {{.originalPrimaryKey}} = {{if .postgreSql}}$1{{else}}?{{end}} limit 1", {{.lowerStartCamelObject}}Rows, m.table)
|
||||
return conn.QueryRow(v, query, {{.lowerStartCamelPrimaryKey}})
|
||||
})
|
||||
switch err {
|
||||
@@ -16,7 +16,7 @@ func (m *default{{.upperStartCamelObject}}Model) FindOne({{.lowerStartCamelPrima
|
||||
return nil, ErrNotFound
|
||||
default:
|
||||
return nil, err
|
||||
}{{else}}query := fmt.Sprintf("select %s from %s where {{.originalPrimaryKey}} = ? limit 1", {{.lowerStartCamelObject}}Rows, m.table)
|
||||
}{{else}}query := fmt.Sprintf("select %s from %s where {{.originalPrimaryKey}} = {{if .postgreSql}}$1{{else}}?{{end}} limit 1", {{.lowerStartCamelObject}}Rows, m.table)
|
||||
var resp {{.upperStartCamelObject}}
|
||||
err := m.conn.QueryRow(&resp, query, {{.lowerStartCamelPrimaryKey}})
|
||||
switch err {
|
||||
@@ -71,7 +71,7 @@ func (m *default{{.upperStartCamelObject}}Model) formatPrimary(primary interface
|
||||
}
|
||||
|
||||
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 )
|
||||
query := fmt.Sprintf("select %s from %s where {{.originalPrimaryField}} = {{if .postgreSql}}$1{{else}}?{{end}} limit 1", {{.lowerStartCamelObject}}Rows, m.table )
|
||||
return conn.QueryRow(v, query, primary)
|
||||
}
|
||||
`
|
||||
|
||||
@@ -5,7 +5,7 @@ var New = `
|
||||
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}}",
|
||||
table: {{.table}},
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user