diff --git a/templates/terraform/nested_query.go.erb b/templates/terraform/nested_query.go.erb index b6acb6212de2..5d30f22d98a0 100644 --- a/templates/terraform/nested_query.go.erb +++ b/templates/terraform/nested_query.go.erb @@ -1,54 +1,72 @@ - var v interface{} - var ok bool +var v interface{} +var ok bool <% object.nested_query.keys[0...-1].each do |k| -%> - v, ok = res["<%=k-%>"] - if !ok || v == nil { - return nil, nil - } - res = v.(map[string]interface{}) +v, ok = res["<%=k-%>"] +if !ok || v == nil { + return nil, nil +} +res = v.(map[string]interface{}) <% end -%> - v, ok = res["<%=object.nested_query.keys[-1]-%>"] - if !ok || v == nil { - return nil, nil - } - - // Final nested resource is either a list of resources we need to filter - // or just the resource itself, which we return. - switch v.(type) { - case []interface{}: - break - case map[string]interface{}: - return v.(map[string]interface{}), nil - default: - return nil, fmt.Errorf("invalid value for <%= object.nested_query.keys.join(".") -%>: %v", v) - } - - items := v.([]interface{}) - for _, vRaw := range items { +v, ok = res["<%=object.nested_query.keys[-1]-%>"] +if !ok || v == nil { + return nil, nil +} + +switch v.(type) { +case []interface{}: + break +case map[string]interface{}: + // Construct list out of single nested resource + v = []interface{}{v} +default: + return nil, fmt.Errorf("expected list or map for value <%= object.nested_query.keys.join(".") -%>. Actual value: %v", v) +} + +<% object.identity.each do |prop| -%> +<% if settable_properties.include?(prop) -%> +expected<%= titlelize_property(prop) -%>, err := expand<%= resource_name -%><%= titlelize_property(prop) -%>(d.Get("<%= prop.name.underscore -%>"), d, meta.(*Config)) +if err != nil { + return nil, err +} +<% else -%> +expected<%= titlelize_property(prop) -%> := d.Get("<%= prop.name.underscore -%>") +<% end # settable_properties.include?(prop)-%> +<% end # object.identity.each -%> + +// Search list for this resource. +items := v.([]interface{}) +for _, itemRaw := range items { + if itemRaw == nil { + continue + } <% if object.nested_query.is_list_of_ids -%> - // If only an id is given in parent resource, - // construct a resource map for that id KV pair. - item := map[string]interface{}{"<%=object.identity.first.api_name%>": vRaw} + // List response only contains the ID - construct a response object. + item := map[string]interface{}{ + "<%=object.identity.first.api_name%>": itemRaw, + } <% else -%> - item := vRaw.(map[string]interface{}) + item := itemRaw.(map[string]interface{}) + <% end -%> + + <% if object.custom_code.decoder -%> + // Decode list item before comparing. + item, err := resource<%= resource_name -%>Decoder(d, meta, item) + if err != nil { + return nil, err + } <% end -%> + <% object.identity.each do |prop| -%> - <% if settable_properties.include?(prop) -%> - itemIdV, err := expand<%= resource_name -%><%= titlelize_property(prop) -%>(d.Get("<%= prop.name.underscore -%>"), d, meta.(*Config)) - if err != nil { - return nil, err - } - <% else -%> - itemIdV := d.Get("<%= prop.name.underscore -%>") - <% end # settable_properties.include?(prop)-%> - actualIdV := flatten<%= resource_name -%><%= titlelize_property(prop) -%>(item["<%= prop.api_name %>"], d) - log.Printf("[DEBUG] Checking if item's <%= prop.api_name %> (%#v) is equal to resource's (%#v)", itemIdV, actualIdV) - if !reflect.DeepEqual(itemIdV, actualIdV) { - continue - } - <% end # object.identity.each -%> - return item, nil - } - return nil, nil + item<%= titlelize_property(prop) -%> := flatten<%= resource_name -%><%= titlelize_property(prop) -%>(item["<%= prop.api_name %>"], d) + if !reflect.DeepEqual(item<%= titlelize_property(prop) -%>, expected<%= titlelize_property(prop) -%>) { + log.Printf("[DEBUG] Skipping item with <%= prop.api_name %>= %#v, looking for %#v)", item<%= titlelize_property(prop) -%>, expected<%= titlelize_property(prop) -%>) + continue + } + <% end -%> + log.Printf("[DEBUG] Found item for resource %q: %#v)", d.Id(), item) + return item, nil +} + +return nil, nil diff --git a/templates/terraform/resource.erb b/templates/terraform/resource.erb index 2872cb6b2eb5..b51b212abe56 100644 --- a/templates/terraform/resource.erb +++ b/templates/terraform/resource.erb @@ -578,15 +578,15 @@ func resource<%= resource_name -%>UpdateEncoder(d *schema.ResourceData, meta int <% end -%> <% if object.nested_query -%> +<%# Note that if both nested_uqery and custom_code.decoder are provided, + #the decoder will be included via nested_query.go.erb -%> func flattenNested<%= resource_name -%>(d *schema.ResourceData, meta interface{}, res map[string]interface{}) (map[string]interface{}, error) { <%= compile_template('templates/terraform/nested_query.go.erb', object: object, settable_properties: object.settable_properties, resource_name: resource_name) -%> } -<% end -%> - -<% if object.custom_code.decoder -%> +<% elsif object.custom_code.decoder -%> func resource<%= resource_name -%>Decoder(d *schema.ResourceData, meta interface{}, res map[string]interface{}) (map[string]interface{}, error) { <%= lines(compile(object.custom_code.decoder)) -%> }