-
Notifications
You must be signed in to change notification settings - Fork 94
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
path: Initial Path Expression Support #396
Merged
Merged
Changes from 2 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
16f0424
path: Initial Path Expression Support
bflad 86dd1a6
Update CHANGELOG for #396
bflad 8aec913
Updates to path expression handling
bflad 9f3d84c
Ensure empty resolved expressions do not match anything
bflad 2c12e6e
Merge branch 'main' into bflad-pathexp
bflad File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
```release-note:enhancement | ||
tfsdk: Added `AttributePathExpression` field to `ModifyAttributePlanRequest` and `ValidateAttributeRequest` types | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
package path | ||
|
||
import ( | ||
"github.com/hashicorp/terraform-plugin-framework/attr" | ||
) | ||
|
||
// Expression represents an attribute path with expression steps, which can | ||
// represent zero, one, or more actual Paths. | ||
type Expression struct { | ||
// steps is the transversals included with the expression. In general, | ||
// operations against the path should protect against modification of the | ||
// original. | ||
steps ExpressionSteps | ||
} | ||
|
||
// AtAnyListIndex returns a copied expression with a new list index step at the | ||
// end. The returned path is safe to modify without affecting the original. | ||
func (e Expression) AtAnyListIndex() Expression { | ||
copiedPath := e.Copy() | ||
|
||
copiedPath.steps.Append(ExpressionStepElementKeyIntAny{}) | ||
|
||
return copiedPath | ||
} | ||
|
||
// AtAnyMapKey returns a copied expression with a new map key step at the end. | ||
// The returned path is safe to modify without affecting the original. | ||
func (e Expression) AtAnyMapKey() Expression { | ||
copiedPath := e.Copy() | ||
|
||
copiedPath.steps.Append(ExpressionStepElementKeyStringAny{}) | ||
|
||
return copiedPath | ||
} | ||
|
||
// AtAnySetValue returns a copied expression with a new set value step at the | ||
// end. The returned path is safe to modify without affecting the original. | ||
func (e Expression) AtAnySetValue() Expression { | ||
copiedPath := e.Copy() | ||
|
||
copiedPath.steps.Append(ExpressionStepElementKeyValueAny{}) | ||
|
||
return copiedPath | ||
} | ||
|
||
// AtListIndex returns a copied expression with a new list index step at the | ||
// end. The returned path is safe to modify without affecting the original. | ||
func (e Expression) AtListIndex(index int) Expression { | ||
copiedPath := e.Copy() | ||
|
||
copiedPath.steps.Append(ExpressionStepElementKeyIntExact(index)) | ||
|
||
return copiedPath | ||
} | ||
|
||
// AtMapKey returns a copied expression with a new map key step at the end. | ||
// The returned path is safe to modify without affecting the original. | ||
func (e Expression) AtMapKey(key string) Expression { | ||
copiedPath := e.Copy() | ||
|
||
copiedPath.steps.Append(ExpressionStepElementKeyStringExact(key)) | ||
|
||
return copiedPath | ||
} | ||
|
||
// AtName returns a copied expression with a new attribute or block name step | ||
// at the end. The returned path is safe to modify without affecting the | ||
// original. | ||
func (e Expression) AtName(name string) Expression { | ||
copiedPath := e.Copy() | ||
|
||
copiedPath.steps.Append(ExpressionStepAttributeNameExact(name)) | ||
|
||
return copiedPath | ||
} | ||
|
||
// AtParent returns a copied expression with a new parent step at the end. | ||
// The returned path is safe to modify without affecting the original. | ||
func (e Expression) AtParent() Expression { | ||
copiedPath := e.Copy() | ||
|
||
copiedPath.steps.Append(ExpressionStepParent{}) | ||
|
||
return copiedPath | ||
} | ||
|
||
// AtSetValue returns a copied expression with a new set value step at the end. | ||
// The returned path is safe to modify without affecting the original. | ||
func (e Expression) AtSetValue(value attr.Value) Expression { | ||
copiedPath := e.Copy() | ||
|
||
copiedPath.steps.Append(ExpressionStepElementKeyValueExact{Value: value}) | ||
|
||
return copiedPath | ||
} | ||
|
||
// Copy returns a duplicate of the expression that is safe to modify without | ||
// affecting the original. | ||
func (e Expression) Copy() Expression { | ||
return Expression{ | ||
steps: e.Steps(), | ||
} | ||
} | ||
|
||
// Equal returns true if the given expression is exactly equivalent. | ||
func (e Expression) Equal(o Expression) bool { | ||
if e.steps == nil && o.steps == nil { | ||
return true | ||
} | ||
|
||
if e.steps == nil { | ||
return false | ||
} | ||
|
||
if !e.steps.Equal(o.steps) { | ||
return false | ||
} | ||
|
||
return true | ||
} | ||
|
||
// Matches returns true if the given Path is valid for the Expression. | ||
func (e Expression) Matches(path Path) bool { | ||
return e.steps.Matches(path.Steps()) | ||
} | ||
|
||
// Steps returns a copy of the underlying expression steps. Returns an empty | ||
// collection of steps if expression is nil. | ||
func (e Expression) Steps() ExpressionSteps { | ||
if len(e.steps) == 0 { | ||
return ExpressionSteps{} | ||
} | ||
|
||
return e.steps.Copy() | ||
} | ||
|
||
// String returns the human-readable representation of the path. | ||
// It is intended for logging and error messages and is not protected by | ||
// compatibility guarantees. | ||
func (e Expression) String() string { | ||
return e.steps.String() | ||
} | ||
|
||
// MatchParent creates an attribute path expression starting with | ||
// ExpressionStepParent. This allows creating a relative expression in | ||
// nested schemas. | ||
func MatchParent() Expression { | ||
return Expression{ | ||
steps: ExpressionSteps{ | ||
ExpressionStepParent{}, | ||
}, | ||
} | ||
} | ||
|
||
// MatchRoot creates an attribute path expression starting with | ||
// ExpressionStepAttributeNameExact. | ||
func MatchRoot(rootAttributeName string) Expression { | ||
return Expression{ | ||
steps: ExpressionSteps{ | ||
ExpressionStepAttributeNameExact(rootAttributeName), | ||
}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package path | ||
|
||
// ExpressionStep represents an expression of an attribute path step, which may | ||
// match zero, one, or more actual paths. | ||
type ExpressionStep interface { | ||
// Equal should return true if the given Step is exactly equivalent. | ||
Equal(ExpressionStep) bool | ||
|
||
// Matches should return true if the given PathStep can be fulfilled by the | ||
// ExpressionStep. | ||
Matches(PathStep) bool | ||
|
||
// String should return a human-readable representation of the step | ||
// intended for logging and error messages. There should not be usage | ||
// that needs to be protected by compatibility guarantees. | ||
String() string | ||
|
||
// unexported prevents outside types from satisfying the interface. | ||
unexported() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package path | ||
|
||
// Ensure ExpressionStepAttributeNameExact satisfies the ExpressionStep | ||
// interface. | ||
var _ ExpressionStep = ExpressionStepAttributeNameExact("") | ||
|
||
// ExpressionStepAttributeNameExact is an attribute path expression for an | ||
// exact attribute name match within an object. | ||
type ExpressionStepAttributeNameExact string | ||
|
||
// Equal returns true if the given ExpressionStep is a | ||
// ExpressionStepAttributeNameExact and the attribute name is equivalent. | ||
func (s ExpressionStepAttributeNameExact) Equal(o ExpressionStep) bool { | ||
other, ok := o.(ExpressionStepAttributeNameExact) | ||
|
||
if !ok { | ||
return false | ||
} | ||
|
||
return string(s) == string(other) | ||
} | ||
|
||
// Matches returns true if the given PathStep is fulfilled by the | ||
// ExpressionStepAttributeNameExact condition. | ||
func (s ExpressionStepAttributeNameExact) Matches(pathStep PathStep) bool { | ||
pathStepAttributeName, ok := pathStep.(PathStepAttributeName) | ||
|
||
if !ok { | ||
return false | ||
} | ||
|
||
return string(s) == string(pathStepAttributeName) | ||
} | ||
|
||
// String returns the human-readable representation of the attribute name | ||
// expression. It is intended for logging and error messages and is not | ||
// protected by compatibility guarantees. | ||
func (s ExpressionStepAttributeNameExact) String() string { | ||
return string(s) | ||
} | ||
|
||
// unexported satisfies the Step interface. | ||
func (s ExpressionStepAttributeNameExact) unexported() {} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Given the description, I was expecting an
.Append()
method here.I see there is one on the
ExpressionSteps
, but not on the expression itself.The reason for me asking, is that I'm trying to imagine how we would take the input for a
schemavalidator
, append it to thepath.Expression
of the attribute, and get to the referred-to attributes.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 goodness, you are absolutely right that I omitted that method. It's important to be able to merge expressions, especially in plan modifiers and validators. I'll get that pushed up shortly.