func buildIteratorFromValue(val otto.Value, qs graph.QuadStore) graph.Iterator { if val.IsNull() || val.IsUndefined() { return qs.NodesAllIterator() } if val.IsPrimitive() { thing, _ := val.Export() switch v := thing.(type) { case string: it := qs.FixedIterator() it.Add(qs.ValueOf(v)) return it default: glog.Errorln("Trying to build unknown primitive value.") } } switch val.Class() { case "Object": return buildIteratorTree(val.Object(), qs) case "Array": // Had better be an array of strings strings := stringsFrom(val.Object()) it := qs.FixedIterator() for _, x := range strings { it.Add(qs.ValueOf(x)) } return it case "Number": fallthrough case "Boolean": fallthrough case "Date": fallthrough case "String": it := qs.FixedIterator() it.Add(qs.ValueOf(val.String())) return it default: glog.Errorln("Trying to handle unsupported Javascript value.") return iterator.NewNull() } }
func buildInOutIterator(obj *otto.Object, qs graph.QuadStore, base graph.Iterator, isReverse bool) graph.Iterator { argList, _ := obj.Get("_gremlin_values") if argList.Class() != "GoArray" { glog.Errorln("How is arglist not an array? Return nothing.", argList.Class()) return iterator.NewNull() } argArray := argList.Object() lengthVal, _ := argArray.Get("length") length, _ := lengthVal.ToInteger() var predicateNodeIterator graph.Iterator if length == 0 { predicateNodeIterator = qs.NodesAllIterator() } else { zero, _ := argArray.Get("0") predicateNodeIterator = buildIteratorFromValue(zero, qs) } if length >= 2 { var tags []string one, _ := argArray.Get("1") if one.IsString() { tags = append(tags, one.String()) } else if one.Class() == "Array" { tags = stringsFrom(one.Object()) } for _, tag := range tags { predicateNodeIterator.Tagger().Add(tag) } } in, out := quad.Subject, quad.Object if isReverse { in, out = out, in } lto := iterator.NewLinksTo(qs, base, in) and := iterator.NewAnd(qs) and.AddSubIterator(iterator.NewLinksTo(qs, predicateNodeIterator, quad.Predicate)) and.AddSubIterator(lto) return iterator.NewHasA(qs, and, out) }
func buildSave(qs graph.QuadStore, via interface{}, tag string, it graph.Iterator, reverse bool) graph.Iterator { all := qs.NodesAllIterator() all.Tagger().Add(tag) node, allDir := quad.Subject, quad.Object var viaPath *Path if via != nil { viaPath = buildViaPath(qs, via) } else { viaPath = buildViaPath(qs) } if reverse { node, allDir = allDir, node } lto := iterator.NewLinksTo(qs, all, allDir) subAnd := iterator.NewAnd(qs) subAnd.AddSubIterator(iterator.NewLinksTo(qs, viaPath.BuildIterator(), quad.Predicate)) subAnd.AddSubIterator(lto) hasa := iterator.NewHasA(qs, subAnd, node) and := iterator.NewAnd(qs) and.AddSubIterator(hasa) and.AddSubIterator(it) return and }
func buildViaPath(qs graph.QuadStore, via ...interface{}) *Path { if len(via) == 0 { return PathFromIterator(qs, qs.NodesAllIterator()) } else if len(via) == 1 { v := via[0] switch p := v.(type) { case *Path: return p case string: return StartPath(qs, p) default: panic("Invalid type passed to buildViaPath.") } } var strings []string for _, s := range via { if str, ok := s.(string); ok { strings = append(strings, str) } else { panic("Non-string type passed to long Via path") } } return StartPath(qs, strings...) }
// BuildIteratorOn will return an iterator for this path on the given QuadStore. func (p *Path) BuildIteratorOn(qs graph.QuadStore) graph.Iterator { return p.Morphism()(qs, qs.NodesAllIterator()) }
func buildIteratorTree(tree *peg.ExpressionTree, qs graph.QuadStore) graph.Iterator { switch tree.Name { case "Start": return buildIteratorTree(tree.Children[0], qs) case "NodeIdentifier": var out graph.Iterator nodeID := getIdentString(tree) if tree.Children[0].Name == "Variable" { allIt := qs.NodesAllIterator() allIt.Tagger().Add(nodeID) out = allIt } else { n := nodeID if tree.Children[0].Children[0].Name == "ColonIdentifier" { n = nodeID[1:] } fixed := qs.FixedIterator() fixed.Add(qs.ValueOf(n)) out = fixed } return out case "PredIdentifier": i := 0 if tree.Children[0].Name == "Reverse" { //Taken care of below i++ } it := buildIteratorTree(tree.Children[i], qs) lto := iterator.NewLinksTo(qs, it, quad.Predicate) return lto case "RootConstraint": constraintCount := 0 and := iterator.NewAnd(qs) for _, c := range tree.Children { switch c.Name { case "NodeIdentifier": fallthrough case "Constraint": it := buildIteratorTree(c, qs) and.AddSubIterator(it) constraintCount++ continue default: continue } } return and case "Constraint": var hasa *iterator.HasA topLevelDir := quad.Subject subItDir := quad.Object subAnd := iterator.NewAnd(qs) isOptional := false for _, c := range tree.Children { switch c.Name { case "PredIdentifier": if c.Children[0].Name == "Reverse" { topLevelDir = quad.Object subItDir = quad.Subject } it := buildIteratorTree(c, qs) subAnd.AddSubIterator(it) continue case "PredicateKeyword": switch c.Children[0].Name { case "OptionalKeyword": isOptional = true } case "NodeIdentifier": fallthrough case "RootConstraint": it := buildIteratorTree(c, qs) l := iterator.NewLinksTo(qs, it, subItDir) subAnd.AddSubIterator(l) continue default: continue } } hasa = iterator.NewHasA(qs, subAnd, topLevelDir) if isOptional { optional := iterator.NewOptional(hasa) return optional } return hasa default: return &iterator.Null{} } }
func buildIteratorTreeHelper(obj *otto.Object, qs graph.QuadStore, base graph.Iterator) graph.Iterator { // TODO: Better error handling var ( it graph.Iterator subIt graph.Iterator ) if prev, _ := obj.Get("_gremlin_prev"); !prev.IsObject() { subIt = base } else { subIt = buildIteratorTreeHelper(prev.Object(), qs, base) } stringArgs := propertiesOf(obj, "string_args") val, _ := obj.Get("_gremlin_type") switch val.String() { case "vertex": if len(stringArgs) == 0 { it = qs.NodesAllIterator() } else { fixed := qs.FixedIterator() for _, name := range stringArgs { fixed.Add(qs.ValueOf(name)) } it = fixed } case "tag": it = subIt for _, tag := range stringArgs { it.Tagger().Add(tag) } case "save": all := qs.NodesAllIterator() if len(stringArgs) > 2 || len(stringArgs) == 0 { return iterator.NewNull() } if len(stringArgs) == 2 { all.Tagger().Add(stringArgs[1]) } else { all.Tagger().Add(stringArgs[0]) } predFixed := qs.FixedIterator() predFixed.Add(qs.ValueOf(stringArgs[0])) subAnd := iterator.NewAnd(qs) subAnd.AddSubIterator(iterator.NewLinksTo(qs, predFixed, quad.Predicate)) subAnd.AddSubIterator(iterator.NewLinksTo(qs, all, quad.Object)) hasa := iterator.NewHasA(qs, subAnd, quad.Subject) and := iterator.NewAnd(qs) and.AddSubIterator(hasa) and.AddSubIterator(subIt) it = and case "saver": all := qs.NodesAllIterator() if len(stringArgs) > 2 || len(stringArgs) == 0 { return iterator.NewNull() } if len(stringArgs) == 2 { all.Tagger().Add(stringArgs[1]) } else { all.Tagger().Add(stringArgs[0]) } predFixed := qs.FixedIterator() predFixed.Add(qs.ValueOf(stringArgs[0])) subAnd := iterator.NewAnd(qs) subAnd.AddSubIterator(iterator.NewLinksTo(qs, predFixed, quad.Predicate)) subAnd.AddSubIterator(iterator.NewLinksTo(qs, all, quad.Subject)) hasa := iterator.NewHasA(qs, subAnd, quad.Object) and := iterator.NewAnd(qs) and.AddSubIterator(hasa) and.AddSubIterator(subIt) it = and case "has": fixed := qs.FixedIterator() if len(stringArgs) < 2 { return iterator.NewNull() } for _, name := range stringArgs[1:] { fixed.Add(qs.ValueOf(name)) } predFixed := qs.FixedIterator() predFixed.Add(qs.ValueOf(stringArgs[0])) subAnd := iterator.NewAnd(qs) subAnd.AddSubIterator(iterator.NewLinksTo(qs, predFixed, quad.Predicate)) subAnd.AddSubIterator(iterator.NewLinksTo(qs, fixed, quad.Object)) hasa := iterator.NewHasA(qs, subAnd, quad.Subject) and := iterator.NewAnd(qs) and.AddSubIterator(hasa) and.AddSubIterator(subIt) it = and case "morphism": it = base case "and": arg, _ := obj.Get("_gremlin_values") firstArg, _ := arg.Object().Get("0") if !isVertexChain(firstArg.Object()) { return iterator.NewNull() } argIt := buildIteratorTree(firstArg.Object(), qs) and := iterator.NewAnd(qs) and.AddSubIterator(subIt) and.AddSubIterator(argIt) it = and case "back": arg, _ := obj.Get("_gremlin_back_chain") argIt := buildIteratorTree(arg.Object(), qs) and := iterator.NewAnd(qs) and.AddSubIterator(subIt) and.AddSubIterator(argIt) it = and case "is": fixed := qs.FixedIterator() for _, name := range stringArgs { fixed.Add(qs.ValueOf(name)) } and := iterator.NewAnd(qs) and.AddSubIterator(fixed) and.AddSubIterator(subIt) it = and case "or": arg, _ := obj.Get("_gremlin_values") firstArg, _ := arg.Object().Get("0") if !isVertexChain(firstArg.Object()) { return iterator.NewNull() } argIt := buildIteratorTree(firstArg.Object(), qs) or := iterator.NewOr() or.AddSubIterator(subIt) or.AddSubIterator(argIt) it = or case "both": // Hardly the most efficient pattern, but the most general. // Worth looking into an Optimize() optimization here. clone := subIt.Clone() it1 := buildInOutIterator(obj, qs, subIt, false) it2 := buildInOutIterator(obj, qs, clone, true) or := iterator.NewOr() or.AddSubIterator(it1) or.AddSubIterator(it2) it = or case "out": it = buildInOutIterator(obj, qs, subIt, false) case "follow": // Follow a morphism arg, _ := obj.Get("_gremlin_values") firstArg, _ := arg.Object().Get("0") if isVertexChain(firstArg.Object()) { return iterator.NewNull() } it = buildIteratorTreeHelper(firstArg.Object(), qs, subIt) case "followr": // Follow a morphism arg, _ := obj.Get("_gremlin_followr") if isVertexChain(arg.Object()) { return iterator.NewNull() } it = buildIteratorTreeHelper(arg.Object(), qs, subIt) case "in": it = buildInOutIterator(obj, qs, subIt, true) case "except": arg, _ := obj.Get("_gremlin_values") firstArg, _ := arg.Object().Get("0") if !isVertexChain(firstArg.Object()) { return iterator.NewNull() } allIt := qs.NodesAllIterator() toComplementIt := buildIteratorTree(firstArg.Object(), qs) notIt := iterator.NewNot(toComplementIt, allIt) and := iterator.NewAnd(qs) and.AddSubIterator(subIt) and.AddSubIterator(notIt) it = and case "in_predicates": it = buildInOutPredicateIterator(obj, qs, subIt, true) case "out_predicates": it = buildInOutPredicateIterator(obj, qs, subIt, false) } if it == nil { panic("Iterator building does not catch the output iterator in some case.") } return it }