Skip to content

Commit 2996888

Browse files
committed
Create NestedSet to populate set branches along with the leaves
1 parent 9f9c770 commit 2996888

File tree

2 files changed

+134
-0
lines changed

2 files changed

+134
-0
lines changed

fieldpath/set.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ package fieldpath
1919
import (
2020
"sort"
2121
"strings"
22+
23+
"sigs.k8s.io/structured-merge-diff/v4/schema"
2224
)
2325

2426
// Set identifies a set of fields.
@@ -110,6 +112,30 @@ func (s *Set) RecursiveDifference(s2 *Set) *Set {
110112
}
111113
}
112114

115+
// EnsureNamedFieldsAreMembers returns a Set that contains all the
116+
// fields in s, as well as all the named fields that are typically not
117+
// included. For example, a set made of "a.b.c" will end-up also owning
118+
// "a" if it's a named fields but not "a.b" if it's a map.
119+
func (s *Set) EnsureNamedFieldsAreMembers(sc *schema.Schema, tr schema.TypeRef) *Set {
120+
members := PathElementSet{
121+
members: make(sortedPathElements, 0, s.Members.Size()+len(s.Children.members)),
122+
}
123+
atom, _ := sc.Resolve(tr)
124+
members.members = append(members.members, s.Members.members...)
125+
for _, node := range s.Children.members {
126+
// Only insert named fields.
127+
if node.pathElement.FieldName != nil && atom.Map != nil {
128+
if _, has := atom.Map.FindField(*node.pathElement.FieldName); has {
129+
members.Insert(node.pathElement)
130+
}
131+
}
132+
}
133+
return &Set{
134+
Members: members,
135+
Children: *s.Children.EnsureNamedFieldsAreMembers(sc, tr),
136+
}
137+
}
138+
113139
// Size returns the number of members of the set.
114140
func (s *Set) Size() int {
115141
return s.Members.Size() + s.Children.Size()
@@ -391,6 +417,31 @@ func (s *SetNodeMap) RecursiveDifference(s2 *Set) *SetNodeMap {
391417
return out
392418
}
393419

420+
// EnsureNamedFieldsAreMembers returns a set that contains all the named fields along with the leaves.
421+
func (s *SetNodeMap) EnsureNamedFieldsAreMembers(sc *schema.Schema, tr schema.TypeRef) *SetNodeMap {
422+
out := make(sortedSetNode, 0, s.Size())
423+
atom, _ := sc.Resolve(tr)
424+
for _, member := range s.members {
425+
tr := schema.TypeRef{}
426+
if member.pathElement.FieldName != nil && atom.Map != nil {
427+
tr = atom.Map.ElementType
428+
if sf, ok := atom.Map.FindField(*member.pathElement.FieldName); ok {
429+
tr = sf.Type
430+
}
431+
} else if member.pathElement.Key != nil && atom.List != nil {
432+
tr = atom.List.ElementType
433+
}
434+
out = append(out, setNode{
435+
pathElement: member.pathElement,
436+
set: member.set.EnsureNamedFieldsAreMembers(sc, tr),
437+
})
438+
}
439+
440+
return &SetNodeMap{
441+
members: out,
442+
}
443+
}
444+
394445
// Iterate calls f for each PathElement in the set.
395446
func (s *SetNodeMap) Iterate(f func(PathElement)) {
396447
for _, n := range s.members {

fieldpath/set_test.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ import (
2121
"fmt"
2222
"math/rand"
2323
"testing"
24+
25+
"gopkg.in/yaml.v2"
26+
"sigs.k8s.io/structured-merge-diff/v4/schema"
2427
)
2528

2629
type randomPathAlphabet []PathElement
@@ -541,6 +544,86 @@ func TestSetDifference(t *testing.T) {
541544
}
542545
}
543546

547+
var nestedSchema = func() (*schema.Schema, schema.TypeRef) {
548+
sc := &schema.Schema{}
549+
name := "type"
550+
err := yaml.Unmarshal([]byte(`types:
551+
- name: type
552+
map:
553+
elementType:
554+
namedType: type
555+
fields:
556+
- name: named
557+
type:
558+
namedType: type
559+
- name: list
560+
type:
561+
list:
562+
elementRelationShip: associative
563+
keys: ["name"]
564+
elementType:
565+
namedType: type
566+
- name: value
567+
type:
568+
scalar: numeric
569+
`), &sc)
570+
if err != nil {
571+
panic(err)
572+
}
573+
return sc, schema.TypeRef{NamedType: &name}
574+
}
575+
576+
var _P = MakePathOrDie
577+
578+
func TestEnsureNamedFieldsAreMembers(t *testing.T) {
579+
table := []struct {
580+
set, expected *Set
581+
}{
582+
{
583+
set: NewSet(_P("named", "named", "value")),
584+
expected: NewSet(
585+
_P("named", "named", "value"),
586+
_P("named", "named"),
587+
_P("named"),
588+
),
589+
},
590+
{
591+
set: NewSet(_P("named", "a", "named", "value"), _P("a", "named", "value"), _P("a", "b", "value")),
592+
expected: NewSet(
593+
_P("named", "a", "named", "value"),
594+
_P("named", "a", "named"),
595+
_P("named"),
596+
_P("a", "named", "value"),
597+
_P("a", "named"),
598+
_P("a", "b", "value"),
599+
),
600+
},
601+
{
602+
set: NewSet(_P("named", "list", KeyByFields("name", "a"), "named", "a", "value")),
603+
expected: NewSet(
604+
_P("named", "list", KeyByFields("name", "a"), "named", "a", "value"),
605+
_P("named", "list", KeyByFields("name", "a"), "named"),
606+
_P("named", "list"),
607+
_P("named"),
608+
),
609+
},
610+
}
611+
612+
for _, test := range table {
613+
t.Run(fmt.Sprintf("%v", test.set), func(t *testing.T) {
614+
got := test.set.EnsureNamedFieldsAreMembers(nestedSchema())
615+
if !got.Equals(test.expected) {
616+
t.Errorf("expected %v, got %v (missing: %v/superfluous: %v)",
617+
test.expected,
618+
got,
619+
test.expected.Difference(got),
620+
got.Difference(test.expected),
621+
)
622+
}
623+
})
624+
}
625+
}
626+
544627
func TestSetNodeMapIterate(t *testing.T) {
545628
set := &SetNodeMap{}
546629
toAdd := 5

0 commit comments

Comments
 (0)