Skip to content
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

Consider Splitting tfsdk.Attribute into datasource.Attribute, provider.Attribute, and resource.Attribute #132

Closed
bflad opened this issue Sep 7, 2021 · 2 comments · Fixed by #576
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 schema Issues and pull requests about the abstraction for specifying schemas.
Milestone

Comments

@bflad
Copy link
Contributor

bflad commented Sep 7, 2021

Module version

Post plan modification support

Use-cases

Plan modifications can only occur on resource attributes. Since the Attribute type is shared across data source, provider, and resource schemas, it is possible to define plan modifiers on data source and provider attributes which will have no effect. This can be confusing for provider developers.

Attempted Solutions

Note behavior in Go documentation.

Proposal

Consider creating separate Go types for data source, provider, and resource attributes which can cause compile-time errors for functionality not supported by each type. e.g.

package datasource
type Attribute struct{
  // ... Type, etc. ....
}

package provider
type Attribute struct{
  // ... Type, etc. ....
}

package resource
type Attribute struct{
  // ... Type, etc. ....
  PlanModifiers []AttributePlanModifier
}

References

@paddycarver
Copy link
Contributor

I am gently suspicious that the fix will make things confusing (nested attributes can accept provider attributes inside a data source attribute?) but I think it's an interesting line of inquiry.

@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 added the schema Issues and pull requests about the abstraction for specifying schemas. label Sep 21, 2021
bflad added a commit that referenced this issue Jul 29, 2022
…packages

Reference: #132
Reference: #365
Reference: #366

Since the framework's initial release, the `tfsdk` Go package has been a monolithic collection of various provider concepts, including but not limited to handling of data sources, providers, resources, schemas, schema data (such as `Config`, `Plan`, and `State`), and various other helpers. For framework maintainers, this monolithic package has made implementations difficult for certain enhancements, such as import cycles. For provider developers, this monolithic package has been difficult to navigate in the Go documentation. This change represents the first major provider coding paradigm shift to colocate related concepts into their own Go packages, starting with new top-level `datasource`, `provider`, and `resource` packages. Overall the changes, other than the migration effort, should feel welcome as it will be much easier to discover related functionality and there is some reduced wordiness.

This particular change and method (no deprecation period) was not desired, but it was unavoidable due to the interconnectedness of the `tfsdk` package and due to the amount of effort it would require to attempt to support both the old and new types. This change is necessary to complete before there are additional code compatibility promises added to this Go module, such as a version 1.0.0 release or release candidate. This type of change is not taken lightly, as it is quite disruptive for existing provider codebases. It is unclear at the time of writing whether splitting out the other concepts from the `tfsdk` package, such as schemas, will present the same issues. Regardless, any other major changes will be spread across releases.

Provider developers should be able to update their code using find and replace operations using the tables below.

To reduce framework maintainer review burden, all code migrations were lift and shift operations while most code and documentation updates were find and replace operations.

### Providers

| Prior tfsdk Package Type | New provider Package Type |
| --- | --- |
| `tfsdk.ConfigureProviderRequest` | `provider.ConfigureRequest` |
| `tfsdk.ConfigureProviderResponse` | `provider.ConfigureResponse` |
| `tfsdk.Provider` | `provider.Provider` |
| `tfsdk.ProviderConfigValidator` | `provider.ConfigValidator` |
| `tfsdk.ProviderWithConfigValidators` | `provider.ProviderWithConfigValidators` |
| `tfsdk.ProviderWithProviderMeta` | `provider.ProviderWithMetaSchema` (note naming realignment) |
| `tfsdk.ProviderWithValidateConfig` | `provider.ProviderWithValidateConfig` |
| `tfsdk.ValidateProviderConfigRequest` | `provider.ValidateConfigRequest` |
| `tfsdk.ValidateProviderConfigResponse` | `provider.ValidateConfigResponse` |

### Data Sources

The `DataSourceType` abstraction migrates to the `provider` package since it relates to data that must be populated before the provider is configured as well as being passed the `Provider` interface, which can be converted into a concrete Go type when creating a `DataSource`. Other data source concept types are migrated to a new `datasource` package.

| Prior tfsdk Package Type | New provider Package Type |
| --- | --- |
| `tfsdk.DataSourceType` | `provider.DataSourceType` |

| Prior tfsdk Package Type | New datasource Package Type |
| --- | --- |
| `tfsdk.DataSource` | `datasource.DataSource` |
| `tfsdk.DataSourceConfigValidator` | `datasource.ConfigValidator` |
| `tfsdk.DataSourceWithConfigValidators` | `datasource.DataSourceWithConfigValidators` |
| `tfsdk.DataSourceWithValidateConfig` | `datasource.DataSourceWithValidateConfig` |
| `tfsdk.ReadDataSourceRequest` | `datasource.ReadRequest` |
| `tfsdk.ReadDataSourceResponse` | `datasource.ReadResponse` |
| `tfsdk.ValidateDataSourceConfigRequest` | `datasource.ValidateConfigRequest` |
| `tfsdk.ValidateDataSourceConfigResponse` | `datasource.ValidateConfigResponse` |

### Resources

The `ResourceType` abstraction migrates to the `provider` package since it relates to data that must be populated before the provider is configured as well as being passed the `Provider` interface, which can be converted into a concrete Go type when creating a `Resource`. Other resource concept types are migrated to a new `resource` package.

| Prior tfsdk Package Type | New provider Package Type |
| --- | --- |
| `tfsdk.ResourceType` | `provider.ResourceType` |

| Prior tfsdk Package Type | New resource Package Type |
| --- | --- |
| `tfsdk.CreateResourceRequest` | `resource.CreateRequest` |
| `tfsdk.CreateResourceResponse` | `resource.CreateResponse` |
| `tfsdk.DeleteResourceRequest` | `resource.DeleteRequest` |
| `tfsdk.DeleteResourceResponse` | `resource.DeleteResponse` |
| `tfsdk.ImportResourceStateRequest` | `resource.ImportStateRequest` |
| `tfsdk.ImportResourceStateResponse` | `resource.ImportStateResponse` |
| `tfsdk.ModifyResourcePlanRequest` | `resource.ModifyPlanRequest` |
| `tfsdk.ModifyResourcePlanResponse` | `resource.ModifyPlanResponse` |
| `tfsdk.ReadResourceRequest` | `resource.ReadRequest` |
| `tfsdk.ReadResourceResponse` | `resource.ReadResponse` |
| `tfsdk.Resource` | `resource.Resource` |
| `tfsdk.ResourceConfigValidator` | `resource.ConfigValidator` |
| `tfsdk.ResourceWithConfigValidators` | `resource.ResourceWithConfigValidators` |
| `tfsdk.ResourceWithImportState` | `resource.ResourceWithImportState` |
| `tfsdk.ResourceWithModifyPlan` | `resource.ResourceWithModifyPlan` |
| `tfsdk.ResourceWithUpgradeState` | `resource.ResourceWithUpgradeState` |
| `tfsdk.ResourceWithValidateConfig` | `resource.ResourceWithValidateConfig` |
| `tfsdk.UpdateResourceRequest` | `resource.UpdateRequest` |
| `tfsdk.UpdateResourceResponse` | `resource.UpdateResponse` |
| `tfsdk.UpgradeResourceStateRequest` | `resource.UpgradeStateRequest` |
| `tfsdk.UpgradeResourceStateResponse` | `resource.UpgradeStateResponse` |
| `tfsdk.ValidateResourceConfigRequest` | `resource.ValidateConfigRequest` |
| `tfsdk.ValidateResourceConfigResponse` | `resource.ValidateConfigResponse` |
bflad added a commit that referenced this issue Jul 29, 2022
…packages

Reference: #132
Reference: #365
Reference: #366

Since the framework's initial release, the `tfsdk` Go package has been a monolithic collection of various provider concepts, including but not limited to handling of data sources, providers, resources, schemas, schema data (such as `Config`, `Plan`, and `State`), and various other helpers. For framework maintainers, this monolithic package has made implementations difficult for certain enhancements, such as import cycles. For provider developers, this monolithic package has been difficult to navigate in the Go documentation. This change represents the first major provider coding paradigm shift to colocate related concepts into their own Go packages, starting with new top-level `datasource`, `provider`, and `resource` packages.

This particular change and method (no deprecation period) was not desired, but it was unavoidable due to the interconnectedness of the `tfsdk` package and due to the amount of effort it would require to attempt to support both the old and new types. This change is necessary to complete before there are additional code compatibility promises added to this Go module, such as a version 1.0.0 release or release candidate.

