// 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. } }
// viewIDs retrieves the item IDs associated with the view. func viewIDs(v *view.View, path *path.Path, key string, graphDB *cayley.Handle) ([]string, embeddedRels, error) { // Build the Cayley iterator. it := path.BuildIterator() it, _ = it.Optimize() defer it.Close() // tagOrder will allow us to look up the ordering of a tag or // the tag corresponding to an order on demand. tagOrder := make(map[string]string) // Extract any tags and the ordering in the View value. var viewTags []string for idx, pth := range v.Paths { alias := strconv.Itoa(idx+1) + "_" for _, segment := range pth.Segments { if segment.Tag != "" { viewTags = append(viewTags, alias+segment.Tag) tagOrder[alias+segment.Tag] = alias + strconv.Itoa(segment.Level) tagOrder[alias+strconv.Itoa(segment.Level)] = alias + segment.Tag } } } // Retrieve the end path and tagged item IDs. var ids []string var embeds embeddedRels for it.Next() { // Tag the results. resultTags := make(map[string]graph.Value) it.TagResults(resultTags) // Extract the tagged item IDs. taggedIDs := make(map[string]relList) for _, tag := range viewTags { if t, ok := resultTags[tag]; ok { // Append the view item ID. ids = append(ids, quad.NativeOf(graphDB.NameOf(t)).(string)) // Add the tagged ID to the tagged map for embedded // relationship extraction. current, ok := taggedIDs[tag] if !ok { taggedIDs[tag] = []string{quad.NativeOf(graphDB.NameOf(t)).(string)} continue } updated := append(current, quad.NativeOf(graphDB.NameOf(t)).(string)) taggedIDs[tag] = updated } } // Extract any IDs that need to be embedded in view items. embed, err := extractEmbeddedRels(v, taggedIDs, tagOrder, key) if err != nil { return ids, embeds, err } embeds = append(embeds, embed...) } if it.Err() != nil { return ids, embeds, it.Err() } // Remove duplicates. found := make(map[string]bool) j := 0 for i, x := range ids { if !found[x] { found[x] = true ids[j] = ids[i] j++ } } ids = ids[:j] // Add root item. if v.ReturnRoot == true { ids = append(ids, key) } return ids, embeds, nil }