-
Notifications
You must be signed in to change notification settings - Fork 206
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow resources to have additional properties #1558
Changes from all commits
b212fd1
605cb2f
c33229b
9e0fe07
2a4865f
18d99a4
65a3f4e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,7 @@ type ResourceType struct { | |
status Type | ||
isStorageVersion bool | ||
owner *TypeName | ||
properties map[PropertyName]*PropertyDefinition | ||
functions map[string]Function | ||
testcases map[string]TestCase | ||
InterfaceImplementer | ||
|
@@ -34,6 +35,7 @@ func NewResourceType(specType Type, statusType Type) *ResourceType { | |
result := &ResourceType{ | ||
isStorageVersion: false, | ||
owner: nil, | ||
properties: make(map[PropertyName]*PropertyDefinition), | ||
functions: make(map[string]Function), | ||
testcases: make(map[string]TestCase), | ||
InterfaceImplementer: MakeInterfaceImplementer(), | ||
|
@@ -286,26 +288,82 @@ func (resource *ResourceType) EmbeddedProperties() []*PropertyDefinition { | |
} | ||
} | ||
|
||
// WithProperty creates a new ResourceType with another property attached to it | ||
// Properties are unique by name, so this can be used to Add and Replace a property | ||
func (resource *ResourceType) WithProperty(property *PropertyDefinition) *ResourceType { | ||
if property.HasName("Status") || property.HasName("Spec") { | ||
panic(fmt.Sprintf("May not modify property %q on a resource", property.PropertyName())) | ||
} | ||
|
||
// Create a copy to preserve immutability | ||
result := resource.copy() | ||
result.properties[property.propertyName] = property | ||
|
||
return result | ||
} | ||
|
||
// WithoutProperty creates a new ResourceType that's a copy without the specified property | ||
func (resource *ResourceType) WithoutProperty(name PropertyName) *ResourceType { | ||
if name == "Status" || name == "Spec" { | ||
panic(fmt.Sprintf("May not remove property %q from a resource", name)) | ||
} | ||
|
||
// Create a copy to preserve immutability | ||
result := resource.copy() | ||
delete(result.properties, name) | ||
|
||
return result | ||
} | ||
|
||
// Properties returns all the properties from this resource type | ||
// An ordered slice is returned to preserve immutability and provide determinism | ||
func (resource *ResourceType) Properties() []*PropertyDefinition { | ||
|
||
specProperty := NewPropertyDefinition("Spec", "spec", resource.spec). | ||
WithTag("json", "omitempty") | ||
|
||
result := []*PropertyDefinition{ | ||
specProperty, | ||
resource.createSpecProperty(), | ||
} | ||
|
||
if resource.status != nil { | ||
statusProperty := NewPropertyDefinition("Status", "status", resource.status). | ||
WithTag("json", "omitempty") | ||
result = append(result, statusProperty) | ||
result = append(result, resource.createStatusProperty()) | ||
} | ||
|
||
for _, property := range resource.properties { | ||
result = append(result, property) | ||
} | ||
|
||
// Sorted so that it's always consistent | ||
sort.Slice(result, func(left int, right int) bool { | ||
return result[left].propertyName < result[right].propertyName | ||
}) | ||
|
||
return result | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And thus we prove that I need to write the test even for code I think I can't possibly get wrong! 😊 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed. |
||
} | ||
|
||
func (resource *ResourceType) createStatusProperty() *PropertyDefinition { | ||
statusProperty := NewPropertyDefinition("Status", "status", resource.status). | ||
WithTag("json", "omitempty") | ||
return statusProperty | ||
} | ||
|
||
func (resource *ResourceType) createSpecProperty() *PropertyDefinition { | ||
return NewPropertyDefinition("Spec", "spec", resource.spec). | ||
WithTag("json", "omitempty") | ||
} | ||
|
||
// Property returns the property and true if the named property is found, nil and false otherwise | ||
func (resource *ResourceType) Property(name PropertyName) (*PropertyDefinition, bool) { | ||
if name == "Spec" { | ||
return resource.createSpecProperty(), true | ||
} | ||
|
||
if name == "Status" { | ||
return resource.createStatusProperty(), true | ||
} | ||
|
||
prop, ok := resource.properties[name] | ||
return prop, ok | ||
} | ||
|
||
// Functions returns all the function implementations | ||
// A sorted slice is returned to preserve immutability and provide determinism | ||
func (resource *ResourceType) Functions() []Function { | ||
|
@@ -541,11 +599,16 @@ func (resource *ResourceType) copy() *ResourceType { | |
status: resource.status, | ||
isStorageVersion: resource.isStorageVersion, | ||
owner: resource.owner, | ||
properties: make(map[PropertyName]*PropertyDefinition), | ||
functions: make(map[string]Function), | ||
testcases: make(map[string]TestCase), | ||
InterfaceImplementer: resource.InterfaceImplementer.copy(), | ||
} | ||
|
||
for key, property := range resource.properties { | ||
result.properties[key] = property | ||
} | ||
|
||
for key, testcase := range resource.testcases { | ||
result.testcases[key] = testcase | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@theunrepentantgeek - Sorry I missed looking at this PR on my Friday, but why do we need this change for the storage versions? The property doesn't have to be on the top level resource type I don't think. It really should be in spec in the storage version too, shouldn't it?
Maybe we can sync up offline or in the meeting today?