Skip to content

Support AttributePaths natively #81

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

Closed
paddycarver opened this issue Jul 27, 2021 · 1 comment · Fixed by #413
Closed

Support AttributePaths natively #81

paddycarver opened this issue Jul 27, 2021 · 1 comment · Fixed by #413
Assignees
Labels
breaking-change This PR introduces a breaking change or the resolution of this issue may require a breaking change. enhancement New feature or request
Milestone

Comments

@paddycarver
Copy link
Contributor

Module version

v0.2.0

Use-cases

We're still using *tftypes.AttributePath all over the place, and that's really verbose to build and can be bothersome to work with, given how close it sticks to the protocol. We should come up with a framework-specific abstraction for attribute paths.

Ideally, this would be much less verbose without sacrificing any of the clarity. Perhaps just shortening the names would be enough?

This would also ideally solve problems we've seen in validation, etc. of wanting to be able to specify wildcard/relative attribute paths. E.g., parent, self, sibling, etc. This would solve the problem with ConflictsWith, etc. behaviors where you may not know the full path, but you mean "this other attribute of the same object". We'd just need to be careful with this, as we want to make sure people don't try and send these attribute paths back in diagnostics.

Attempted Solutions

#52

@paddycarver paddycarver added the enhancement New feature or request label Jul 27, 2021
@paddycarver paddycarver added this to the v0.3.0 milestone Jul 27, 2021
@paddycarver paddycarver removed this from the v0.3.0 milestone Aug 30, 2021
@paddycarver paddycarver added the breaking-change This PR introduces a breaking change or the resolution of this issue may require a breaking change. label Sep 9, 2021
@paddycarver paddycarver self-assigned this Nov 29, 2021
@bflad bflad added this to the v0.6.0 milestone Jan 11, 2022
@bflad bflad modified the milestones: v0.6.0, v0.7.0 Mar 10, 2022
@bflad bflad modified the milestones: v0.7.0, v1.0.0 May 2, 2022
@bflad bflad self-assigned this Jun 6, 2022
bflad added a commit that referenced this issue Jun 22, 2022
Reference: #81
Reference: #161
Reference: #215
Reference: #365

This introduces a native abstraction over terraform-plugin-go's `tftypes.AttributePath`, allowing the framework to own the implementation details and extend the functionality further. Provider developers will be closer to removing a direct dependency on terraform-plugin-go. This is a major breaking change, however it is necessary before 1.0 to prevent compatibility issues in the future.

This functionality is only intended to replace `tftypes.AttributePath` usage and not mess with the `tfsdk.Config`, `tfsdk.Plan`, and `tfsdk.State` type `tftypes.Value` data storage fields or their underlying data manipulation logic. This does leave the framework in an awkward half-state until those are further refactored (likely towards native `attr.Value`), but is done to try and reduce the review complexity of this initial migration. Additional followup changes will introduce the concept of path expressions, which will allow provider developers to match against multiple paths or reference parent paths in schema-based plan modifier and validation functionality.

To prevent import cycles between `attr` and `diag` packages due changing the `attr.TypeWithValidate` type `Validate` method signature from `Validate(context.Context, tftypes.Value, *tftypes.AttributePath) diag.Diagnostics` to `Validate(context.Context, tftypes.Value, path.Path) diag.Diagnostics`, the `TypeWithValidation` interface is moved a new `xattr` package underneath `attr` with Go and website documentation to direct provider developers to the other package. This will also solve a prior issue with trying to implement `TypeWithModifyPlan` support.

Naming and location of anything in this initial implementation can be adjusted as necessary.

Provider developers can migrate to the new path handling by replacing:

```go
tftypes.NewAttributePath().WithAttributeName("example")
```

With the equivalent:

```go
path.RootPath("example")
```

Then using the `(Path).At*` methods to extend the path definition instead of `(*tftypes.AttributePath).With*` methods:

| Current                  | New             |
| ------------------------ | --------------- |
| `WithAttributeName()`    | `AtName()`      |
| `WithElementKeyInt()`    | `AtListIndex()` |
| `WithElementKeyString()` | `AtMapKey()`    |
| `WithElementKeyValue()`  | `AtSetValue()`  |
bflad added a commit that referenced this issue Jun 22, 2022
#390)

* path: Introduce package with initial tftypes.AttributePath abstraction

Reference: #81
Reference: #161
Reference: #172
Reference: #365

This introduces a native abstraction over terraform-plugin-go's `tftypes.AttributePath`, allowing the framework to own the implementation details and extend the functionality further. Provider developers will be closer to removing a direct dependency on terraform-plugin-go. This is a major breaking change, however it is necessary before 1.0 to prevent compatibility issues in the future.

This functionality is only intended to replace `tftypes.AttributePath` usage and not mess with the `tfsdk.Config`, `tfsdk.Plan`, and `tfsdk.State` type `tftypes.Value` data storage fields or their underlying data manipulation logic. This does leave the framework in an awkward half-state until those are further refactored (likely towards native `attr.Value`), but is done to try and reduce the review complexity of this initial migration. Additional followup changes will introduce the concept of path expressions, which will allow provider developers to match against multiple paths or reference parent paths in schema-based plan modifier and validation functionality.

To prevent import cycles between `attr` and `diag` packages due changing the `attr.TypeWithValidate` type `Validate` method signature from `Validate(context.Context, tftypes.Value, *tftypes.AttributePath) diag.Diagnostics` to `Validate(context.Context, tftypes.Value, path.Path) diag.Diagnostics`, the `TypeWithValidation` interface is moved a new `xattr` package underneath `attr` with Go and website documentation to direct provider developers to the other package. This will also solve a prior issue with trying to implement `TypeWithModifyPlan` support.

