// applyOrderAndPagination orders each posting list by a given attribute // before applying pagination. func (sg *SubGraph) applyOrderAndPagination(ctx context.Context) error { if len(sg.Params.Order) == 0 { return nil } if sg.Params.Count == 0 { // Only retrieve up to 1000 results by default. sg.Params.Count = 1000 } sort := &task.Sort{ Attr: sg.Params.Order, UidMatrix: sg.uidMatrix, Offset: int32(sg.Params.Offset), Count: int32(sg.Params.Count), Desc: sg.Params.OrderDesc, } result, err := worker.SortOverNetwork(ctx, sort) if err != nil { return err } x.AssertTrue(len(result.UidMatrix) == len(sg.uidMatrix)) sg.uidMatrix = result.GetUidMatrix() // Update sg.destUID. Iterate over the UID matrix (which is not sorted by // UID). For each element in UID matrix, we do a binary search in the // current destUID and mark it. Then we scan over this bool array and // rebuild destUIDs. included := make([]bool, len(sg.DestUIDs.Uids)) for _, ul := range sg.uidMatrix { for _, uid := range ul.Uids { idx := algo.IndexOf(sg.DestUIDs, uid) // Binary search. if idx >= 0 { included[idx] = true } } } algo.ApplyFilter(sg.DestUIDs, func(uid uint64, idx int) bool { return included[idx] }) return nil }
// This method gets the values and children for a subgraph. func (sg *SubGraph) preTraverse(uid uint64, dst outputNode) error { invalidUids := make(map[uint64]bool) // We go through all predicate children of the subgraph. for _, pc := range sg.Children { idx := algo.IndexOf(pc.SrcUIDs, uid) if idx < 0 { continue } ul := pc.uidMatrix[idx] fieldName := pc.Attr if pc.Params.Alias != "" { fieldName = pc.Params.Alias } if sg.Params.GetUID || sg.Params.isDebug { dst.SetUID(uid) } if len(pc.counts) > 0 { c := types.Int32(pc.counts[idx]) uc := dst.New(fieldName) uc.AddValue("_count_", &c) dst.AddChild(fieldName, uc) } else if len(ul.Uids) > 0 || len(pc.Children) > 0 { // We create as many predicate entity children as the length of uids for // this predicate. for _, childUID := range ul.Uids { if invalidUids[childUID] { continue } uc := dst.New(fieldName) // Doing check for UID here is no good because some of these might be // invalid nodes. // if pc.Params.GetUID || pc.Params.isDebug { // dst.SetUID(uid) // } if rerr := pc.preTraverse(childUID, uc); rerr != nil { if rerr.Error() == "_INV_" { invalidUids[childUID] = true continue // next UID. } // Some other error. log.Printf("Error while traversal: %v", rerr) return rerr } if !uc.IsEmpty() { dst.AddChild(fieldName, uc) } } } else { tv := pc.values[idx] v, err := getValue(tv) if err != nil { return err } if pc.Attr == "_xid_" { txt, err := v.MarshalText() if err != nil { return err } dst.SetXID(string(txt)) } else { globalType := schema.TypeOf(pc.Attr) schemaType := pc.Params.AttrType sv := v if schemaType != nil { // Do type checking on response values if !schemaType.IsScalar() { return x.Errorf("Unknown Scalar:%v. Leaf predicate:'%v' must be"+ " one of the scalar types defined in the schema.", pc.Params.AttrType, pc.Attr) } st := schemaType.(types.Scalar) // Convert to schema type. sv, err = st.Convert(v) if bytes.Equal(tv.Val, nil) || err != nil { // skip values that don't convert. return x.Errorf("_INV_") } } else if globalType != nil { // Try to coerce types if this is an optional scalar outside an // object definition. if !globalType.IsScalar() { return x.Errorf("Leaf predicate:'%v' must be a scalar.", pc.Attr) } gt := globalType.(types.Scalar) // Convert to schema type. sv, err = gt.Convert(v) if bytes.Equal(tv.Val, nil) || err != nil { continue } } if bytes.Equal(tv.Val, nil) { continue } dst.AddValue(fieldName, sv) } } } return nil }