--- name: schema-model-generator description: Given a Go SDK contract (DTOs), generate the corresponding Terraform schema attributes and model structs with high fidelity. USE FOR: creating schema_*.go and models.go files from SDK DTOs, mapping Go types to Terraform attribute types and custom types. --- # Skill: Schema & Model Generator Given a Go SDK contract (DTOs), generate the corresponding Terraform schema attributes and model structs with high fidelity. ## Prerequisites - SDK DTO struct fields have been identified (from `#skill:sdk-contract-navigator`) - You know the item archetype (basic, definition, properties, etc.) - If the issue contains a **๐ŸŒณ DTO Nesting Depth Map**, use it to determine: - One model struct per tree node that introduces `[]Type` or `*Type` - Each such struct needs its own `set()` method - Which fields use `supertypes.ListNestedObjectValueOf` (nested objects) vs `supertypes.ListValueOf` (scalars) vs `supertypes.SingleNestedObjectValueOf` (optional nested) ## Step 1 โ€” Classify Each SDK Field For each field in the SDK DTO struct, determine its category using the **"Attribute Behaviors"** table in `.github/instructions/schema-model-patterns.instructions.md`. Classification criteria: | Category | Criterion | | ------------------------- | -------------------------------------------------- | | **Read-only** | Only appears in Get response `Properties` struct | | **Create-time-only** | Appears in `CreationPayload` and cannot be updated | | **Updatable required** | User must provide, can be changed after create | | **Updatable optional** | User may provide, can be changed after create | | **Optional with default** | Server sets a default if not provided | ## Step 2 โ€” Generate Model Struct Fields Map each SDK field type to the corresponding Terraform model type using the **"SDK Type โ†’ Model Type Mapping"** table in `.github/instructions/schema-model-patterns.instructions.md`. Every field must have a `tfsdk:""` tag. ### Naming Conventions - Model struct: `Model` โ€” e.g. `lakehousePropertiesModel`, `lakehouseConfigurationModel` - Nested model: `Model` โ€” e.g. `lakehouseSQLEndpointPropertiesModel` - Field names: PascalCase in Go, with `tfsdk:"snake_case"` tag - SDK PascalCase โ†’ Terraform snake_case: `OneLakeFilesPath` โ†’ `onelake_files_path` ### Example Properties Model ```go type lakehousePropertiesModel struct { OneLakeFilesPath types.String `tfsdk:"onelake_files_path"` OneLakeTablesPath types.String `tfsdk:"onelake_tables_path"` SQLEndpointProperties supertypes.SingleNestedObjectValueOf[lakehouseSQLEndpointPropertiesModel] `tfsdk:"sql_endpoint_properties"` DefaultSchema types.String `tfsdk:"default_schema"` } ``` ### Example Configuration Model (CreationPayload) ```go type lakehouseConfigurationModel struct { EnableSchemas types.Bool `tfsdk:"enable_schemas"` } ``` ### Example Nested Model ```go type lakehouseSQLEndpointPropertiesModel struct { ID customtypes.UUID `tfsdk:"id"` ConnectionString types.String `tfsdk:"connection_string"` ProvisioningStatus types.String `tfsdk:"provisioning_status"` } ``` ## Step 3 โ€” Generate Model Methods Generate both directions of mapping: **response `set()`** (SDK โ†’ TF) and **request builders** (TF โ†’ SDK). ### 3a. Response `set()` โ€” SDK โ†’ TF (both Fabric Items and non-items) Every model struct needs a `set()` method that maps SDK response DTO โ†’ TF model. **Top-level `set()` (with nested objects):** Signature includes `context.Context` and returns `diag.Diagnostics`: ```go func (to *PropertiesModel) set(ctx context.Context, from fab.) diag.Diagnostics { to.SimpleField = types.StringPointerValue(from.SimpleField) // ... other simple fields // Handle nested struct nestedValue := supertypes.NewSingleNestedObjectValueOfNull[](ctx) if from.NestedField != nil { nestedModel := &{} nestedModel.set(*from.NestedField) // or with ctx if nested has its own nested if diags := nestedValue.Set(ctx, nestedModel); diags.HasError() { return diags } } to.NestedField = nestedValue return nil } ``` **Leaf `set()` (no nested objects):** Simpler signature without `context.Context` or `diag.Diagnostics`: ```go func (to *) set(from fab.) { to.ID = customtypes.NewUUIDPointerValue(from.ID) to.StringField = types.StringPointerValue(from.StringField) to.EnumField = types.StringPointerValue((*string)(from.EnumField)) } ``` **Setter patterns by type:** Use the "Setter Pattern" column in the "SDK Type โ†’ Model Type Mapping" table and collection iteration templates in `schema-model-patterns.instructions.md`. ### 3b. Request Builders โ€” TF โ†’ SDK (Create/Update) Both Fabric Items and non-items need TFโ†’SDK mapping for writable fields. The pattern differs by category: - **Fabric Items:** Inline in `creationPayloadSetter` closure (simple โ€” typically 1-3 fields from configuration model). See `fabric-item-patterns.instructions.md` ยง "Closure Examples". - **Non-items:** Dedicated request builder structs with `set()` method that builds the SDK request directly (complex โ€” full request DTOs) **Non-item request builder struct** โ€” embeds the SDK request type, `set()` populates it: ```go type requestCreate struct { fabcore.CreateRequest // embedded SDK request type } func (to *requestCreate) set(ctx context.Context, from ResourceModel) diag.Diagnostics { to.DisplayName = from.DisplayName.ValueStringPointer() to.Description = from.Description.ValueStringPointer() // ... map each writable field into the embedded struct return nil } ``` Usage: `r.client.Create(ctx, reqCreate.CreateRequest, nil)` **Inverse mapping rules:** Use the inverse of the "SDK Type โ†’ Model Type Mapping" table in `schema-model-patterns.instructions.md`. For each TF type, call its `Value*Pointer()` method (e.g., `types.String` โ†’ `.ValueStringPointer()`, `types.Bool` โ†’ `.ValueBoolPointer()`). **Non-obvious cases:** | TF Model Type | SDK Type | Pattern | | ----------------------------------------- | ------------- | ------------------------------------------------------------------ | | `types.Int64` | `*int32` | `ptr.To(int32(from.Field.ValueInt64()))` โ€” type narrowing required | | `supertypes.SingleNestedObjectValueOf[M]` | `*NestedDTO` | `.Get(ctx)` โ†’ construct nested DTO from sub-model | | `supertypes.ListNestedObjectValueOf[M]` | `[]NestedDTO` | `.Get(ctx)` โ†’ iterate slice, build each DTO | Reference: `internal/services/connection/models_resource_connection.go` ## Step 4 โ€” Generate Schema Attributes For Fabric Item resources, schema attributes go in separate functions: ### Resource Properties Schema ```go // schema_resource_.go func getResourcePropertiesAttributes(ctx context.Context) map[string]schema.Attribute { return map[string]schema.Attribute{ "": schema.StringAttribute{ MarkdownDescription: ".", Computed: true, }, // ... more attributes } } ``` ### Resource Configuration Schema (for CreationPayload) ```go func getResourceConfigurationAttributes() map[string]schema.Attribute { return map[string]schema.Attribute{ "": schema.BoolAttribute{ MarkdownDescription: ".", Required: true, PlanModifiers: []planmodifier.Bool{ boolplanmodifier.RequiresReplace(), }, }, } } ``` ### Schema Attribute Type Mapping Use the **"SDK Type โ†’ Schema Mapping"** table in `.github/instructions/schema-model-patterns.instructions.md`. ### Rules for All Schema Attributes For attribute behavior flags, plan modifiers, and validators, refer to the **"Attribute Behaviors"**, **"Plan Modifiers"**, and **"Validators"** sections in `.github/instructions/schema-model-patterns.instructions.md`. Additional rules: 1. **Always** use `MarkdownDescription` (never `Description`) 2. **Nested objects**: Must include `CustomType: supertypes.NewSingleNestedObjectTypeOf[](ctx)` 3. **UUID fields**: Must include `CustomType: customtypes.UUIDType{}` ### Example Nested Attribute ```go "sql_endpoint_properties": schema.SingleNestedAttribute{ MarkdownDescription: "An object containing the properties of the SQL endpoint.", Computed: true, CustomType: supertypes.NewSingleNestedObjectTypeOf[lakehouseSQLEndpointPropertiesModel](ctx), Attributes: map[string]schema.Attribute{ "provisioning_status": schema.StringAttribute{ MarkdownDescription: "The SQL endpoint provisioning status.", Computed: true, }, "connection_string": schema.StringAttribute{ MarkdownDescription: "SQL endpoint connection string.", Computed: true, }, "id": schema.StringAttribute{ MarkdownDescription: "SQL endpoint ID.", Computed: true, CustomType: customtypes.UUIDType{}, }, }, }, ``` ## Canonical References - Model struct patterns: `internal/services/lakehouse/models.go` - Resource schema patterns: `internal/services/lakehouse/schema_resource_lakehouse.go` - Data source schema patterns: `internal/services/lakehouse/schema_data_lakehouse.go` - Non-item schema (superschema): `internal/services/connection/schema.go` - Request builder patterns: `internal/services/connection/models_resource_connection.go`