Naming and location of anything in this initial implementation can be adjusted as necessary.

Provider developers can migrate to the new path handling by replacing:

```go
tftypes.NewAttributePath().WithAttributeName("example")
```

With the equivalent:

```go
path.Root("example")
```

Then using the `(Path).At*` methods to extend the path definition instead of `(*tftypes.AttributePath).With*` methods:

| Current                  | New             |
| ------------------------ | --------------- |
| `WithAttributeName()`    | `AtName()`      |
| `WithElementKeyInt()`    | `AtListIndex()` |
| `WithElementKeyString()` | `AtMapKey()`    |
| `WithElementKeyValue()`  | `AtSetValue()`  |
@bflad bflad modified the milestones: v1.0.0, v0.10.0 Jun 27, 2022
bflad added a commit that referenced this issue Jun 28, 2022
Reference: #81
Reference: hashicorp/terraform-plugin-framework-validators#14
Reference: hashicorp/terraform-plugin-framework-validators#15
Reference: hashicorp/terraform-plugin-framework-validators#16
Reference: hashicorp/terraform-plugin-framework-validators#17
Reference: hashicorp/terraform-plugin-framework-validators#20

This introduces the concept of an attribute path expression, an abstraction on top of an attribute path, which enables provider developers to declare logic which might match zero, one, or more paths.

Paths are directly convertable into path expressions as exact expression steps. The builder-like syntax for exact expression steps matches the syntax for path steps, such as `AtName()` in both cases always represents an exact transversal into the attribute name of an object. Additional expression steps enable matching any list, map, or set element, such as `AtAnyListIndex()`. It also supports relative attribute path expressions, by supporting a parent expression step `AtParent()` or starting an expression with `MatchParent()` which can be combined with a prior path expression.

The framework will automatically expose path expressions to attribute plan modifiers and validators, so they can more intuitively support relative paths as inputs to their logic. For example, the `terraform-plugin-framework-validators` Go module will implement support for `terraform-plugin-sdk` multiple attribute schema behaviors such as `ConflictsWith`. It is expected that the downstream implementation can allow provider developers to declare the validator with expressions such as:

```go
tfsdk.Attribute{
	// ... other fields ...

	Validators: []AttributeValidators{
		schemavalidator.ConflictsWith(
			// Example absolute path from root
			path.MatchRoot("root_attribute"),

			// Example relative path from current attribute
			// e.g. another attribute at the same list index of ListNestedAttributes
			path.MatchParent().AtName("another_same_level_attribute"),
		),
	},
}
```

Then the logic within the validator can take the `ValidateAttributeRequest.AttributePathExpression` and use the `(path.Expression).Append()` method to combine the current attribute expression with any incoming expressions.

While this introduction will expose the expression types and make them available to attribute plan modifiers and validators, there is not yet a simple methodology for getting valid paths within data stored in `tfsdk.Config`, `tfsdk.Plan`, and `tfsdk.State` that match the expression. This will be added after this initial expression API is reviewed and approved.
bflad added a commit that referenced this issue Jun 29, 2022
Reference: #81
Reference: hashicorp/terraform-plugin-framework-validators#14
Reference: hashicorp/terraform-plugin-framework-validators#15
Reference: hashicorp/terraform-plugin-framework-validators#16
Reference: hashicorp/terraform-plugin-framework-validators#17
Reference: hashicorp/terraform-plugin-framework-validators#20

This introduces the concept of root and relative attribute path expressions, abstractions on top of an attribute path, which enables provider developers to declare logic which might match zero, one, or more paths.

Paths are directly convertible into path expressions as exact expression steps. The builder-like syntax for exact expression steps matches the syntax for regular path steps, such as `AtName()` in both cases always represents an exact transversal into the attribute name of an object. Additional expression steps enable matching any list, map, or set element, such as `AtAnyListIndex()`. It also supports relative attribute path expressions, by supporting a parent expression step `AtParent()` and starting an expression with `MatchRelative()` so it can be combined with a prior path expression.

The framework will automatically expose path expressions to attribute plan modifiers and validators, so they can more intuitively support relative paths as inputs to their logic. For example, the `terraform-plugin-framework-validators` Go module will implement support for `terraform-plugin-sdk` multiple attribute schema behaviors such as `ConflictsWith`. It is expected that the downstream implementation can allow provider developers to declare the validator with expressions such as:

```go
tfsdk.Attribute{
	// ... other fields ...

	Validators: []AttributeValidators{
		schemavalidator.ConflictsWith(
			// Example absolute path from root
			path.MatchRoot("root_attribute"),

			// Example relative path from current attribute
			// e.g. another attribute at the same list index of ListNestedAttributes
			path.MatchRelative().AtParent().AtName("another_same_level_attribute"),
		),
	},
}
```

Then the logic within the validator can take the `ValidateAttributeRequest.AttributePathExpression` and use the `(path.Expression).Merge()` method to combine the current attribute expression with any incoming expressions.

To find matching attribute paths based on a path expression within `tfsdk.Config`, `tfsdk.Plan`, and `tfsdk.State`, a `PathMatches(path.Expression)` method has been added to each type. The resulting paths can then be used to fetch data via existing functionality, such as the `GetAttribute()` method of each type.
bflad added a commit that referenced this issue Jul 14, 2022
bflad added a commit that referenced this issue Jul 14, 2022
bflad added a commit that referenced this issue Jul 18, 2022
…tation for paths and path expressions (#413)

Reference: #81
@github-actions
Copy link

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.
If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 18, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
breaking-change This PR introduces a breaking change or the resolution of this issue may require a breaking change. enhancement New feature or request
Projects
None yet
2 participants