Compare commits

...

56 Commits

Author SHA1 Message Date
Kevin Wan
421e6617b1 chore: add more tests (#3592) 2023-09-27 22:33:27 +08:00
Kevin Wan
0ee7a271d3 fix: avoid float overflow in mapping.Unmarshal (#3590) 2023-09-26 13:46:34 +00:00
dependabot[bot]
af022b9655 chore(deps): bump google.golang.org/grpc from 1.58.1 to 1.58.2 in /tools/goctl (#3584) 2023-09-25 16:23:29 +08:00
dependabot[bot]
98d46261d9 chore(deps): bump google.golang.org/grpc from 1.58.1 to 1.58.2 (#3585)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-24 23:27:02 +08:00
Kevin Wan
4222fd97bc chore: add test for logging rotate size (#3587) 2023-09-24 22:28:03 +08:00
dependabot[bot]
814852f0b8 chore(deps): bump github.com/fullstorydev/grpcurl from 1.8.7 to 1.8.8 (#3586)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-24 19:04:34 +08:00
Kevin Wan
ded2888759 fix: avoid integer overflow in mapping.Unmarshal (#3582) 2023-09-21 14:22:33 +00:00
Kevin Wan
18d66a795d chore: add more tests (#3578) 2023-09-20 23:52:10 +08:00
Kevin Wan
4211672bfd chore: add more tests (#3577) 2023-09-20 00:01:26 +08:00
Kevin Wan
68df0c3620 chore: add more tests (#3575) 2023-09-18 11:01:46 +08:00
xt-inking
5e435b6a76 fix: avoid losing logs before closing (#3573) 2023-09-17 11:38:53 +00:00
Kevin Wan
0dcede6457 chore: refactor log limit in rest (#3572) 2023-09-16 22:33:30 +08:00
Awadabang
cc21f5fae2 update: limit logBrief http body size (#3498)
Co-authored-by: 常公征 <changgz@yealink.com>
2023-09-16 11:58:21 +00:00
dependabot[bot]
b22ad50d59 chore(deps): bump google.golang.org/grpc from 1.58.0 to 1.58.1 in /tools/goctl (#3568)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-16 16:52:01 +08:00
Kevin Wan
974252980c chore: upgrade grpc (#3570) 2023-09-15 23:21:22 +08:00
dependabot[bot]
8d83986d27 chore(deps): bump google.golang.org/grpc from 1.57.0 to 1.58.0 in /tools/goctl (#3546) 2023-09-12 20:00:52 +08:00
Kevin Wan
6821b0a7dd chore: upgrade grpc (#3558) 2023-09-12 10:30:26 +08:00
Kevin Wan
1ba1724c65 chore: refactor (#3545) 2023-09-06 22:36:43 +08:00
Xinwei Xiong
ca5a7df5b0 feat: Optimize Encoding Functions and Add Descriptive Comments (#3543) 2023-09-06 14:19:50 +00:00
dependabot[bot]
69a3024853 chore(deps): bump golang.org/x/net from 0.14.0 to 0.15.0 (#3544)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-06 20:28:03 +08:00
dependabot[bot]
fd3abf3717 chore(deps): bump golang.org/x/text from 0.12.0 to 0.13.0 in /tools/goctl (#3542)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Kevin Wan <wanjunfeng@gmail.com>
2023-09-06 20:20:12 +08:00
dependabot[bot]
99b3750d10 chore(deps): bump golang.org/x/sys from 0.11.0 to 0.12.0 (#3541)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-06 00:02:00 +08:00
POABOB
33f6d7ebb8 fix: goctl pg gen will extract all fields when the same table name exists in different schemas (#3496) (#3517) 2023-09-04 20:48:26 +08:00
kesonan
c4ef9ceb68 Add api version (#3536) 2023-09-02 01:45:48 +00:00
dependabot[bot]
e95861f28a chore(deps): bump github.com/pelletier/go-toml/v2 from 2.0.9 to 2.1.0 (#3532)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-31 22:52:23 +08:00
Kevin Wan
d3cd7b17c0 Revert "add:func() QueryRowsPartial,QueryRowPartial into cachedsql.go" (#3523) 2023-08-27 21:36:14 +08:00
liumin-go
a50515496c add:func() QueryRowsPartial,QueryRowPartial into cachedsql.go (#3512)
Co-authored-by: 刘敏 <liumin@liumindeMac-mini.local>
2023-08-27 08:05:02 +00:00
Kevin Wan
0423313d9b feat: support json:"-" in mapping (#3521) 2023-08-27 16:04:38 +08:00
dependabot[bot]
7bbe7de05f chore(deps): bump github.com/google/uuid from 1.3.0 to 1.3.1 (#3511)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-24 14:59:49 +08:00
dependabot[bot]
83a451f2f4 chore(deps): bump github.com/jhump/protoreflect from 1.15.1 to 1.15.2 (#3518)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-24 14:39:50 +08:00
Kevin Wan
d2a874f21d chore: upgrade go-zero, and update goctl version (#3509) 2023-08-21 09:09:51 +08:00
Kevin Wan
fd85b24b25 Update readme-cn.md 2023-08-20 23:38:39 +08:00
Kevin Wan
14fcbd7658 fix #3499 (#3508) 2023-08-19 22:17:24 +08:00
Kevin Wan
cb3ffc76a3 fix: #3478 (#3493) 2023-08-14 14:22:22 +00:00
dependabot[bot]
45fbd7dc35 chore(deps): bump github.com/alicebob/miniredis/v2 from 2.30.4 to 2.30.5 (#3490)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-10 19:53:17 +08:00
dependabot[bot]
af821cf794 chore(deps): bump golang.org/x/net from 0.13.0 to 0.14.0 (#3484)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-09 10:39:32 +08:00
dependabot[bot]
ec69950153 chore(deps): bump github.com/jackc/pgx/v5 from 5.4.2 to 5.4.3 (#3483)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-09 10:18:27 +08:00
Kevin Wan
ce5e78db53 chore: use jsonTagKey to replace json literals (#3479) 2023-08-06 22:00:24 +08:00
dependabot[bot]
ed75802eaa chore(deps): bump golang.org/x/text from 0.11.0 to 0.12.0 in /tools/goctl (#3477)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-06 09:57:19 +08:00
dependabot[bot]
76c92b571d chore(deps): bump golang.org/x/sys from 0.10.0 to 0.11.0 (#3476)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-06 00:19:00 +08:00
dependabot[bot]
a2e703c53e chore(deps): bump golang.org/x/net from 0.12.0 to 0.13.0 (#3463)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Kevin Wan <wanjunfeng@gmail.com>
2023-08-04 20:39:17 +08:00
dependabot[bot]
ca698deb2a chore(deps): bump go.mongodb.org/mongo-driver from 1.12.0 to 1.12.1 (#3472)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-04 19:13:16 +08:00
guangwu
a9f4aab86b fix: "EXPRIMENTAL" is a misspelling of "EXPERIMENTAL" (#3462) 2023-08-02 23:59:37 +08:00
Kevin Wan
c3f57e9b0a chore: fix potential nil pointer errors (#3454) 2023-07-30 21:37:41 +08:00
Kevin Wan
ad4cce959d chore: add more tests (#3453) 2023-07-29 22:34:16 +08:00
Shyunn
279123f4a7 feat: add prometheus summary metrics (#3440)
Co-authored-by: chen quan <chenquan.dev@gmail.com>
2023-07-29 16:51:43 +08:00
dependabot[bot]
457eb1961b chore(deps): bump google.golang.org/grpc from 1.56.2 to 1.57.0 (#3445)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-28 22:18:14 +08:00
dependabot[bot]
63df384a4b chore(deps): bump google.golang.org/grpc from 1.56.2 to 1.57.0 in /tools/goctl (#3446)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-28 22:17:23 +08:00
MarkJoyMa
42bfa26e2b fix: remove mapping redundant error (#3439) 2023-07-24 00:10:50 +08:00
Kevin Wan
ff04356704 fix: format error should not trigger circuit breaker in sqlx (#3437) 2023-07-23 20:40:03 +08:00
MarkJoyMa
05db706c62 feat: optimize mapping error (#3438) 2023-07-23 12:10:41 +00:00
dependabot[bot]
ef2e0d859d chore(deps): bump go.uber.org/automaxprocs from 1.5.2 to 1.5.3 (#3435)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-22 00:03:07 +08:00
dependabot[bot]
05ec16ae9d chore(deps): bump github.com/gookit/color from 1.5.3 to 1.5.4 in /tools/goctl (#3433)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-21 23:27:49 +08:00
dependabot[bot]
13e685e0db chore(deps): bump github.com/emicklei/proto from 1.12.0 to 1.12.1 in /tools/goctl (#3431)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-21 23:12:06 +08:00
dependabot[bot]
c10f44b74e chore(deps): bump github.com/emicklei/proto from 1.11.2 to 1.12.0 in /tools/goctl (#3429) 2023-07-18 09:41:13 +08:00
Kevin Wan
57644420ed chore: update go-zero for goctl (#3426) 2023-07-14 21:38:42 +08:00
47 changed files with 2740 additions and 270 deletions

View File

@@ -29,6 +29,8 @@ func NewSafeMap() *SafeMap {
// Del deletes the value with the given key from m.
func (m *SafeMap) Del(key any) {
m.lock.Lock()
defer m.lock.Unlock()
if _, ok := m.dirtyOld[key]; ok {
delete(m.dirtyOld, key)
m.deletionOld++
@@ -52,7 +54,6 @@ func (m *SafeMap) Del(key any) {
m.dirtyNew = make(map[any]any)
m.deletionNew = 0
}
m.lock.Unlock()
}
// Get gets the value with the given key from m.
@@ -89,6 +90,8 @@ func (m *SafeMap) Range(f func(key, val any) bool) {
// Set sets the value into m with the given key.
func (m *SafeMap) Set(key, value any) {
m.lock.Lock()
defer m.lock.Unlock()
if m.deletionOld <= maxDeletion {
if _, ok := m.dirtyNew[key]; ok {
delete(m.dirtyNew, key)
@@ -102,7 +105,6 @@ func (m *SafeMap) Set(key, value any) {
}
m.dirtyNew[key] = value
}
m.lock.Unlock()
}
// Size returns the size of m.

View File

@@ -147,3 +147,65 @@ func TestSafeMap_Range(t *testing.T) {
assert.Equal(t, m.dirtyNew, newMap.dirtyNew)
assert.Equal(t, m.dirtyOld, newMap.dirtyOld)
}
func TestSetManyTimes(t *testing.T) {
const iteration = maxDeletion * 2
m := NewSafeMap()
for i := 0; i < iteration; i++ {
m.Set(i, i)
if i%3 == 0 {
m.Del(i / 2)
}
}
var count int
m.Range(func(k, v any) bool {
count++
return count < maxDeletion/2
})
assert.Equal(t, maxDeletion/2, count)
for i := 0; i < iteration; i++ {
m.Set(i, i)
if i%3 == 0 {
m.Del(i / 2)
}
}
for i := 0; i < iteration; i++ {
m.Set(i, i)
if i%3 == 0 {
m.Del(i / 2)
}
}
for i := 0; i < iteration; i++ {
m.Set(i, i)
if i%3 == 0 {
m.Del(i / 2)
}
}
count = 0
m.Range(func(k, v any) bool {
count++
return count < maxDeletion
})
assert.Equal(t, maxDeletion, count)
}
func TestSetManyTimesNew(t *testing.T) {
m := NewSafeMap()
for i := 0; i < maxDeletion*3; i++ {
m.Set(i, i)
}
for i := 0; i < maxDeletion*2; i++ {
m.Del(i)
}
for i := 0; i < maxDeletion*3; i++ {
m.Set(i+maxDeletion*3, i+maxDeletion*3)
}
for i := 0; i < maxDeletion*2; i++ {
m.Del(i + maxDeletion*2)
}
for i := 0; i < maxDeletion-copyThreshold+1; i++ {
m.Del(i + maxDeletion*2)
}
assert.Equal(t, 0, len(m.dirtyNew))
}

View File

@@ -32,6 +32,10 @@ func (bp *BufferPool) Get() *bytes.Buffer {
// Put returns buf into bp.
func (bp *BufferPool) Put(buf *bytes.Buffer) {
if buf == nil {
return
}
if buf.Cap() < bp.capability {
bp.pool.Put(buf)
}

View File

@@ -13,3 +13,26 @@ func TestBufferPool(t *testing.T) {
pool.Put(bytes.NewBuffer(make([]byte, 0, 2*capacity)))
assert.True(t, pool.Get().Cap() <= capacity)
}
func TestBufferPool_Put(t *testing.T) {
t.Run("with nil buf", func(t *testing.T) {
pool := NewBufferPool(1024)
pool.Put(nil)
val := pool.Get()
assert.IsType(t, new(bytes.Buffer), val)
})
t.Run("with less-cap buf", func(t *testing.T) {
pool := NewBufferPool(1024)
pool.Put(bytes.NewBuffer(make([]byte, 0, 512)))
val := pool.Get()
assert.IsType(t, new(bytes.Buffer), val)
})
t.Run("with more-cap buf", func(t *testing.T) {
pool := NewBufferPool(1024)
pool.Put(bytes.NewBuffer(make([]byte, 0, 1024<<1)))
val := pool.Get()
assert.IsType(t, new(bytes.Buffer), val)
})
}

View File

@@ -0,0 +1,12 @@
package iox
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestNopCloser(t *testing.T) {
closer := NopCloser(nil)
assert.NoError(t, closer.Close())
}

View File

@@ -35,6 +35,16 @@ func KeepSpace() TextReadOption {
}
}
// LimitDupReadCloser returns two io.ReadCloser that read from the first will be written to the second.
// But the second io.ReadCloser is limited to up to n bytes.
// The first returned reader needs to be read first, because the content
// read from it will be written to the underlying buffer of the second reader.
func LimitDupReadCloser(reader io.ReadCloser, n int64) (io.ReadCloser, io.ReadCloser) {
var buf bytes.Buffer
tee := LimitTeeReader(reader, &buf, n)
return io.NopCloser(tee), io.NopCloser(&buf)
}
// ReadBytes reads exactly the bytes with the length of len(buf)
func ReadBytes(reader io.Reader, buf []byte) error {
var got int

View File

@@ -51,6 +51,11 @@ b`,
}
}
func TestReadTextError(t *testing.T) {
_, err := ReadText("not-exist")
assert.NotNil(t, err)
}
func TestReadTextLines(t *testing.T) {
text := `1
@@ -94,6 +99,11 @@ func TestReadTextLines(t *testing.T) {
}
}
func TestReadTextLinesError(t *testing.T) {
_, err := ReadTextLines("not-exist")
assert.NotNil(t, err)
}
func TestDupReadCloser(t *testing.T) {
input := "hello"
reader := io.NopCloser(bytes.NewBufferString(input))
@@ -108,6 +118,29 @@ func TestDupReadCloser(t *testing.T) {
verify(r2)
}
func TestLimitDupReadCloser(t *testing.T) {
input := "hello world"
limitBytes := int64(4)
reader := io.NopCloser(bytes.NewBufferString(input))
r1, r2 := LimitDupReadCloser(reader, limitBytes)
verify := func(r io.Reader) {
output, err := io.ReadAll(r)
assert.Nil(t, err)
assert.Equal(t, input, string(output))
}
verifyLimit := func(r io.Reader, limit int64) {
output, err := io.ReadAll(r)
if limit < int64(len(input)) {
input = input[:limit]
}
assert.Nil(t, err)
assert.Equal(t, input, string(output))
}
verify(r1)
verifyLimit(r2, limitBytes)
}
func TestReadBytes(t *testing.T) {
reader := io.NopCloser(bytes.NewBufferString("helloworld"))
buf := make([]byte, 5)

35
core/iox/tee.go Normal file
View File

@@ -0,0 +1,35 @@
package iox
import "io"
// LimitTeeReader returns a Reader that writes up to n bytes to w what it reads from r.
// First n bytes reads from r performed through it are matched with
// corresponding writes to w. There is no internal buffering -
// the write must complete before the first n bytes read completes.
// Any error encountered while writing is reported as a read error.
func LimitTeeReader(r io.Reader, w io.Writer, n int64) io.Reader {
return &limitTeeReader{r, w, n}
}
type limitTeeReader struct {
r io.Reader
w io.Writer
n int64 // limit bytes remaining
}
func (t *limitTeeReader) Read(p []byte) (n int, err error) {
n, err = t.r.Read(p)
if n > 0 && t.n > 0 {
limit := int64(n)
if limit > t.n {
limit = t.n
}
if n, err := t.w.Write(p[:limit]); err != nil {
return n, err
}
t.n -= limit
}
return
}

40
core/iox/tee_test.go Normal file
View File

@@ -0,0 +1,40 @@
package iox
import (
"bytes"
"io"
"testing"
"github.com/stretchr/testify/assert"
)
func TestLimitTeeReader(t *testing.T) {
limit := int64(4)
src := []byte("hello, world")
dst := make([]byte, len(src))
rb := bytes.NewBuffer(src)
wb := new(bytes.Buffer)
r := LimitTeeReader(rb, wb, limit)
if n, err := io.ReadFull(r, dst); err != nil || n != len(src) {
t.Fatalf("ReadFull(r, dst) = %d, %v; want %d, nil", n, err, len(src))
}
if !bytes.Equal(dst, src) {
t.Errorf("bytes read = %q want %q", dst, src)
}
if !bytes.Equal(wb.Bytes(), src[:limit]) {
t.Errorf("bytes written = %q want %q", wb.Bytes(), src)
}
n, err := r.Read(dst)
assert.Equal(t, 0, n)
assert.Equal(t, io.EOF, err)
rb = bytes.NewBuffer(src)
pr, pw := io.Pipe()
if assert.NoError(t, pr.Close()) {
r = LimitTeeReader(rb, pw, limit)
n, err := io.ReadFull(r, dst)
assert.Equal(t, 0, n)
assert.Equal(t, io.ErrClosedPipe, err)
}
}

View File

@@ -2,6 +2,7 @@ package iox
import (
"bytes"
"errors"
"io"
"os"
)
@@ -26,7 +27,7 @@ func CountLines(file string) (int, error) {
count += bytes.Count(buf[:c], lineSep)
switch {
case err == io.EOF:
case errors.Is(err, io.EOF):
if noEol {
count++
}

View File

@@ -24,3 +24,8 @@ func TestCountLines(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, 4, lines)
}
func TestCountLinesError(t *testing.T) {
_, err := CountLines("not-exist")
assert.NotNil(t, err)
}

View File

@@ -3,6 +3,7 @@ package iox
import (
"strings"
"testing"
"testing/iotest"
"github.com/stretchr/testify/assert"
)
@@ -22,3 +23,10 @@ func TestScanner(t *testing.T) {
}
assert.EqualValues(t, []string{"1", "2", "3", "4"}, lines)
}
func TestBadScanner(t *testing.T) {
scanner := NewTextLineScanner(iotest.ErrReader(iotest.ErrTimeout))
assert.False(t, scanner.Scan())
_, err := scanner.Line()
assert.ErrorIs(t, err, iotest.ErrTimeout)
}

View File

@@ -298,6 +298,7 @@ func (l *RotateLogger) initialize() error {
if l.fp, err = os.OpenFile(l.filename, os.O_APPEND|os.O_WRONLY, defaultFileMode); err != nil {
return err
}
l.currentSize = fileInfo.Size()
}
@@ -381,7 +382,15 @@ func (l *RotateLogger) startWorker() {
case event := <-l.channel:
l.write(event)
case <-l.done:
return
// avoid losing logs before closing.
for {
select {
case event := <-l.channel:
l.write(event)
default:
return
}
}
}
}
}()

View File

@@ -206,6 +206,27 @@ func TestRotateLoggerClose(t *testing.T) {
_, err := logger.Write([]byte("foo"))
assert.ErrorIs(t, err, ErrLogFileClosed)
})
t.Run("close without losing logs", func(t *testing.T) {
text := "foo"
filename, err := fs.TempFilenameWithText(text)
assert.Nil(t, err)
if len(filename) > 0 {
defer os.Remove(filename)
}
logger, err := NewLogger(filename, new(DailyRotateRule), false)
assert.Nil(t, err)
msg := []byte("foo")
n := 100
for i := 0; i < n; i++ {
_, err = logger.Write(msg)
assert.Nil(t, err)
}
assert.Nil(t, logger.Close())
bs, err := os.ReadFile(filename)
assert.Nil(t, err)
assert.Equal(t, len(msg)*n+len(text), len(bs))
})
}
func TestRotateLoggerGetBackupFilename(t *testing.T) {
@@ -496,6 +517,21 @@ func TestGzipFile(t *testing.T) {
})
}
func TestRotateLogger_WithExistingFile(t *testing.T) {
const body = "foo"
filename, err := fs.TempFilenameWithText(body)
assert.Nil(t, err)
if len(filename) > 0 {
defer os.Remove(filename)
}
rule := NewSizeLimitRotateRule(filename, "-", 1, 100, 3, false)
logger, err := NewLogger(filename, rule, false)
assert.Nil(t, err)
assert.Equal(t, int64(len(body)), logger.currentSize)
assert.Nil(t, logger.Close())
}
func BenchmarkRotateLogger(b *testing.B) {
filename := "./test.log"
filename2 := "./test2.log"

View File

@@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
"math"
"reflect"
"strconv"
"strings"
@@ -20,6 +21,7 @@ import (
const (
defaultKeyName = "key"
delimiter = '.'
ignoreKey = "-"
)
var (
@@ -49,6 +51,7 @@ type (
unmarshalOptions struct {
fillDefault bool
fromString bool
opaqueKeys bool
canonicalKey func(key string) string
}
)
@@ -72,7 +75,11 @@ func UnmarshalKey(m map[string]any, v any) error {
}
// Unmarshal unmarshals m into v.
func (u *Unmarshaler) Unmarshal(i any, v any) error {
func (u *Unmarshaler) Unmarshal(i, v any) error {
return u.unmarshal(i, v, "")
}
func (u *Unmarshaler) unmarshal(i, v any, fullName string) error {
valueType := reflect.TypeOf(v)
if valueType.Kind() != reflect.Ptr {
return errValueNotSettable
@@ -85,13 +92,13 @@ func (u *Unmarshaler) Unmarshal(i any, v any) error {
return errTypeMismatch
}
return u.UnmarshalValuer(mapValuer(iv), v)
return u.unmarshalValuer(mapValuer(iv), v, fullName)
case []any:
if elemType.Kind() != reflect.Slice {
return errTypeMismatch
}
return u.fillSlice(elemType, reflect.ValueOf(v).Elem(), iv)
return u.fillSlice(elemType, reflect.ValueOf(v).Elem(), iv, fullName)
default:
return errUnsupportedType
}
@@ -99,17 +106,21 @@ func (u *Unmarshaler) Unmarshal(i any, v any) error {
// UnmarshalValuer unmarshals m into v.
func (u *Unmarshaler) UnmarshalValuer(m Valuer, v any) error {
return u.unmarshalWithFullName(simpleValuer{current: m}, v, "")
return u.unmarshalValuer(simpleValuer{current: m}, v, "")
}
func (u *Unmarshaler) fillMap(fieldType reflect.Type, value reflect.Value, mapValue any) error {
func (u *Unmarshaler) unmarshalValuer(m Valuer, v any, fullName string) error {
return u.unmarshalWithFullName(simpleValuer{current: m}, v, fullName)
}
func (u *Unmarshaler) fillMap(fieldType reflect.Type, value reflect.Value, mapValue any, fullName string) error {
if !value.CanSet() {
return errValueNotSettable
}
fieldKeyType := fieldType.Key()
fieldElemType := fieldType.Elem()
targetValue, err := u.generateMap(fieldKeyType, fieldElemType, mapValue)
targetValue, err := u.generateMap(fieldKeyType, fieldElemType, mapValue, fullName)
if err != nil {
return err
}
@@ -143,14 +154,14 @@ func (u *Unmarshaler) fillMapFromString(value reflect.Value, mapValue any) error
return nil
}
func (u *Unmarshaler) fillSlice(fieldType reflect.Type, value reflect.Value, mapValue any) error {
func (u *Unmarshaler) fillSlice(fieldType reflect.Type, value reflect.Value, mapValue any, fullName string) error {
if !value.CanSet() {
return errValueNotSettable
}
refValue := reflect.ValueOf(mapValue)
if refValue.Kind() != reflect.Slice {
return errTypeMismatch
return newTypeMismatchErrorWithHint(fullName, reflect.Slice.String(), refValue.Type().String())
}
if refValue.IsNil() {
return nil
@@ -173,6 +184,8 @@ func (u *Unmarshaler) fillSlice(fieldType reflect.Type, value reflect.Value, map
}
valid = true
sliceFullName := fmt.Sprintf("%s[%d]", fullName, i)
switch dereffedBaseKind {
case reflect.Struct:
target := reflect.New(dereffedBaseType)
@@ -181,17 +194,17 @@ func (u *Unmarshaler) fillSlice(fieldType reflect.Type, value reflect.Value, map
return errTypeMismatch
}
if err := u.Unmarshal(val, target.Interface()); err != nil {
if err := u.unmarshal(val, target.Interface(), sliceFullName); err != nil {
return err
}
SetValue(fieldType.Elem(), conv.Index(i), target.Elem())
case reflect.Slice:
if err := u.fillSlice(dereffedBaseType, conv.Index(i), ithValue); err != nil {
if err := u.fillSlice(dereffedBaseType, conv.Index(i), ithValue, sliceFullName); err != nil {
return err
}
default:
if err := u.fillSliceValue(conv, i, dereffedBaseKind, ithValue); err != nil {
if err := u.fillSliceValue(conv, i, dereffedBaseKind, ithValue, sliceFullName); err != nil {
return err
}
}
@@ -205,7 +218,7 @@ func (u *Unmarshaler) fillSlice(fieldType reflect.Type, value reflect.Value, map
}
func (u *Unmarshaler) fillSliceFromString(fieldType reflect.Type, value reflect.Value,
mapValue any) error {
mapValue any, fullName string) error {
var slice []any
switch v := mapValue.(type) {
case fmt.Stringer:
@@ -225,7 +238,7 @@ func (u *Unmarshaler) fillSliceFromString(fieldType reflect.Type, value reflect.
conv := reflect.MakeSlice(reflect.SliceOf(baseFieldType), len(slice), cap(slice))
for i := 0; i < len(slice); i++ {
if err := u.fillSliceValue(conv, i, baseFieldKind, slice[i]); err != nil {
if err := u.fillSliceValue(conv, i, baseFieldKind, slice[i], fullName); err != nil {
return err
}
}
@@ -235,7 +248,7 @@ func (u *Unmarshaler) fillSliceFromString(fieldType reflect.Type, value reflect.
}
func (u *Unmarshaler) fillSliceValue(slice reflect.Value, index int,
baseKind reflect.Kind, value any) error {
baseKind reflect.Kind, value any, fullName string) error {
ithVal := slice.Index(index)
switch v := value.(type) {
case fmt.Stringer:
@@ -243,7 +256,7 @@ func (u *Unmarshaler) fillSliceValue(slice reflect.Value, index int,
case string:
return setValueFromString(baseKind, ithVal, v)
case map[string]any:
return u.fillMap(ithVal.Type(), ithVal, value)
return u.fillMap(ithVal.Type(), ithVal, value, fullName)
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.
@@ -269,7 +282,7 @@ func (u *Unmarshaler) fillSliceValue(slice reflect.Value, index int,
}
func (u *Unmarshaler) fillSliceWithDefault(derefedType reflect.Type, value reflect.Value,
defaultValue string) error {
defaultValue, fullName string) error {
baseFieldType := Deref(derefedType.Elem())
baseFieldKind := baseFieldType.Kind()
defaultCacheLock.Lock()
@@ -287,10 +300,10 @@ func (u *Unmarshaler) fillSliceWithDefault(derefedType reflect.Type, value refle
defaultCacheLock.Unlock()
}
return u.fillSlice(derefedType, value, slice)
return u.fillSlice(derefedType, value, slice, fullName)
}
func (u *Unmarshaler) generateMap(keyType, elemType reflect.Type, mapValue any) (reflect.Value, error) {
func (u *Unmarshaler) generateMap(keyType, elemType reflect.Type, mapValue any, fullName string) (reflect.Value, error) {
mapType := reflect.MapOf(keyType, elemType)
valueType := reflect.TypeOf(mapValue)
if mapType == valueType {
@@ -309,11 +322,12 @@ func (u *Unmarshaler) generateMap(keyType, elemType reflect.Type, mapValue any)
for _, key := range refValue.MapKeys() {
keythValue := refValue.MapIndex(key)
keythData := keythValue.Interface()
mapFullName := fmt.Sprintf("%s[%s]", fullName, key.String())
switch dereffedElemKind {
case reflect.Slice:
target := reflect.New(dereffedElemType)
if err := u.fillSlice(elemType, target.Elem(), keythData); err != nil {
if err := u.fillSlice(elemType, target.Elem(), keythData, mapFullName); err != nil {
return emptyValue, err
}
@@ -325,7 +339,7 @@ func (u *Unmarshaler) generateMap(keyType, elemType reflect.Type, mapValue any)
}
target := reflect.New(dereffedElemType)
if err := u.Unmarshal(keythMap, target.Interface()); err != nil {
if err := u.unmarshal(keythMap, target.Interface(), mapFullName); err != nil {
return emptyValue, err
}
@@ -336,7 +350,7 @@ func (u *Unmarshaler) generateMap(keyType, elemType reflect.Type, mapValue any)
return emptyValue, errTypeMismatch
}
innerValue, err := u.generateMap(elemType.Key(), elemType.Elem(), keythMap)
innerValue, err := u.generateMap(elemType.Key(), elemType.Elem(), keythMap, mapFullName)
if err != nil {
return emptyValue, err
}
@@ -425,6 +439,10 @@ func (u *Unmarshaler) processAnonymousField(field reflect.StructField, value ref
return err
}
if key == ignoreKey {
return nil
}
if options.optional() {
return u.processAnonymousFieldOptional(field, value, key, m, fullName)
}
@@ -483,7 +501,7 @@ func (u *Unmarshaler) processAnonymousStructFieldOptional(fieldType reflect.Type
return err
}
_, hasValue := getValue(m, fieldKey)
_, hasValue := getValue(m, fieldKey, u.opts.opaqueKeys)
if hasValue {
if !filled {
filled = true
@@ -541,13 +559,13 @@ func (u *Unmarshaler) processFieldNotFromString(fieldType reflect.Type, value re
parent: vp.parent,
}, fullName)
case typeKind == reflect.Slice && valueKind == reflect.Slice:
return u.fillSlice(fieldType, value, mapValue)
return u.fillSlice(fieldType, value, mapValue, fullName)
case valueKind == reflect.Map && typeKind == reflect.Map:
return u.fillMap(fieldType, value, mapValue)
return u.fillMap(fieldType, value, mapValue, fullName)
case valueKind == reflect.String && typeKind == reflect.Map:
return u.fillMapFromString(value, mapValue)
case valueKind == reflect.String && typeKind == reflect.Slice:
return u.fillSliceFromString(fieldType, value, mapValue)
return u.fillSliceFromString(fieldType, value, mapValue, fullName)
case valueKind == reflect.String && derefedFieldType == durationType:
return fillDurationValue(fieldType, value, mapValue.(string))
default:
@@ -592,25 +610,23 @@ func (u *Unmarshaler) processFieldPrimitiveWithJSONNumber(fieldType reflect.Type
target := reflect.New(Deref(fieldType)).Elem()
switch typeKind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
iValue, err := v.Int64()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
if err := setValueFromString(typeKind, target, v.String()); err != nil {
return err
}
case reflect.Float32:
fValue, err := v.Float64()
if err != nil {
return err
}
target.SetInt(iValue)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
iValue, err := v.Int64()
if err != nil {
return err
if fValue > math.MaxFloat32 {
return float32OverflowError(v.String())
}
if iValue < 0 {
return fmt.Errorf("unmarshal %q with bad value %q", fullName, v.String())
}
target.SetUint(uint64(iValue))
case reflect.Float32, reflect.Float64:
target.SetFloat(fValue)
case reflect.Float64:
fValue, err := v.Float64()
if err != nil {
return err
@@ -712,6 +728,10 @@ func (u *Unmarshaler) processNamedField(field reflect.StructField, value reflect
return err
}
if key == ignoreKey {
return nil
}
fullName = join(fullName, key)
if opts != nil && len(opts.EnvVar) > 0 {
envVal := proc.Env(opts.EnvVar)
@@ -726,7 +746,7 @@ func (u *Unmarshaler) processNamedField(field reflect.StructField, value reflect
}
valuer := createValuer(m, opts)
mapValue, hasValue := getValue(valuer, canonicalKey)
mapValue, hasValue := getValue(valuer, canonicalKey, u.opts.opaqueKeys)
// When fillDefault is used, m is a null value, hasValue must be false, all priority judgments fillDefault.
if u.opts.fillDefault {
@@ -819,7 +839,7 @@ func (u *Unmarshaler) processNamedFieldWithoutValue(fieldType reflect.Type, valu
switch fieldKind {
case reflect.Array, reflect.Slice:
return u.fillSliceWithDefault(derefedType, value, defaultValue)
return u.fillSliceWithDefault(derefedType, value, defaultValue, fullName)
default:
return setValueFromString(fieldKind, value, defaultValue)
}
@@ -867,7 +887,7 @@ func (u *Unmarshaler) processNamedFieldWithoutValue(fieldType reflect.Type, valu
func (u *Unmarshaler) unmarshalWithFullName(m valuerWithParent, v any, fullName string) error {
rv := reflect.ValueOf(v)
if err := ValidatePtr(&rv); err != nil {
if err := ValidatePtr(rv); err != nil {
return err
}
@@ -889,11 +909,6 @@ func (u *Unmarshaler) unmarshalWithFullName(m valuerWithParent, v any, fullName
typeField := baseType.Field(i)
valueField := valElem.Field(i)
if err := u.processField(typeField, valueField, m, fullName); err != nil {
if len(fullName) > 0 {
err = fmt.Errorf("%w, fullName: %s, field: %s, type: %s",
err, fullName, typeField.Name, valueField.Type().Name())
}
return err
}
}
@@ -922,6 +937,14 @@ func WithDefault() UnmarshalOption {
}
}
// WithOpaqueKeys customizes an Unmarshaler with opaque keys.
// Opaque keys are keys that are not processed by the unmarshaler.
func WithOpaqueKeys() UnmarshalOption {
return func(opt *unmarshalOptions) {
opt.opaqueKeys = true
}
}
func createValuer(v valuerWithParent, opts *fieldOptionsWithContext) valuerWithParent {
if opts.inherit() {
return recursiveValuer{
@@ -999,8 +1022,8 @@ func fillWithSameType(fieldType reflect.Type, value reflect.Value, mapValue any,
}
// getValue gets the value for the specific key, the key can be in the format of parentKey.childKey
func getValue(m valuerWithParent, key string) (any, bool) {
keys := readKeys(key)
func getValue(m valuerWithParent, key string, opaque bool) (any, bool) {
keys := readKeys(key, opaque)
return getValueWithChainedKeys(m, keys)
}
@@ -1059,7 +1082,11 @@ func newTypeMismatchErrorWithHint(name, expectType, actualType string) error {
name, expectType, actualType)
}
func readKeys(key string) []string {
func readKeys(key string, opaque bool) []string {
if opaque {
return []string{key}
}
cacheKeysLock.Lock()
keys, ok := cacheKeys[key]
cacheKeysLock.Unlock()

File diff suppressed because it is too large Load Diff

View File

@@ -42,6 +42,10 @@ var (
)
type (
integer interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64
}
optionsCacheValue struct {
key string
options *fieldOptions
@@ -79,7 +83,7 @@ func SetMapIndexValue(tp reflect.Type, value, key, target reflect.Value) {
}
// ValidatePtr validates v if it's a valid pointer.
func ValidatePtr(v *reflect.Value) error {
func ValidatePtr(v reflect.Value) error {
// sequence is very important, IsNil must be called after checking Kind() with reflect.Ptr,
// panic otherwise
if !v.IsValid() || v.Kind() != reflect.Ptr || v.IsNil() {
@@ -103,21 +107,32 @@ func convertTypeFromString(kind reflect.Kind, str string) (any, error) {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
intValue, err := strconv.ParseInt(str, 10, 64)
if err != nil {
return 0, fmt.Errorf("the value %q cannot parsed as int", str)
return 0, err
}
return intValue, nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
uintValue, err := strconv.ParseUint(str, 10, 64)
if err != nil {
return 0, fmt.Errorf("the value %q cannot parsed as uint", str)
return 0, err
}
return uintValue, nil
case reflect.Float32, reflect.Float64:
case reflect.Float32:
floatValue, err := strconv.ParseFloat(str, 64)
if err != nil {
return 0, fmt.Errorf("the value %q cannot parsed as float", str)
return 0, err
}
if floatValue > math.MaxFloat32 {
return 0, float32OverflowError(str)
}
return floatValue, nil
case reflect.Float64:
floatValue, err := strconv.ParseFloat(str, 64)
if err != nil {
return 0, err
}
return floatValue, nil
@@ -215,6 +230,10 @@ func implicitValueRequiredStruct(tag string, tp reflect.Type) (bool, error) {
return false, nil
}
func intOverflowError[T integer](v T, kind reflect.Kind) error {
return fmt.Errorf("parsing \"%d\" as %s: value out of range", v, kind.String())
}
func isLeftInclude(b byte) (bool, error) {
switch b {
case '[':
@@ -237,6 +256,10 @@ func isRightInclude(b byte) (bool, error) {
}
}
func float32OverflowError(str string) error {
return fmt.Errorf("parsing %q as float32: value out of range", str)
}
func maybeNewValue(fieldType reflect.Type, value reflect.Value) {
if fieldType.Kind() == reflect.Ptr && value.IsNil() {
value.Set(reflect.New(value.Type().Elem()))
@@ -482,22 +505,61 @@ func parseSegments(val string) []string {
return segments
}
func setIntValue(value reflect.Value, v any, min, max int64) error {
iv := v.(int64)
if iv < min || iv > max {
return intOverflowError(iv, value.Kind())
}
value.SetInt(iv)
return nil
}
func setMatchedPrimitiveValue(kind reflect.Kind, value reflect.Value, v any) error {
switch kind {
case reflect.Bool:
value.SetBool(v.(bool))
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return nil
case reflect.Int: // int depends on int size, 32 or 64
return setIntValue(value, v, math.MinInt, math.MaxInt)
case reflect.Int8:
return setIntValue(value, v, math.MinInt8, math.MaxInt8)
case reflect.Int16:
return setIntValue(value, v, math.MinInt16, math.MaxInt16)
case reflect.Int32:
return setIntValue(value, v, math.MinInt32, math.MaxInt32)
case reflect.Int64:
value.SetInt(v.(int64))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return nil
case reflect.Uint: // uint depends on int size, 32 or 64
return setUintValue(value, v, math.MaxUint)
case reflect.Uint8:
return setUintValue(value, v, math.MaxUint8)
case reflect.Uint16:
return setUintValue(value, v, math.MaxUint16)
case reflect.Uint32:
return setUintValue(value, v, math.MaxUint32)
case reflect.Uint64:
value.SetUint(v.(uint64))
return nil
case reflect.Float32, reflect.Float64:
value.SetFloat(v.(float64))
return nil
case reflect.String:
value.SetString(v.(string))
return nil
default:
return errUnsupportedType
}
}
func setUintValue(value reflect.Value, v any, boundary uint64) error {
iv := v.(uint64)
if iv > boundary {
return intOverflowError(iv, value.Kind())
}
value.SetUint(iv)
return nil
}
@@ -575,7 +637,8 @@ func usingDifferentKeys(key string, field reflect.StructField) bool {
return false
}
func validateAndSetValue(kind reflect.Kind, value reflect.Value, str string, opts *fieldOptionsWithContext) error {
func validateAndSetValue(kind reflect.Kind, value reflect.Value, str string,
opts *fieldOptionsWithContext) error {
if !value.CanSet() {
return errValueNotSettable
}

View File

@@ -218,25 +218,25 @@ func TestParseSegments(t *testing.T) {
func TestValidatePtrWithNonPtr(t *testing.T) {
var foo string
rve := reflect.ValueOf(foo)
assert.NotNil(t, ValidatePtr(&rve))
assert.NotNil(t, ValidatePtr(rve))
}
func TestValidatePtrWithPtr(t *testing.T) {
var foo string
rve := reflect.ValueOf(&foo)
assert.Nil(t, ValidatePtr(&rve))
assert.Nil(t, ValidatePtr(rve))
}
func TestValidatePtrWithNilPtr(t *testing.T) {
var foo *string
rve := reflect.ValueOf(foo)
assert.NotNil(t, ValidatePtr(&rve))
assert.NotNil(t, ValidatePtr(rve))
}
func TestValidatePtrWithZeroValue(t *testing.T) {
var s string
e := reflect.Zero(reflect.TypeOf(s))
assert.NotNil(t, ValidatePtr(&e))
assert.NotNil(t, ValidatePtr(e))
}
func TestSetValueNotSettable(t *testing.T) {

View File

@@ -6,7 +6,6 @@ import (
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/proc"
)
func TestNewHistogramVec(t *testing.T) {
@@ -48,6 +47,4 @@ func TestHistogramObserve(t *testing.T) {
err := testutil.CollectAndCompare(hv.histogram, strings.NewReader(metadata+val))
assert.Nil(t, err)
proc.Shutdown()
}

65
core/metric/summary.go Normal file
View File

@@ -0,0 +1,65 @@
package metric
import (
prom "github.com/prometheus/client_golang/prometheus"
"github.com/zeromicro/go-zero/core/proc"
"github.com/zeromicro/go-zero/core/prometheus"
)
type (
// A SummaryVecOpts is a summary vector options
SummaryVecOpts struct {
VecOpt VectorOpts
Objectives map[float64]float64
}
// A SummaryVec interface represents a summary vector.
SummaryVec interface {
// Observe adds observation v to labels.
Observe(v float64, labels ...string)
close() bool
}
promSummaryVec struct {
summary *prom.SummaryVec
}
)
// NewSummaryVec return a SummaryVec
func NewSummaryVec(cfg *SummaryVecOpts) SummaryVec {
if cfg == nil {
return nil
}
vec := prom.NewSummaryVec(
prom.SummaryOpts{
Namespace: cfg.VecOpt.Namespace,
Subsystem: cfg.VecOpt.Subsystem,
Name: cfg.VecOpt.Name,
Help: cfg.VecOpt.Help,
Objectives: cfg.Objectives,
},
cfg.VecOpt.Labels,
)
prom.MustRegister(vec)
sv := &promSummaryVec{
summary: vec,
}
proc.AddShutdownListener(func() {
sv.close()
})
return sv
}
func (sv *promSummaryVec) Observe(v float64, labels ...string) {
if !prometheus.Enabled() {
return
}
sv.summary.WithLabelValues(labels...).Observe(v)
}
func (sv *promSummaryVec) close() bool {
return prom.Unregister(sv.summary)
}

View File

@@ -0,0 +1,68 @@
package metric
import (
"strings"
"testing"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/proc"
)
func TestNewSummaryVec(t *testing.T) {
summaryVec := NewSummaryVec(&SummaryVecOpts{
VecOpt: VectorOpts{
Namespace: "http_server",
Subsystem: "requests",
Name: "duration_quantiles",
Help: "rpc client requests duration(ms) φ quantiles ",
Labels: []string{"method"},
},
Objectives: map[float64]float64{
0.5: 0.01,
0.9: 0.01,
},
})
defer summaryVec.close()
summaryVecNil := NewSummaryVec(nil)
assert.NotNil(t, summaryVec)
assert.Nil(t, summaryVecNil)
}
func TestSummaryObserve(t *testing.T) {
startAgent()
summaryVec := NewSummaryVec(&SummaryVecOpts{
VecOpt: VectorOpts{
Namespace: "http_server",
Subsystem: "requests",
Name: "duration_quantiles",
Help: "rpc client requests duration(ms) φ quantiles ",
Labels: []string{"method"},
},
Objectives: map[float64]float64{
0.3: 0.01,
0.6: 0.01,
1: 0.01,
},
})
defer summaryVec.close()
sv := summaryVec.(*promSummaryVec)
sv.Observe(100, "GET")
sv.Observe(200, "GET")
sv.Observe(300, "GET")
metadata := `
# HELP http_server_requests_duration_quantiles rpc client requests duration(ms) φ quantiles
# TYPE http_server_requests_duration_quantiles summary
`
val := `
http_server_requests_duration_quantiles{method="GET",quantile="0.3"} 100
http_server_requests_duration_quantiles{method="GET",quantile="0.6"} 200
http_server_requests_duration_quantiles{method="GET",quantile="1"} 300
http_server_requests_duration_quantiles_sum{method="GET"} 600
http_server_requests_duration_quantiles_count{method="GET"} 3
`
err := testutil.CollectAndCompare(sv.summary, strings.NewReader(metadata+val))
assert.Nil(t, err)
proc.Shutdown()
}

View File

@@ -96,4 +96,6 @@ func (lm *listenerManager) notifyListeners() {
group.RunSafe(listener)
}
group.Wait()
lm.listeners = nil
}

View File

@@ -28,3 +28,33 @@ func TestShutdown(t *testing.T) {
called()
assert.Equal(t, 3, val)
}
func TestNotifyMoreThanOnce(t *testing.T) {
ch := make(chan struct{}, 1)
go func() {
var val int
called := AddWrapUpListener(func() {
val++
})
WrapUp()
WrapUp()
called()
assert.Equal(t, 1, val)
called = AddShutdownListener(func() {
val += 2
})
Shutdown()
Shutdown()
called()
assert.Equal(t, 3, val)
ch <- struct{}{}
}()
select {
case <-ch:
case <-time.After(time.Second):
t.Fatal("timeout, check error logs")
}
}

View File

@@ -3,6 +3,8 @@ package redis
import (
"testing"
"github.com/alicebob/miniredis/v2"
red "github.com/go-redis/redis/v8"
"github.com/stretchr/testify/assert"
)
@@ -41,3 +43,17 @@ func TestSplitClusterAddrs(t *testing.T) {
})
}
}
func TestGetCluster(t *testing.T) {
r := miniredis.RunT(t)
defer r.Close()
c, err := getCluster(&Redis{
Addr: r.Addr(),
Type: ClusterType,
tls: true,
hooks: []red.Hook{durationHook},
})
if assert.NoError(t, err) {
assert.NotNil(t, c)
}
}

View File

@@ -146,7 +146,7 @@ func unmarshalRow(v any, scanner rowsScanner, strict bool) error {
}
rv := reflect.ValueOf(v)
if err := mapping.ValidatePtr(&rv); err != nil {
if err := mapping.ValidatePtr(rv); err != nil {
return err
}
@@ -182,7 +182,7 @@ func unmarshalRow(v any, scanner rowsScanner, strict bool) error {
func unmarshalRows(v any, scanner rowsScanner, strict bool) error {
rv := reflect.ValueOf(v)
if err := mapping.ValidatePtr(&rv); err != nil {
if err := mapping.ValidatePtr(rv); err != nil {
return err
}

View File

@@ -291,12 +291,19 @@ func (db *commonSqlConn) TransactCtx(ctx context.Context, fn func(context.Contex
}
func (db *commonSqlConn) acceptable(err error) bool {
ok := err == nil || err == sql.ErrNoRows || err == sql.ErrTxDone || err == context.Canceled
if db.accept == nil {
return ok
if err == nil || err == sql.ErrNoRows || err == sql.ErrTxDone || err == context.Canceled {
return true
}
return ok || db.accept(err)
if _, ok := err.(acceptableError); ok {
return true
}
if db.accept == nil {
return false
}
return db.accept(err)
}
func (db *commonSqlConn) queryRows(ctx context.Context, scanner func(*sql.Rows) error,

View File

@@ -236,6 +236,33 @@ func TestStatement(t *testing.T) {
})
}
func TestBreakerWithFormatError(t *testing.T) {
dbtest.RunTest(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
conn := NewSqlConnFromDB(db, withMysqlAcceptable())
for i := 0; i < 1000; i++ {
var val string
if !assert.NotEqual(t, breaker.ErrServiceUnavailable,
conn.QueryRow(&val, "any ?, ?", "foo")) {
break
}
}
})
}
func TestBreakerWithScanError(t *testing.T) {
dbtest.RunTest(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
conn := NewSqlConnFromDB(db, withMysqlAcceptable())
for i := 0; i < 1000; i++ {
rows := sqlmock.NewRows([]string{"foo"}).AddRow("bar")
mock.ExpectQuery("any").WillReturnRows(rows)
var val int
if !assert.NotEqual(t, breaker.ErrServiceUnavailable, conn.QueryRow(&val, "any")) {
break
}
}
})
}
func buildConn() (mock sqlmock.Sqlmock, err error) {
_, err = connManager.GetResource(mockedDatasource, func() (io.Closer, error) {
var db *sql.DB

View File

@@ -51,7 +51,13 @@ func escape(input string) string {
return b.String()
}
func format(query string, args ...any) (string, error) {
func format(query string, args ...any) (val string, err error) {
defer func() {
if err != nil {
err = newAcceptableError(err)
}
}()
numArgs := len(args)
if numArgs == 0 {
return query, nil
@@ -66,7 +72,8 @@ func format(query string, args ...any) (string, error) {
switch ch {
case '?':
if argIndex >= numArgs {
return "", fmt.Errorf("%d ? in sql, but less arguments provided", argIndex)
return "", fmt.Errorf("%d ? in sql, but only %d arguments provided",
argIndex+1, numArgs)
}
writeValue(&b, args[argIndex])
@@ -165,3 +172,17 @@ func writeValue(buf *strings.Builder, arg any) {
buf.WriteString(mapping.Repr(v))
}
}
type acceptableError struct {
err error
}
func newAcceptableError(err error) error {
return acceptableError{
err: err,
}
}
func (e acceptableError) Error() string {
return e.err.Error()
}

View File

@@ -26,6 +26,7 @@ const (
kindOtlpGrpc = "otlpgrpc"
kindOtlpHttp = "otlphttp"
kindFile = "file"
protocolUdp = "udp"
)
var (
@@ -65,9 +66,10 @@ func createExporter(c Config) (sdktrace.SpanExporter, error) {
// Just support jaeger and zipkin now, more for later
switch c.Batcher {
case kindJaeger:
u, _ := url.Parse(c.Endpoint)
if u.Scheme == "udp" {
return jaeger.New(jaeger.WithAgentEndpoint(jaeger.WithAgentHost(u.Hostname()), jaeger.WithAgentPort(u.Port())))
u, err := url.Parse(c.Endpoint)
if err == nil && u.Scheme == protocolUdp {
return jaeger.New(jaeger.WithAgentEndpoint(jaeger.WithAgentHost(u.Hostname()),
jaeger.WithAgentPort(u.Port())))
}
return jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(c.Endpoint)))
case kindZipkin:

38
go.mod
View File

@@ -4,25 +4,25 @@ go 1.18
require (
github.com/DATA-DOG/go-sqlmock v1.5.0
github.com/alicebob/miniredis/v2 v2.30.4
github.com/alicebob/miniredis/v2 v2.30.5
github.com/fatih/color v1.15.0
github.com/fullstorydev/grpcurl v1.8.7
github.com/fullstorydev/grpcurl v1.8.8
github.com/go-redis/redis/v8 v8.11.5
github.com/go-sql-driver/mysql v1.7.1
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/golang/mock v1.6.0
github.com/golang/protobuf v1.5.3
github.com/google/uuid v1.3.0
github.com/jackc/pgx/v5 v5.4.2
github.com/jhump/protoreflect v1.15.1
github.com/google/uuid v1.3.1
github.com/jackc/pgx/v5 v5.4.3
github.com/jhump/protoreflect v1.15.2
github.com/olekukonko/tablewriter v0.0.5
github.com/pelletier/go-toml/v2 v2.0.9
github.com/pelletier/go-toml/v2 v2.1.0
github.com/prometheus/client_golang v1.16.0
github.com/spaolacci/murmur3 v1.1.0
github.com/stretchr/testify v1.8.4
go.etcd.io/etcd/api/v3 v3.5.9
go.etcd.io/etcd/client/v3 v3.5.9
go.mongodb.org/mongo-driver v1.12.0
go.mongodb.org/mongo-driver v1.12.1
go.opentelemetry.io/otel v1.14.0
go.opentelemetry.io/otel/exporters/jaeger v1.14.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0
@@ -31,13 +31,13 @@ require (
go.opentelemetry.io/otel/exporters/zipkin v1.14.0
go.opentelemetry.io/otel/sdk v1.14.0
go.opentelemetry.io/otel/trace v1.14.0
go.uber.org/automaxprocs v1.5.2
go.uber.org/automaxprocs v1.5.3
go.uber.org/goleak v1.2.1
golang.org/x/net v0.12.0
golang.org/x/sys v0.10.0
golang.org/x/net v0.15.0
golang.org/x/sys v0.12.0
golang.org/x/time v0.3.0
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1
google.golang.org/grpc v1.56.2
google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e
google.golang.org/grpc v1.58.2
google.golang.org/protobuf v1.31.0
gopkg.in/cheggaaa/pb.v1 v1.0.28
gopkg.in/h2non/gock.v1 v1.1.2
@@ -51,7 +51,7 @@ require (
require (
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bufbuild/protocompile v0.4.0 // indirect
github.com/bufbuild/protocompile v0.6.0 // indirect
github.com/cenkalti/backoff/v4 v4.2.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
@@ -103,12 +103,14 @@ require (
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/crypto v0.11.0 // indirect
golang.org/x/oauth2 v0.7.0 // indirect
golang.org/x/sync v0.2.0 // indirect
golang.org/x/term v0.10.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/crypto v0.13.0 // indirect
golang.org/x/oauth2 v0.10.0 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/term v0.12.0 // indirect
golang.org/x/text v0.13.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/klog/v2 v2.90.1 // indirect

1138
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -9,36 +9,27 @@ import (
"gopkg.in/yaml.v2"
)
// TomlToJson converts TOML data into its JSON representation.
func TomlToJson(data []byte) ([]byte, error) {
var val any
if err := toml.NewDecoder(bytes.NewReader(data)).Decode(&val); err != nil {
return nil, err
}
var buf bytes.Buffer
if err := json.NewEncoder(&buf).Encode(val); err != nil {
return nil, err
}
return buf.Bytes(), nil
return encodeToJSON(val)
}
// YamlToJson converts YAML data into its JSON representation.
func YamlToJson(data []byte) ([]byte, error) {
var val any
if err := yaml.Unmarshal(data, &val); err != nil {
return nil, err
}
val = toStringKeyMap(val)
var buf bytes.Buffer
if err := json.NewEncoder(&buf).Encode(val); err != nil {
return nil, err
}
return buf.Bytes(), nil
return encodeToJSON(toStringKeyMap(val))
}
// convertKeyToString ensures all keys of the map are of type string.
func convertKeyToString(in map[any]any) map[string]any {
res := make(map[string]any)
for k, v := range in {
@@ -47,10 +38,12 @@ func convertKeyToString(in map[any]any) map[string]any {
return res
}
// convertNumberToJsonNumber converts numbers into json.Number type for compatibility.
func convertNumberToJsonNumber(in any) json.Number {
return json.Number(lang.Repr(in))
}
// convertSlice processes slice items to ensure key compatibility.
func convertSlice(in []any) []any {
res := make([]any, len(in))
for i, v := range in {
@@ -59,6 +52,17 @@ func convertSlice(in []any) []any {
return res
}
// encodeToJSON encodes the given value into its JSON representation.
func encodeToJSON(val any) ([]byte, error) {
var buf bytes.Buffer
if err := json.NewEncoder(&buf).Encode(val); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// toStringKeyMap processes the data to ensure that all map keys are of type string.
func toStringKeyMap(v any) any {
switch v := v.(type) {
case []any:

View File

@@ -295,6 +295,7 @@ go-zero 已被许多公司用于生产部署,接入场景如在线教育、电
>91. 宁波甬风信息科技有限公司
>92. 深圳市万佳安物联科技股份有限公司
>93. 武侯区编程之美软件开发工作室
>94. 西安交通大学智慧能源与碳中和研究中心
如果贵公司也已使用 go-zero欢迎在 [登记地址](https://github.com/zeromicro/go-zero/issues/602) 登记,仅仅为了推广,不做其它用途。

View File

@@ -132,7 +132,7 @@ func (w *cryptionResponseWriter) flush(key []byte) {
body := base64.StdEncoding.EncodeToString(content)
if n, err := io.WriteString(w.ResponseWriter, body); err != nil {
logx.Errorf("write response failed, error: %s", err)
} else if n < len(content) {
logx.Errorf("actual bytes: %d, written bytes: %d", len(content), n)
} else if n < len(body) {
logx.Errorf("actual bytes: %d, written bytes: %d", len(body), n)
}
}

View File

@@ -2,15 +2,18 @@ package handler
import (
"bytes"
"crypto/rand"
"encoding/base64"
"io"
"math/rand"
"net/http"
"net/http/httptest"
"strings"
"testing"
"testing/iotest"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/codec"
"github.com/zeromicro/go-zero/core/logx/logtest"
)
const (
@@ -37,6 +40,19 @@ func TestCryptionHandlerGet(t *testing.T) {
assert.Equal(t, base64.StdEncoding.EncodeToString(expect), recorder.Body.String())
}
func TestCryptionHandlerGet_badKey(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/any", http.NoBody)
handler := CryptionHandler(append(aesKey, aesKey...))(http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
_, err := w.Write([]byte(respText))
w.Header().Set("X-Test", "test")
assert.Nil(t, err)
}))
recorder := httptest.NewRecorder()
handler.ServeHTTP(recorder, req)
assert.Equal(t, http.StatusInternalServerError, recorder.Code)
}
func TestCryptionHandlerPost(t *testing.T) {
var buf bytes.Buffer
enc, err := codec.EcbEncrypt(aesKey, []byte(reqText))
@@ -120,10 +136,110 @@ func TestCryptionHandler_ContentTooLong(t *testing.T) {
defer svr.Close()
body := make([]byte, maxBytes+1)
rand.Read(body)
_, err := rand.Read(body)
assert.NoError(t, err)
req, err := http.NewRequest(http.MethodPost, svr.URL, bytes.NewReader(body))
assert.Nil(t, err)
resp, err := http.DefaultClient.Do(req)
assert.Nil(t, err)
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
}
func TestCryptionHandler_BadBody(t *testing.T) {
req, err := http.NewRequest(http.MethodPost, "/foo", iotest.ErrReader(io.ErrUnexpectedEOF))
assert.Nil(t, err)
err = decryptBody(maxBytes, aesKey, req)
assert.ErrorIs(t, err, io.ErrUnexpectedEOF)
}
func TestCryptionHandler_BadKey(t *testing.T) {
var buf bytes.Buffer
enc, err := codec.EcbEncrypt(aesKey, []byte(reqText))
assert.Nil(t, err)
buf.WriteString(base64.StdEncoding.EncodeToString(enc))
req := httptest.NewRequest(http.MethodPost, "/any", &buf)
err = decryptBody(maxBytes, append(aesKey, aesKey...), req)
assert.Error(t, err)
}
func TestCryptionResponseWriter_Flush(t *testing.T) {
body := []byte("hello, world!")
t.Run("half", func(t *testing.T) {
recorder := httptest.NewRecorder()
f := flushableResponseWriter{
writer: &halfWriter{recorder},
}
w := newCryptionResponseWriter(f)
_, err := w.Write(body)
assert.NoError(t, err)
w.flush(aesKey)
b, err := io.ReadAll(recorder.Body)
assert.NoError(t, err)
expected, err := codec.EcbEncrypt(aesKey, body)
assert.NoError(t, err)
assert.True(t, strings.HasPrefix(base64.StdEncoding.EncodeToString(expected), string(b)))
assert.True(t, len(string(b)) < len(base64.StdEncoding.EncodeToString(expected)))
})
t.Run("full", func(t *testing.T) {
recorder := httptest.NewRecorder()
f := flushableResponseWriter{
writer: recorder,
}
w := newCryptionResponseWriter(f)
_, err := w.Write(body)
assert.NoError(t, err)
w.flush(aesKey)
b, err := io.ReadAll(recorder.Body)
assert.NoError(t, err)
expected, err := codec.EcbEncrypt(aesKey, body)
assert.NoError(t, err)
assert.Equal(t, base64.StdEncoding.EncodeToString(expected), string(b))
})
t.Run("bad writer", func(t *testing.T) {
buf := logtest.NewCollector(t)
f := flushableResponseWriter{
writer: new(badWriter),
}
w := newCryptionResponseWriter(f)
_, err := w.Write(body)
assert.NoError(t, err)
w.flush(aesKey)
assert.True(t, strings.Contains(buf.Content(), io.ErrClosedPipe.Error()))
})
}
type flushableResponseWriter struct {
writer io.Writer
}
func (m flushableResponseWriter) Header() http.Header {
panic("implement me")
}
func (m flushableResponseWriter) Write(p []byte) (int, error) {
return m.writer.Write(p)
}
func (m flushableResponseWriter) WriteHeader(statusCode int) {
panic("implement me")
}
type halfWriter struct {
w io.Writer
}
func (t *halfWriter) Write(p []byte) (n int, err error) {
n = len(p) >> 1
return t.w.Write(p[0:n])
}
type badWriter struct {
}
func (b *badWriter) Write(p []byte) (n int, err error) {
return 0, io.ErrClosedPipe
}

View File

@@ -10,7 +10,6 @@ import (
"net/http"
"net/http/httputil"
"strconv"
"strings"
"time"
"github.com/zeromicro/go-zero/core/color"
@@ -39,7 +38,7 @@ func LogHandler(next http.Handler) http.Handler {
lrw := response.NewWithCodeResponseWriter(w)
var dup io.ReadCloser
r.Body, dup = iox.DupReadCloser(r.Body)
r.Body, dup = iox.LimitDupReadCloser(r.Body, limitBodyBytes)
next.ServeHTTP(lrw, r.WithContext(internal.WithLogCollector(r.Context(), logs)))
r.Body = dup
logBrief(r, lrw.Code, timer, logs)
@@ -136,14 +135,7 @@ func logBrief(r *http.Request, code int, timer *utils.ElapsedTimer, logs *intern
ok := isOkResponse(code)
if !ok {
fullReq := dumpRequest(r)
limitReader := io.LimitReader(strings.NewReader(fullReq), limitBodyBytes)
body, err := io.ReadAll(limitReader)
if err != nil {
buf.WriteString(fmt.Sprintf("\n%s", fullReq))
} else {
buf.WriteString(fmt.Sprintf("\n%s", string(body)))
}
buf.WriteString(fmt.Sprintf("\n%s", dumpRequest(r)))
}
body := logs.Flush()

View File

@@ -23,8 +23,8 @@ const (
)
var (
formUnmarshaler = mapping.NewUnmarshaler(formKey, mapping.WithStringValues())
pathUnmarshaler = mapping.NewUnmarshaler(pathKey, mapping.WithStringValues())
formUnmarshaler = mapping.NewUnmarshaler(formKey, mapping.WithStringValues(), mapping.WithOpaqueKeys())
pathUnmarshaler = mapping.NewUnmarshaler(pathKey, mapping.WithStringValues(), mapping.WithOpaqueKeys())
validator atomic.Value
)

View File

@@ -326,6 +326,8 @@ func TestParseHeaders_Error(t *testing.T) {
func TestParseWithValidator(t *testing.T) {
SetValidator(mockValidator{})
defer SetValidator(mockValidator{nop: true})
var v struct {
Name string `form:"name"`
Age int `form:"age"`
@@ -343,6 +345,8 @@ func TestParseWithValidator(t *testing.T) {
func TestParseWithValidatorWithError(t *testing.T) {
SetValidator(mockValidator{})
defer SetValidator(mockValidator{nop: true})
var v struct {
Name string `form:"name"`
Age int `form:"age"`
@@ -356,12 +360,41 @@ func TestParseWithValidatorWithError(t *testing.T) {
func TestParseWithValidatorRequest(t *testing.T) {
SetValidator(mockValidator{})
defer SetValidator(mockValidator{nop: true})
var v mockRequest
r, err := http.NewRequest(http.MethodGet, "/a?&age=18", http.NoBody)
assert.Nil(t, err)
assert.Error(t, Parse(r, &v))
}
func TestParseFormWithDot(t *testing.T) {
var v struct {
Age int `form:"user.age"`
}
r, err := http.NewRequest(http.MethodGet, "/a?user.age=18", http.NoBody)
assert.Nil(t, err)
assert.NoError(t, Parse(r, &v))
assert.Equal(t, 18, v.Age)
}
func TestParsePathWithDot(t *testing.T) {
var v struct {
Name string `path:"name.val"`
Age int `path:"age.val"`
}
r := httptest.NewRequest(http.MethodGet, "/", http.NoBody)
r = pathvar.WithVars(r, map[string]string{
"name.val": "foo",
"age.val": "18",
})
err := Parse(r, &v)
assert.Nil(t, err)
assert.Equal(t, "foo", v.Name)
assert.Equal(t, 18, v.Age)
}
func BenchmarkParseRaw(b *testing.B) {
r, err := http.NewRequest(http.MethodGet, "http://hello.com/a?name=hello&age=18&percent=3.4", http.NoBody)
if err != nil {
@@ -406,9 +439,15 @@ func BenchmarkParseAuto(b *testing.B) {
}
}
type mockValidator struct{}
type mockValidator struct {
nop bool
}
func (m mockValidator) Validate(r *http.Request, data any) error {
if m.nop {
return nil
}
if r.URL.Path == "/a" {
val := reflect.ValueOf(data).Elem().FieldByName("Name").String()
if val != "hello" {

View File

@@ -58,7 +58,7 @@ func TestFormat(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, formattedStr, r)
_, err = apiFormat(notFormattedStr, false)
assert.Errorf(t, err, " line 7:13 can not found declaration 'Student' in context")
assert.Errorf(t, err, " line 7:13 can not find declaration 'Student' in context")
}
func Test_apiFormatReader_issue1721(t *testing.T) {

View File

@@ -1,3 +1,5 @@
syntax = "v1"
type Request {
Name string `path:"name,options=you|me"`
}

View File

@@ -420,7 +420,7 @@ func (p *Parser) checkServices(apiItem *Api, types map[string]TypeExpr, linePref
_, ok := types[structName]
if !ok {
return fmt.Errorf("%s line %d:%d can not found declaration '%s' in context",
return fmt.Errorf("%s line %d:%d can not find declaration '%s' in context",
linePrefix, route.Reply.Name.Expr().Line(), route.Reply.Name.Expr().Column(), structName)
}
}
@@ -433,7 +433,7 @@ func (p *Parser) checkRequestBody(route *Route, types map[string]TypeExpr, lineP
if route.Req != nil && route.Req.Name.IsNotNil() && route.Req.Name.Expr().IsNotNil() {
_, ok := types[route.Req.Name.Expr().Text()]
if !ok {
return fmt.Errorf("%s line %d:%d can not found declaration '%s' in context",
return fmt.Errorf("%s line %d:%d can not find declaration '%s' in context",
linePrefix, route.Req.Name.Expr().Line(), route.Req.Name.Expr().Column(), route.Req.Name.Expr().Text())
}
}
@@ -470,7 +470,7 @@ func (p *Parser) checkType(linePrefix string, types map[string]TypeExpr, expr Da
}
_, ok := types[name]
if !ok {
return fmt.Errorf("%s line %d:%d can not found declaration '%s' in context",
return fmt.Errorf("%s line %d:%d can not find declaration '%s' in context",
linePrefix, v.Literal.Line(), v.Literal.Column(), name)
}
@@ -481,7 +481,7 @@ func (p *Parser) checkType(linePrefix string, types map[string]TypeExpr, expr Da
}
_, ok := types[name]
if !ok {
return fmt.Errorf("%s line %d:%d can not found declaration '%s' in context",
return fmt.Errorf("%s line %d:%d can not find declaration '%s' in context",
linePrefix, v.Name.Line(), v.Name.Column(), name)
}
case *Map:

View File

@@ -2,7 +2,7 @@ package main
import "github.com/zeromicro/go-zero/tools/goctl/compare/cmd"
// EXPRIMENTAL: compare goctl generated code results between old and new, it will be removed in the feature.
// EXPERIMENTAL: compare goctl generated code results between old and new, it will be removed in the feature.
// TODO: BEFORE RUNNING: export DSN=$datasource, the database must be gozero, and there has no limit for tables.
// TODO: AFTER RUNNING: diff --recursive old_fs new_fs

View File

@@ -4,10 +4,10 @@ go 1.18
require (
github.com/DATA-DOG/go-sqlmock v1.5.0
github.com/emicklei/proto v1.11.2
github.com/emicklei/proto v1.12.1
github.com/fatih/structtag v1.2.0
github.com/go-sql-driver/mysql v1.7.1
github.com/gookit/color v1.5.3
github.com/gookit/color v1.5.4
github.com/iancoleman/strcase v0.3.0
github.com/spf13/cobra v1.7.0
github.com/spf13/pflag v1.0.5
@@ -15,15 +15,15 @@ require (
github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1
github.com/zeromicro/antlr v0.0.1
github.com/zeromicro/ddl-parser v1.0.5
github.com/zeromicro/go-zero v1.5.3
golang.org/x/text v0.11.0
google.golang.org/grpc v1.56.2
github.com/zeromicro/go-zero v1.5.5
golang.org/x/text v0.13.0
google.golang.org/grpc v1.58.2
google.golang.org/protobuf v1.31.0
)
require (
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect
github.com/alicebob/miniredis/v2 v2.30.3 // indirect
github.com/alicebob/miniredis/v2 v2.30.5 // indirect
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521184019-c5ad59b459ec // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.2.0 // indirect
@@ -51,7 +51,7 @@ require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.3.1 // indirect
github.com/jackc/pgx/v5 v5.4.3 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
@@ -63,12 +63,12 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/openzipkin/zipkin-go v0.4.1 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/pelletier/go-toml/v2 v2.0.9 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.15.1 // indirect
github.com/prometheus/client_golang v1.16.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.9.0 // indirect
github.com/prometheus/procfs v0.10.1 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
github.com/yuin/gopher-lua v1.1.0 // indirect
@@ -87,17 +87,19 @@ require (
go.opentelemetry.io/otel/trace v1.14.0 // indirect
go.opentelemetry.io/proto/otlp v0.19.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/automaxprocs v1.5.2 // indirect
go.uber.org/automaxprocs v1.5.3 // indirect
go.uber.org/multierr v1.9.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/crypto v0.6.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/oauth2 v0.7.0 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/term v0.8.0 // indirect
golang.org/x/crypto v0.12.0 // indirect
golang.org/x/net v0.14.0 // indirect
golang.org/x/oauth2 v0.10.0 // indirect
golang.org/x/sys v0.11.0 // indirect
golang.org/x/term v0.11.0 // indirect
golang.org/x/time v0.3.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect

View File

@@ -38,8 +38,8 @@ github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
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.30.3 h1:hrqDB4cHFSHQf4gO3xu6YKQg8PqJpNjLYsQAFYHstqw=
github.com/alicebob/miniredis/v2 v2.30.3/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg=
github.com/alicebob/miniredis/v2 v2.30.5 h1:3r6kTHdKnuP4fkS8k2IrvSfxpxUTcW1SOL0wN7b7Dt0=
github.com/alicebob/miniredis/v2 v2.30.5/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg=
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=
@@ -78,8 +78,8 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cu
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE=
github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/emicklei/proto v1.11.2 h1:DiIeyTJ+gPSyJI+RIAqvuTeKb0tLUmaGXbYg6aFKsnE=
github.com/emicklei/proto v1.11.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
github.com/emicklei/proto v1.12.1 h1:6n/Z2pZAnBwuhU66Gs8160B8rrrYKo7h2F2sCOnNceE=
github.com/emicklei/proto v1.12.1/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=
@@ -181,8 +181,8 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gookit/color v1.5.3 h1:twfIhZs4QLCtimkP7MOxlF3A0U/5cDPseRT9M/+2SCE=
github.com/gookit/color v1.5.3/go.mod h1:NUzwzeehUfl7GIb36pqId+UGmRfQcU/WiiyTTeNjHtE=
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0 h1:1JYBfzqrWPcCclBwxFCPAou9n+q86mfnu7NAeHfte7A=
@@ -199,8 +199,8 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU=
github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8=
github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY=
github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
@@ -241,21 +241,21 @@ github.com/onsi/ginkgo/v2 v2.7.0 h1:/XxtEV3I3Eif/HobnVx9YmJgk8ENdRsuUmM+fLCFNow=
github.com/onsi/gomega v1.26.0 h1:03cDLK28U6hWvCAns6NeydX3zIm4SF3ci69ulidS32Q=
github.com/openzipkin/zipkin-go v0.4.1 h1:kNd/ST2yLLWhaWrkgchya40TJabe8Hioj9udfPcEO5A=
github.com/openzipkin/zipkin-go v0.4.1/go.mod h1:qY0VqDSN1pOBN94dBc6w2GJlWLiovAyg7Qt6/I9HecM=
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0=
github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI=
github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
@@ -279,7 +279,6 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1 h1:+dBg5k7nuTE38VVdoroRsT0Z88fmvdYrI2EjzJst35I=
@@ -297,8 +296,8 @@ github.com/zeromicro/antlr v0.0.1 h1:CQpIn/dc0pUjgGQ81y98s/NGOm2Hfru2NNio2I9mQgk
github.com/zeromicro/antlr v0.0.1/go.mod h1:nfpjEwFR6Q4xGDJMcZnCL9tEfQRgszMwu3rDz2Z+p5M=
github.com/zeromicro/ddl-parser v1.0.5 h1:LaVqHdzMTjasua1yYpIYaksxKqRzFrEukj2Wi2EbWaQ=
github.com/zeromicro/ddl-parser v1.0.5/go.mod h1:ISU/8NuPyEpl9pa17Py9TBPetMjtsiHrb9f5XGiYbo8=
github.com/zeromicro/go-zero v1.5.3 h1:9poyd+raeL7gSMUu6P19N7bssTppieR2j7Oos2j1yFQ=
github.com/zeromicro/go-zero v1.5.3/go.mod h1:dmoBpgJTxt9KWmgrNGpv06XxZRPXMakrxUVgROFAR3g=
github.com/zeromicro/go-zero v1.5.5 h1:qEHnDuCBu/gDBmfWEZXYow6ZmWmzsrJTjtjSMVm4SiY=
github.com/zeromicro/go-zero v1.5.5/go.mod h1:AGCspTFitHzYjl5ddAmYWLfdt341+BrhefqlwO45UbU=
go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs=
go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k=
go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2IGsE=
@@ -335,8 +334,8 @@ go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJP
go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/automaxprocs v1.5.2 h1:2LxUOGiR3O6tw8ui5sZa2LAaHnsviZdVOUZw4fvbnME=
go.uber.org/automaxprocs v1.5.2/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8=
go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
@@ -347,8 +346,8 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/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/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -408,16 +407,16 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R
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.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
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-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g=
golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4=
golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8=
golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI=
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=
@@ -460,19 +459,19 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0=
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
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.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
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/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -581,8 +580,12 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 h1:Z0hjGZePRE0ZBWotvtrwxFNrNE9CUAGtplaDK5NNI/g=
google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0=
google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw=
google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -599,8 +602,8 @@ google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTp
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI=
google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I=
google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
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=

View File

@@ -6,7 +6,7 @@ import (
)
// BuildVersion is the version of goctl.
const BuildVersion = "1.5.4"
const BuildVersion = "1.5.5"
var tag = map[string]int{"pre-alpha": 0, "alpha": 1, "pre-bata": 2, "beta": 3, "released": 4, "": 5}

View File

@@ -72,7 +72,8 @@ from (
t.typname AS type,
a.atttypmod AS lengthvar,
a.attnotnull AS not_null,
b.description AS comment
b.description AS comment,
(c.relnamespace::regnamespace)::varchar AS schema_name
FROM pg_class c,
pg_attribute a
LEFT OUTER JOIN pg_description b ON a.attrelid = b.objoid AND a.attnum = b.objsubid,
@@ -81,10 +82,11 @@ from (
and a.attnum > 0
and a.attrelid = c.oid
and a.atttypid = t.oid
GROUP BY a.attnum, c.relname, a.attname, t.typname, a.atttypmod, a.attnotnull, b.description
GROUP BY a.attnum, c.relname, a.attname, t.typname, a.atttypmod, a.attnotnull, b.description, c.relnamespace::regnamespace
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`
left join information_schema.columns AS c on t.relname = c.table_name and t.schema_name = c.table_schema
and t.field = c.column_name
where c.table_schema = $2`
var reply []*PostgreColumn
err := m.conn.QueryRowsPartial(&reply, querySql, table, schema)

View File

@@ -147,3 +147,6 @@ func (m mockClientConn) UpdateAddresses(addresses []resolver.Address) {
func (m mockClientConn) Connect() {
}
func (m mockClientConn) Shutdown() {
}