Esempio n. 1
0
// 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.
	}
}
Esempio n. 2
0
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))
	}
}
Esempio n. 3
0
// 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
}
Esempio n. 4
0
// viewPathToGraphPath translates the path in a view into a "path"
// utilized in graph queries.
func viewPathToGraphPath(v *view.View, key string, graphDB *cayley.Handle) (*path.Path, error) {

	// outputPath is the final tranlated graph path.
	var outputPath *path.Path

	// Loop over the paths in the view translating the metadata.
	for idx, pth := range v.Paths {

		// We create an alias prefix for tags, so we can track which
		// path a tag is in.
		alias := strconv.Itoa(idx+1) + "_"

		// Sort the view Path value.
		sort.Sort(pth.Segments)

		// graphPath will contain the entire strict graph path.
		var graphPath *path.Path

		// subPaths will contain each sub path of the full graph path,
		// as a separate graph path.
		var subPaths []path.Path

		// Loop over the path segments translating the path.
		level := 1
		for _, segment := range pth.Segments {

			// Check that the level is the level we expect (i.e., that the levels
			// are in order)
			if level != segment.Level {
				err := fmt.Errorf("Invalid view path level, expected %d but seeing %d", level, segment.Level)
				return graphPath, err
			}

			// Initialize the path, if we are on level 1.
			if level == 1 {

				// Add the first level relationship.
				switch segment.Direction {
				case inString:
					graphPath = cayley.StartPath(graphDB, quad.String(key)).In(quad.String(segment.Predicate))
				case outString:
					graphPath = cayley.StartPath(graphDB, quad.String(key)).Out(quad.String(segment.Predicate))
				}

				// Add the tag, if present.
				if segment.Tag != "" {
					graphPath = graphPath.Clone().Tag(alias + segment.Tag)
				}

				// Track this as a subpath.
				subPaths = append(subPaths, *graphPath.Clone())

				level++
				continue
			}

			// Add the relationship.
			switch segment.Direction {
			case inString:
				graphPath = graphPath.Clone().In(quad.String(segment.Predicate))
			case outString:
				graphPath = graphPath.Clone().Out(quad.String(segment.Predicate))
			}

			// Add the tag, if present.
			if segment.Tag != "" {
				graphPath = graphPath.Clone().Tag(alias + segment.Tag)
			}

			// Add this as a subpath.
			subPaths = append(subPaths, *graphPath.Clone())

			level++
		}

		// If we are forcing a strict path, return only the resulting or
		// tagged items along the full path.
		if pth.StrictPath {
			if outputPath == nil {
				outputPath = graphPath
				continue
			}
			outputPath = outputPath.Clone().Or(graphPath)
			continue
		}

		// Otherwise add all the subpaths to the output path.
		for _, subPath := range subPaths {
			if outputPath == nil {
				addedPath := &subPath
				outputPath = addedPath.Clone()
				continue
			}
			outputPath = outputPath.Clone().Or(&subPath)
		}
	}

	return outputPath, nil
}