예제 #1
0
파일: parser.go 프로젝트: lytics/cayley
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{}
	}
}
예제 #2
0
func (q *Query) buildIteratorTreeMapInternal(query map[string]interface{}, path Path) (graph.Iterator, error) {
	it := iterator.NewAnd(q.ses.qs)
	it.AddSubIterator(q.ses.qs.NodesAllIterator())
	var err error
	err = nil
	outputStructure := make(map[string]interface{})
	for key, subquery := range query {
		optional := false
		outputStructure[key] = nil
		reverse := false
		pred := key
		if strings.HasPrefix(pred, "@") {
			i := strings.Index(pred, ":")
			if i != -1 {
				pred = pred[(i + 1):]
			}
		}
		if strings.HasPrefix(pred, "!") {
			reverse = true
			pred = strings.TrimPrefix(pred, "!")
		}

		// Other special constructs here
		var subit graph.Iterator
		if key == "id" {
			subit, optional, err = q.buildIteratorTreeInternal(subquery, path.Follow(key))
			if err != nil {
				return nil, err
			}
		} else {
			var builtIt graph.Iterator
			builtIt, optional, err = q.buildIteratorTreeInternal(subquery, path.Follow(key))
			if err != nil {
				return nil, err
			}
			subAnd := iterator.NewAnd(q.ses.qs)
			predFixed := q.ses.qs.FixedIterator()
			predFixed.Add(q.ses.qs.ValueOf(pred))
			subAnd.AddSubIterator(iterator.NewLinksTo(q.ses.qs, predFixed, quad.Predicate))
			if reverse {
				lto := iterator.NewLinksTo(q.ses.qs, builtIt, quad.Subject)
				subAnd.AddSubIterator(lto)
				hasa := iterator.NewHasA(q.ses.qs, subAnd, quad.Object)
				subit = hasa
			} else {
				lto := iterator.NewLinksTo(q.ses.qs, builtIt, quad.Object)
				subAnd.AddSubIterator(lto)
				hasa := iterator.NewHasA(q.ses.qs, subAnd, quad.Subject)
				subit = hasa
			}
		}
		if optional {
			it.AddSubIterator(iterator.NewOptional(subit))
		} else {
			it.AddSubIterator(subit)
		}
	}
	if err != nil {
		return nil, err
	}
	q.queryStructure[path] = outputStructure
	return it, nil
}