This type of change is not taken lightly, as it is quite disruptive for existing provider codebases. On the surface, this change may look fairly unbeneficial for provider developers other than the easier discoverability and reduced wordiness, however it is required to unblock other future refactoring and enhancement efforts in the framework. It is unclear at the time of writing whether splitting out the other concepts from the `tfsdk` package, such as schemas, will present the same issues. Regardless, any other major changes will be spread across releases.

Provider developers should be able to update their code using find and replace operations using the tables below.

To reduce framework maintainer review burden, all code migrations were lift and shift operations while most code and documentation updates were find and replace operations.

| Prior tfsdk Package Type | New provider Package Type |
| --- | --- |
| `tfsdk.ConfigureProviderRequest` | `provider.ConfigureRequest` |
| `tfsdk.ConfigureProviderResponse` | `provider.ConfigureResponse` |
| `tfsdk.Provider` | `provider.Provider` |
| `tfsdk.ProviderConfigValidator` | `provider.ConfigValidator` |
| `tfsdk.ProviderWithConfigValidators` | `provider.ProviderWithConfigValidators` |
| `tfsdk.ProviderWithProviderMeta` | `provider.ProviderWithMetaSchema` (note naming realignment) |
| `tfsdk.ProviderWithValidateConfig` | `provider.ProviderWithValidateConfig` |
| `tfsdk.ValidateProviderConfigRequest` | `provider.ValidateConfigRequest` |
| `tfsdk.ValidateProviderConfigResponse` | `provider.ValidateConfigResponse` |

The `DataSourceType` abstraction migrates to the `provider` package since it relates to data that must be populated before the provider is configured as well as being passed the `Provider` interface, which can be converted into a concrete Go type when creating a `DataSource`. Other data source concept types are migrated to a new `datasource` package.

| Prior tfsdk Package Type | New provider Package Type |
| --- | --- |
| `tfsdk.DataSourceType` | `provider.DataSourceType` |

| Prior tfsdk Package Type | New datasource Package Type |
| --- | --- |
| `tfsdk.DataSource` | `datasource.DataSource` |
| `tfsdk.DataSourceConfigValidator` | `datasource.ConfigValidator` |
| `tfsdk.DataSourceWithConfigValidators` | `datasource.DataSourceWithConfigValidators` |
| `tfsdk.DataSourceWithValidateConfig` | `datasource.DataSourceWithValidateConfig` |
| `tfsdk.ReadDataSourceRequest` | `datasource.ReadRequest` |
| `tfsdk.ReadDataSourceResponse` | `datasource.ReadResponse` |
| `tfsdk.ValidateDataSourceConfigRequest` | `datasource.ValidateConfigRequest` |
| `tfsdk.ValidateDataSourceConfigResponse` | `datasource.ValidateConfigResponse` |

The `ResourceType` abstraction migrates to the `provider` package since it relates to data that must be populated before the provider is configured as well as being passed the `Provider` interface, which can be converted into a concrete Go type when creating a `Resource`. Other resource concept types are migrated to a new `resource` package.

Additionally, the `tfsdk.ResourceImportStatePassthroughID()` function has been migrated to `resource.ImportStatePassthroughID()`.

| Prior tfsdk Package Type | New provider Package Type |
| --- | --- |
| `tfsdk.ResourceType` | `provider.ResourceType` |

| Prior tfsdk Package Type | New resource Package Type |
| --- | --- |
| `tfsdk.CreateResourceRequest` | `resource.CreateRequest` |
| `tfsdk.CreateResourceResponse` | `resource.CreateResponse` |
| `tfsdk.DeleteResourceRequest` | `resource.DeleteRequest` |
| `tfsdk.DeleteResourceResponse` | `resource.DeleteResponse` |
| `tfsdk.ImportResourceStateRequest` | `resource.ImportStateRequest` |
| `tfsdk.ImportResourceStateResponse` | `resource.ImportStateResponse` |
| `tfsdk.ModifyResourcePlanRequest` | `resource.ModifyPlanRequest` |
| `tfsdk.ModifyResourcePlanResponse` | `resource.ModifyPlanResponse` |
| `tfsdk.ReadResourceRequest` | `resource.ReadRequest` |
| `tfsdk.ReadResourceResponse` | `resource.ReadResponse` |
| `tfsdk.Resource` | `resource.Resource` |
| `tfsdk.ResourceConfigValidator` | `resource.ConfigValidator` |
| `tfsdk.ResourceWithConfigValidators` | `resource.ResourceWithConfigValidators` |
| `tfsdk.ResourceWithImportState` | `resource.ResourceWithImportState` |
| `tfsdk.ResourceWithModifyPlan` | `resource.ResourceWithModifyPlan` |
| `tfsdk.ResourceWithUpgradeState` | `resource.ResourceWithUpgradeState` |
| `tfsdk.ResourceWithValidateConfig` | `resource.ResourceWithValidateConfig` |
| `tfsdk.UpdateResourceRequest` | `resource.UpdateRequest` |
| `tfsdk.UpdateResourceResponse` | `resource.UpdateResponse` |
| `tfsdk.UpgradeResourceStateRequest` | `resource.UpgradeStateRequest` |
| `tfsdk.UpgradeResourceStateResponse` | `resource.UpgradeStateResponse` |
| `tfsdk.ValidateResourceConfigRequest` | `resource.ValidateConfigRequest` |
| `tfsdk.ValidateResourceConfigResponse` | `resource.ValidateConfigResponse` |
bflad added a commit that referenced this issue Aug 1, 2022
…packages

Reference: #132
Reference: #365
Reference: #366

Since the framework's initial release, the `tfsdk` Go package has been a monolithic collection of various provider concepts, including but not limited to handling of data sources, providers, resources, schemas, schema data (such as `Config`, `Plan`, and `State`), and various other helpers. For framework maintainers, this monolithic package has made implementations difficult for certain enhancements, such as import cycles. For provider developers, this monolithic package has been difficult to navigate in the Go documentation. This change represents the first major provider coding paradigm shift to colocate related concepts into their own Go packages, starting with new top-level `datasource`, `provider`, and `resource` packages.

This particular change and method (no deprecation period) was not desired, but it was unavoidable due to the interconnectedness of the `tfsdk` package and due to the amount of effort it would require to attempt to support both the old and new types. This change is necessary to complete before there are additional code compatibility promises added to this Go module, such as a version 1.0.0 release or release candidate.

This type of change is not taken lightly, as it is quite disruptive for existing provider codebases. On the surface, this change may look fairly unbeneficial for provider developers other than the easier discoverability and reduced wordiness, however it is required to unblock other future refactoring and enhancement efforts in the framework. It is unclear at the time of writing whether splitting out the other concepts from the `tfsdk` package, such as schemas, will present the same issues. Regardless, any other major changes will be spread across releases.

Provider developers should be able to update their code using find and replace operations using the tables below.

To reduce framework maintainer review burden, all code migrations were lift and shift operations while most code and documentation updates were find and replace operations.

| Prior tfsdk Package Type | New provider Package Type |
| --- | --- |
| `tfsdk.ConfigureProviderRequest` | `provider.ConfigureRequest` |
| `tfsdk.ConfigureProviderResponse` | `provider.ConfigureResponse` |
| `tfsdk.Provider` | `provider.Provider` |
| `tfsdk.ProviderConfigValidator` | `provider.ConfigValidator` |
| `tfsdk.ProviderWithConfigValidators` | `provider.ProviderWithConfigValidators` |
| `tfsdk.ProviderWithProviderMeta` | `provider.ProviderWithMetaSchema` (note naming realignment) |
| `tfsdk.ProviderWithValidateConfig` | `provider.ProviderWithValidateConfig` |
| `tfsdk.ValidateProviderConfigRequest` | `provider.ValidateConfigRequest` |
| `tfsdk.ValidateProviderConfigResponse` | `provider.ValidateConfigResponse` |

The `DataSourceType` abstraction migrates to the `provider` package since it relates to data that must be populated before the provider is configured as well as being passed the `Provider` interface, which can be converted into a concrete Go type when creating a `DataSource`. Other data source concept types are migrated to a new `datasource` package.

| Prior tfsdk Package Type | New provider Package Type |
| --- | --- |
| `tfsdk.DataSourceType` | `provider.DataSourceType` |

| Prior tfsdk Package Type | New datasource Package Type |
| --- | --- |
| `tfsdk.DataSource` | `datasource.DataSource` |
| `tfsdk.DataSourceConfigValidator` | `datasource.ConfigValidator` |
| `tfsdk.DataSourceWithConfigValidators` | `datasource.DataSourceWithConfigValidators` |
| `tfsdk.DataSourceWithValidateConfig` | `datasource.DataSourceWithValidateConfig` |
| `tfsdk.ReadDataSourceRequest` | `datasource.ReadRequest` |
| `tfsdk.ReadDataSourceResponse` | `datasource.ReadResponse` |
| `tfsdk.ValidateDataSourceConfigRequest` | `datasource.ValidateConfigRequest` |
| `tfsdk.ValidateDataSourceConfigResponse` | `datasource.ValidateConfigResponse` |

