Skip to content

Commit a0d2dce

Browse files
authored
Merge pull request #73 from jennybuckley/anyof-atom
Support atoms with multiple types
2 parents 646549c + 9ccdda5 commit a0d2dce

14 files changed

+302
-282
lines changed

merge/multiple_appliers_test.go

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,120 @@ func TestMultipleAppliersNestedType(t *testing.T) {
684684
}
685685
}
686686

687+
func TestMultipleAppliersDeducedType(t *testing.T) {
688+
tests := map[string]TestCase{
689+
"multiple_appliers_recursive_map_deduced": {
690+
Ops: []Operation{
691+
Apply{
692+
Manager: "apply-one",
693+
Object: `
694+
a:
695+
b:
696+
c:
697+
d:
698+
`,
699+
APIVersion: "v1",
700+
},
701+
Apply{
702+
Manager: "apply-two",
703+
Object: `
704+
a:
705+
c:
706+
d:
707+
`,
708+
APIVersion: "v2",
709+
},
710+
Update{
711+
Manager: "controller-one",
712+
Object: `
713+
a:
714+
b:
715+
c:
716+
c:
717+
d:
718+
e:
719+
`,
720+
APIVersion: "v3",
721+
},
722+
Update{
723+
Manager: "controller-two",
724+
Object: `
725+
a:
726+
b:
727+
c:
728+
d:
729+
c:
730+
d:
731+
e:
732+
f:
733+
`,
734+
APIVersion: "v2",
735+
},
736+
Update{
737+
Manager: "controller-one",
738+
Object: `
739+
a:
740+
b:
741+
c:
742+
d:
743+
e:
744+
c:
745+
d:
746+
e:
747+
f:
748+
g:
749+
`,
750+
APIVersion: "v3",
751+
},
752+
Apply{
753+
Manager: "apply-one",
754+
Object: ``,
755+
APIVersion: "v4",
756+
},
757+
},
758+
Object: `
759+
a:
760+
c:
761+
d:
762+
e:
763+
f:
764+
g:
765+
`,
766+
Managed: fieldpath.ManagedFields{
767+
"apply-two": &fieldpath.VersionedSet{
768+
Set: _NS(
769+
_P("a"),
770+
_P("c"),
771+
_P("c", "d"),
772+
),
773+
APIVersion: "v2",
774+
},
775+
"controller-one": &fieldpath.VersionedSet{
776+
Set: _NS(
777+
_P("c", "d", "e"),
778+
_P("c", "d", "e", "f", "g"),
779+
),
780+
APIVersion: "v3",
781+
},
782+
"controller-two": &fieldpath.VersionedSet{
783+
Set: _NS(
784+
_P("c", "d", "e", "f"),
785+
),
786+
APIVersion: "v2",
787+
},
788+
},
789+
},
790+
}
791+
792+
for name, test := range tests {
793+
t.Run(name, func(t *testing.T) {
794+
if err := test.Test(typed.DeducedParseableType); err != nil {
795+
t.Fatal(err)
796+
}
797+
})
798+
}
799+
}
800+
687801
func TestMultipleAppliersRealConversion(t *testing.T) {
688802
tests := map[string]TestCase{
689803
"multiple_appliers_recursive_map_real_conversion": {

schema/elements.go

Lines changed: 11 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ limitations under the License.
1616

1717
package schema
1818

19-
import "sigs.k8s.io/structured-merge-diff/value"
20-
2119
// Schema is a list of named types.
2220
type Schema struct {
2321
Types []TypeDef `yaml:"types,omitempty"`
@@ -45,13 +43,15 @@ type TypeRef struct {
4543
}
4644

4745
// Atom represents the smallest possible pieces of the type system.
46+
// Each set field in the Atom represents a possible type for the object.
47+
// If none of the fields are set, any object will fail validation against the atom.
4848
type Atom struct {
49-
// Exactly one of the below must be set.
50-
*Scalar `yaml:"scalar,omitempty"`
51-
*Struct `yaml:"struct,omitempty"`
52-
*List `yaml:"list,omitempty"`
53-
*Map `yaml:"map,omitempty"`
54-
*Untyped `yaml:"untyped,omitempty"`
49+
*Scalar `yaml:"scalar,omitempty"`
50+
*List `yaml:"list,omitempty"`
51+
52+
// At most, one of the below must be set, since both look the same when serialized
53+
*Struct `yaml:"struct,omitempty"`
54+
*Map `yaml:"map,omitempty"`
5555
}
5656

5757
// Scalar (AKA "primitive") represents a type which has a single value which is
@@ -67,20 +67,18 @@ const (
6767
)
6868

6969
// ElementRelationship is an enum of the different possible relationships
70-
// between the elements of container types (maps, lists, structs, untyped).
70+
// between the elements of container types (maps, lists, structs).
7171
type ElementRelationship string
7272

7373
const (
7474
// Associative only applies to lists (see the documentation there).
7575
Associative = ElementRelationship("associative")
76-
// Atomic makes container types (lists, maps, structs, untyped) behave
77-
// as scalars / leaf fields (which is the default for untyped data).
76+
// Atomic makes container types (lists, maps, structs) behave
77+
// as scalars / leaf fields
7878
Atomic = ElementRelationship("atomic")
7979
// Separable means the items of the container type have no particular
8080
// relationship (default behavior for maps and structs).
8181
Separable = ElementRelationship("separable")
82-
// Deduced only applies to untyped (see the documentation there).
83-
Deduced = ElementRelationship("deduced")
8482
)
8583

8684
// Struct represents a type which is composed of a number of different fields.
@@ -179,50 +177,6 @@ type Map struct {
179177
ElementRelationship ElementRelationship `yaml:"elementRelationship,omitempty"`
180178
}
181179

182-
// Untyped represents types that allow arbitrary content. (Think: plugin
183-
// objects.)
184-
type Untyped struct {
185-
// ElementRelationship states the relationship between the items, if
186-
// container-typed data happens to be present here.
187-
// * `deduced` implies that the behavior is based on the type of data.
188-
// Structs and maps are both treated as a `separable` Map with `deduced` Untyped elements.
189-
// Lists and Scalars are both treated as an `atomic` Untyped.
190-
// * `atomic` implies that all elements depend on each other, and this
191-
// is effectively a scalar / leaf field; it doesn't make sense for
192-
// separate actors to set the elements.
193-
// TODO: support "guess" (guesses at associative list keys)
194-
// The default behavior for untyped data is `atomic`; it's permitted to
195-
// leave this unset to get the default behavior.
196-
ElementRelationship ElementRelationship `yaml:"elementRelationship,omitempty"`
197-
}
198-
199-
// DeduceType determines the behavior based on a value.
200-
func DeduceType(v *value.Value) TypeRef {
201-
if v != nil && v.MapValue != nil {
202-
return TypeRef{
203-
Inlined: Atom{
204-
Map: &Map{
205-
ElementType: TypeRef{
206-
Inlined: Atom{
207-
Untyped: &Untyped{
208-
ElementRelationship: Deduced,
209-
},
210-
},
211-
},
212-
ElementRelationship: Separable,
213-
},
214-
},
215-
}
216-
}
217-
return TypeRef{
218-
Inlined: Atom{
219-
Untyped: &Untyped{
220-
ElementRelationship: Atomic,
221-
},
222-
},
223-
}
224-
}
225-
226180
// FindNamedType is a convenience function that returns the referenced TypeDef,
227181
// if it exists, or (nil, false) if it doesn't.
228182
func (s Schema) FindNamedType(name string) (TypeDef, bool) {

schema/elements_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ func TestFindNamedType(t *testing.T) {
5353
func TestResolve(t *testing.T) {
5454
existing := "existing"
5555
notExisting := "not-existing"
56-
a := Atom{Untyped: &Untyped{}}
56+
a := Atom{List: &List{}}
5757

5858
tests := []struct {
5959
testName string

schema/fromvalue.go

Lines changed: 0 additions & 57 deletions
This file was deleted.

schema/fromvalue_test.go

Lines changed: 0 additions & 85 deletions
This file was deleted.

0 commit comments

Comments
 (0)