Skip to content

Commit

Permalink
feat: Add typeIndexJoin explainable attributes. (#499)
Browse files Browse the repository at this point in the history
- RELEVANT ISSUE(S)

Resolves #475 

- DESCRIPTION

Add the remaining attributes for `typeIndexJoin` node that we want to see in the explainable response.

Example:

Request:
```
query @Explain {
  author {
    _key
    name
    contact {
      email
      address {
      city
      }
    }
  }
}
```

Response: 
```
{
  "explain": {
    "selectTopNode": {
      "renderNode": {
        "selectNode": {
          "filter": nil
          "typeIndexJoin": {
            "joinType":  "typeJoinOne"
            "direction": "primary"
            "rootName":  "author"
            "root": {
              "scanNode": {
                "filter":         nil
                "collectionID":   "3"
                "collectionName": "author"
                "spans": []{
                  {
                    "start": "/3"
                    "end":   "/4"
                  }
                }
              }
            }
            "subTypeName": "contact"
            "subType": {
              "selectTopNode": {
                "selectNode": {
                  "filter": nil
                  "typeIndexJoin": {
                    "joinType":  "typeJoinOne"
                    "direction": "primary"
                    "rootName":  "contact"
                    "root": {
                      "scanNode": {
                        "filter":         nil
                        "collectionID":   "4"
                        "collectionName": "authorContact"
                        "spans": []{
                          {
                            "start": "/4"
                            "end":   "/5"
                          }
                        }
                      }
                    }
                    "subTypeName": "address"
                    "subType": {
                      "selectTopNode": {
                        "selectNode": {
                          "filter": nil
                          "scanNode": {
                            "filter":         nil
                            "collectionID":   "5"
                            "collectionName": "contactAddress"
                            "spans": []{
                              {
                                "start": "/5"
                                "end":   "/6"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
```
  • Loading branch information
shahzadlone authored Jun 10, 2022
1 parent 954d22d commit 8210564
Show file tree
Hide file tree
Showing 12 changed files with 1,682 additions and 535 deletions.
21 changes: 21 additions & 0 deletions query/graphql/planner/explain.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,27 @@ func buildExplainGraph(source planNode) (map[string]interface{}, error) {
explainNodeLabelTitle := strcase.ToLowerCamel(node.Kind())
explainGraph[explainNodeLabelTitle] = multiChildExplainGraph

// For typeIndexJoin restructure the graphs to show both `root` and `subType` at the same level.
case *typeIndexJoin:
// Get the non-restructured explain graph.
indexJoinGraph, err := node.Explain()
if err != nil {
return nil, err
}

// If not the last child then keep walking and explaining the root graph,
// as long as there are more explainable nodes left under root.
if node.Source() != nil {
indexJoinRootExplainGraph, err := buildExplainGraph(node.Source())
if err != nil {
return nil, err
}
// Add the explaination of the rest of the explain graph under the "root" graph.
indexJoinGraph["root"] = indexJoinRootExplainGraph
}
// Add this restructured typeIndexJoin explain graph.
explainGraph[strcase.ToLowerCamel(node.Kind())] = indexJoinGraph

// If this node has subscribed to the optable-interface that makes a node explainable.
case explainablePlanNode:
// Start building the explain graph.
Expand Down
2 changes: 1 addition & 1 deletion query/graphql/planner/select.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func (n *selectTopNode) Spans(spans core.Spans) { n.plan.Spans(spans) }

func (n *selectTopNode) Value() map[string]interface{} { return n.plan.Value() }

func (n *selectTopNode) Source() planNode { return n.plan.Source() }
func (n *selectTopNode) Source() planNode { return n.plan }

// Explain method for selectTopNode returns no attributes but is used to
// subscribe / opt-into being an explainablePlanNode.
Expand Down
53 changes: 50 additions & 3 deletions query/graphql/planner/type_join.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,59 @@ func (n *typeIndexJoin) Source() planNode { return n.joinPlan }
// 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 *typeIndexJoin) Explain() (map[string]interface{}, error) {
const (
joinTypeLabel = "joinType"
joinDirectionLabel = "direction"
joinDirectionPrimaryLabel = "primary"
joinDirectionSecondaryLabel = "secondary"
joinSubTypeLabel = "subType"
joinSubTypeNameLabel = "subTypeName"
joinRootLabel = "rootName"
)

explainerMap := map[string]interface{}{}

// @TODO {defradb/issues/475} Add explain attributes:
// Add the type attribute.
// Add the relation attribute.
// Add the direction attribute.
explainerMap[joinTypeLabel] = n.joinPlan.Kind()

switch joinType := n.joinPlan.(type) {

case *typeJoinOne:
// Add the direction attribute.
if joinType.primary {
explainerMap[joinDirectionLabel] = joinDirectionPrimaryLabel
} else {
explainerMap[joinDirectionLabel] = joinDirectionSecondaryLabel
}

// Add the attribute(s).
explainerMap[joinRootLabel] = joinType.subTypeFieldName
explainerMap[joinSubTypeNameLabel] = joinType.subTypeName

subTypeExplainGraph, err := buildExplainGraph(joinType.subType)
if err != nil {
return nil, err
}

// Add the joined (subType) type's entire explain graph.
explainerMap[joinSubTypeLabel] = subTypeExplainGraph

case *typeJoinMany:
// Add the attribute(s).
explainerMap[joinRootLabel] = joinType.rootName
explainerMap[joinSubTypeNameLabel] = joinType.subTypeName

subTypeExplainGraph, err := buildExplainGraph(joinType.subType)
if err != nil {
return nil, err
}

// Add the joined (subType) type's entire explain graph.
explainerMap[joinSubTypeLabel] = subTypeExplainGraph

default:
return explainerMap, fmt.Errorf("Unknown type of an index join to explain.")
}

return explainerMap, nil
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,16 @@ func TestExplainRelationalDeletionOfADocumentUsingSingleKey_Success(t *testing.T
{
"explain": dataMap{
"selectTopNode": dataMap{
"selectNode": dataMap{
"deleteNode": dataMap{
"renderNode": dataMap{
"selectNode": dataMap{
"filter": nil,
"ids": []string{
"bae-2f80f359-535d-508e-ba58-088a309ce3c3",
"deleteNode": dataMap{
"filter": nil,
"ids": []string{
"bae-2f80f359-535d-508e-ba58-088a309ce3c3",
},
},
},
"filter": nil,
},
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,18 @@ func TestExplainMutationCreateSimple(t *testing.T) {
{
"explain": dataMap{
"selectTopNode": dataMap{
"selectNode": dataMap{
"createNode": dataMap{
"data": dataMap{
"age": float64(27),
"name": "John",
"points": float64(42.1),
"verified": true,
"renderNode": dataMap{
"selectNode": dataMap{
"createNode": dataMap{
"data": dataMap{
"age": float64(27),
"name": "John",
"points": float64(42.1),
"verified": true,
},
},
"filter": nil,
},
"filter": nil,
},
},
},
Expand Down Expand Up @@ -81,14 +83,16 @@ func TestExplainMutationCreateSimpleDoesNotCreateDocGivenDuplicate(t *testing.T)
{
"explain": dataMap{
"selectTopNode": dataMap{
"selectNode": dataMap{
"createNode": dataMap{
"data": dataMap{
"age": float64(27),
"name": "John",
"renderNode": dataMap{
"selectNode": dataMap{
"createNode": dataMap{
"data": dataMap{
"age": float64(27),
"name": "John",
},
},
"filter": nil,
},
"filter": nil,
},
},
},
Expand Down
Loading

0 comments on commit 8210564

Please sign in to comment.