-
Notifications
You must be signed in to change notification settings - Fork 38
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
Construct Template Enhancements #993
Conversation
431cdaf
to
37a28b8
Compare
if value, ok := path.Get(); ok { | ||
return value, nil | ||
} | ||
// Backwards compatibility: if the property does not exist, return nil instead of an error. |
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.
Was this causing problems? I don't mind breaking and internal API's backwards compatibility. If it does break the functional tests, then can you throw up a ticket for this cleanup?
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.
IIRC, I did this, so I wouldn't have to introduce error handling in places that were relying on the previous behavior.
v, _ := path.Get() | ||
otherV, _ := otherPath.Get() |
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.
Shouldn't this check the error to see if they match? Eg, if both are non-existent
Unmarshal(data *bytes.Buffer, v any) error | ||
} | ||
|
||
DefaultExecutionContext struct{} |
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.
Generally, interfaces are defined where they're used, not implemented. I also don't see any other implementations (maybe I'm missing it), so probably not necessary to preemptively make an interface for it.
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.
It's used in the properties
package, which contains all the property implementations. I'm open to moving it if you feel strongly about it.
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.
I don't feel strongly, but the general practice of putting interfaces at the usage site makes them be way less bloated over time. It's a little weird compare to other languages like Java / TS, but it also makes it much easier to test since the surface area is smaller (the interface is what's used, not the union of all the uses).
|
||
return err | ||
|
||
} |
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.
Publishing WIP review. This comment is a bookmark so I can return to it.
} | ||
|
||
// fieldConversion is a map providing functionality on how to convert inputs into our internal types if they are not inherently the same structure | ||
var fieldConversion = map[string]func(val reflect.Value, p *InputTemplate, kp property.Property) error{ |
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.
nit: for readability, would be nice to type alias the func
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.
This bit is copied verbatim from the knowledgebase properties implementation, but I can take a closer look at the points you raised in this comment and related subsequent comments.
// generate random uuid as the name of the template | ||
name := uuid.New().String() |
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.
Why use a uuid and not the property's name? Since we don't have delegate templates, the only place this is relevant is in making the error messages.
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func Test_ConvertProperty(t *testing.T) { |
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.
non-blocking: would be nice to have more test cases
type Properties struct { | ||
propertyMap property.PropertyMap |
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.
Is there a need for a dedicated type for this?
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.
PropertyMap
is largely functionality extracted from ResourceTemplate
and applied more generically to a map instead of to a template's Properties
field. Its primary use is for working with nested properties. Interestingly, it looks like it also inherits a lack of support for seg1[seg2.seg3]
path syntax in its GetProperty()
method.
|
||
func (c *ConstructType) UnmarshalYAML(value *yaml.Node) error { | ||
// Split the value into parts | ||
parts := strings.Split(value.Value, ".") |
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.
is value.Value
safe to assume being the string? How does it behave if using a multiline string or other cases that have characters that wouldn't be present when unmarshalling to a string
nit: reduce the 3x copy of the parsing to one and reuse
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.
I don't understand what you mean by the nit. For the rest, I can decode the value to a string and validate it with a regex.
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.
Oh, the nit is that UnmarshalYAML
, ParseConstrucType
and FromString
all do the same thing. Decoding to string is the most safe, since I know it'd behave well in those edge cases.
79d3ab6
to
896c5fe
Compare
This PR make substantial enhancements to construct templates
Features
Interpolation enhancements
{{}}
and existing${}
interpolation syntax in construct/binding templates..
is now possible using[part1.part2]
syntax.Input rule enhancements
for_each
-do
oriented rules (mixingfor_each
andif
in a single rule will cause an error). Thedo
component of the rule will be executed once for each index or entry in the item selected in thefor_each
go template using the.Select
function.for_each
, rule, use the.Select
function to select a value from the current interpolation context to iterate over and reference the current selection with.Selected
..Selected
where applicable:.Key
.Index
.Value
rules
field that enables nested rules. Nested rules inherit theprefix
of their parent by default. Prefix hierarchies are merged with a.
separator (e.g.,MyRoute.Method
)Structured Inputs
Structured inputs are now supported using the same syntax as resource template properties. Notably,
model
inputs are not available and resource refs (e.g.resource:Id#property
are not supported)No validation enhancements were made to this functionality -- that will be a separate effort, so most validation declared in templates is still ignored.