11package google
22
33import (
4- "context"
54 "encoding/json"
65 "errors"
76 "fmt"
87 "log"
98
10- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff"
119 "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
1210 "github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure"
1311 "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
@@ -91,14 +89,20 @@ func bigQueryTableMapKeyOverride(key string, objectA, objectB map[string]interfa
9189 valB := objectB [key ]
9290 switch key {
9391 case "mode" :
94- eq := bigQueryTableModeEq (valA , valB )
92+ equivelentSet := []interface {}{nil , "NULLABLE" }
93+ eq := valueIsInArray (valA , equivelentSet ) && valueIsInArray (valB , equivelentSet )
9594 return eq
9695 case "description" :
97- equivalentSet := []interface {}{nil , "" }
98- eq := valueIsInArray (valA , equivalentSet ) && valueIsInArray (valB , equivalentSet )
96+ equivelentSet := []interface {}{nil , "" }
97+ eq := valueIsInArray (valA , equivelentSet ) && valueIsInArray (valB , equivelentSet )
9998 return eq
10099 case "type" :
101- return bigQueryTableTypeEq (valA , valB )
100+ equivelentSet1 := []interface {}{"INTEGER" , "INT64" }
101+ equivelentSet2 := []interface {}{"FLOAT" , "FLOAT64" }
102+ eq1 := valueIsInArray (valA , equivelentSet1 ) && valueIsInArray (valB , equivelentSet1 )
103+ eq2 := valueIsInArray (valA , equivelentSet2 ) && valueIsInArray (valB , equivelentSet2 )
104+ eq := eq1 || eq2
105+ return eq
102106 }
103107
104108 // otherwise rely on default behavior
@@ -128,141 +132,6 @@ func bigQueryTableSchemaDiffSuppress(_, old, new string, _ *schema.ResourceData)
128132 return eq
129133}
130134
131- func bigQueryTableTypeEq (old , new interface {}) bool {
132- equivalentSet1 := []interface {}{"INTEGER" , "INT64" }
133- equivalentSet2 := []interface {}{"FLOAT" , "FLOAT64" }
134- equivalentSet3 := []interface {}{"BOOLEAN" , "BOOL" }
135- eq0 := old == new
136- eq1 := valueIsInArray (old , equivalentSet1 ) && valueIsInArray (new , equivalentSet1 )
137- eq2 := valueIsInArray (old , equivalentSet2 ) && valueIsInArray (new , equivalentSet2 )
138- eq3 := valueIsInArray (old , equivalentSet3 ) && valueIsInArray (new , equivalentSet3 )
139- eq := eq0 || eq1 || eq2 || eq3
140- return eq
141- }
142-
143- func bigQueryTableModeEq (old , new interface {}) bool {
144- equivalentSet := []interface {}{nil , "NULLABLE" }
145- eq0 := old == new
146- eq1 := valueIsInArray (old , equivalentSet ) && valueIsInArray (new , equivalentSet )
147- eq := eq0 || eq1
148- return eq
149- }
150-
151- func bigQueryTableModeIsForceNew (old , new interface {}) bool {
152- eq := bigQueryTableModeEq (old , new )
153- reqToNull := old == "REQUIRED" && new == "NULLABLE"
154- return ! eq && ! reqToNull
155- }
156-
157- // Compares two existing schema implementations and decides if
158- // it is changeable.. pairs with a force new on not changeable
159- func resourceBigQueryTableSchemaIsChangeable (old , new interface {}) (bool , error ) {
160- switch old .(type ) {
161- case []interface {}:
162- arrayOld := old .([]interface {})
163- arrayNew , ok := new .([]interface {})
164- if ! ok {
165- // if not both arrays not changeable
166- return false , nil
167- }
168- if len (arrayOld ) > len (arrayNew ) {
169- // if not growing not changeable
170- return false , nil
171- }
172- for i := range arrayOld {
173- if isChangable , err :=
174- resourceBigQueryTableSchemaIsChangeable (arrayOld [i ], arrayNew [i ]); err != nil || ! isChangable {
175- return false , err
176- }
177- }
178- return true , nil
179- case map [string ]interface {}:
180- objectOld := old .(map [string ]interface {})
181- objectNew , ok := new .(map [string ]interface {})
182- if ! ok {
183- // if both aren't objects
184- return false , nil
185- }
186-
187- var unionOfKeys map [string ]bool = make (map [string ]bool )
188- for key := range objectOld {
189- unionOfKeys [key ] = true
190- }
191- for key := range objectNew {
192- unionOfKeys [key ] = true
193- }
194-
195- for key := range unionOfKeys {
196- valOld := objectOld [key ]
197- valNew := objectNew [key ]
198- switch key {
199- case "name" :
200- if valOld != valNew {
201- return false , nil
202- }
203- case "type" :
204- if ! bigQueryTableTypeEq (valOld , valNew ) {
205- return false , nil
206- }
207- case "mode" :
208- if bigQueryTableModeIsForceNew (valOld , valNew ) {
209- return false , nil
210- }
211- case "fields" :
212- return resourceBigQueryTableSchemaIsChangeable (valOld , valNew )
213-
214- // other parameters: description, policyTags and
215- // policyTags.names[] are changeable
216- }
217- }
218- return true , nil
219- case string , float64 , bool , nil :
220- // realistically this shouldn't hit
221- log .Printf ("[DEBUG] comparison of generics hit... not expected" )
222- return old == new , nil
223- default :
224- log .Printf ("[DEBUG] tried to iterate through json but encountered a non native type to json deserialization... please ensure you are passing a json object from json.Unmarshall" )
225- return false , errors .New ("unable to compare values" )
226- }
227- }
228-
229- func resourceBigQueryTableSchemaCustomizeDiffFunc (d TerraformResourceDiff ) error {
230- if _ , hasSchema := d .GetOk ("schema" ); hasSchema {
231- oldSchema , newSchema := d .GetChange ("schema" )
232- oldSchemaText := oldSchema .(string )
233- newSchemaText := newSchema .(string )
234- if oldSchemaText == "null" {
235- // The API can return an empty schema which gets encoded to "null" during read.
236- oldSchemaText = "[]"
237- }
238- var old , new interface {}
239- if err := json .Unmarshal ([]byte (oldSchemaText ), & old ); err != nil {
240- // don't return error, its possible we are going from no schema to schema
241- // this case will be cover on the conparision regardless.
242- log .Printf ("[DEBUG] unable to unmarshal json customized diff - %v" , err )
243- }
244- if err := json .Unmarshal ([]byte (newSchemaText ), & new ); err != nil {
245- // same as above
246- log .Printf ("[DEBUG] unable to unmarshal json customized diff - %v" , err )
247- }
248- isChangeable , err := resourceBigQueryTableSchemaIsChangeable (old , new )
249- if err != nil {
250- return err
251- }
252- if ! isChangeable {
253- if err := d .ForceNew ("schema" ); err != nil {
254- return err
255- }
256- }
257- return nil
258- }
259- return nil
260- }
261-
262- func resourceBigQueryTableSchemaCustomizeDiff (_ context.Context , d * schema.ResourceDiff , meta interface {}) error {
263- return resourceBigQueryTableSchemaCustomizeDiffFunc (d )
264- }
265-
266135func resourceBigQueryTable () * schema.Resource {
267136 return & schema.Resource {
268137 Create : resourceBigQueryTableCreate ,
@@ -272,9 +141,6 @@ func resourceBigQueryTable() *schema.Resource {
272141 Importer : & schema.ResourceImporter {
273142 State : resourceBigQueryTableImport ,
274143 },
275- CustomizeDiff : customdiff .All (
276- resourceBigQueryTableSchemaCustomizeDiff ,
277- ),
278144 Schema : map [string ]* schema.Schema {
279145 // TableId: [Required] The ID of the table. The ID must contain only
280146 // letters (a-z, A-Z), numbers (0-9), or underscores (_). The maximum
@@ -556,6 +422,7 @@ func resourceBigQueryTable() *schema.Resource {
556422 DiffSuppressFunc : bigQueryTableSchemaDiffSuppress ,
557423 Description : `A JSON schema for the table.` ,
558424 },
425+
559426 // View: [Optional] If specified, configures this table as a view.
560427 "view" : {
561428 Type : schema .TypeList ,
@@ -895,6 +762,7 @@ func resourceTable(d *schema.ResourceData, meta interface{}) (*bigquery.Table, e
895762 if err != nil {
896763 return nil , err
897764 }
765+
898766 table .Schema = schema
899767 }
900768
@@ -1081,6 +949,7 @@ func resourceBigQueryTableRead(d *schema.ResourceData, meta interface{}) error {
1081949 if err != nil {
1082950 return err
1083951 }
952+
1084953 if err := d .Set ("schema" , schema ); err != nil {
1085954 return fmt .Errorf ("Error setting schema: %s" , err )
1086955 }
0 commit comments