Skip to content

Commit 428e647

Browse files
committed
Add server-state reconsiliation logic to ensure TF can better detect/overwrite remote changes
1 parent b03f962 commit 428e647

File tree

6 files changed

+102
-3
lines changed

6 files changed

+102
-3
lines changed

.vscode/launch.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"version": "0.2.0",
3+
"configurations": [
4+
{
5+
"name": "Debug",
6+
"type": "go",
7+
"request": "launch",
8+
"mode": "debug",
9+
"program": "${workspaceFolder}",
10+
"args": [
11+
"--debug"
12+
],
13+
"env": {
14+
"TF_LOG": "debug"
15+
}
16+
}
17+
]
18+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Subproject commit cf2e4400b11c81f451bf31d282b06a493caafda2
1+
Subproject commit 3dcb5028045e697de357f58a69158a14d558e2a3

e2e/test_basic/test.tf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ resource "graphql_mutation" "basic_mutation" {
1818
compute_from_create = var.compute_from_create
1919
mutation_variables = {
2020
"text" = var.todo_text
21-
"userId" = "\"${var.todo_user_id}\""
22-
"list" = "[\"this\", \"that\"]"
21+
"userId" = var.todo_user_id
22+
"list" = "[\"this\",\"that\"]"
2323
}
2424

2525
delete_mutation_variables = {

graphql/keys.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,39 @@ func getResourceKey(m map[string]interface{}, ks ...string) (val interface{}, er
9292
}
9393
}
9494

95+
func mapQueryResponseInputKey(m map[string]interface{}, value, prev string, parentKeys []string) (key string, ok bool) {
96+
for k, v := range m {
97+
var jsonV string
98+
if str, isString := v.(string); !isString {
99+
bytes, err := json.Marshal(v)
100+
if err != nil {
101+
return
102+
}
103+
jsonV = string(bytes)
104+
} else {
105+
jsonV = str
106+
}
107+
108+
if jsonV == value {
109+
if len(parentKeys) != 0 {
110+
newPrev := parentKeys[len(parentKeys)-1]
111+
if newPrev != prev {
112+
parentKeys = parentKeys[:len(parentKeys)-1]
113+
}
114+
}
115+
116+
parentKeys = append(parentKeys, k)
117+
key = strings.Join(parentKeys, ".")
118+
ok = true
119+
return
120+
} else if nv, isMap := v.(map[string]interface{}); isMap {
121+
parentKeys = append(parentKeys, k)
122+
key, ok = mapQueryResponseInputKey(nv, value, k, parentKeys)
123+
}
124+
}
125+
return
126+
}
127+
95128
func hash(v []byte) int {
96129
queryResponseObj := make(map[string]interface{})
97130
_ = json.Unmarshal(v, &queryResponseObj)

graphql/resource_graphql_mutation.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"encoding/json"
66
"fmt"
77
"log"
8+
"strings"
89

910
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
1011
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -93,6 +94,13 @@ func resourceGraphqlMutation() *schema.Resource {
9394
Description: "The raw body of the HTTP response from the last read of the object.",
9495
Computed: true,
9596
},
97+
"query_response_input_key_map": {
98+
Type: schema.TypeMap,
99+
Elem: &schema.Schema{
100+
Type: schema.TypeString,
101+
},
102+
Computed: true,
103+
},
96104
"existing_hash": {
97105
Type: schema.TypeString,
98106
Description: "Represents the state of existence of a mutation in order to support intelligent updates.",
@@ -149,6 +157,7 @@ func resourceGraphqlRead(ctx context.Context, d *schema.ResourceData, m interfac
149157

150158
queryVariables := d.Get("read_query_variables").(map[string]interface{})
151159
computedVariables := d.Get("computed_read_operation_variables").(map[string]interface{})
160+
queryResponseInputKeyMap := d.Get("query_response_input_key_map").(map[string]interface{})
152161

153162
for k, v := range queryVariables {
154163
computedVariables[k] = v
@@ -171,6 +180,44 @@ func resourceGraphqlRead(ctx context.Context, d *schema.ResourceData, m interfac
171180
return diag.FromErr(err)
172181
}
173182

183+
mappedKeys := make(map[string]interface{})
184+
mutationVars := d.Get("mutation_variables").(map[string]interface{})
185+
186+
for k, v := range mutationVars {
187+
key, ok := mapQueryResponseInputKey(queryResponse.Data, v.(string), "", nil)
188+
if !ok {
189+
if qrk, found := queryResponseInputKeyMap[k]; !found || qrk == "" {
190+
mutationVars[k] = ""
191+
} else {
192+
ks := strings.Split(qrk.(string), ".")
193+
remoteVal, err := getResourceKey(queryResponse.Data, ks...)
194+
if err != nil {
195+
mutationVars[k] = ""
196+
}
197+
198+
if _, isString := remoteVal.(string); !isString {
199+
bytes, err := json.Marshal(remoteVal)
200+
if err != nil {
201+
return diag.FromErr(err)
202+
}
203+
mutationVars[k] = string(bytes)
204+
} else {
205+
mutationVars[k] = remoteVal
206+
}
207+
}
208+
209+
}
210+
mappedKeys[k] = key
211+
}
212+
213+
if err := d.Set("query_response_input_key_map", mappedKeys); err != nil {
214+
return diag.FromErr(err)
215+
}
216+
217+
if err := d.Set("mutation_variables", mutationVars); err != nil {
218+
return diag.FromErr(err)
219+
}
220+
174221
computeFromCreate := d.Get("compute_from_create").(bool)
175222
if !computeFromCreate {
176223
if err := computeMutationVariables(resBytes, d); err != nil {

testdata/readQuery

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ query findTodos{
33
id
44
text
55
user {
6+
id
67
name
78
}
89
list

0 commit comments

Comments
 (0)