// BuildNodeIterator returns an iterator for retrieving the results of the query, with // each result being a struct representing the node and the values found outgoing at the // given predicates. func (gq GraphQuery) BuildNodeIterator(predicates ...Predicate) NodeIterator { if (gq.singleDirection == 1 || gq.singleDirection == -1) && gq.singleStartingValue != nil && gq.singlePredicate != nil && len(predicates) == 0 { // Special case: An iterator from a single starting node in a single direction over // a single predicate with no custom values. return newSimpleDirectionalIterator(gq.layer, gq.singleStartingValue, gq.singlePredicate, gq.singleDirection) } var updatedPath *path.Path = gq.path // Save the predicates the user requested. for _, predicate := range predicates { fullPredicate := gq.layer.getPrefixedPredicate(predicate) updatedPath = updatedPath.Save(fullPredicate, valueToPredicateString(fullPredicate)) } // Save the predicate for the kind of the node as well. fullKindPredicate := gq.layer.getPrefixedPredicate(gq.layer.nodeKindPredicate) updatedPath = updatedPath.Save(fullKindPredicate, valueToPredicateString(fullKindPredicate)) it := updatedPath.BuildIterator() oit, _ := it.Optimize() return &graphNodeIterator{ layer: gq.layer, iterator: oit, tagCount: gq.tagCount + 1 + len(predicates), // +1 for kind. } }
func buildPathFromObject(obj *otto.Object) *path.Path { var p *path.Path val, _ := obj.Get("_gremlin_type") stringArgs := propertiesOf(obj, "string_args") gremlinType := val.String() if prev, _ := obj.Get("_gremlin_prev"); !prev.IsObject() { switch gremlinType { case "vertex": return path.StartMorphism(stringArgs...) case "morphism": return path.StartMorphism() default: panic("No base gremlin path other than 'vertex' or 'morphism'") } } else { p = buildPathFromObject(prev.Object()) } if p == nil { return nil } switch gremlinType { case "Is": return p.Is(stringArgs...) case "In": preds, tags, ok := getViaData(obj) if !ok { return nil } return p.InWithTags(tags, preds...) case "Out": preds, tags, ok := getViaData(obj) if !ok { return nil } return p.OutWithTags(tags, preds...) case "Both": preds, _, ok := getViaData(obj) if !ok { return nil } return p.Both(preds...) case "Follow": subobj := getFirstArgAsMorphismChain(obj) if subobj == nil { return nil } return p.Follow(buildPathFromObject(subobj)) case "FollowR": subobj := getFirstArgAsMorphismChain(obj) if subobj == nil { return nil } return p.FollowReverse(buildPathFromObject(subobj)) case "And", "Intersect": subobj := getFirstArgAsVertexChain(obj) if subobj == nil { return nil } return p.And(buildPathFromObject(subobj)) case "Union", "Or": subobj := getFirstArgAsVertexChain(obj) if subobj == nil { return nil } return p.Or(buildPathFromObject(subobj)) case "Back": if len(stringArgs) != 1 { return nil } return p.Back(stringArgs[0]) case "Tag", "As": return p.Tag(stringArgs...) case "Has": if len(stringArgs) < 2 { return nil } return p.Has(stringArgs[0], stringArgs[1:]...) case "Save", "SaveR": if len(stringArgs) > 2 || len(stringArgs) == 0 { return nil } tag := stringArgs[0] if len(stringArgs) == 2 { tag = stringArgs[1] } if gremlinType == "SaveR" { return p.SaveReverse(stringArgs[0], tag) } return p.Save(stringArgs[0], tag) case "Except", "Difference": subobj := getFirstArgAsVertexChain(obj) if subobj == nil { return nil } return p.Except(buildPathFromObject(subobj)) case "InPredicates": return p.InPredicates() case "OutPredicates": return p.OutPredicates() case "LabelContext": labels, tags, ok := getViaData(obj) if !ok { return nil } return p.LabelContextWithTags(tags, labels...) default: panic(fmt.Sprint("Unimplemented Gremlin function", gremlinType)) } }