Feature: Add goctl env (#1557)
This commit is contained in:
208
tools/goctl/pkg/collection/sortedmap.go
Normal file
208
tools/goctl/pkg/collection/sortedmap.go
Normal file
@@ -0,0 +1,208 @@
|
||||
package sortedmap
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/zeromicro/go-zero/tools/goctl/util/stringx"
|
||||
)
|
||||
|
||||
var ErrInvalidKVExpression = errors.New(`invalid key-value expression`)
|
||||
var ErrInvalidKVS = errors.New("the length of kv must be a even number")
|
||||
|
||||
type KV []interface{}
|
||||
|
||||
type SortedMap struct {
|
||||
kv *list.List
|
||||
keys map[interface{}]*list.Element
|
||||
}
|
||||
|
||||
func New() *SortedMap {
|
||||
return &SortedMap{
|
||||
kv: list.New(),
|
||||
keys: make(map[interface{}]*list.Element),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *SortedMap) SetExpression(expression string) (key interface{}, value interface{}, err error) {
|
||||
idx := strings.Index(expression, "=")
|
||||
if idx == -1 {
|
||||
return "", "", ErrInvalidKVExpression
|
||||
}
|
||||
key = expression[:idx]
|
||||
if len(expression) == idx {
|
||||
value = ""
|
||||
} else {
|
||||
value = expression[idx+1:]
|
||||
}
|
||||
if keys, ok := key.(string); ok && stringx.ContainsWhiteSpace(keys) {
|
||||
return "", "", ErrInvalidKVExpression
|
||||
}
|
||||
if values, ok := value.(string); ok && stringx.ContainsWhiteSpace(values) {
|
||||
return "", "", ErrInvalidKVExpression
|
||||
}
|
||||
if len(key.(string)) == 0 {
|
||||
return "", "", ErrInvalidKVExpression
|
||||
}
|
||||
|
||||
m.SetKV(key, value)
|
||||
return
|
||||
}
|
||||
|
||||
func (m *SortedMap) SetKV(key, value interface{}) {
|
||||
e, ok := m.keys[key]
|
||||
if !ok {
|
||||
e = m.kv.PushBack(KV{
|
||||
key, value,
|
||||
})
|
||||
} else {
|
||||
e.Value.(KV)[1] = value
|
||||
}
|
||||
m.keys[key] = e
|
||||
}
|
||||
|
||||
func (m *SortedMap) Set(kv KV) error {
|
||||
if len(kv) == 0 {
|
||||
return nil
|
||||
}
|
||||
if len(kv)%2 != 0 {
|
||||
return ErrInvalidKVS
|
||||
}
|
||||
for idx := 0; idx < len(kv); idx += 2 {
|
||||
m.SetKV(kv[idx], kv[idx+1])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *SortedMap) Get(key interface{}) (interface{}, bool) {
|
||||
e, ok := m.keys[key]
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
return e.Value.(KV)[1], true
|
||||
}
|
||||
|
||||
func (m *SortedMap) GetOr(key interface{}, dft interface{}) interface{} {
|
||||
e, ok := m.keys[key]
|
||||
if !ok {
|
||||
return dft
|
||||
}
|
||||
return e.Value.(KV)[1]
|
||||
}
|
||||
|
||||
func (m *SortedMap) GetString(key interface{}) (string, bool) {
|
||||
value, ok := m.Get(key)
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
vs, ok := value.(string)
|
||||
return vs, ok
|
||||
}
|
||||
|
||||
func (m *SortedMap) GetStringOr(key interface{}, dft string) string {
|
||||
value, ok := m.GetString(key)
|
||||
if !ok {
|
||||
return dft
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func (m *SortedMap) HasKey(key interface{}) bool {
|
||||
_, ok := m.keys[key]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (m *SortedMap) HasValue(value interface{}) bool {
|
||||
var contains bool
|
||||
m.RangeIf(func(key, v interface{}) bool {
|
||||
if value == v {
|
||||
contains = true
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
return contains
|
||||
}
|
||||
|
||||
func (m *SortedMap) Keys() []interface{} {
|
||||
keys := make([]interface{}, 0)
|
||||
next := m.kv.Front()
|
||||
for next != nil {
|
||||
keys = append(keys, next.Value.(KV)[0])
|
||||
next = next.Next()
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
func (m *SortedMap) Values() []interface{} {
|
||||
keys := m.Keys()
|
||||
values := make([]interface{}, len(keys))
|
||||
for idx, key := range keys {
|
||||
values[idx] = m.keys[key].Value.(KV)[1]
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
func (m *SortedMap) Range(iterator func(key, value interface{})) {
|
||||
next := m.kv.Front()
|
||||
for next != nil {
|
||||
value := next.Value.(KV)
|
||||
iterator(value[0], value[1])
|
||||
next = next.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func (m *SortedMap) RangeIf(iterator func(key, value interface{}) bool) {
|
||||
next := m.kv.Front()
|
||||
for next != nil {
|
||||
value := next.Value.(KV)
|
||||
loop := iterator(value[0], value[1])
|
||||
if !loop {
|
||||
return
|
||||
}
|
||||
next = next.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func (m *SortedMap) Remove(key interface{}) (value interface{}, ok bool) {
|
||||
v, ok := m.keys[key]
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
value = v.Value.(KV)[1]
|
||||
ok = true
|
||||
m.kv.Remove(v)
|
||||
delete(m.keys, key)
|
||||
return
|
||||
}
|
||||
|
||||
func (m *SortedMap) Insert(sm *SortedMap) {
|
||||
sm.Range(func(key, value interface{}) {
|
||||
m.SetKV(key, value)
|
||||
})
|
||||
}
|
||||
|
||||
func (m *SortedMap) Copy() *SortedMap {
|
||||
sm := New()
|
||||
m.Range(func(key, value interface{}) {
|
||||
sm.SetKV(key, value)
|
||||
})
|
||||
return sm
|
||||
}
|
||||
|
||||
func (m *SortedMap) Format() []string {
|
||||
var format = make([]string, 0)
|
||||
m.Range(func(key, value interface{}) {
|
||||
format = append(format, fmt.Sprintf("%s=%s", key, value))
|
||||
})
|
||||
return format
|
||||
}
|
||||
|
||||
func (m *SortedMap) Reset() {
|
||||
m.kv.Init()
|
||||
for key := range m.keys {
|
||||
delete(m.keys, key)
|
||||
}
|
||||
}
|
||||
235
tools/goctl/pkg/collection/sortedmap_test.go
Normal file
235
tools/goctl/pkg/collection/sortedmap_test.go
Normal file
@@ -0,0 +1,235 @@
|
||||
package sortedmap
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_SortedMap(t *testing.T) {
|
||||
sm := New()
|
||||
t.Run("SetExpression", func(t *testing.T) {
|
||||
_, _, err := sm.SetExpression("")
|
||||
assert.ErrorIs(t, err, ErrInvalidKVExpression)
|
||||
_, _, err = sm.SetExpression("foo")
|
||||
assert.ErrorIs(t, err, ErrInvalidKVExpression)
|
||||
_, _, err = sm.SetExpression("foo= ")
|
||||
assert.ErrorIs(t, err, ErrInvalidKVExpression)
|
||||
_, _, err = sm.SetExpression(" foo=")
|
||||
assert.ErrorIs(t, err, ErrInvalidKVExpression)
|
||||
_, _, err = sm.SetExpression("foo =")
|
||||
assert.ErrorIs(t, err, ErrInvalidKVExpression)
|
||||
_, _, err = sm.SetExpression("=")
|
||||
assert.ErrorIs(t, err, ErrInvalidKVExpression)
|
||||
_, _, err = sm.SetExpression("=bar")
|
||||
assert.ErrorIs(t, err, ErrInvalidKVExpression)
|
||||
key, value, err := sm.SetExpression("foo=bar")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "foo", key)
|
||||
assert.Equal(t, "bar", value)
|
||||
key, value, err = sm.SetExpression("foo=")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, value, sm.GetOr(key, ""))
|
||||
sm.Reset()
|
||||
})
|
||||
|
||||
t.Run("SetKV", func(t *testing.T) {
|
||||
sm.SetKV("foo", "bar")
|
||||
assert.Equal(t, "bar", sm.GetOr("foo", ""))
|
||||
sm.SetKV("foo", "bar-changed")
|
||||
assert.Equal(t, "bar-changed", sm.GetOr("foo", ""))
|
||||
sm.Reset()
|
||||
})
|
||||
|
||||
t.Run("Set", func(t *testing.T) {
|
||||
err := sm.Set(KV{})
|
||||
assert.Nil(t, err)
|
||||
err = sm.Set(KV{"foo"})
|
||||
assert.ErrorIs(t, ErrInvalidKVS, err)
|
||||
err = sm.Set(KV{"foo", "bar", "bar", "foo"})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "bar", sm.GetOr("foo", ""))
|
||||
assert.Equal(t, "foo", sm.GetOr("bar", ""))
|
||||
sm.Reset()
|
||||
})
|
||||
|
||||
t.Run("Get", func(t *testing.T) {
|
||||
_, ok := sm.Get("foo")
|
||||
assert.False(t, ok)
|
||||
sm.SetKV("foo", "bar")
|
||||
value, ok := sm.Get("foo")
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "bar", value)
|
||||
sm.Reset()
|
||||
})
|
||||
|
||||
t.Run("GetString", func(t *testing.T) {
|
||||
_, ok := sm.GetString("foo")
|
||||
assert.False(t, ok)
|
||||
sm.SetKV("foo", "bar")
|
||||
value, ok := sm.GetString("foo")
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "bar", value)
|
||||
sm.Reset()
|
||||
})
|
||||
|
||||
t.Run("GetStringOr", func(t *testing.T) {
|
||||
value := sm.GetStringOr("foo", "bar")
|
||||
assert.Equal(t, "bar", value)
|
||||
sm.SetKV("foo", "foo")
|
||||
value = sm.GetStringOr("foo", "bar")
|
||||
assert.Equal(t, "foo", value)
|
||||
sm.Reset()
|
||||
})
|
||||
|
||||
t.Run("GetOr", func(t *testing.T) {
|
||||
value := sm.GetOr("foo", "bar")
|
||||
assert.Equal(t, "bar", value)
|
||||
sm.SetKV("foo", "foo")
|
||||
value = sm.GetOr("foo", "bar")
|
||||
assert.Equal(t, "foo", value)
|
||||
sm.Reset()
|
||||
})
|
||||
|
||||
t.Run("HasKey", func(t *testing.T) {
|
||||
ok := sm.HasKey("foo")
|
||||
assert.False(t, ok)
|
||||
sm.SetKV("foo", "")
|
||||
assert.True(t, sm.HasKey("foo"))
|
||||
sm.Reset()
|
||||
})
|
||||
|
||||
t.Run("HasValue", func(t *testing.T) {
|
||||
assert.False(t, sm.HasValue("bar"))
|
||||
sm.SetKV("foo", "bar")
|
||||
assert.True(t, sm.HasValue("bar"))
|
||||
sm.Reset()
|
||||
})
|
||||
|
||||
t.Run("Keys", func(t *testing.T) {
|
||||
keys := sm.Keys()
|
||||
assert.Equal(t, 0, len(keys))
|
||||
expected := []string{"foo1", "foo2", "foo3"}
|
||||
for _, key := range expected {
|
||||
sm.SetKV(key, "")
|
||||
}
|
||||
keys = sm.Keys()
|
||||
var actual []string
|
||||
for _, key := range keys {
|
||||
actual = append(actual, key.(string))
|
||||
}
|
||||
|
||||
assert.Equal(t, expected, actual)
|
||||
sm.Reset()
|
||||
})
|
||||
|
||||
t.Run("Values", func(t *testing.T) {
|
||||
values := sm.Values()
|
||||
assert.Equal(t, 0, len(values))
|
||||
expected := []string{"foo1", "foo2", "foo3"}
|
||||
for _, key := range expected {
|
||||
sm.SetKV(key, key)
|
||||
}
|
||||
values = sm.Values()
|
||||
var actual []string
|
||||
for _, value := range values {
|
||||
actual = append(actual, value.(string))
|
||||
}
|
||||
|
||||
assert.Equal(t, expected, actual)
|
||||
sm.Reset()
|
||||
})
|
||||
|
||||
t.Run("Range", func(t *testing.T) {
|
||||
var keys, values []string
|
||||
sm.Range(func(key, value interface{}) {
|
||||
keys = append(keys, key.(string))
|
||||
values = append(values, value.(string))
|
||||
})
|
||||
assert.Len(t, keys, 0)
|
||||
assert.Len(t, values, 0)
|
||||
|
||||
expected := []string{"foo1", "foo2", "foo3"}
|
||||
for _, key := range expected {
|
||||
sm.SetKV(key, key)
|
||||
}
|
||||
sm.Range(func(key, value interface{}) {
|
||||
keys = append(keys, key.(string))
|
||||
values = append(values, value.(string))
|
||||
})
|
||||
assert.Equal(t, expected, keys)
|
||||
assert.Equal(t, expected, values)
|
||||
sm.Reset()
|
||||
})
|
||||
|
||||
t.Run("RangeIf", func(t *testing.T) {
|
||||
var keys, values []string
|
||||
sm.RangeIf(func(key, value interface{}) bool {
|
||||
keys = append(keys, key.(string))
|
||||
values = append(values, value.(string))
|
||||
return true
|
||||
})
|
||||
assert.Len(t, keys, 0)
|
||||
assert.Len(t, values, 0)
|
||||
|
||||
expected := []string{"foo1", "foo2", "foo3"}
|
||||
for _, key := range expected {
|
||||
sm.SetKV(key, key)
|
||||
}
|
||||
sm.RangeIf(func(key, value interface{}) bool {
|
||||
keys = append(keys, key.(string))
|
||||
values = append(values, value.(string))
|
||||
if key.(string) == "foo1" {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
assert.Equal(t, []string{"foo1"}, keys)
|
||||
assert.Equal(t, []string{"foo1"}, values)
|
||||
sm.Reset()
|
||||
})
|
||||
|
||||
t.Run("Remove", func(t *testing.T) {
|
||||
_, ok := sm.Remove("foo")
|
||||
assert.False(t, ok)
|
||||
sm.SetKV("foo", "bar")
|
||||
value, ok := sm.Remove("foo")
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "bar", value)
|
||||
assert.False(t, sm.HasKey("foo"))
|
||||
assert.False(t, sm.HasValue("bar"))
|
||||
sm.Reset()
|
||||
})
|
||||
|
||||
t.Run("Insert", func(t *testing.T) {
|
||||
data := New()
|
||||
data.SetKV("foo", "bar")
|
||||
sm.SetKV("foo1", "bar1")
|
||||
sm.Insert(data)
|
||||
assert.True(t, sm.HasKey("foo"))
|
||||
assert.True(t, sm.HasValue("bar"))
|
||||
sm.Reset()
|
||||
})
|
||||
|
||||
t.Run("Copy", func(t *testing.T) {
|
||||
sm.SetKV("foo", "bar")
|
||||
data := sm.Copy()
|
||||
assert.True(t, data.HasKey("foo"))
|
||||
assert.True(t, data.HasValue("bar"))
|
||||
sm.SetKV("foo", "bar1")
|
||||
assert.True(t, data.HasKey("foo"))
|
||||
assert.True(t, data.HasValue("bar"))
|
||||
sm.Reset()
|
||||
})
|
||||
|
||||
t.Run("Format", func(t *testing.T) {
|
||||
format := sm.Format()
|
||||
assert.Equal(t, []string{}, format)
|
||||
sm.SetKV("foo1", "bar1")
|
||||
sm.SetKV("foo2", "bar2")
|
||||
sm.SetKV("foo3", "")
|
||||
format = sm.Format()
|
||||
assert.Equal(t, []string{"foo1=bar1", "foo2=bar2", "foo3="}, format)
|
||||
sm.Reset()
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user