From 630ad068f1818124a89eda0748ad46282cad7df1 Mon Sep 17 00:00:00 2001 From: Shahzad Lone <shahzadlone@gmail.com> Date: Fri, 10 Jun 2022 12:35:58 -0400 Subject: [PATCH] feat: Add ability to explain updateNode attributes. --- query/graphql/planner/update.go | 26 +- .../update/explain_simple_update_test.go | 307 ++++++++++++++++++ 2 files changed, 331 insertions(+), 2 deletions(-) create mode 100644 tests/integration/mutation/simple/update/explain_simple_update_test.go diff --git a/query/graphql/planner/update.go b/query/graphql/planner/update.go index 104283f4dc..c20086e16b 100644 --- a/query/graphql/planner/update.go +++ b/query/graphql/planner/update.go @@ -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" @@ -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) { diff --git a/tests/integration/mutation/simple/update/explain_simple_update_test.go b/tests/integration/mutation/simple/update/explain_simple_update_test.go new file mode 100644 index 0000000000..4a16c1aada --- /dev/null +++ b/tests/integration/mutation/simple/update/explain_simple_update_test.go @@ -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) +}