The `ResourceType` abstraction migrates to the `provider` package since it relates to data that must be populated before the provider is configured as well as being passed the `Provider` interface, which can be converted into a concrete Go type when creating a `Resource`. Other resource concept types are migrated to a new `resource` package.

Additionally, the `tfsdk.ResourceImportStatePassthroughID()` function has been migrated to `resource.ImportStatePassthroughID()`.

| Prior tfsdk Package Type | New provider Package Type |
| --- | --- |
| `tfsdk.ResourceType` | `provider.ResourceType` |

| Prior tfsdk Package Type | New resource Package Type |
| --- | --- |
| `tfsdk.CreateResourceRequest` | `resource.CreateRequest` |
| `tfsdk.CreateResourceResponse` | `resource.CreateResponse` |
| `tfsdk.DeleteResourceRequest` | `resource.DeleteRequest` |
| `tfsdk.DeleteResourceResponse` | `resource.DeleteResponse` |
| `tfsdk.ImportResourceStateRequest` | `resource.ImportStateRequest` |
| `tfsdk.ImportResourceStateResponse` | `resource.ImportStateResponse` |
| `tfsdk.ModifyResourcePlanRequest` | `resource.ModifyPlanRequest` |
| `tfsdk.ModifyResourcePlanResponse` | `resource.ModifyPlanResponse` |
| `tfsdk.ReadResourceRequest` | `resource.ReadRequest` |
| `tfsdk.ReadResourceResponse` | `resource.ReadResponse` |
| `tfsdk.Resource` | `resource.Resource` |
| `tfsdk.ResourceConfigValidator` | `resource.ConfigValidator` |
| `tfsdk.ResourceWithConfigValidators` | `resource.ResourceWithConfigValidators` |
| `tfsdk.ResourceWithImportState` | `resource.ResourceWithImportState` |
| `tfsdk.ResourceWithModifyPlan` | `resource.ResourceWithModifyPlan` |
| `tfsdk.ResourceWithUpgradeState` | `resource.ResourceWithUpgradeState` |
| `tfsdk.ResourceWithValidateConfig` | `resource.ResourceWithValidateConfig` |
| `tfsdk.UpdateResourceRequest` | `resource.UpdateRequest` |
| `tfsdk.UpdateResourceResponse` | `resource.UpdateResponse` |
| `tfsdk.UpgradeResourceStateRequest` | `resource.UpgradeStateRequest` |
| `tfsdk.UpgradeResourceStateResponse` | `resource.UpgradeStateResponse` |
| `tfsdk.ValidateResourceConfigRequest` | `resource.ValidateConfigRequest` |
| `tfsdk.ValidateResourceConfigResponse` | `resource.ValidateConfigResponse` |
bflad added a commit that referenced this issue Aug 2, 2022
…packages (#432)

Reference: #132
Reference: #365
Reference: #366

Since the framework's initial release, the `tfsdk` Go package has been a monolithic collection of various provider concepts, including but not limited to handling of data sources, providers, resources, schemas, schema data (such as `Config`, `Plan`, and `State`), and various other helpers. For framework maintainers, this monolithic package has made implementations difficult for certain enhancements, such as import cycles. For provider developers, this monolithic package has been difficult to navigate in the Go documentation. This change represents the first major provider coding paradigm shift to colocate related concepts into their own Go packages, starting with new top-level `datasource`, `provider`, and `resource` packages.

This particular change and method (no deprecation period) was not desired, but it was unavoidable due to the interconnectedness of the `tfsdk` package and due to the amount of effort it would require to attempt to support both the old and new types. This change is necessary to complete before there are additional code compatibility promises added to this Go module, such as a version 1.0.0 release or release candidate.

This type of change is not taken lightly, as it is quite disruptive for existing provider codebases. On the surface, this change may look fairly unbeneficial for provider developers other than the easier discoverability and reduced wordiness, however it is required to unblock other future refactoring and enhancement efforts in the framework. It is unclear at the time of writing whether splitting out the other concepts from the `tfsdk` package, such as schemas, will present the same issues. Regardless, any other major changes will be spread across releases.

Provider developers should be able to update their code using find and replace operations using the tables below.

To reduce framework maintainer review burden, all code migrations were lift and shift operations while most code and documentation updates were find and replace operations.

| Prior tfsdk Package Type | New provider Package Type |
| --- | --- |
| `tfsdk.ConfigureProviderRequest` | `provider.ConfigureRequest` |
| `tfsdk.ConfigureProviderResponse` | `provider.ConfigureResponse` |
| `tfsdk.Provider` | `provider.Provider` |
| `tfsdk.ProviderConfigValidator` | `provider.ConfigValidator` |
| `tfsdk.ProviderWithConfigValidators` | `provider.ProviderWithConfigValidators` |
| `tfsdk.ProviderWithProviderMeta` | `provider.ProviderWithMetaSchema` (note naming realignment) |
| `tfsdk.ProviderWithValidateConfig` | `provider.ProviderWithValidateConfig` |
| `tfsdk.ValidateProviderConfigRequest` | `provider.ValidateConfigRequest` |
| `tfsdk.ValidateProviderConfigResponse` | `provider.ValidateConfigResponse` |

The `DataSourceType` abstraction migrates to the `provider` package since it relates to data that must be populated before the provider is configured as well as being passed the `Provider` interface, which can be converted into a concrete Go type when creating a `DataSource`. Other data source concept types are migrated to a new `datasource` package.

| Prior tfsdk Package Type | New provider Package Type |
| --- | --- |
| `tfsdk.DataSourceType` | `provider.DataSourceType` |

| Prior tfsdk Package Type | New datasource Package Type |
| --- | --- |
| `tfsdk.DataSource` | `datasource.DataSource` |
| `tfsdk.DataSourceConfigValidator` | `datasource.ConfigValidator` |
| `tfsdk.DataSourceWithConfigValidators` | `datasource.DataSourceWithConfigValidators` |
| `tfsdk.DataSourceWithValidateConfig` | `datasource.DataSourceWithValidateConfig` |
| `tfsdk.ReadDataSourceRequest` | `datasource.ReadRequest` |
| `tfsdk.ReadDataSourceResponse` | `datasource.ReadResponse` |
| `tfsdk.ValidateDataSourceConfigRequest` | `datasource.ValidateConfigRequest` |
| `tfsdk.ValidateDataSourceConfigResponse` | `datasource.ValidateConfigResponse` |

The `ResourceType` abstraction migrates to the `provider` package since it relates to data that must be populated before the provider is configured as well as being passed the `Provider` interface, which can be converted into a concrete Go type when creating a `Resource`. Other resource concept types are migrated to a new `resource` package.

Additionally, the `tfsdk.ResourceImportStatePassthroughID()` function has been migrated to `resource.ImportStatePassthroughID()`.

| Prior tfsdk Package Type | New provider Package Type |
| --- | --- |
| `tfsdk.ResourceType` | `provider.ResourceType` |

| Prior tfsdk Package Type | New resource Package Type |
| --- | --- |
| `tfsdk.CreateResourceRequest` | `resource.CreateRequest` |
| `tfsdk.CreateResourceResponse` | `resource.CreateResponse` |
| `tfsdk.DeleteResourceRequest` | `resource.DeleteRequest` |
| `tfsdk.DeleteResourceResponse` | `resource.DeleteResponse` |
| `tfsdk.ImportResourceStateRequest` | `resource.ImportStateRequest` |
| `tfsdk.ImportResourceStateResponse` | `resource.ImportStateResponse` |
| `tfsdk.ModifyResourcePlanRequest` | `resource.ModifyPlanRequest` |
| `tfsdk.ModifyResourcePlanResponse` | `resource.ModifyPlanResponse` |
| `tfsdk.ReadResourceRequest` | `resource.ReadRequest` |
| `tfsdk.ReadResourceResponse` | `resource.ReadResponse` |
| `tfsdk.Resource` | `resource.Resource` |
| `tfsdk.ResourceConfigValidator` | `resource.ConfigValidator` |
| `tfsdk.ResourceWithConfigValidators` | `resource.ResourceWithConfigValidators` |
| `tfsdk.ResourceWithImportState` | `resource.ResourceWithImportState` |
| `tfsdk.ResourceWithModifyPlan` | `resource.ResourceWithModifyPlan` |
| `tfsdk.ResourceWithUpgradeState` | `resource.ResourceWithUpgradeState` |
| `tfsdk.ResourceWithValidateConfig` | `resource.ResourceWithValidateConfig` |
| `tfsdk.UpdateResourceRequest` | `resource.UpdateRequest` |
| `tfsdk.UpdateResourceResponse` | `resource.UpdateResponse` |
| `tfsdk.UpgradeResourceStateRequest` | `resource.UpgradeStateRequest` |
| `tfsdk.UpgradeResourceStateResponse` | `resource.UpgradeStateResponse` |
| `tfsdk.ValidateResourceConfigRequest` | `resource.ValidateConfigRequest` |
| `tfsdk.ValidateResourceConfigResponse` | `resource.ValidateConfigResponse` |
bflad added a commit that referenced this issue Aug 2, 2022
…ateForUnknown()` plan modifier functions to the `resource` package

Reference: #132
Reference: #365
Reference: #366
Reference: #432

Plan modification in the framework is a concept that only applies to managed resources via the protocol `PlanResourceChange` RPC. Following the migration of other `tfsdk` package types into separate `datasource`, `provider`, and `resource` packages, this change migrates the `RequiresReplace()`, `RequiresReplaceIf()` and `UseStateForUnknown()` plan modifier functions into the `resource` package. This change should be bundled in the same release as the package refactoring since it is similar in nature.

This change has two immediate benefits:

- Aligning the Go package placement tof these functions o hint to provider developers that these are only intended for managed resources.
- For future refactoring this removes additional schema-based code imports from the `tfsdk` package, which could enable refactoring the schema logic into internal packages with potentially less breaking changes for provider developers by removing a source of import cycles.

Provider developers should be able to update their code using find and replace operations using the table below:

| Prior tfsdk Package Function | New resource Package Function |
| --- | --- |
| `tfsdk.RequiresReplace` | `resource.RequiresReplace` |
| `tfsdk.RequiresReplaceIf` | `resource.RequiresReplaceIf` |
| `tfsdk.UseStateForUnknown` | `resource.UseStateForUnknown` |

To reduce framework maintainer review burden, this code migrations was primarily a lift and shift operation while most code and documentation updates were find and replace operations. The modifier types were unexported as exposing them should not be beneficial for provider developers and should help reduce the Go documentation surface area. The plan modifier unit testing was updated to use a `_test` package so it is verifying only exported functionality.
bflad added a commit that referenced this issue Aug 2, 2022
…ateForUnknown()` plan modifier functions to the `resource` package (#434)

Reference: #132
Reference: #365
Reference: #366
Reference: #432

Plan modification in the framework is a concept that only applies to managed resources via the protocol `PlanResourceChange` RPC. Following the migration of other `tfsdk` package types into separate `datasource`, `provider`, and `resource` packages, this change migrates the `RequiresReplace()`, `RequiresReplaceIf()` and `UseStateForUnknown()` plan modifier functions into the `resource` package. This change should be bundled in the same release as the package refactoring since it is similar in nature.

This change has two immediate benefits:

- Aligning the Go package placement tof these functions o hint to provider developers that these are only intended for managed resources.
- For future refactoring this removes additional schema-based code imports from the `tfsdk` package, which could enable refactoring the schema logic into internal packages with potentially less breaking changes for provider developers by removing a source of import cycles.

Provider developers should be able to update their code using find and replace operations using the table below:

| Prior tfsdk Package Function | New resource Package Function |
| --- | --- |
| `tfsdk.RequiresReplace` | `resource.RequiresReplace` |
| `tfsdk.RequiresReplaceIf` | `resource.RequiresReplaceIf` |
| `tfsdk.UseStateForUnknown` | `resource.UseStateForUnknown` |

To reduce framework maintainer review burden, this code migrations was primarily a lift and shift operation while most code and documentation updates were find and replace operations. The modifier types were unexported as exposing them should not be beneficial for provider developers and should help reduce the Go documentation surface area. The plan modifier unit testing was updated to use a `_test` package so it is verifying only exported functionality.
iwarapter pushed a commit to iwarapter/terraform-plugin-framework that referenced this issue Sep 4, 2022
Reference: hashicorp#31
Reference: hashicorp#132
Reference: hashicorp#223
Reference: hashicorp#326
Reference: hashicorp#365
Reference: hashicorp#389

The main goals of this change are:

- Prepare the Go module to support multiple packages that implement concept-specific schema declarations, in particular the `datasource`, `provider`, and `resource` packages
- Continue supporting the existing `tfsdk` package schema implementation with minimal provider developer breaking changes, allowing a deprecation period when the concept-specific schemas are introduced
- Migrate unexported or unintentially exported `tfsdk` schema functionality to internal packages

These goals are accomplished by creating new `internal/fwschema` and `internal/fwxschema` packages, which contain interface types that the provider developer facing packages implement. Currently, the `tfsdk` package is the only implementation, until the design of those concept-specific schema declarations is fully determined. Those designs may include changes to schema implementation details, which cannot be accomplished in the existing `tfsdk` implementation without breaking it and provider developers migrating code to the new packages is a great time to make those types of changes.

The internal interface method design here is purposefully similar to the existing `tfsdk` implementations as we cannot name the methods the same as existing fields and to reduce review burden. After the `tfsdk` implementations are removed, we can consider tidying up the interface methods to drop the `Get` and `Is` method name prefixes.

There are some minor followup changes that will happen either between or during concept-specific schema implementation work, namely:

- Swapping calls `tfsdk` package type `TerraformType()` methods for `AttributeType().TerraformType()` to reduce implementation work for new schema implementations
- Updating unit testing that relies on `tfsdk.Schema` to set up sub-tests via `(*testing.T).Run()` to against multiple implementations

These were not included here to reduce the review burden as they are separate details which can be handled later.
@bflad bflad changed the title Consider Splitting tfsdk.Attribute into DataSourceAttribute, ProviderAttribute, and ResourceAttribute Consider Splitting tfsdk.Attribute into datasource.Attribute, provider.Attribute, and resource.Attribute Sep 23, 2022
@bflad bflad added this to the v1.0.0 milestone Nov 9, 2022
bflad added a commit that referenced this issue Nov 16, 2022
Reference: #83
Reference: #132

As part of upcoming effort to split schema functionality into the `datasource`, `provider`, and `resource` packages, there are some improvements that will land in the new implementations rather than breaking the existing `tfsdk` package schema functionality.

One area which has caused developer burden is that "attribute" validators, currently implementations of the `tfsdk.AttributeValidator` interface,  receive a generic `attr.Value` as the configuration value to perform validation logic. This means that implementors must currently handle validating and converting the value into the concrete type they expect.

The upcoming split schemas handling will introduce separate attribute/block types that will enable to framework to strongly type validators and other future schema enhancements. This change prepares the exported interfaces and internal validation logic for those enhancements.
bflad added a commit that referenced this issue Nov 16, 2022
…tribute interface methods

Reference: #132

As part of upcoming effort to split schema functionality into the `datasource`, `provider`, and `resource` packages, there are some internal implementation details which need to be sorted beforehand. Throughout the 0.x versions, schema functionality has been migrated from the `tfsdk` package into the `internal/fwschema` package, but there is some lingering technical debt of duplicate and confusing methods.

This change creates a new `NestedAttribute` (singular) interface which extends the `Attribute` interface with the methods only required for an attribute that does in fact implement nested attributes. The `tfsdk.Attribute` type is updated to support both the `Attribute` and `NestedAttribute` interfaces as it accurately describes the overloaded abstraction. The `NestedAttributes` (plural) interface remains to describe how `tfsdk.Attribute` implements that concepts under its `Attributes` field. The `NestedAttributes` (plural) interface and its implementations will be removed when `tfsdk.Attribute` is removed.

Another aspect of these changes is cleaning up the type describing methods, removing the separate `Attribute` type `FrameworkType()` method and `NestedAttributes` type `AttributeType()` method.

The upcoming split schemas will implement explicit attribute types which only implement `NestedAttribute` (singular) as appropriate.
bflad added a commit that referenced this issue Nov 17, 2022
Reference: #83
Reference: #132

As part of upcoming effort to split schema functionality into the `datasource`, `provider`, and `resource` packages, there are some improvements that will land in the new implementations rather than breaking the existing `tfsdk` package schema functionality.

One area which has caused developer burden is that "attribute" validators, currently implementations of the `tfsdk.AttributeValidator` interface,  receive a generic `attr.Value` as the configuration value to perform validation logic. This means that implementors must currently handle validating and converting the value into the concrete type they expect.

The upcoming split schemas handling will introduce separate attribute/block types that will enable to framework to strongly type validators and other future schema enhancements. This change prepares the exported interfaces and internal validation logic for those enhancements.
bflad added a commit that referenced this issue Nov 17, 2022
…tribute interface methods (#543)

Reference: #132

As part of upcoming effort to split schema functionality into the `datasource`, `provider`, and `resource` packages, there are some internal implementation details which need to be sorted beforehand. Throughout the 0.x versions, schema functionality has been migrated from the `tfsdk` package into the `internal/fwschema` package, but there is some lingering technical debt of duplicate and confusing methods.

This change creates a new `NestedAttribute` (singular) interface which extends the `Attribute` interface with the methods only required for an attribute that does in fact implement nested attributes. The `tfsdk.Attribute` type is updated to support both the `Attribute` and `NestedAttribute` interfaces as it accurately describes the overloaded abstraction. The `NestedAttributes` (plural) interface remains to describe how `tfsdk.Attribute` implements that concepts under its `Attributes` field. The `NestedAttributes` (plural) interface and its implementations will be removed when `tfsdk.Attribute` is removed.

Another aspect of these changes is cleaning up the type describing methods, removing the separate `Attribute` type `FrameworkType()` method and `NestedAttributes` type `AttributeType()` method.

The upcoming split schemas will implement explicit attribute types which only implement `NestedAttribute` (singular) as appropriate.
bflad added a commit that referenced this issue Nov 17, 2022
Reference: #132

As part of upcoming effort to split schema functionality into the datasource, provider, and resource packages, there are some internal implementation details which need to be sorted beforehand. Throughout the 0.x versions, schema functionality has been migrated from the `tfsdk` package into the `internal/fwschema` package, however the exported `Config`, `Plan`, and `State` type `Schema` fields remained hardcoded to the `tfsdk.Schema` type. This change migrates the field type to the `fwschema.Schema` interface, so other framework schema implementations can be introduced.
bflad added a commit that referenced this issue Nov 17, 2022
…#544)

Reference: #132

As part of upcoming effort to split schema functionality into the datasource, provider, and resource packages, there are some internal implementation details which need to be sorted beforehand. Throughout the 0.x versions, schema functionality has been migrated from the `tfsdk` package into the `internal/fwschema` package, however the exported `Config`, `Plan`, and `State` type `Schema` fields remained hardcoded to the `tfsdk.Schema` type. This change migrates the field type to the `fwschema.Schema` interface, so other framework schema implementations can be introduced.
bflad added a commit that referenced this issue Nov 18, 2022
…terfaces

Reference: #132
Reference: #508
Reference: #532

Since the initial version of the framework, it has treated nested attributes and blocks as a singular entity with some internal gynastics to handle the one (single; object) or two (list, map, set to object) actual types that make up the nested attribute or block. Having these schema abstractions as single entities caused developer confusion when attempting to extract data or create paths.

Other desirable features for the framework are the ability to customize the types, define validators, and define plan modifiers of nested attributes and blocks. This type customization, validation, or plan modification may need to be on the nested object to simplify provider implementations. Exposing these options with a flat abstraction could be confusing.

This change introduces the concept of a nested attribute object and a nested block object into the `internal/fwschema` package and makes the necessary implementation changes to `tfsdk.Attribute` and `tfsdk.Block`. While the `tfsdk` package schema handling does not expose the new potential enhancements, the upcoming `datasource`, `provider`, and `resource` schema handling will. The existing unit testing shows no regressions and the new unit tests with validation show it should be possible to implement nested object validation (and when implemented in the near future, plan modification).

This changeset additionally migrates more `tfsdk.Schema` logic into the `internal/fwschema` package in further preparation for creating additional schema implementations that will benefit from the existing schema logic.
bflad added a commit that referenced this issue Nov 29, 2022
Reference: #132

As part of upcoming effort to split schema functionality into the `datasource`, `provider`, and `resource` packages, there are some improvements that will land in the new implementations rather than breaking the existing `tfsdk` package schema functionality.

One area which has caused developer burden is that "attribute" plan modifiers, currently implementations of the `tfsdk.AttributePlanModifier` interface,  receive generic `attr.Value` as the configuration, plan, and state values to perform modification logic. This means that implementors must currently handle validating and converting the value into the concrete type they expect.

The upcoming split schemas handling will introduce separate attribute/block types that will enable to framework to strongly type validators and other future schema enhancements. This change prepares the exported interfaces and internal validation logic for those enhancements. Plan modifiers are only available for resources, so this package is explicitly placed under that structure to further reduce usage confusion.
bflad added a commit that referenced this issue Nov 29, 2022
Reference: #132
Reference: #326
Reference: #437
Reference: #491
Reference: #508
Reference: #532

This change introduces a new `resource/schema` package, which contains schema interfaces and types relevant to resources. This new schema implementation also provides strongly typed attributes, nested attributes, and blocks with customizable types. Nested attributes and blocks are exposed with a separate nested object for customization, plan modification, and validation.

The implementation leans heavily on the design choice of the framework being responsible for preventing provider developer runtime errors. The tailored fields no longer expose functionality that is not available for resources. The framework design will also raise compiler-time errors for errant typing of validators.

No changes are required for data handling in any other `resource.Resource` methods.

Example definition:

```go
package test

import (
	"context"

	"github.com/bflad/terraform-plugin-framework-type-time/timetypes"
	"github.com/hashicorp/terraform-plugin-framework-validators/float64validator"
	"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
	"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
	"github.com/hashicorp/terraform-plugin-framework/resource"
	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
	"github.com/hashicorp/terraform-plugin-framework/types"
)

type ThingResource struct{}

func (r ThingResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
	resp.Schema = schema.Schema{
		Attributes: map[string]schema.Attribute{
			"string_attribute": schema.StringAttribute{
				Required: true,
				Validators: []validator.String{
					stringvalidator.LengthBetween(3, 256),
				},
			},
			"custom_string_attribute": schema.StringAttribute{
				CustomType: timetypes.RFC3339Type,
				Optional:   true,
			},
			"list_attribute": schema.ListAttribute{
				ElementType: types.StringType,
				Optional:    true,
			},
			"list_nested_attribute": schema.ListNestedAttribute{
				NestedObject: schema.NestedAttributeObject{
					Attributes: map[string]schema.Attribute{
						"bool_attribute": schema.BoolAttribute{
							Optional: true,
						},
					},
					Validators: []validator.Object{ /*...*/ },
				},
				Optional: true,
				Validators: []validator.List{
					listvalidator.SizeAtMost(2),
				},
			},
			"single_nested_attribute": schema.SingleNestedAttribute{
				Attributes: map[string]schema.Attribute{
					"int64_attribute": schema.Int64Attribute{
						Optional: true,
					},
				},
				Optional: true,
			},
		},
		Blocks: map[string]schema.Block{
			"list_block": schema.ListNestedBlock{
				NestedObject: schema.NestedBlockObject{
					Attributes: map[string]schema.Attribute{
						"float64_attribute": schema.Float64Attribute{
							Optional: true,
							Validators: []validator.Float64{
								float64validator.OneOf(1.2, 2.4),
							},
						},
					},
					Validators: []validator.Object{ /*...*/ },
				},
				Validators: []validator.List{
					listvalidator.SizeAtMost(2),
				},
			},
		},
	}
}
```

To migrate a resource schema:

- Add `github.com/hashicorp/terraform-plugin-framework/resource/schema` to the `import` statement
- Switch the `resource.Resource` implementation `GetSchema` method to `Schema` whose response includes a `schema.Schema` from the new package.

Prior implementation:

```go
func (r ThingResource) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
  return tfsdk.Schema{/* ... */}, nil
}
```

Migrated implementation:

```go
func (r ThingResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
  resp.Schema = schema.Schema{/*...*/}
}
```

If the resource requires no schema, the method can be entirely empty.

- Switch `map[string]tfsdk.Attribute` with `map[string]schema.Attribute`
- Switch `map[string]tfsdk.Block` with `map[string]schema.Block`
- Switch individual attribute and block definitions. Unless the code was already taking advantage of custom attribute types (uncommon so far), the `Type` field will be removed and the map entries must declare the typed implementation, e.g. a `tfsdk.Attribute` with `Type: types.StringType` is equivalent to `schema.StringAttribute`. Custom attribute types can be specified via the `CustomType` field in each of the implementations.

Prior primitive type (`types.BoolType`, `types.Float64Type`, `types.Int64Type`, `types.NumberType`, `types.StringType`) attribute implementation:

```go
// The "tfsdk.Attribute" could be omitted inside a map[string]tfsdk.Attribute
tfsdk.Attribute{
  Required: true,
  Type: types.StringType,
}
```

Migrated implementation:

```go
// The schema.XXXAttribute must be declared inside map[string]schema.Attribute
schema.StringAttribute{
  Required: true,
}
```

Prior collection type (`types.ListType`, `types.MapType`, `types.SetType`) attribute implementation:

```go
// The "tfsdk.Attribute" could be omitted inside a map[string]tfsdk.Attribute
tfsdk.Attribute{
  Required: true,
  Type: types.ListType{
    ElemType: types.StringType,
  },
}
```

Migrated implementation:

```go
// The schema.XXXAttribute must be declared inside map[string]schema.Attribute
schema.ListAttribute{
  ElementType: types.StringType,
  Required: true,
}
```

Prior single nested attributes type (`tfsdk.SingleNestedAttributes()`) attribute implementation:

```go
// The "tfsdk.Attribute" could be omitted inside a map[string]tfsdk.Attribute
tfsdk.Attribute{
  Attributes: tfsdk.SingleNestedAttributes(map[string]tfsdk.Attribute{/*...*/}),
  Required: true,
},
```

Migrated implementation:

```go
// The schema.XXXAttribute must be declared inside map[string]schema.Attribute
schema.SingleNestedAttribute{
  Attributes: map[string]schema.Attribute{/*...*/},
  Required: true,
}
```

Prior collection nested attributes type (`tfsdk.ListNestedAttributes()`, `tfsdk.MapNestedAttributes()`, `tfsdk.SetNestedAttributes()`) attribute implementation:

```go
// The "tfsdk.Attribute" could be omitted inside a map[string]tfsdk.Attribute
tfsdk.Attribute{
  Attributes: tfsdk.ListNestedAttributes(map[string]tfsdk.Attribute{/*...*/}),
  Required: true,
},
```

Migrated implementation:

```go
// The schema.XXXAttribute must be declared inside map[string]schema.Attribute
schema.ListNestedAttribute{
  NestedObject: schema.NestedAttributeObject{
    Attributes: map[string]schema.Attribute{/*...*/},
  },
  Required: true,
}
```

Prior collection blocks type (`tfsdk.Block`) attribute implementation:

```go
// The "tfsdk.Block" could be omitted inside a map[string]tfsdk.Block
tfsdk.Block{
  Attributes: map[string]tfsdk.Attribute{/*...*/},
  Blocks: map[string]tfsdk.Block{/*...*/},
  NestingMode: tfsdk.BlockNestingModeList,
},
```

Migrated implementation:

```go
// The schema.XXXBlock must be declared inside map[string]schema.Block
schema.ListNestedBlock{
  NestedObject: schema.NestedBlockObject{
    Attributes: map[string]schema.Attribute{/*...*/},
    Blocks: map[string]schema.Block{/*...*/},
  },
}
```
bflad added a commit that referenced this issue Nov 29, 2022
#557)

Reference: #132

As part of upcoming effort to split schema functionality into the `datasource`, `provider`, and `resource` packages, there are some improvements that will land in the new implementations rather than breaking the existing `tfsdk` package schema functionality.

One area which has caused developer burden is that "attribute" plan modifiers, currently implementations of the `tfsdk.AttributePlanModifier` interface,  receive generic `attr.Value` as the configuration, plan, and state values to perform modification logic. This means that implementors must currently handle validating and converting the value into the concrete type they expect.

The upcoming split schemas handling will introduce separate attribute/block types that will enable to framework to strongly type validators and other future schema enhancements. This change prepares the exported interfaces and internal validation logic for those enhancements. Plan modifiers are only available for resources, so this package is explicitly placed under that structure to further reduce usage confusion.
bflad added a commit that referenced this issue Nov 29, 2022
Reference: #132
Reference: #326
Reference: #437
Reference: #491
Reference: #508
Reference: #532

This change introduces a new `resource/schema` package, which contains schema interfaces and types relevant to resources. This new schema implementation also provides strongly typed attributes, nested attributes, and blocks with customizable types. Nested attributes and blocks are exposed with a separate nested object for customization, plan modification, and validation.

The implementation leans heavily on the design choice of the framework being responsible for preventing provider developer runtime errors. The tailored fields no longer expose functionality that is not available for resources. The framework design will also raise compiler-time errors for errant typing of validators.

No changes are required for data handling in any other `resource.Resource` methods.

Example definition:

```go
package test

import (
	"context"

	"github.com/bflad/terraform-plugin-framework-type-time/timetypes"
	"github.com/hashicorp/terraform-plugin-framework-validators/float64validator"
	"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
	"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
	"github.com/hashicorp/terraform-plugin-framework/resource"
	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
	"github.com/hashicorp/terraform-plugin-framework/types"
)

type ThingResource struct{}

func (r ThingResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
	resp.Schema = schema.Schema{
		Attributes: map[string]schema.Attribute{
			"string_attribute": schema.StringAttribute{
				Required: true,
				Validators: []validator.String{
					stringvalidator.LengthBetween(3, 256),
				},
			},
			"custom_string_attribute": schema.StringAttribute{
				CustomType: timetypes.RFC3339Type,
				Optional:   true,
			},
			"list_attribute": schema.ListAttribute{
				ElementType: types.StringType,
				Optional:    true,
			},
			"list_nested_attribute": schema.ListNestedAttribute{
				NestedObject: schema.NestedAttributeObject{
					Attributes: map[string]schema.Attribute{
						"bool_attribute": schema.BoolAttribute{
							Optional: true,
						},
					},
					Validators: []validator.Object{ /*...*/ },
				},
				Optional: true,
				Validators: []validator.List{
					listvalidator.SizeAtMost(2),
				},
			},
			"single_nested_attribute": schema.SingleNestedAttribute{
				Attributes: map[string]schema.Attribute{
					"int64_attribute": schema.Int64Attribute{
						Optional: true,
					},
				},
				Optional: true,
			},
		},
		Blocks: map[string]schema.Block{
			"list_block": schema.ListNestedBlock{
				NestedObject: schema.NestedBlockObject{
					Attributes: map[string]schema.Attribute{
						"float64_attribute": schema.Float64Attribute{
							Optional: true,
							Validators: []validator.Float64{
								float64validator.OneOf(1.2, 2.4),
							},
						},
					},
					Validators: []validator.Object{ /*...*/ },
				},
				Validators: []validator.List{
					listvalidator.SizeAtMost(2),
				},
			},
		},
	}
}
```

To migrate a resource schema:

- Add `github.com/hashicorp/terraform-plugin-framework/resource/schema` to the `import` statement
- Switch the `resource.Resource` implementation `GetSchema` method to `Schema` whose response includes a `schema.Schema` from the new package.

Prior implementation:

```go
func (r ThingResource) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
  return tfsdk.Schema{/* ... */}, nil
}
```

Migrated implementation:

```go
func (r ThingResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
  resp.Schema = schema.Schema{/*...*/}
}
```

If the resource requires no schema, the method can be entirely empty.

- Switch `map[string]tfsdk.Attribute` with `map[string]schema.Attribute`
- Switch `map[string]tfsdk.Block` with `map[string]schema.Block`
- Switch individual attribute and block definitions. Unless the code was already taking advantage of custom attribute types (uncommon so far), the `Type` field will be removed and the map entries must declare the typed implementation, e.g. a `tfsdk.Attribute` with `Type: types.StringType` is equivalent to `schema.StringAttribute`. Custom attribute types can be specified via the `CustomType` field in each of the implementations.

Prior primitive type (`types.BoolType`, `types.Float64Type`, `types.Int64Type`, `types.NumberType`, `types.StringType`) attribute implementation:

```go
// The "tfsdk.Attribute" could be omitted inside a map[string]tfsdk.Attribute
tfsdk.Attribute{
  Required: true,
  Type: types.StringType,
}
```

Migrated implementation:

```go
// The schema.XXXAttribute must be declared inside map[string]schema.Attribute
schema.StringAttribute{
  Required: true,
}
```

Prior collection type (`types.ListType`, `types.MapType`, `types.SetType`) attribute implementation:

```go
// The "tfsdk.Attribute" could be omitted inside a map[string]tfsdk.Attribute
tfsdk.Attribute{
  Required: true,
  Type: types.ListType{
    ElemType: types.StringType,
  },
}
```

Migrated implementation:

```go
// The schema.XXXAttribute must be declared inside map[string]schema.Attribute
schema.ListAttribute{
  ElementType: types.StringType,
  Required: true,
}
```

Prior single nested attributes type (`tfsdk.SingleNestedAttributes()`) attribute implementation:

```go
// The "tfsdk.Attribute" could be omitted inside a map[string]tfsdk.Attribute
tfsdk.Attribute{
  Attributes: tfsdk.SingleNestedAttributes(map[string]tfsdk.Attribute{/*...*/}),
  Required: true,
},
```

Migrated implementation:

```go
// The schema.XXXAttribute must be declared inside map[string]schema.Attribute
schema.SingleNestedAttribute{
  Attributes: map[string]schema.Attribute{/*...*/},
  Required: true,
}
```

Prior collection nested attributes type (`tfsdk.ListNestedAttributes()`, `tfsdk.MapNestedAttributes()`, `tfsdk.SetNestedAttributes()`) attribute implementation:

```go
// The "tfsdk.Attribute" could be omitted inside a map[string]tfsdk.Attribute
tfsdk.Attribute{
  Attributes: tfsdk.ListNestedAttributes(map[string]tfsdk.Attribute{/*...*/}),
  Required: true,
},
```

Migrated implementation:

```go
// The schema.XXXAttribute must be declared inside map[string]schema.Attribute
schema.ListNestedAttribute{
  NestedObject: schema.NestedAttributeObject{
    Attributes: map[string]schema.Attribute{/*...*/},
  },
  Required: true,
}
```

Prior collection blocks type (`tfsdk.Block`) attribute implementation:

```go
// The "tfsdk.Block" could be omitted inside a map[string]tfsdk.Block
tfsdk.Block{
  Attributes: map[string]tfsdk.Attribute{/*...*/},
  Blocks: map[string]tfsdk.Block{/*...*/},
  NestingMode: tfsdk.BlockNestingModeList,
},
```

Migrated implementation:

```go
// The schema.XXXBlock must be declared inside map[string]schema.Block
schema.ListNestedBlock{
  NestedObject: schema.NestedBlockObject{
    Attributes: map[string]schema.Attribute{/*...*/},
    Blocks: map[string]schema.Block{/*...*/},
  },
}
```
bflad added a commit that referenced this issue Nov 29, 2022
Reference: #132
Reference: #326
Reference: #437
Reference: #491
Reference: #508
Reference: #532

This change introduces a new `provider/metaschema` package, which contains schema interfaces and types relevant to provider meta schemas, such as omitting `Computed`, `DeprecatedMessage`, `Sensitive`, plan modifiers, validators, blocks, schema descriptions, and schema versioning. This new schema implementation also provides strongly typed attributes and nested attributes with customizable types. Nested attributes are exposed with a separate nested object for customization.

The implementation leans heavily on the design choice of the framework being responsible for preventing provider developer runtime errors. The tailored fields no longer expose functionality that is not available for provider meta schemas.

No changes are required for data handling during requests.

Example definition:

```go
package test

import (
	"context"

	"github.com/bflad/terraform-plugin-framework-type-time/timetypes"
	"github.com/hashicorp/terraform-plugin-framework-validators/float64validator"
	"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
	"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
	"github.com/hashicorp/terraform-plugin-framework/provider"
	"github.com/hashicorp/terraform-plugin-framework/provider/metaschema"
	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
	"github.com/hashicorp/terraform-plugin-framework/types"
)

type ExampleCloudProvider struct{}

func (p ExampleCloudProvider) MetaSchema(ctx context.Context, req provider.MetaSchemaRequest, resp *provider.MetaSchemaResponse) {
	resp.Schema = metaschema.Schema{
		Attributes: map[string]schema.Attribute{
			"string_attribute": schema.StringAttribute{
				Required: true,
			},
			"custom_string_attribute": schema.StringAttribute{
				CustomType: timetypes.RFC3339Type,
				Optional:   true,
			},
			"list_attribute": schema.ListAttribute{
				ElementType: types.StringType,
				Optional:    true,
			},
			"list_nested_attribute": schema.ListNestedAttribute{
				NestedObject: schema.NestedAttributeObject{
					Attributes: map[string]schema.Attribute{
						"bool_attribute": schema.BoolAttribute{
							Optional: true,
						},
					},
				},
				Optional: true,
			},
			"single_nested_attribute": schema.SingleNestedAttribute{
				Attributes: map[string]schema.Attribute{
					"int64_attribute": schema.Int64Attribute{
						Optional: true,
					},
				},
				Optional: true,
			},
		},
	}
}
```

To migrate a provider meta schema:

- Add `github.com/hashicorp/terraform-plugin-framework/provider/metaschema` to the `import` statement
- Switch the `provider.ProviderWithMetaSchema` implementation `GetMetaSchema` method to `MetaSchema` whose response includes a `metaschema.Schema` from the new package.

Prior implementation:

```go
func (p ExampleCloudProvider) GetMetaSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
  return tfsdk.Schema{/* ... */}, nil
}
```

Migrated implementation:

```go
func (p ExampleCloudProvider) MetaSchema(ctx context.Context, req provider.MetaSchemaRequest, resp *provider.MetaSchemaResponse) {
  resp.Schema =  metaschema.Schema{/*...*/}
}
```

If the provider requires no meta schema, the method can be removed entirely.

- Switch `map[string]tfsdk.Attribute` with `map[string]metaschema.Attribute`
- Switch individual attribute  definitions. Unless the code was already taking advantage of custom attribute types (uncommon so far), the `Type` field will be removed and the map entries must declare the typed implementation, e.g. a `tfsdk.Attribute` with `Type: types.StringType` is equivalent to `metaschema.StringAttribute`. Custom attribute types can be specified via the `CustomType` field in each of the implementations.

Prior primitive type (`types.BoolType`, `types.Float64Type`, `types.Int64Type`, `types.NumberType`, `types.StringType`) attribute implementation:

```go
// The "tfsdk.Attribute" could be omitted inside a map[string]tfsdk.Attribute
tfsdk.Attribute{
  Required: true,
  Type: types.StringType,
}
```

Migrated implementation:

```go
// The metaschema.XXXAttribute must be declared inside map[string]metaschema.Attribute
schema.StringAttribute{
  Required: true,
}
```

Prior collection type (`types.ListType`, `types.MapType`, `types.SetType`) attribute implementation:

```go
// The "tfsdk.Attribute" could be omitted inside a map[string]tfsdk.Attribute
tfsdk.Attribute{
  Required: true,
  Type: types.ListType{
    ElemType: types.StringType,
  },
}
```

Migrated implementation:

```go
// The metaschema.XXXAttribute must be declared inside map[string]metaschema.Attribute
metaschema.ListAttribute{
  ElementType: types.StringType,
  Required: true,
}
```

Prior single nested attributes type (`tfsdk.SingleNestedAttributes()`) attribute implementation:

```go
// The "tfsdk.Attribute" could be omitted inside a map[string]tfsdk.Attribute
tfsdk.Attribute{
  Attributes: tfsdk.SingleNestedAttributes(map[string]tfsdk.Attribute{/*...*/}),
  Required: true,
},
```

Migrated implementation:

```go
// The metaschema.XXXAttribute must be declared inside map[string]metaschema.Attribute
metaschema.SingleNestedAttribute{
  Attributes: map[string]metaschema.Attribute{/*...*/},
  Required: true,
}
```

Prior collection nested attributes type (`tfsdk.ListNestedAttributes()`, `tfsdk.MapNestedAttributes()`, `tfsdk.SetNestedAttributes()`) attribute implementation:

```go
// The "tfsdk.Attribute" could be omitted inside a map[string]tfsdk.Attribute
tfsdk.Attribute{
  Attributes: tfsdk.ListNestedAttributes(map[string]tfsdk.Attribute{/*...*/}),
  Required: true,
},
```

Migrated implementation:

```go
// The metaschema.XXXAttribute must be declared inside map[string]metaschema.Attribute
metaschema.ListNestedAttribute{
  NestedObject: metaschema.NestedAttributeObject{
    Attributes: map[string]metaschema.Attribute{/*...*/},
  },
  Required: true,
}
```
bflad added a commit that referenced this issue Nov 29, 2022
Reference: #132
Reference: #326
Reference: #437
Reference: #491
Reference: #546
Reference: #553
Reference: #558
Reference: #562
bflad added a commit that referenced this issue Nov 29, 2022
Reference: #132
Reference: #326
Reference: #437
Reference: #491
Reference: #508
Reference: #532

This change introduces a new `provider/metaschema` package, which contains schema interfaces and types relevant to provider meta schemas, such as omitting `Computed`, `DeprecatedMessage`, `Sensitive`, plan modifiers, validators, blocks, schema descriptions, and schema versioning. This new schema implementation also provides strongly typed attributes and nested attributes with customizable types. Nested attributes are exposed with a separate nested object for customization.

The implementation leans heavily on the design choice of the framework being responsible for preventing provider developer runtime errors. The tailored fields no longer expose functionality that is not available for provider meta schemas.

No changes are required for data handling during requests.

Example definition:

```go
package test

import (
	"context"

	"github.com/bflad/terraform-plugin-framework-type-time/timetypes"
	"github.com/hashicorp/terraform-plugin-framework-validators/float64validator"
	"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
	"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
	"github.com/hashicorp/terraform-plugin-framework/provider"
	"github.com/hashicorp/terraform-plugin-framework/provider/metaschema"
	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
	"github.com/hashicorp/terraform-plugin-framework/types"
)

type ExampleCloudProvider struct{}

func (p ExampleCloudProvider) MetaSchema(ctx context.Context, req provider.MetaSchemaRequest, resp *provider.MetaSchemaResponse) {
	resp.Schema = metaschema.Schema{
		Attributes: map[string]schema.Attribute{
			"string_attribute": schema.StringAttribute{
				Required: true,
			},
			"custom_string_attribute": schema.StringAttribute{
				CustomType: timetypes.RFC3339Type,
				Optional:   true,
			},
			"list_attribute": schema.ListAttribute{
				ElementType: types.StringType,
				Optional:    true,
			},
			"list_nested_attribute": schema.ListNestedAttribute{
				NestedObject: schema.NestedAttributeObject{
					Attributes: map[string]schema.Attribute{
						"bool_attribute": schema.BoolAttribute{
							Optional: true,
						},
					},
				},
				Optional: true,
			},
			"single_nested_attribute": schema.SingleNestedAttribute{
				Attributes: map[string]schema.Attribute{
					"int64_attribute": schema.Int64Attribute{
						Optional: true,
					},
				},
				Optional: true,
			},
		},
	}
}
```

To migrate a provider meta schema:

- Add `github.com/hashicorp/terraform-plugin-framework/provider/metaschema` to the `import` statement
- Switch the `provider.ProviderWithMetaSchema` implementation `GetMetaSchema` method to `MetaSchema` whose response includes a `metaschema.Schema` from the new package.

Prior implementation:

```go
func (p ExampleCloudProvider) GetMetaSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
  return tfsdk.Schema{/* ... */}, nil
}
```

Migrated implementation:

```go
func (p ExampleCloudProvider) MetaSchema(ctx context.Context, req provider.MetaSchemaRequest, resp *provider.MetaSchemaResponse) {
  resp.Schema =  metaschema.Schema{/*...*/}
}
```

If the provider requires no meta schema, the method can be removed entirely.

- Switch `map[string]tfsdk.Attribute` with `map[string]metaschema.Attribute`
- Switch individual attribute  definitions. Unless the code was already taking advantage of custom attribute types (uncommon so far), the `Type` field will be removed and the map entries must declare the typed implementation, e.g. a `tfsdk.Attribute` with `Type: types.StringType` is equivalent to `metaschema.StringAttribute`. Custom attribute types can be specified via the `CustomType` field in each of the implementations.

Prior primitive type (`types.BoolType`, `types.Float64Type`, `types.Int64Type`, `types.NumberType`, `types.StringType`) attribute implementation:

```go
// The "tfsdk.Attribute" could be omitted inside a map[string]tfsdk.Attribute
tfsdk.Attribute{
  Required: true,
  Type: types.StringType,
}
```

Migrated implementation:

```go
// The metaschema.XXXAttribute must be declared inside map[string]metaschema.Attribute
schema.StringAttribute{
  Required: true,
}
```

Prior collection type (`types.ListType`, `types.MapType`, `types.SetType`) attribute implementation:

```go
// The "tfsdk.Attribute" could be omitted inside a map[string]tfsdk.Attribute
tfsdk.Attribute{
  Required: true,
  Type: types.ListType{
    ElemType: types.StringType,
  },
}
```

Migrated implementation:

```go
// The metaschema.XXXAttribute must be declared inside map[string]metaschema.Attribute
metaschema.ListAttribute{
  ElementType: types.StringType,
  Required: true,
}
```

Prior single nested attributes type (`tfsdk.SingleNestedAttributes()`) attribute implementation:

```go
// The "tfsdk.Attribute" could be omitted inside a map[string]tfsdk.Attribute
tfsdk.Attribute{
  Attributes: tfsdk.SingleNestedAttributes(map[string]tfsdk.Attribute{/*...*/}),
  Required: true,
},
```

Migrated implementation:

```go
// The metaschema.XXXAttribute must be declared inside map[string]metaschema.Attribute
metaschema.SingleNestedAttribute{
  Attributes: map[string]metaschema.Attribute{/*...*/},
  Required: true,
}
```

Prior collection nested attributes type (`tfsdk.ListNestedAttributes()`, `tfsdk.MapNestedAttributes()`, `tfsdk.SetNestedAttributes()`) attribute implementation:

```go
// The "tfsdk.Attribute" could be omitted inside a map[string]tfsdk.Attribute
tfsdk.Attribute{
  Attributes: tfsdk.ListNestedAttributes(map[string]tfsdk.Attribute{/*...*/}),
  Required: true,
},
```

Migrated implementation:

```go
// The metaschema.XXXAttribute must be declared inside map[string]metaschema.Attribute
metaschema.ListNestedAttribute{
  NestedObject: metaschema.NestedAttributeObject{
    Attributes: map[string]metaschema.Attribute{/*...*/},
  },
  Required: true,
}
```
bflad added a commit that referenced this issue Nov 29, 2022
Reference: #132
Reference: #326
Reference: #437
Reference: #491
Reference: #546
Reference: #553
Reference: #558
Reference: #562
Reference: #563
bflad added a commit that referenced this issue Nov 29, 2022
Reference: #132
Reference: #326
Reference: #437
Reference: #491
Reference: #546
Reference: #553
Reference: #558
Reference: #562
bflad added a commit that referenced this issue Nov 30, 2022
… modifier implementations

Reference: #132

When developers migrate from `tfsdk.Schema` to `resource/schema.Schema`, they will need to also migrate to the type-specific plan modifiers. New packages have been introduced under `resource/schema`, such as `resource/schema/stringplanmodifier`. The existing plan modifiers are deprecated, similar to the `tfsdk` schema handling.
bflad added a commit that referenced this issue Nov 30, 2022
… modifier implementations (#565)

Reference: #132

When developers migrate from `tfsdk.Schema` to `resource/schema.Schema`, they will need to also migrate to the type-specific plan modifiers. New packages have been introduced under `resource/schema`, such as `resource/schema/stringplanmodifier`. The existing plan modifiers are deprecated, similar to the `tfsdk` schema handling.
bflad added a commit that referenced this issue Nov 30, 2022
…564)

Reference: #132
Reference: #326
Reference: #437
Reference: #491
Reference: #546
Reference: #553
Reference: #558
Reference: #562
Reference: #563
bflad added a commit that referenced this issue Dec 13, 2022
…e in unit testing

Reference: #132

Precursor for fully removing `tfsdk` package `Schema`, `Attribute`, and `Block` types. Replaced with `internal/testing/testschema`, `datasource/schema`, `provider/metaschema`, `provider/schema`, and `resource/schema` equivalents. Removed extraneous unit testing such as datasource versioning, provider Computed, etc. since it will be no longer possible to declare invalid schemas based on the concept.
bflad added a commit that referenced this issue Dec 13, 2022
Reference: #132
Reference: #326
Reference: #491

Refer to the following pull request descriptions for migration information about migrating to the split schema packages:

- `datasource/schema`: #546
- `provider/schema`: #553
- `resource/schema`: #558
- `provider/metaschema`: #562
bflad added a commit that referenced this issue Dec 13, 2022
…e in unit testing (#575)

Reference: #132

Precursor for fully removing `tfsdk` package `Schema`, `Attribute`, and `Block` types. Replaced with `internal/testing/testschema`, `datasource/schema`, `provider/metaschema`, `provider/schema`, and `resource/schema` equivalents. Removed extraneous unit testing such as datasource versioning, provider Computed, etc. since it will be no longer possible to declare invalid schemas based on the concept.
bflad added a commit that referenced this issue Dec 13, 2022
Reference: #132
Reference: #326
Reference: #491

Refer to the following pull request descriptions for migration information about migrating to the split schema packages:

- `datasource/schema`: #546
- `provider/schema`: #553
- `resource/schema`: #558
- `provider/metaschema`: #562
bflad added a commit that referenced this issue Dec 13, 2022
Reference: #132
Reference: #326
Reference: #491

Refer to the following pull request descriptions for migration information about migrating to the split schema packages:

- `datasource/schema`: #546
- `provider/schema`: #553
- `resource/schema`: #558
- `provider/metaschema`: #562
bflad added a commit that referenced this issue Dec 13, 2022
Reference: #132
Reference: #326
Reference: #491

Refer to the following pull request descriptions for migration information about migrating to the split schema packages:

- `datasource/schema`: #546
- `provider/schema`: #553
- `resource/schema`: #558
- `provider/metaschema`: #562
@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 Jan 13, 2023
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 schema Issues and pull requests about the abstraction for specifying schemas.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants