github.com/unigraph-dev/dgraph@v1.1.1-0.20200923154953-8b52b426f765/query/outputnode.go (about)

     1  /*
     2   * Copyright 2017-2018 Dgraph Labs, Inc. and Contributors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package query
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/json"
    22  	"fmt"
    23  	"sort"
    24  	"strings"
    25  	"time"
    26  
    27  	"github.com/golang/glog"
    28  	"github.com/pkg/errors"
    29  	geom "github.com/twpayne/go-geom"
    30  	"github.com/twpayne/go-geom/encoding/geojson"
    31  
    32  	"github.com/dgraph-io/dgo/protos/api"
    33  	"github.com/dgraph-io/dgraph/algo"
    34  	"github.com/dgraph-io/dgraph/protos/pb"
    35  	"github.com/dgraph-io/dgraph/task"
    36  	"github.com/dgraph-io/dgraph/types"
    37  	"github.com/dgraph-io/dgraph/types/facets"
    38  	"github.com/dgraph-io/dgraph/x"
    39  )
    40  
    41  // ToJson converts the list of subgraph into a JSON response by calling toFastJSON.
    42  func ToJson(l *Latency, sgl []*SubGraph) ([]byte, error) {
    43  	sgr := &SubGraph{}
    44  	for _, sg := range sgl {
    45  		if sg.Params.Alias == "var" || sg.Params.Alias == "shortest" {
    46  			continue
    47  		}
    48  		if sg.Params.GetUid {
    49  			sgr.Params.GetUid = true
    50  		}
    51  		sgr.Children = append(sgr.Children, sg)
    52  	}
    53  	return sgr.toFastJSON(l)
    54  }
    55  
    56  // outputNode is the generic output / writer for preTraverse.
    57  type outputNode interface {
    58  	AddValue(attr string, v types.Val)
    59  	AddListValue(attr string, v types.Val, list bool)
    60  	AddMapChild(attr string, node outputNode, isRoot bool)
    61  	AddListChild(attr string, child outputNode)
    62  	New(attr string) outputNode
    63  	SetUID(uid uint64, attr string)
    64  	IsEmpty() bool
    65  
    66  	addCountAtRoot(*SubGraph)
    67  	addGroupby(*SubGraph, *groupResults, string)
    68  	addAggregations(*SubGraph) error
    69  }
    70  
    71  func makeScalarNode(attr string, isChild bool, val []byte, list bool) *fastJsonNode {
    72  	return &fastJsonNode{
    73  		attr:      attr,
    74  		isChild:   isChild,
    75  		scalarVal: val,
    76  		list:      list,
    77  	}
    78  }
    79  
    80  type fastJsonNode struct {
    81  	attr      string
    82  	order     int // relative ordering (for sorted results)
    83  	isChild   bool
    84  	scalarVal []byte
    85  	attrs     []*fastJsonNode
    86  	list      bool
    87  }
    88  
    89  func (fj *fastJsonNode) AddValue(attr string, v types.Val) {
    90  	fj.AddListValue(attr, v, false)
    91  }
    92  
    93  func (fj *fastJsonNode) AddListValue(attr string, v types.Val, list bool) {
    94  	if bs, err := valToBytes(v); err == nil {
    95  		fj.attrs = append(fj.attrs, makeScalarNode(attr, false, bs, list))
    96  	}
    97  }
    98  
    99  func (fj *fastJsonNode) AddMapChild(attr string, val outputNode, isRoot bool) {
   100  	var childNode *fastJsonNode
   101  	for _, c := range fj.attrs {
   102  		if c.attr == attr {
   103  			childNode = c
   104  			break
   105  		}
   106  	}
   107  
   108  	if childNode != nil {
   109  		val.(*fastJsonNode).isChild = true
   110  		val.(*fastJsonNode).attr = attr
   111  		childNode.attrs = append(childNode.attrs, val.(*fastJsonNode).attrs...)
   112  	} else {
   113  		val.(*fastJsonNode).isChild = false
   114  		val.(*fastJsonNode).attr = attr
   115  		fj.attrs = append(fj.attrs, val.(*fastJsonNode))
   116  	}
   117  }
   118  
   119  func (fj *fastJsonNode) AddListChild(attr string, child outputNode) {
   120  	child.(*fastJsonNode).attr = attr
   121  	child.(*fastJsonNode).isChild = true
   122  	fj.attrs = append(fj.attrs, child.(*fastJsonNode))
   123  }
   124  
   125  func (fj *fastJsonNode) New(attr string) outputNode {
   126  	return &fastJsonNode{attr: attr, isChild: false}
   127  }
   128  
   129  func (fj *fastJsonNode) SetUID(uid uint64, attr string) {
   130  	// if we're in debug mode, uid may be added second time, skip this
   131  	if attr == "uid" {
   132  		for _, a := range fj.attrs {
   133  			if a.attr == attr {
   134  				return
   135  			}
   136  		}
   137  	}
   138  	fj.attrs = append(fj.attrs, makeScalarNode(attr, false, []byte(fmt.Sprintf("\"%#x\"", uid)),
   139  		false))
   140  }
   141  
   142  func (fj *fastJsonNode) IsEmpty() bool {
   143  	return len(fj.attrs) == 0
   144  }
   145  
   146  func valToBytes(v types.Val) ([]byte, error) {
   147  	switch v.Tid {
   148  	case types.StringID, types.DefaultID:
   149  		return json.Marshal(v.Value)
   150  	case types.BinaryID:
   151  		return []byte(fmt.Sprintf("%q", v.Value)), nil
   152  	case types.IntID:
   153  		return []byte(fmt.Sprintf("%d", v.Value)), nil
   154  	case types.FloatID:
   155  		return []byte(fmt.Sprintf("%f", v.Value)), nil
   156  	case types.BoolID:
   157  		if v.Value.(bool) {
   158  			return []byte("true"), nil
   159  		}
   160  		return []byte("false"), nil
   161  	case types.DateTimeID:
   162  		// Return empty string instead of zero-time value string - issue#3166
   163  		t := v.Value.(time.Time)
   164  		if t.IsZero() {
   165  			return []byte(`""`), nil
   166  		}
   167  		return t.MarshalJSON()
   168  	case types.GeoID:
   169  		return geojson.Marshal(v.Value.(geom.T))
   170  	case types.UidID:
   171  		return []byte(fmt.Sprintf("\"%#x\"", v.Value)), nil
   172  	case types.PasswordID:
   173  		return []byte(fmt.Sprintf("%q", v.Value.(string))), nil
   174  	default:
   175  		return nil, errors.New("Unsupported types.Val.Tid")
   176  	}
   177  }
   178  
   179  type nodeSlice []*fastJsonNode
   180  
   181  func (n nodeSlice) Len() int {
   182  	return len(n)
   183  }
   184  
   185  func (n nodeSlice) Less(i, j int) bool {
   186  	cmp := strings.Compare(n[i].attr, n[j].attr)
   187  	if cmp == 0 {
   188  		return n[i].order < n[j].order
   189  	}
   190  	return cmp < 0
   191  }
   192  
   193  func (n nodeSlice) Swap(i, j int) {
   194  	n[i], n[j] = n[j], n[i]
   195  }
   196  
   197  func (fj *fastJsonNode) writeKey(out *bytes.Buffer) {
   198  	out.WriteRune('"')
   199  	out.WriteString(fj.attr)
   200  	out.WriteRune('"')
   201  	out.WriteRune(':')
   202  }
   203  
   204  func (fj *fastJsonNode) encode(out *bytes.Buffer) {
   205  	// set relative ordering
   206  	for i, a := range fj.attrs {
   207  		a.order = i
   208  	}
   209  
   210  	i := 0
   211  	if i < len(fj.attrs) {
   212  		out.WriteRune('{')
   213  		cur := fj.attrs[i]
   214  		i++
   215  		cnt := 1
   216  		last := false
   217  		inArray := false
   218  		for {
   219  			var next *fastJsonNode
   220  			if i < len(fj.attrs) {
   221  				next = fj.attrs[i]
   222  				i++
   223  			} else {
   224  				last = true
   225  			}
   226  
   227  			if !last {
   228  				if cur.attr == next.attr {
   229  					if cnt == 1 {
   230  						cur.writeKey(out)
   231  						out.WriteRune('[')
   232  						inArray = true
   233  					}
   234  					cur.encode(out)
   235  					cnt++
   236  				} else {
   237  					if cnt == 1 {
   238  						cur.writeKey(out)
   239  						if cur.isChild || cur.list {
   240  							out.WriteRune('[')
   241  							inArray = true
   242  						}
   243  					}
   244  					cur.encode(out)
   245  					if cnt != 1 || (cur.isChild || cur.list) {
   246  						out.WriteRune(']')
   247  						inArray = false
   248  					}
   249  					cnt = 1
   250  				}
   251  				out.WriteRune(',')
   252  
   253  				cur = next
   254  			} else {
   255  				if cnt == 1 {
   256  					cur.writeKey(out)
   257  				}
   258  				if (cur.isChild || cur.list) && !inArray {
   259  					out.WriteRune('[')
   260  				}
   261  				cur.encode(out)
   262  				if cnt != 1 || (cur.isChild || cur.list) {
   263  					out.WriteRune(']')
   264  				}
   265  				break
   266  			}
   267  		}
   268  		out.WriteRune('}')
   269  	} else {
   270  		out.Write(fj.scalarVal)
   271  	}
   272  }
   273  
   274  func merge(parent [][]*fastJsonNode, child [][]*fastJsonNode) ([][]*fastJsonNode, error) {
   275  	if len(parent) == 0 {
   276  		return child, nil
   277  	}
   278  
   279  	// Here we merge two slices of maps.
   280  	mergedList := make([][]*fastJsonNode, 0, len(parent)*len(child))
   281  	cnt := 0
   282  	for _, pa := range parent {
   283  		for _, ca := range child {
   284  			cnt += len(pa) + len(ca)
   285  			if cnt > x.Config.NormalizeNodeLimit {
   286  				return nil, errors.Errorf(
   287  					"Couldn't evaluate @normalize directive - too many results")
   288  			}
   289  			list := make([]*fastJsonNode, 0, len(pa)+len(ca))
   290  			list = append(list, pa...)
   291  			list = append(list, ca...)
   292  			mergedList = append(mergedList, list)
   293  		}
   294  	}
   295  	return mergedList, nil
   296  }
   297  
   298  func (fj *fastJsonNode) normalize() ([][]*fastJsonNode, error) {
   299  	cnt := 0
   300  	for _, a := range fj.attrs {
   301  		if a.isChild {
   302  			cnt++
   303  		}
   304  	}
   305  
   306  	if cnt == 0 {
   307  		// Recursion base case
   308  		// There are no children, we can just return slice with fj.attrs map.
   309  		return [][]*fastJsonNode{fj.attrs}, nil
   310  	}
   311  
   312  	parentSlice := make([][]*fastJsonNode, 0, 5)
   313  	// If the parents has attrs, lets add them to the slice so that it can be
   314  	// merged with children later.
   315  	attrs := make([]*fastJsonNode, 0, len(fj.attrs)-cnt)
   316  	for _, a := range fj.attrs {
   317  		if !a.isChild {
   318  			attrs = append(attrs, a)
   319  		}
   320  	}
   321  	parentSlice = append(parentSlice, attrs)
   322  
   323  	for ci := 0; ci < len(fj.attrs); {
   324  		childNode := fj.attrs[ci]
   325  		if !childNode.isChild {
   326  			ci++
   327  			continue
   328  		}
   329  		childSlice := make([][]*fastJsonNode, 0, 5)
   330  		for ci < len(fj.attrs) && childNode.attr == fj.attrs[ci].attr {
   331  			normalized, err := fj.attrs[ci].normalize()
   332  			if err != nil {
   333  				return nil, err
   334  			}
   335  			childSlice = append(childSlice, normalized...)
   336  			ci++
   337  		}
   338  		// Merging with parent.
   339  		var err error
   340  		parentSlice, err = merge(parentSlice, childSlice)
   341  		if err != nil {
   342  			return nil, err
   343  		}
   344  	}
   345  	for i, slice := range parentSlice {
   346  		sort.Sort(nodeSlice(slice))
   347  
   348  		first := -1
   349  		last := 0
   350  		for i := range slice {
   351  			if slice[i].attr == "uid" {
   352  				if first == -1 {
   353  					first = i
   354  				}
   355  				last = i
   356  			}
   357  		}
   358  		if first != -1 && first != last {
   359  			if first == 0 {
   360  				parentSlice[i] = slice[last:]
   361  			} else {
   362  				parentSlice[i] = append(slice[:first], slice[last:]...)
   363  			}
   364  		}
   365  	}
   366  
   367  	return parentSlice, nil
   368  }
   369  
   370  func (fj *fastJsonNode) addGroupby(sg *SubGraph, res *groupResults, fname string) {
   371  	// Don't add empty groupby
   372  	if len(res.group) == 0 {
   373  		return
   374  	}
   375  	g := fj.New(fname)
   376  	for _, grp := range res.group {
   377  		uc := g.New("@groupby")
   378  		for _, it := range grp.keys {
   379  			uc.AddValue(it.attr, it.key)
   380  		}
   381  		for _, it := range grp.aggregates {
   382  			uc.AddValue(it.attr, it.key)
   383  		}
   384  		g.AddListChild("@groupby", uc)
   385  	}
   386  	fj.AddListChild(fname, g)
   387  }
   388  
   389  func (fj *fastJsonNode) addCountAtRoot(sg *SubGraph) {
   390  	c := types.ValueForType(types.IntID)
   391  	c.Value = int64(len(sg.DestUIDs.Uids))
   392  	n1 := fj.New(sg.Params.Alias)
   393  	field := sg.Params.uidCountAlias
   394  	if field == "" {
   395  		field = "count"
   396  	}
   397  	n1.AddValue(field, c)
   398  	fj.AddListChild(sg.Params.Alias, n1)
   399  }
   400  
   401  func (fj *fastJsonNode) addAggregations(sg *SubGraph) error {
   402  	for _, child := range sg.Children {
   403  		aggVal, ok := child.Params.uidToVal[0]
   404  		if !ok {
   405  			if len(child.Params.NeedsVar) == 0 {
   406  				return errors.Errorf("Only aggregated variables allowed within empty block.")
   407  			}
   408  			// the aggregation didn't happen, most likely was called with unset vars.
   409  			// See: query.go:fillVars
   410  			aggVal = types.Val{Tid: types.FloatID, Value: float64(0)}
   411  		}
   412  		if child.Params.Normalize && child.Params.Alias == "" {
   413  			continue
   414  		}
   415  		fieldName := aggWithVarFieldName(child)
   416  		n1 := fj.New(fieldName)
   417  		n1.AddValue(fieldName, aggVal)
   418  		fj.AddListChild(sg.Params.Alias, n1)
   419  	}
   420  	if fj.IsEmpty() {
   421  		fj.AddListChild(sg.Params.Alias, &fastJsonNode{})
   422  	}
   423  	return nil
   424  }
   425  
   426  func processNodeUids(fj *fastJsonNode, sg *SubGraph) error {
   427  	var seedNode *fastJsonNode
   428  	if sg.Params.IsEmpty {
   429  		return fj.addAggregations(sg)
   430  	}
   431  
   432  	if sg.uidMatrix == nil {
   433  		fj.AddListChild(sg.Params.Alias, &fastJsonNode{})
   434  		return nil
   435  	}
   436  
   437  	hasChild := false
   438  	if sg.Params.uidCount && !(sg.Params.uidCountAlias == "" && sg.Params.Normalize) {
   439  		hasChild = true
   440  		fj.addCountAtRoot(sg)
   441  	}
   442  
   443  	if sg.Params.isGroupBy {
   444  		if len(sg.GroupbyRes) == 0 {
   445  			return errors.Errorf("Expected GroupbyRes to have length > 0.")
   446  		}
   447  		fj.addGroupby(sg, sg.GroupbyRes[0], sg.Params.Alias)
   448  		return nil
   449  	}
   450  
   451  	lenList := len(sg.uidMatrix[0].Uids)
   452  	for i := 0; i < lenList; i++ {
   453  		uid := sg.uidMatrix[0].Uids[i]
   454  		if algo.IndexOf(sg.DestUIDs, uid) < 0 {
   455  			// This UID was filtered. So Ignore it.
   456  			continue
   457  		}
   458  
   459  		n1 := seedNode.New(sg.Params.Alias)
   460  		if err := sg.preTraverse(uid, n1); err != nil {
   461  			if err.Error() == "_INV_" {
   462  				continue
   463  			}
   464  			return err
   465  		}
   466  
   467  		if n1.IsEmpty() {
   468  			continue
   469  		}
   470  
   471  		hasChild = true
   472  		if !sg.Params.Normalize {
   473  			fj.AddListChild(sg.Params.Alias, n1)
   474  			continue
   475  		}
   476  
   477  		// Lets normalize the response now.
   478  		normalized, err := n1.(*fastJsonNode).normalize()
   479  		if err != nil {
   480  			return err
   481  		}
   482  		for _, c := range normalized {
   483  			fj.AddListChild(sg.Params.Alias, &fastJsonNode{attrs: c})
   484  		}
   485  	}
   486  
   487  	if !hasChild {
   488  		// So that we return an empty key if the root didn't have any children.
   489  		fj.AddListChild(sg.Params.Alias, &fastJsonNode{})
   490  	}
   491  	return nil
   492  }
   493  
   494  // Extensions represents the extra information appended to query results.
   495  type Extensions struct {
   496  	Latency *api.Latency    `json:"server_latency,omitempty"`
   497  	Txn     *api.TxnContext `json:"txn,omitempty"`
   498  }
   499  
   500  func (sg *SubGraph) toFastJSON(l *Latency) ([]byte, error) {
   501  	encodingStart := time.Now()
   502  	defer func() {
   503  		l.Json = time.Since(encodingStart)
   504  	}()
   505  
   506  	var seedNode *fastJsonNode
   507  	var err error
   508  	n := seedNode.New("_root_")
   509  	for _, sg := range sg.Children {
   510  		err = processNodeUids(n.(*fastJsonNode), sg)
   511  		if err != nil {
   512  			return nil, err
   513  		}
   514  	}
   515  
   516  	// According to GraphQL spec response should only contain data, errors and extensions as top
   517  	// level keys. Hence we send server_latency under extensions key.
   518  	// https://facebook.github.io/graphql/#sec-Response-Format
   519  
   520  	var bufw bytes.Buffer
   521  	if len(n.(*fastJsonNode).attrs) == 0 {
   522  		bufw.WriteString(`{}`)
   523  	} else {
   524  		n.(*fastJsonNode).encode(&bufw)
   525  	}
   526  	return bufw.Bytes(), nil
   527  }
   528  
   529  func (sg *SubGraph) fieldName() string {
   530  	fieldName := sg.Attr
   531  	if sg.Params.Alias != "" {
   532  		fieldName = sg.Params.Alias
   533  	}
   534  	return fieldName
   535  }
   536  
   537  func addCount(pc *SubGraph, count uint64, dst outputNode) {
   538  	if pc.Params.Normalize && pc.Params.Alias == "" {
   539  		return
   540  	}
   541  	c := types.ValueForType(types.IntID)
   542  	c.Value = int64(count)
   543  	fieldName := pc.Params.Alias
   544  	if fieldName == "" {
   545  		fieldName = fmt.Sprintf("count(%s)", pc.Attr)
   546  	}
   547  	dst.AddValue(fieldName, c)
   548  }
   549  
   550  func aggWithVarFieldName(pc *SubGraph) string {
   551  	if pc.Params.Alias != "" {
   552  		return pc.Params.Alias
   553  	}
   554  	fieldName := fmt.Sprintf("val(%v)", pc.Params.Var)
   555  	if len(pc.Params.NeedsVar) > 0 {
   556  		fieldName = fmt.Sprintf("val(%v)", pc.Params.NeedsVar[0].Name)
   557  		if pc.SrcFunc != nil {
   558  			fieldName = fmt.Sprintf("%s(%v)", pc.SrcFunc.Name, fieldName)
   559  		}
   560  	}
   561  	return fieldName
   562  }
   563  
   564  func addInternalNode(pc *SubGraph, uid uint64, dst outputNode) error {
   565  	sv, ok := pc.Params.uidToVal[uid]
   566  	if !ok || sv.Value == nil {
   567  		return nil
   568  	}
   569  	fieldName := aggWithVarFieldName(pc)
   570  	dst.AddValue(fieldName, sv)
   571  	return nil
   572  }
   573  
   574  func addCheckPwd(pc *SubGraph, vals []*pb.TaskValue, dst outputNode) {
   575  	c := types.ValueForType(types.BoolID)
   576  	if len(vals) == 0 {
   577  		c.Value = false
   578  	} else {
   579  		c.Value = task.ToBool(vals[0])
   580  	}
   581  
   582  	fieldName := pc.Params.Alias
   583  	if fieldName == "" {
   584  		fieldName = fmt.Sprintf("checkpwd(%s)", pc.Attr)
   585  	}
   586  	dst.AddValue(fieldName, c)
   587  }
   588  
   589  func alreadySeen(parentIds []uint64, uid uint64) bool {
   590  	for _, id := range parentIds {
   591  		if id == uid {
   592  			return true
   593  		}
   594  	}
   595  	return false
   596  }
   597  
   598  func facetName(fieldName string, f *api.Facet) string {
   599  	if f.Alias != "" {
   600  		return f.Alias
   601  	}
   602  	return fieldName + x.FacetDelimeter + f.Key
   603  }
   604  
   605  // This method gets the values and children for a subprotos.
   606  func (sg *SubGraph) preTraverse(uid uint64, dst outputNode) error {
   607  	if sg.Params.IgnoreReflex {
   608  		if alreadySeen(sg.Params.parentIds, uid) {
   609  			// A node can't have itself as the child at any level.
   610  			return nil
   611  		}
   612  		// Push myself to stack before sending this to children.
   613  		sg.Params.parentIds = append(sg.Params.parentIds, uid)
   614  	}
   615  
   616  	var invalidUids map[uint64]bool
   617  	// We go through all predicate children of the subprotos.
   618  	for _, pc := range sg.Children {
   619  		if pc.Params.ignoreResult {
   620  			continue
   621  		}
   622  		if pc.IsInternal() {
   623  			if pc.Params.Expand != "" {
   624  				continue
   625  			}
   626  			if pc.Params.Normalize && pc.Params.Alias == "" {
   627  				continue
   628  			}
   629  			if err := addInternalNode(pc, uid, dst); err != nil {
   630  				return err
   631  			}
   632  			continue
   633  		}
   634  
   635  		if len(pc.uidMatrix) == 0 {
   636  			// Can happen in recurse query.
   637  			continue
   638  		}
   639  		if len(pc.facetsMatrix) > 0 && len(pc.facetsMatrix) != len(pc.uidMatrix) {
   640  			return errors.Errorf("Length of facetsMatrix and uidMatrix mismatch: %d vs %d",
   641  				len(pc.facetsMatrix), len(pc.uidMatrix))
   642  		}
   643  
   644  		idx := algo.IndexOf(pc.SrcUIDs, uid)
   645  		if idx < 0 {
   646  			continue
   647  		}
   648  		if pc.Params.isGroupBy {
   649  			if len(pc.GroupbyRes) <= idx {
   650  				return errors.Errorf("Unexpected length while adding Groupby. Idx: [%v], len: [%v]",
   651  					idx, len(pc.GroupbyRes))
   652  			}
   653  			dst.addGroupby(pc, pc.GroupbyRes[idx], pc.fieldName())
   654  			continue
   655  		}
   656  
   657  		fieldName := pc.fieldName()
   658  		if len(pc.counts) > 0 {
   659  			addCount(pc, uint64(pc.counts[idx]), dst)
   660  
   661  		} else if pc.SrcFunc != nil && pc.SrcFunc.Name == "checkpwd" {
   662  			addCheckPwd(pc, pc.valueMatrix[idx].Values, dst)
   663  
   664  		} else if idx < len(pc.uidMatrix) && len(pc.uidMatrix[idx].Uids) > 0 {
   665  			var fcsList []*pb.Facets
   666  			if pc.Params.Facet != nil {
   667  				fcsList = pc.facetsMatrix[idx].FacetsList
   668  			}
   669  
   670  			if sg.Params.IgnoreReflex {
   671  				pc.Params.parentIds = sg.Params.parentIds
   672  			}
   673  			// We create as many predicate entity children as the length of uids for
   674  			// this predicate.
   675  			ul := pc.uidMatrix[idx]
   676  			for childIdx, childUID := range ul.Uids {
   677  				if fieldName == "" || (invalidUids != nil && invalidUids[childUID]) {
   678  					continue
   679  				}
   680  				uc := dst.New(fieldName)
   681  				if rerr := pc.preTraverse(childUID, uc); rerr != nil {
   682  					if rerr.Error() == "_INV_" {
   683  						if invalidUids == nil {
   684  							invalidUids = make(map[uint64]bool)
   685  						}
   686  
   687  						invalidUids[childUID] = true
   688  						continue // next UID.
   689  					}
   690  					// Some other error.
   691  					glog.Errorf("Error while traversal: %v", rerr)
   692  					return rerr
   693  				}
   694  
   695  				if pc.Params.Facet != nil && len(fcsList) > childIdx {
   696  					fs := fcsList[childIdx]
   697  					for _, f := range fs.Facets {
   698  						fVal, err := facets.ValFor(f)
   699  						if err != nil {
   700  							return err
   701  						}
   702  
   703  						uc.AddValue(facetName(fieldName, f), fVal)
   704  					}
   705  				}
   706  
   707  				if !uc.IsEmpty() {
   708  					if sg.Params.GetUid {
   709  						uc.SetUID(childUID, "uid")
   710  					}
   711  					if pc.List {
   712  						dst.AddListChild(fieldName, uc)
   713  					} else {
   714  						dst.AddMapChild(fieldName, uc, false)
   715  					}
   716  				}
   717  			}
   718  			if pc.Params.uidCount && !(pc.Params.uidCountAlias == "" && pc.Params.Normalize) {
   719  				uc := dst.New(fieldName)
   720  				c := types.ValueForType(types.IntID)
   721  				c.Value = int64(len(ul.Uids))
   722  				alias := pc.Params.uidCountAlias
   723  				if alias == "" {
   724  					alias = "count"
   725  				}
   726  				uc.AddValue(alias, c)
   727  				dst.AddListChild(fieldName, uc)
   728  			}
   729  		} else {
   730  			if pc.Params.Alias == "" && len(pc.Params.Langs) > 0 {
   731  				fieldName += "@"
   732  				fieldName += strings.Join(pc.Params.Langs, ":")
   733  			}
   734  
   735  			if pc.Attr == "uid" {
   736  				dst.SetUID(uid, pc.fieldName())
   737  				continue
   738  			}
   739  
   740  			if len(pc.facetsMatrix) > idx && len(pc.facetsMatrix[idx].FacetsList) > 0 {
   741  				// in case of Value we have only one Facets
   742  				for _, f := range pc.facetsMatrix[idx].FacetsList[0].Facets {
   743  					fVal, err := facets.ValFor(f)
   744  					if err != nil {
   745  						return err
   746  					}
   747  
   748  					dst.AddValue(facetName(fieldName, f), fVal)
   749  				}
   750  			}
   751  
   752  			if len(pc.valueMatrix) <= idx {
   753  				continue
   754  			}
   755  
   756  			for i, tv := range pc.valueMatrix[idx].Values {
   757  				// if conversion not possible, we ignore it in the result.
   758  				sv, convErr := convertWithBestEffort(tv, pc.Attr)
   759  				if convErr != nil {
   760  					return convErr
   761  				}
   762  
   763  				if pc.Params.expandAll && len(pc.LangTags[idx].Lang) != 0 {
   764  					if i >= len(pc.LangTags[idx].Lang) {
   765  						return errors.Errorf(
   766  							"pb.error: all lang tags should be either present or absent")
   767  					}
   768  					fieldNameWithTag := fieldName
   769  					lang := pc.LangTags[idx].Lang[i]
   770  					if lang != "" {
   771  						fieldNameWithTag += "@" + lang
   772  					}
   773  					encodeAsList := pc.List && len(lang) == 0
   774  					dst.AddListValue(fieldNameWithTag, sv, encodeAsList)
   775  					continue
   776  				}
   777  
   778  				encodeAsList := pc.List && len(pc.Params.Langs) == 0
   779  				if !pc.Params.Normalize {
   780  					dst.AddListValue(fieldName, sv, encodeAsList)
   781  					continue
   782  				}
   783  				// If the query had the normalize directive, then we only add nodes
   784  				// with an Alias.
   785  				if pc.Params.Alias != "" {
   786  					dst.AddListValue(fieldName, sv, encodeAsList)
   787  				}
   788  			}
   789  		}
   790  	}
   791  
   792  	if sg.Params.IgnoreReflex && len(sg.Params.parentIds) > 0 {
   793  		// Lets pop the stack.
   794  		sg.Params.parentIds = (sg.Params.parentIds)[:len(sg.Params.parentIds)-1]
   795  	}
   796  
   797  	// Only for shortest path query we wan't to return uid always if there is
   798  	// nothing else at that level.
   799  	if (sg.Params.GetUid && !dst.IsEmpty()) || sg.Params.shortest {
   800  		dst.SetUID(uid, "uid")
   801  	}
   802  
   803  	if sg.pathMeta != nil {
   804  		totalWeight := types.Val{
   805  			Tid:   types.FloatID,
   806  			Value: sg.pathMeta.weight,
   807  		}
   808  		dst.AddValue("_weight_", totalWeight)
   809  	}
   810  
   811  	return nil
   812  }