mirror of
https://github.com/rancher/os.git
synced 2025-08-19 07:19:05 +00:00
slices union and intersection
useful for merging and splitting configs
This commit is contained in:
parent
974206235d
commit
4d6530be73
@ -10,55 +10,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNilMap(t *testing.T) {
|
|
||||||
assert := require.New(t)
|
|
||||||
var m map[string]interface{} = nil
|
|
||||||
assert.True(m == nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMapCopy(t *testing.T) {
|
|
||||||
assert := require.New(t)
|
|
||||||
m0 := map[interface{}]interface{}{"a": 1, "b": map[interface{}]interface{}{"c": 3}, "d": "4"}
|
|
||||||
m1 := util.MapCopy(m0)
|
|
||||||
|
|
||||||
delete(m0, "a")
|
|
||||||
assert.Equal(len(m1), len(m0)+1)
|
|
||||||
|
|
||||||
b0 := m0["b"].(map[interface{}]interface{})
|
|
||||||
b1 := m1["b"].(map[interface{}]interface{})
|
|
||||||
b1["e"] = "queer"
|
|
||||||
|
|
||||||
assert.Equal(len(b1), len(b0)+1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMapsIntersection(t *testing.T) {
|
|
||||||
assert := require.New(t)
|
|
||||||
|
|
||||||
m0 := map[interface{}]interface{}{"a": 1, "b": map[interface{}]interface{}{"c": 3}, "d": "4"}
|
|
||||||
m1 := util.MapCopy(m0)
|
|
||||||
|
|
||||||
delete(m0, "a")
|
|
||||||
b1 := m1["b"].(map[interface{}]interface{})
|
|
||||||
delete(b1, "c")
|
|
||||||
expected := map[interface{}]interface{}{"b": map[interface{}]interface{}{}, "d": "4"}
|
|
||||||
assert.Equal(expected, util.MapsIntersection(m0, m1, util.Equal))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMapsUnion(t *testing.T) {
|
|
||||||
assert := require.New(t)
|
|
||||||
|
|
||||||
m0 := map[interface{}]interface{}{"a": 1, "b": map[interface{}]interface{}{"c": 3}, "d": "4"}
|
|
||||||
m1 := util.MapCopy(m0)
|
|
||||||
m1["e"] = "added"
|
|
||||||
m1["d"] = "replaced"
|
|
||||||
|
|
||||||
delete(m0, "a")
|
|
||||||
b1 := m1["b"].(map[interface{}]interface{})
|
|
||||||
delete(b1, "c")
|
|
||||||
expected := map[interface{}]interface{}{"a": 1, "b": map[interface{}]interface{}{"c": 3}, "d": "replaced", "e": "added"}
|
|
||||||
assert.Equal(expected, util.MapsUnion(m0, m1, util.Replace))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFilterKey(t *testing.T) {
|
func TestFilterKey(t *testing.T) {
|
||||||
assert := require.New(t)
|
assert := require.New(t)
|
||||||
data := map[interface{}]interface{}{
|
data := map[interface{}]interface{}{
|
||||||
|
69
util/util.go
69
util/util.go
@ -181,6 +181,8 @@ func Copy(d interface{}) interface{} {
|
|||||||
switch d := d.(type) {
|
switch d := d.(type) {
|
||||||
case map[interface{}]interface{}:
|
case map[interface{}]interface{}:
|
||||||
return MapCopy(d)
|
return MapCopy(d)
|
||||||
|
case []interface{}:
|
||||||
|
return SliceCopy(d)
|
||||||
default:
|
default:
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
@ -197,11 +199,40 @@ func Equal(l, r interface{}) interface{} {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExistsIn(x interface{}, s []interface{}) bool {
|
||||||
|
for _, y := range s {
|
||||||
|
if reflect.DeepEqual(x, y) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func SlicesUnion(left, right []interface{}, op func(interface{}, interface{}) interface{}) []interface{} {
|
||||||
|
result := SliceCopy(left)
|
||||||
|
for _, r := range right {
|
||||||
|
if !ExistsIn(r, result) {
|
||||||
|
result = append(result, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func SlicesIntersection(left, right []interface{}, op func(interface{}, interface{}) interface{}) []interface{} {
|
||||||
|
result := []interface{}{}
|
||||||
|
for _, r := range right {
|
||||||
|
if ExistsIn(r, left) {
|
||||||
|
result = append(result, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func MapsUnion(left, right map[interface{}]interface{}, op func(interface{}, interface{}) interface{}) map[interface{}]interface{} {
|
func MapsUnion(left, right map[interface{}]interface{}, op func(interface{}, interface{}) interface{}) map[interface{}]interface{} {
|
||||||
result := MapCopy(left)
|
result := MapCopy(left)
|
||||||
|
|
||||||
for k, r := range right {
|
for k, r := range right {
|
||||||
if l, ok := result[k]; ok {
|
if l, ok := left[k]; ok {
|
||||||
switch l := l.(type) {
|
switch l := l.(type) {
|
||||||
case map[interface{}]interface{}:
|
case map[interface{}]interface{}:
|
||||||
switch r := r.(type) {
|
switch r := r.(type) {
|
||||||
@ -210,6 +241,13 @@ func MapsUnion(left, right map[interface{}]interface{}, op func(interface{}, int
|
|||||||
default:
|
default:
|
||||||
result[k] = op(l, r)
|
result[k] = op(l, r)
|
||||||
}
|
}
|
||||||
|
case []interface{}:
|
||||||
|
switch r := r.(type) {
|
||||||
|
case []interface{}:
|
||||||
|
result[k] = SlicesUnion(l, r, op)
|
||||||
|
default:
|
||||||
|
result[k] = op(l, r)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
result[k] = op(l, r)
|
result[k] = op(l, r)
|
||||||
}
|
}
|
||||||
@ -226,19 +264,28 @@ func MapsIntersection(left, right map[interface{}]interface{}, op func(interface
|
|||||||
|
|
||||||
for k, l := range left {
|
for k, l := range left {
|
||||||
if r, ok := right[k]; ok {
|
if r, ok := right[k]; ok {
|
||||||
switch r := r.(type) {
|
|
||||||
case map[interface{}]interface{}:
|
|
||||||
switch l := l.(type) {
|
switch l := l.(type) {
|
||||||
|
case map[interface{}]interface{}:
|
||||||
|
switch r := r.(type) {
|
||||||
case map[interface{}]interface{}:
|
case map[interface{}]interface{}:
|
||||||
result[k] = MapsIntersection(l, r, op)
|
result[k] = MapsIntersection(l, r, op)
|
||||||
default:
|
default:
|
||||||
if i := op(l, r); i != nil {
|
if v := op(l, r); v != nil {
|
||||||
result[k] = i
|
result[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case []interface{}:
|
||||||
|
switch r := r.(type) {
|
||||||
|
case []interface{}:
|
||||||
|
result[k] = SlicesIntersection(l, r, op)
|
||||||
|
default:
|
||||||
|
if v := op(l, r); v != nil {
|
||||||
|
result[k] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
if i := op(l, r); i != nil {
|
if v := op(l, r); v != nil {
|
||||||
result[k] = i
|
result[k] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -255,6 +302,14 @@ func MapCopy(data map[interface{}]interface{}) map[interface{}]interface{} {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SliceCopy(data []interface{}) []interface{} {
|
||||||
|
result := make([]interface{}, len(data), len(data))
|
||||||
|
for k, v := range data {
|
||||||
|
result[k] = Copy(v)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func GetServices(urls []string) ([]string, error) {
|
func GetServices(urls []string) ([]string, error) {
|
||||||
result := []string{}
|
result := []string{}
|
||||||
|
|
||||||
|
@ -6,6 +6,90 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestNilMap(t *testing.T) {
|
||||||
|
assert := require.New(t)
|
||||||
|
var m map[string]interface{} = nil
|
||||||
|
assert.True(m == nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMapCopy(t *testing.T) {
|
||||||
|
assert := require.New(t)
|
||||||
|
m0 := map[interface{}]interface{}{"a": 1, "b": map[interface{}]interface{}{"c": 3}, "d": "4"}
|
||||||
|
m1 := MapCopy(m0)
|
||||||
|
assert.Equal(m0, m1)
|
||||||
|
|
||||||
|
delete(m0, "a")
|
||||||
|
assert.Equal(len(m1), len(m0)+1)
|
||||||
|
|
||||||
|
b0 := m0["b"].(map[interface{}]interface{})
|
||||||
|
b1 := m1["b"].(map[interface{}]interface{})
|
||||||
|
b1["e"] = "queer"
|
||||||
|
|
||||||
|
assert.Equal(len(b1), len(b0)+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSliceCopy(t *testing.T) {
|
||||||
|
assert := require.New(t)
|
||||||
|
m0 := []interface{}{1, map[interface{}]interface{}{"c": 3}, "4"}
|
||||||
|
m1 := SliceCopy(m0)
|
||||||
|
assert.Equal(m0, m1)
|
||||||
|
|
||||||
|
m0 = m0[1:]
|
||||||
|
assert.Equal(len(m1), len(m0)+1)
|
||||||
|
|
||||||
|
b0 := m0[0].(map[interface{}]interface{})
|
||||||
|
b1 := m1[1].(map[interface{}]interface{})
|
||||||
|
b1["e"] = "queer"
|
||||||
|
|
||||||
|
assert.Equal(len(b1), len(b0)+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMapsIntersection(t *testing.T) {
|
||||||
|
assert := require.New(t)
|
||||||
|
|
||||||
|
m0 := map[interface{}]interface{}{
|
||||||
|
"a": 1,
|
||||||
|
"b": map[interface{}]interface{}{"c": 3},
|
||||||
|
"d": "4",
|
||||||
|
"e": []interface{}{1, 2, 3},
|
||||||
|
}
|
||||||
|
m1 := MapCopy(m0)
|
||||||
|
|
||||||
|
delete(m0, "a")
|
||||||
|
b1 := m1["b"].(map[interface{}]interface{})
|
||||||
|
delete(b1, "c")
|
||||||
|
m1["e"] = []interface{}{2, 3, 4}
|
||||||
|
expected := map[interface{}]interface{}{"b": map[interface{}]interface{}{}, "d": "4", "e": []interface{}{2, 3}}
|
||||||
|
assert.Equal(expected, MapsIntersection(m0, m1, Equal))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMapsUnion(t *testing.T) {
|
||||||
|
assert := require.New(t)
|
||||||
|
|
||||||
|
m0 := map[interface{}]interface{}{
|
||||||
|
"a": 1,
|
||||||
|
"b": map[interface{}]interface{}{"c": 3},
|
||||||
|
"d": "4",
|
||||||
|
"f": []interface{}{1, 2, 3},
|
||||||
|
}
|
||||||
|
m1 := MapCopy(m0)
|
||||||
|
m1["e"] = "added"
|
||||||
|
m1["d"] = "replaced"
|
||||||
|
m1["f"] = []interface{}{2, 3, 4}
|
||||||
|
|
||||||
|
delete(m0, "a")
|
||||||
|
b1 := m1["b"].(map[interface{}]interface{})
|
||||||
|
delete(b1, "c")
|
||||||
|
expected := map[interface{}]interface{}{
|
||||||
|
"a": 1,
|
||||||
|
"b": map[interface{}]interface{}{"c": 3},
|
||||||
|
"d": "replaced",
|
||||||
|
"e": "added",
|
||||||
|
"f": []interface{}{1, 2, 3, 4},
|
||||||
|
}
|
||||||
|
assert.Equal(expected, MapsUnion(m0, m1, Replace))
|
||||||
|
}
|
||||||
|
|
||||||
func TestLoadResourceSimple(t *testing.T) {
|
func TestLoadResourceSimple(t *testing.T) {
|
||||||
assert := require.New(t)
|
assert := require.New(t)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user