Skip to content

Commit

Permalink
feat: Add ability to explain sortNode attribute(s). (#558)
Browse files Browse the repository at this point in the history
- Relevant issue(s):
  Resolves #481.
  Fixes #584 ([2] case).

- Description
Adds the attributes for `sortNode` to be included in the returned explain graph response.
So far, we are only introducing 1 attribute, which represents a list containing all the `orderings` of each field requested to be sorted, with its corresponding direction.

- Request:
```
query @Explain {
  author(order: {age: ASC}) {
    name
    age
    verified
  }
}
```

- Response:
```
{
  "explain": {
    "selectTopNode": {
      "sortNode": {
        "selectNode": {
          "filter": null,
          "scanNode": {
            "filter":         null,
            "collectionID":   "3",
            "collectionName": "author",
            "spans": []{
              {
                "start": "/3",
                "end":   "/4",
              }
            }
          }
        }
        "orderings": []{
          {
            "direction": "ASC",
            "fields":     [ "age" ],
          }
        }
      }
    }
  }
}
```
  • Loading branch information
shahzadlone committed Jul 5, 2022
1 parent 70c8363 commit c3c6495
Show file tree
Hide file tree
Showing 5 changed files with 563 additions and 5 deletions.
24 changes: 24 additions & 0 deletions core/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,3 +222,27 @@ func (m *DocumentMapping) SetChildAt(index int, childMapping DocumentMapping) {
newMappings[index] = childMapping
m.ChildMappings = newMappings
}

// TryToFindNameFromIndex returns the corresponding name of the given index.
//
// Additionally, will also return true if the index was found, and false otherwise.
func (mapping *DocumentMapping) TryToFindNameFromIndex(targetIndex int) (string, bool) {
// Try to find the name of this index in the IndexesByName.
for name, indexes := range mapping.IndexesByName {
for _, index := range indexes {
if index == targetIndex {
return name, true
}
}
}

// Try to find the name of this index in the ChildMappings.
for _, childMapping := range mapping.ChildMappings {
name, found := childMapping.TryToFindNameFromIndex(targetIndex)
if found {
return name, true
}
}

return "", false
}
7 changes: 7 additions & 0 deletions query/graphql/mapper/targetable.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,13 @@ type OrderCondition struct {
Direction SortDirection
}

func (oc OrderCondition) IsEmpty() bool {
if oc.Direction == "" && len(oc.FieldIndexes) == 0 {
return true
}
return false
}

type OrderBy struct {
Conditions []OrderCondition
}
Expand Down
2 changes: 1 addition & 1 deletion query/graphql/planner/planner.go
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ func (p *Planner) explainRequest(

explainGraph, err := buildExplainGraph(plan)
if err != nil {
return nil, err
return nil, multiErr(err, plan.Close())
}

topExplainGraph := []map[string]interface{}{
Expand Down
39 changes: 35 additions & 4 deletions query/graphql/planner/sort.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
package planner

import (
"fmt"

"github.com/sourcenetwork/defradb/core"
"github.com/sourcenetwork/defradb/query/graphql/mapper"
)
Expand Down Expand Up @@ -54,6 +56,7 @@ type sortNode struct {
// that sorts, then provides the values
// sorted
sortStrategy sortingStrategy

// indicates if our underlying sortStrategy is still
// consuming and sorting data.
needSort bool
Expand Down Expand Up @@ -97,7 +100,38 @@ func (n *sortNode) Value() core.Doc {
// 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 *sortNode) Explain() (map[string]interface{}, error) {
return map[string]interface{}{}, nil
orderings := []map[string]interface{}{}

for _, element := range n.ordering {
// Skip all empty elements.
if element.IsEmpty() {
continue
}

// Build the list containing the corresponding names of all the indexes.
fieldNames := []string{}
for _, fieldIndex := range element.FieldIndexes {
// Try to find the name of this index.
fieldName, found := n.documentMapping.TryToFindNameFromIndex(fieldIndex)
if !found {
return nil, fmt.Errorf("No corresponding name was found for index=%d", fieldIndex)
}

fieldNames = append(fieldNames, fieldName)
}

// Put it all together for this order element.
orderings = append(orderings,
map[string]interface{}{
"fields": fieldNames,
"direction": string(element.Direction),
},
)
}

return map[string]interface{}{
"orderings": orderings,
}, nil
}

func (n *sortNode) Next() (bool, error) {
Expand All @@ -124,9 +158,6 @@ func (n *sortNode) Next() (bool, error) {
if err := n.sortStrategy.Add(n.plan.Value()); err != nil {
return false, err
}

// finalize, assign valueIter = sortStrategy
// break
}

next, err := n.valueIter.Next()
Expand Down
Loading

0 comments on commit c3c6495

Please sign in to comment.