Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add ability to explain updateNode attributes. #514

Merged
merged 1 commit into from
Jun 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
}