Skip to content

Commit

Permalink
Made bigquery table schema diffsuppress func handle nested lists grac…
Browse files Browse the repository at this point in the history
…efully (#4832)

* Added basic tests for biquery table schema diff suppress

* Only sort the top level of a bigquery schema when checking diff suppression

* Keep suppressing diff for subfield reordering

* Merged BigQueryDataTableJSONEquivalencyTestCases into diff suppress test cases

* Formatting cleanup

* Added a test with multiple levels of reordering and also policyTags at multiple levels
  • Loading branch information
melinath authored Jun 4, 2021
1 parent 333471c commit c57c10b
Show file tree
Hide file tree
Showing 2 changed files with 375 additions and 124 deletions.
49 changes: 27 additions & 22 deletions mmv1/third_party/terraform/resources/resource_bigquery_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"log"
"sort"
"strconv"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
Expand Down Expand Up @@ -43,7 +44,7 @@ func bigQueryTablecheckNameExists(jsonList []interface{}) error {
// Compares two json's while optionally taking in a compareMapKeyVal function.
// This function will override any comparison of a given map[string]interface{}
// on a specific key value allowing for a separate equality in specific scenarios
func jsonCompareWithMapKeyOverride(a, b interface{}, compareMapKeyVal func(key string, val1, val2 map[string]interface{}) bool) (bool, error) {
func jsonCompareWithMapKeyOverride(key string, a, b interface{}, compareMapKeyVal func(key string, val1, val2 map[string]interface{}) bool) (bool, error) {
switch a.(type) {
case []interface{}:
arrayA := a.([]interface{})
Expand All @@ -53,16 +54,20 @@ func jsonCompareWithMapKeyOverride(a, b interface{}, compareMapKeyVal func(key s
} else if len(arrayA) != len(arrayB) {
return false, nil
}
if err := bigQueryTablecheckNameExists(arrayA); err != nil {
return false, err
}
bigQueryTableSortArrayByName(arrayA)
if err := bigQueryTablecheckNameExists(arrayB); err != nil {
return false, err

// Sort fields by name so reordering them doesn't cause a diff.
if key == "schema" || key == "fields" {
if err := bigQueryTablecheckNameExists(arrayA); err != nil {
return false, err
}
bigQueryTableSortArrayByName(arrayA)
if err := bigQueryTablecheckNameExists(arrayB); err != nil {
return false, err
}
bigQueryTableSortArrayByName(arrayB)
}
bigQueryTableSortArrayByName(arrayB)
for i := range arrayA {
eq, err := jsonCompareWithMapKeyOverride(arrayA[i], arrayB[i], compareMapKeyVal)
eq, err := jsonCompareWithMapKeyOverride(strconv.Itoa(i), arrayA[i], arrayB[i], compareMapKeyVal)
if err != nil {
return false, err
} else if !eq {
Expand All @@ -78,22 +83,22 @@ func jsonCompareWithMapKeyOverride(a, b interface{}, compareMapKeyVal func(key s
}

var unionOfKeys map[string]bool = make(map[string]bool)
for key := range objectA {
unionOfKeys[key] = true
for subKey := range objectA {
unionOfKeys[subKey] = true
}
for key := range objectB {
unionOfKeys[key] = true
for subKey := range objectB {
unionOfKeys[subKey] = true
}

for key := range unionOfKeys {
eq := compareMapKeyVal(key, objectA, objectB)
for subKey := range unionOfKeys {
eq := compareMapKeyVal(subKey, objectA, objectB)
if !eq {
valA, ok1 := objectA[key]
valB, ok2 := objectB[key]
valA, ok1 := objectA[subKey]
valB, ok2 := objectB[subKey]
if !ok1 || !ok2 {
return false, nil
}
eq, err := jsonCompareWithMapKeyOverride(valA, valB, compareMapKeyVal)
eq, err := jsonCompareWithMapKeyOverride(subKey, valA, valB, compareMapKeyVal)
if err != nil || !eq {
return false, err
}
Expand Down Expand Up @@ -140,20 +145,20 @@ func bigQueryTableMapKeyOverride(key string, objectA, objectB map[string]interfa
}

// Compare the JSON strings are equal
func bigQueryTableSchemaDiffSuppress(_, old, new string, _ *schema.ResourceData) bool {
func bigQueryTableSchemaDiffSuppress(name, old, new string, _ *schema.ResourceData) bool {
// The API can return an empty schema which gets encoded to "null" during read.
if old == "null" {
old = "[]"
}
var a, b interface{}
if err := json.Unmarshal([]byte(old), &a); err != nil {
log.Printf("[DEBUG] unable to unmarshal json - %v", err)
log.Printf("[DEBUG] unable to unmarshal old json - %v", err)
}
if err := json.Unmarshal([]byte(new), &b); err != nil {
log.Printf("[DEBUG] unable to unmarshal json - %v", err)
log.Printf("[DEBUG] unable to unmarshal new json - %v", err)
}

eq, err := jsonCompareWithMapKeyOverride(a, b, bigQueryTableMapKeyOverride)
eq, err := jsonCompareWithMapKeyOverride(name, a, b, bigQueryTableMapKeyOverride)
if err != nil {
log.Printf("[DEBUG] %v", err)
log.Printf("[DEBUG] Error comparing JSON: %v, %v", old, new)
Expand Down
Loading

0 comments on commit c57c10b

Please sign in to comment.