Skip to content

Commit

Permalink
feat: Add ability to explain updateNode attributes. (#514)
Browse files Browse the repository at this point in the history
- Resolves #483 

- Add the attributes for `updateNode` that we want to see in the explainable response.

Request:
```
mutation @Explain {
	update_user(
		ids: [
			"bae-0a24cf29-b2c2-5861-9d00-abd6250c475d",
			"bae-958c9334-73cf-5695-bf06-cf06826babfa"
		],
		data: "{\"points\": 59}"
	) {
		_key
		name
		points
	}
}
```

Response: 
```
"explain": {
	"updateNode": {
		"data": {
			"points": float64(59),
		}
		"filter": nil,
		"ids": []string{
			"bae-0a24cf29-b2c2-5861-9d00-abd6250c475d",
			"bae-958c9334-73cf-5695-bf06-cf06826babfa",
		}
		"selectTopNode": {
			"renderNode": {
				"selectNode": {
					"filter": nil,
					"scanNode": {
						"collectionID":   "1",
						"collectionName": "user",
						"filter":         nil,
						"spans":          []{},
					}
				}
			}
		}
	}
}
```
  • Loading branch information
shahzadlone authored Jun 14, 2022
1 parent 64ea968 commit f020961
Show file tree
Hide file tree
Showing 2 changed files with 331 additions and 2 deletions.
26 changes: 24 additions & 2 deletions query/graphql/planner/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
package planner

import (
"encoding/json"

"github.com/sourcenetwork/defradb/client"
"github.com/sourcenetwork/defradb/core"
"github.com/sourcenetwork/defradb/db/base"
Expand Down Expand Up @@ -136,12 +138,32 @@ func (n *updateNode) Close() error {
return n.results.Close()
}

func (n *updateNode) Source() planNode { return nil }
func (n *updateNode) Source() planNode { return n.results }

// Explain method returns a map containing all attributes of this node that
// are to be explained, subscribes / opts-in this node to be an explainablePlanNode.
func (n *updateNode) Explain() (map[string]interface{}, error) {
return map[string]interface{}{}, nil
explainerMap := map[string]interface{}{}

// Add the document id(s) that request wants to update.
explainerMap[idsLabel] = n.ids

// Add the filter attribute if it exists, otherwise have it nil.
if n.filter == nil || n.filter.Conditions == nil {
explainerMap[filterLabel] = nil
} else {
explainerMap[filterLabel] = n.filter.Conditions
}

// Add the attribute that represents the patch to update with.
data := map[string]interface{}{}
err := json.Unmarshal([]byte(n.patch), &data)
if err != nil {
return nil, err
}
explainerMap[dataLabel] = data

return explainerMap, nil
}

func (p *Planner) UpdateDocs(parsed *parser.Mutation) (planNode, error) {
Expand Down
307 changes: 307 additions & 0 deletions tests/integration/mutation/simple/update/explain_simple_update_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,307 @@
// Copyright 2022 Democratized Data Foundation
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.

package update

import (
"testing"

testUtils "github.com/sourcenetwork/defradb/tests/integration"
simpleTests "github.com/sourcenetwork/defradb/tests/integration/mutation/simple"
)

type dataMap = map[string]interface{}

func TestExplainSimpleMutationUpdateWithBooleanFilter(t *testing.T) {
tests := []testUtils.QueryTestCase{

{
Description: "Explain simple update mutation with boolean equals filter, multiple rows",

Query: `mutation @explain {
update_user(
filter: {
verified: {
_eq: true
}
},
data: "{\"points\": 59}"
) {
_key
name
points
}
}`,

Docs: map[int][]string{
0: {
(`{
"name": "John",
"age": 27,
"verified": true,
"points": 42.1
}`),
(`{
"name": "Bob",
"age": 39,
"verified": true,
"points": 66.6
}`)},
},

Results: []dataMap{
{
"explain": dataMap{
"updateNode": dataMap{
"data": dataMap{
"points": float64(59),
},
"filter": dataMap{
"verified": dataMap{
"$eq": true,
},
},
"ids": []string(nil),
"selectTopNode": dataMap{
"renderNode": dataMap{
"selectNode": dataMap{
"filter": nil,
"scanNode": dataMap{
"collectionID": "1",
"collectionName": "user",
"filter": nil,
"spans": []dataMap{},
},
},
},
},
},
},
},
},
},
}

for _, test := range tests {
simpleTests.ExecuteTestCase(t, test)
}
}

func TestExplainSimpleMutationUpdateWithIdInFilter(t *testing.T) {
test := testUtils.QueryTestCase{

Description: "Explain simple update mutation with id in filter, multiple rows",

Query: `mutation @explain {
update_user(
ids: [
"bae-0a24cf29-b2c2-5861-9d00-abd6250c475d",
"bae-958c9334-73cf-5695-bf06-cf06826babfa"
],
data: "{\"points\": 59}"
) {
_key
name
points
}
}`,

Docs: map[int][]string{
0: {
(`{
"name": "John",
"age": 27,
"verified": true,
"points": 42.1
}`),
(`{
"name": "Bob",
"age": 39,
"verified": false,
"points": 66.6
}`)},
},

Results: []dataMap{
{
"explain": dataMap{
"updateNode": dataMap{
"data": dataMap{
"points": float64(59),
},
"filter": nil,
"ids": []string{
"bae-0a24cf29-b2c2-5861-9d00-abd6250c475d",
"bae-958c9334-73cf-5695-bf06-cf06826babfa",
},
"selectTopNode": dataMap{
"renderNode": dataMap{
"selectNode": dataMap{
"filter": nil,
"scanNode": dataMap{
"collectionID": "1",
"collectionName": "user",
"filter": nil,
"spans": []dataMap{},
},
},
},
},
},
},
},
},
}

simpleTests.ExecuteTestCase(t, test)
}

func TestExplainSimpleMutationUpdateWithIdEqualsFilter(t *testing.T) {
test := testUtils.QueryTestCase{

Description: "Explain simple update mutation with id equals filter, multiple rows but single match",

Query: `mutation @explain {
update_user(
id: "bae-0a24cf29-b2c2-5861-9d00-abd6250c475d",
data: "{\"points\": 59}"
) {
_key
name
points
}
}`,

Docs: map[int][]string{
0: {
(`{
"name": "John",
"age": 27,
"verified": true,
"points": 42.1
}`),
(`{
"name": "Bob",
"age": 39,
"verified": false,
"points": 66.6
}`)},
},

Results: []dataMap{
{
"explain": dataMap{
"updateNode": dataMap{
"data": dataMap{
"points": float64(59),
},
"filter": nil,
"ids": []string{
"bae-0a24cf29-b2c2-5861-9d00-abd6250c475d",
},
"selectTopNode": dataMap{
"renderNode": dataMap{
"selectNode": dataMap{
"filter": nil,
"scanNode": dataMap{
"collectionID": "1",
"collectionName": "user",
"filter": nil,
"spans": []dataMap{},
},
},
},
},
},
},
},
},
}

simpleTests.ExecuteTestCase(t, test)
}

func TestExplainSimpleMutationUpdateWithIdAndFilter(t *testing.T) {
test := testUtils.QueryTestCase{

Description: "Explain simple update mutation with ids and filter, multiple rows",

Query: `mutation @explain {
update_user(
filter: {
verified: {
_eq: true
}
},
ids: [
"bae-0a24cf29-b2c2-5861-9d00-abd6250c475d",
"bae-958c9334-73cf-5695-bf06-cf06826babfa"
],
data: "{\"points\": 59}"
) {
_key
name
points
}
}`,

Docs: map[int][]string{
0: {
(`{
"name": "John",
"age": 27,
"verified": true,
"points": 42.1
}`),
(`{
"name": "Bob",
"age": 39,
"verified": false,
"points": 66.6
}`)},
},

Results: []dataMap{
{
"explain": dataMap{
"updateNode": dataMap{
"data": dataMap{
"points": float64(59),
},
"filter": dataMap{
"verified": dataMap{
"$eq": true,
},
},
"ids": []string{
"bae-0a24cf29-b2c2-5861-9d00-abd6250c475d",
"bae-958c9334-73cf-5695-bf06-cf06826babfa",
},
"selectTopNode": dataMap{
"renderNode": dataMap{
"selectNode": dataMap{
"filter": nil,
"scanNode": dataMap{
"collectionID": "1",
"collectionName": "user",
"filter": nil,
"spans": []dataMap{},
},
},
},
},
},
},
},
},
}

simpleTests.ExecuteTestCase(t, test)
}

0 comments on commit f020961

Please sign in to comment.