Repository: cayleygraph/cayley
Pull request #904 (2019-12-27 17:14:06)

LinkedQL: Context step
Depends on #902 

 - [x] Define context step
 - [x] Add voc.Namespaces to all steps path building
 - [x] Separate steps definition to easily find where IRIs need to be parsed
 - [x] Removed Type() method to reduce `quad.IRI` references
 - [x] Parse all IRIs using the newly provided ns

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/cayleygraph/cayley/904)
<!-- Reviewable:end -->


iddan: In another PR we are going to make all the names in LinkedQL private as the language should only be consumed
iddan: "Context" will not be an actual step in the schema. Rather later we'd refactor it to be implemented per client  as it is more of a JSON-LD serialization thing than a logical step.
dennwc: As agreed, merging earlier, feedback will be addressed in the following PRs.

Patch:
diff --git a/internal/linkedql/schema/schema.go b/internal/linkedql/schema/schema.go
index 7d8d128..b3c3aab 100644
--- a/internal/linkedql/schema/schema.go
+++ b/internal/linkedql/schema/schema.go
@@ -5,6 +5,7 @@ import (
 	"reflect"
 
 	"github.com/cayleygraph/cayley/query/linkedql"
+	_ "github.com/cayleygraph/cayley/query/linkedql/steps"
 	"github.com/cayleygraph/quad"
 	"github.com/cayleygraph/quad/voc/owl"
 	"github.com/cayleygraph/quad/voc/rdf"
@@ -19,9 +20,13 @@ var (
 	value            = reflect.TypeOf((*quad.Value)(nil)).Elem()
 	operator         = reflect.TypeOf((*linkedql.Operator)(nil)).Elem()
 	propertyPath     = reflect.TypeOf((*linkedql.PropertyPath)(nil)).Elem()
+	stringMap        = reflect.TypeOf(map[string]string{})
 )
 
 func typeToRange(t reflect.Type) string {
+	if t == stringMap {
+		return "rdf:JSON"
+	}
 	if t.Kind() == reflect.Slice {
 		return typeToRange(t.Elem())
 	}
diff --git a/query/linkedql/entity_identfier.go b/query/linkedql/entity_identfier.go
new file mode 100644
index 0000000..72e674f
--- /dev/null
+++ b/query/linkedql/entity_identfier.go
@@ -0,0 +1,38 @@
+package linkedql
+
+import "github.com/cayleygraph/quad"
+
+import "github.com/cayleygraph/quad/voc"
+
+// EntityIdentifier is an interface to be used where a single entity identifier is expected.
+type EntityIdentifier interface {
+	BuildIdentifier(ns *voc.Namespaces) (quad.Value, error)
+}
+
+// EntityIRI is an entity IRI.
+type EntityIRI quad.IRI
+
+// BuildIdentifier implements EntityIdentifier
+func (iri EntityIRI) BuildIdentifier(ns *voc.Namespaces) (quad.Value, error) {
+	return quad.IRI(iri).FullWith(ns), nil
+}
+
+// EntityBNode is an entity BNode.
+type EntityBNode quad.BNode
+
+// BuildIdentifier implements EntityIdentifier
+func (i EntityBNode) BuildIdentifier(ns *voc.Namespaces) (quad.Value, error) {
+	return quad.BNode(i), nil
+}
+
+// EntityIdentifierString is an entity IRI or BNode strings.
+type EntityIdentifierString string
+
+// BuildIdentifier implements EntityIdentifier
+func (i EntityIdentifierString) BuildIdentifier(ns *voc.Namespaces) (quad.Value, error) {
+	identifier, err := parseIdentifier(string(i))
+	if err != nil {
+		return nil, err
+	}
+	return AbsoluteValue(identifier, ns), nil
+}
diff --git a/query/linkedql/iter_docs.go b/query/linkedql/iter_docs.go
index 5d15d29..335f015 100644
--- a/query/linkedql/iter_docs.go
+++ b/query/linkedql/iter_docs.go
@@ -23,7 +23,7 @@ type DocumentIterator struct {
 
 // NewDocumentIterator returns a new DocumentIterator for a QuadStore and Path.
 func NewDocumentIterator(valueIt *ValueIterator) *DocumentIterator {
-	tagsIt := &TagsIterator{valueIt: valueIt, selected: nil}
+	tagsIt := &TagsIterator{ValueIt: valueIt, Selected: nil}
 	return &DocumentIterator{tagsIt: tagsIt, current: -1}
 }
 
@@ -32,7 +32,7 @@ func (it *DocumentIterator) Next(ctx context.Context) bool {
 	if it.properties == nil {
 		it.properties = make(idToProperties)
 		for it.tagsIt.Next(ctx) {
-			id := it.tagsIt.valueIt.Value()
+			id := it.tagsIt.ValueIt.Value()
 			tags := it.tagsIt.getTags()
 			it.ids = append(it.ids, id)
 			for k, v := range tags {
diff --git a/query/linkedql/iter_tags.go b/query/linkedql/iter_tags.go
index a4668af..c0b0c76 100644
--- a/query/linkedql/iter_tags.go
+++ b/query/linkedql/iter_tags.go
@@ -13,28 +13,28 @@ var _ query.Iterator = (*TagsIterator)(nil)
 // TagsIterator is a result iterator for records consisting of selected tags
 // or all the tags in the query.
 type TagsIterator struct {
-	valueIt  *ValueIterator
-	selected []string
+	ValueIt  *ValueIterator
+	Selected []string
 }
 
 // Next implements query.Iterator.
 func (it *TagsIterator) Next(ctx context.Context) bool {
-	return it.valueIt.Next(ctx)
+	return it.ValueIt.Next(ctx)
 }
 
 func (it *TagsIterator) getTags() map[string]interface{} {
 	refTags := make(map[string]refs.Ref)
-	it.valueIt.scanner.TagResults(refTags)
+	it.ValueIt.scanner.TagResults(refTags)
 
 	tags := make(map[string]interface{})
 	// FIXME(iddan): only convert when collation is JSON/JSON-LD, leave as Ref otherwise
-	if it.selected != nil {
-		for _, tag := range it.selected {
-			tags[tag] = jsonld.FromValue(it.valueIt.getName(refTags[tag]))
+	if it.Selected != nil {
+		for _, tag := range it.Selected {
+			tags[tag] = jsonld.FromValue(it.ValueIt.getName(refTags[tag]))
 		}
 	} else {
 		for tag, ref := range refTags {
-			tags[tag] = jsonld.FromValue(it.valueIt.getName(ref))
+			tags[tag] = jsonld.FromValue(it.ValueIt.getName(ref))
 		}
 	}
 
@@ -48,10 +48,10 @@ func (it *TagsIterator) Result() interface{} {
 
 // Err implements query.Iterator.
 func (it *TagsIterator) Err() error {
-	return it.valueIt.Err()
+	return it.ValueIt.Err()
 }
 
 // Close implements query.Iterator.
 func (it *TagsIterator) Close() error {
-	return it.valueIt.Close()
+	return it.ValueIt.Close()
 }
diff --git a/query/linkedql/iter_values.go b/query/linkedql/iter_values.go
index 9f926e5..d391970 100644
--- a/query/linkedql/iter_values.go
+++ b/query/linkedql/iter_values.go
@@ -10,6 +10,7 @@ import (
 	"github.com/cayleygraph/cayley/query/path"
 	"github.com/cayleygraph/quad"
 	"github.com/cayleygraph/quad/jsonld"
+	"github.com/cayleygraph/quad/voc"
 )
 
 var _ query.Iterator = (*ValueIterator)(nil)
@@ -28,8 +29,8 @@ func NewValueIterator(p *path.Path, namer refs.Namer) *ValueIterator {
 
 // NewValueIteratorFromPathStep attempts to build a path from PathStep and return a new ValueIterator of it.
 // If BuildPath fails returns error.
-func NewValueIteratorFromPathStep(step PathStep, qs graph.QuadStore) (*ValueIterator, error) {
-	p, err := step.BuildPath(qs)
+func NewValueIteratorFromPathStep(step PathStep, qs graph.QuadStore, ns *voc.Namespaces) (*ValueIterator, error) {
+	p, err := step.BuildPath(qs, ns)
 	if err != nil {
 		return nil, err
 	}
diff --git a/query/linkedql/linkedql.go b/query/linkedql/linkedql.go
index 7efdf72..d4c2363 100644
--- a/query/linkedql/linkedql.go
+++ b/query/linkedql/linkedql.go
@@ -54,5 +54,6 @@ func (s *Session) Execute(ctx context.Context, query string, opt query.Options)
 	if !ok {
 		return nil, errors.New("must execute a valid step")
 	}
-	return step.BuildIterator(s.qs)
+	ns := voc.Namespaces{}
+	return step.BuildIterator(s.qs, &ns)
 }
diff --git a/query/linkedql/operator.go b/query/linkedql/operator.go
new file mode 100644
index 0000000..99ef3ad
--- /dev/null
+++ b/query/linkedql/operator.go
@@ -0,0 +1,9 @@
+package linkedql
+
+import "github.com/cayleygraph/cayley/query/path"
+
+// Operator represents an operator used in a query inside a step (e.g. greater than).
+type Operator interface {
+	RegistryItem
+	Apply(p *path.Path) (*path.Path, error)
+}
diff --git a/query/linkedql/property_path.go b/query/linkedql/property_path.go
index c26d99f..d823757 100644
--- a/query/linkedql/property_path.go
+++ b/query/linkedql/property_path.go
@@ -6,20 +6,16 @@ import (
 	"github.com/cayleygraph/cayley/graph"
 	"github.com/cayleygraph/cayley/query/path"
 	"github.com/cayleygraph/quad"
+	"github.com/cayleygraph/quad/voc"
 )
 
-type propertyPathI interface {
-	BuildPath(qs graph.QuadStore) (*path.Path, error)
+type PropertyPathI interface {
+	BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error)
 }
 
 // PropertyPath is an interface to be used where a path of properties is expected.
 type PropertyPath struct {
-	p propertyPathI
-}
-
-// Type implements Step
-func (*PropertyPath) Type() string {
-	return Prefix + "PropertyPath"
+	PropertyPathI
 }
 
 // Description implements Step.
@@ -27,10 +23,6 @@ func (*PropertyPath) Description() string {
 	return "PropertyPath is a string, multiple strins or path describing a set of properties"
 }
 
-func (p *PropertyPath) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	return p.p.BuildPath(qs)
-}
-
 // UnmarshalJSON implements RawMessage
 func (p *PropertyPath) UnmarshalJSON(data []byte) error {
 	var errors []error
@@ -38,7 +30,7 @@ func (p *PropertyPath) UnmarshalJSON(data []byte) error {
 	var propertyIRIs PropertyIRIs
 	err := json.Unmarshal(data, &propertyIRIs)
 	if err == nil {
-		p.p = propertyIRIs
+		p.PropertyPathI = propertyIRIs
 		return nil
 	}
 	errors = append(errors, err)
@@ -46,7 +38,7 @@ func (p *PropertyPath) UnmarshalJSON(data []byte) error {
 	var propertyIRIStrings PropertyIRIStrings
 	err = json.Unmarshal(data, &propertyIRIStrings)
 	if err == nil {
-		p.p = propertyIRIStrings
+		p.PropertyPathI = propertyIRIStrings
 		return nil
 	}
 	errors = append(errors, err)
@@ -54,7 +46,7 @@ func (p *PropertyPath) UnmarshalJSON(data []byte) error {
 	var propertyIRI PropertyIRI
 	err = json.Unmarshal(data, &propertyIRI)
 	if err == nil {
-		p.p = propertyIRI
+		p.PropertyPathI = propertyIRI
 		return nil
 	}
 	errors = append(errors, err)
@@ -62,7 +54,7 @@ func (p *PropertyPath) UnmarshalJSON(data []byte) error {
 	var propertyIRIString PropertyIRIString
 	err = json.Unmarshal(data, &propertyIRIString)
 	if err == nil {
-		p.p = propertyIRIString
+		p.PropertyPathI = propertyIRIString
 		return nil
 	}
 	errors = append(errors, err)
@@ -71,44 +63,46 @@ func (p *PropertyPath) UnmarshalJSON(data []byte) error {
 }
 
 // PropertyIRIs is a slice of property IRIs.
-type PropertyIRIs []quad.IRI
+type PropertyIRIs []PropertyIRI
 
 // BuildPath implements PropertyPath.
-func (p PropertyIRIs) BuildPath(qs graph.QuadStore) (*path.Path, error) {
+func (p PropertyIRIs) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
 	var values []quad.Value
 	for _, iri := range p {
-		values = append(values, iri)
+		values = append(values, iri.full(ns))
 	}
-	vertex := &Vertex{Values: values}
-	return vertex.BuildPath(qs)
+	return path.StartPath(qs, values...), nil
 }
 
 // PropertyIRIStrings is a slice of property IRI strings.
 type PropertyIRIStrings []string
 
 // BuildPath implements PropertyPath.
-func (p PropertyIRIStrings) BuildPath(qs graph.QuadStore) (*path.Path, error) {
+func (p PropertyIRIStrings) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
 	var iris PropertyIRIs
 	for _, iri := range p {
-		iris = append(iris, quad.IRI(iri))
+		iris = append(iris, PropertyIRI(iri))
 	}
-	return iris.BuildPath(qs)
+	return iris.BuildPath(qs, ns)
 }
 
 // PropertyIRI is an IRI of a Property
 type PropertyIRI quad.IRI
 
+func (p PropertyIRI) full(ns *voc.Namespaces) quad.IRI {
+	return quad.IRI(p).FullWith(ns)
+}
+
 // BuildPath implements PropertyPath
-func (p PropertyIRI) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	vertex := &Vertex{Values: []quad.Value{quad.IRI(p)}}
-	return vertex.BuildPath(qs)
+func (p PropertyIRI) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	return path.StartPath(qs, p.full(ns)), nil
 }
 
 // PropertyIRIString is a string of IRI of a Property
 type PropertyIRIString string
 
 // BuildPath implements PropertyPath
-func (p PropertyIRIString) BuildPath(qs graph.QuadStore) (*path.Path, error) {
+func (p PropertyIRIString) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
 	iri := PropertyIRI(p)
-	return iri.BuildPath(qs)
+	return iri.BuildPath(qs, ns)
 }
diff --git a/query/linkedql/registry.go b/query/linkedql/registry.go
index 4e12e67..260380e 100644
--- a/query/linkedql/registry.go
+++ b/query/linkedql/registry.go
@@ -31,7 +31,6 @@ func RegisteredTypes() []string {
 
 // RegistryItem in the registry.
 type RegistryItem interface {
-	Type() quad.IRI
 	Description() string
 }
 
@@ -44,7 +43,7 @@ func Register(typ RegistryItem) {
 	if tp.Kind() != reflect.Struct {
 		panic("only structs are allowed")
 	}
-	name := string(typ.Type())
+	name := Prefix + tp.Name()
 	if _, ok := typeByName[name]; ok {
 		panic("this name was already registered")
 	}
diff --git a/query/linkedql/step_types.go b/query/linkedql/step_types.go
new file mode 100644
index 0000000..924665f
--- /dev/null
+++ b/query/linkedql/step_types.go
@@ -0,0 +1,25 @@
+package linkedql
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+// Step is a logical part in the query
+type Step interface {
+	RegistryItem
+}
+
+// IteratorStep is a step that can build an Iterator.
+type IteratorStep interface {
+	Step
+	BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error)
+}
+
+// PathStep is a Step that can build a Path.
+type PathStep interface {
+	Step
+	BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error)
+}
diff --git a/query/linkedql/steps.go b/query/linkedql/steps.go
deleted file mode 100644
index bb1fcb6..0000000
--- a/query/linkedql/steps.go
+++ /dev/null
@@ -1,1390 +0,0 @@
-package linkedql
-
-import (
-	"github.com/cayleygraph/cayley/graph"
-	"github.com/cayleygraph/cayley/graph/iterator"
-	"github.com/cayleygraph/cayley/query"
-	"github.com/cayleygraph/cayley/query/path"
-	"github.com/cayleygraph/quad"
-)
-
-func init() {
-	Register(&Entity{})
-	Register(&Entities{})
-	Register(&Vertex{})
-	Register(&Placeholder{})
-	Register(&Visit{})
-	Register(&Out{})
-	Register(&As{})
-	Register(&Intersect{})
-	Register(&Is{})
-	Register(&Back{})
-	Register(&Both{})
-	Register(&Count{})
-	Register(&Difference{})
-	Register(&Filter{})
-	Register(&Follow{})
-	Register(&FollowReverse{})
-	Register(&Has{})
-	Register(&HasReverse{})
-	Register(&VisitReverse{})
-	Register(&In{})
-	Register(&ReversePropertyNames{})
-	Register(&Labels{})
-	Register(&Limit{})
-	Register(&PropertyNames{})
-	Register(&Properties{})
-	Register(&ReversePropertyNamesAs{})
-	Register(&PropertyNamesAs{})
-	Register(&ReverseProperties{})
-	Register(&Skip{})
-	Register(&Union{})
-	Register(&Unique{})
-	Register(&Order{})
-	Register(&Optional{})
-	Register(&Where{})
-	Register(&LessThan{})
-	Register(&LessThanEquals{})
-	Register(&GreaterThan{})
-	Register(&GreaterThanEquals{})
-}
-
-// Step is the tree representation of a call in a Path context.
-//
-// Example:
-// 		g.V(g.IRI("alice"))
-// 		is represented as
-// 		&Vertex{ Values: []quad.Value{quad.IRI("alice")} }
-//
-// 		g.V().out(g.IRI("likes"))
-// 		is represented as
-// 		&Out{ Properties: []quad.Value{quad.IRI("likes")}, From: &Vertex{} }
-type Step interface {
-	RegistryItem
-}
-
-// IteratorStep is a step that can build an Iterator.
-type IteratorStep interface {
-	Step
-	BuildIterator(qs graph.QuadStore) (query.Iterator, error)
-}
-
-// PathStep is a Step that can build a Path.
-type PathStep interface {
-	Step
-	BuildPath(qs graph.QuadStore) (*path.Path, error)
-}
-
-// EntityIdentifier is an interface to be used where a single entity identifier is expected.
-type EntityIdentifier interface {
-	BuildIdentifier() (quad.Value, error)
-}
-
-// EntityIRI is an entity IRI.
-type EntityIRI quad.IRI
-
-// BuildIdentifier implements EntityIdentifier
-func (i EntityIRI) BuildIdentifier() (quad.Value, error) {
-	return quad.IRI(i), nil
-}
-
-// EntityBNode is an entity BNode.
-type EntityBNode quad.BNode
-
-// BuildIdentifier implements EntityIdentifier
-func (i EntityBNode) BuildIdentifier() (quad.Value, error) {
-	return quad.BNode(i), nil
-}
-
-// EntityIdentifierString is an entity IRI or BNode strings.
-type EntityIdentifierString string
-
-// BuildIdentifier implements EntityIdentifier
-func (i EntityIdentifierString) BuildIdentifier() (quad.Value, error) {
-	return parseIdentifier(string(i))
-}
-
-var _ IteratorStep = (*Entity)(nil)
-var _ PathStep = (*Entity)(nil)
-
-// Entity corresponds to g.Entity().
-type Entity struct {
-	Identifier EntityIdentifier `json:"identifier"`
-}
-
-// Type implements Step.
-func (s *Entity) Type() quad.IRI {
-	return Prefix + "Entity"
-}
-
-// Description implements Step.
-func (s *Entity) Description() string {
-	return "resolves to the object matching given identifier in the graph."
-}
-
-// BuildIterator implements IteratorStep.
-func (s *Entity) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *Entity) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	identifier, err := s.Identifier.BuildIdentifier()
-	if err != nil {
-		return nil, err
-	}
-	return path.StartPath(qs, identifier), nil
-}
-
-var _ IteratorStep = (*Entities)(nil)
-var _ PathStep = (*Entities)(nil)
-
-// Entities corresponds to g.Entities().
-type Entities struct {
-	Identifiers []EntityIdentifier `json:"identifiers"`
-}
-
-// Type implements Step.
-func (s *Entities) Type() quad.IRI {
-	return Prefix + "Entities"
-}
-
-// Description implements Step.
-func (s *Entities) Description() string {
-	return "resolves to all the existing objects in the graph. If provided with identifiers resolves to a sublist of all the existing identifiers in the graph."
-}
-
-// BuildIterator implements IteratorStep.
-func (s *Entities) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *Entities) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	var values []quad.Value
-	for _, identifier := range s.Identifiers {
-		value, err := identifier.BuildIdentifier()
-		if err != nil {
-			return nil, err
-		}
-		values = append(values, value)
-	}
-	// TODO(iddan): Construct a path that only match entities
-	return path.StartPath(qs, values...), nil
-}
-
-var _ IteratorStep = (*Vertex)(nil)
-var _ PathStep = (*Vertex)(nil)
-
-// Vertex corresponds to g.Vertex() and g.V().
-type Vertex struct {
-	Values []quad.Value `json:"values"`
-}
-
-// Type implements Step.
-func (s *Vertex) Type() quad.IRI {
-	return Prefix + "Vertex"
-}
-
-// Description implements Step.
-func (s *Vertex) Description() string {
-	return "resolves to all the existing objects and primitive values in the graph. If provided with values resolves to a sublist of all the existing values in the graph."
-}
-
-// BuildIterator implements IteratorStep.
-func (s *Vertex) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *Vertex) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	return path.StartPath(qs, s.Values...), nil
-}
-
-var _ PathStep = (*Placeholder)(nil)
-
-// Placeholder corresponds to .Placeholder().
-type Placeholder struct{}
-
-// Type implements Step.
-func (s *Placeholder) Type() quad.IRI {
-	return Prefix + "Placeholder"
-}
-
-// Description implements Step.
-func (s *Placeholder) Description() string {
-	return "is like Vertex but resolves to the values in the context it is placed in. It should only be used where a PathStep is expected and can't be resolved on its own."
-}
-
-// BuildPath implements PathStep.
-func (s *Placeholder) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	return path.StartMorphism(), nil
-}
-
-var _ IteratorStep = (*Visit)(nil)
-var _ PathStep = (*Visit)(nil)
-
-// Visit corresponds to .view().
-type Visit struct {
-	From       PathStep     `json:"from"`
-	Properties PropertyPath `json:"properties"`
-}
-
-// Type implements Step.
-func (s *Visit) Type() quad.IRI {
-	return Prefix + "Visit"
-}
-
-// Description implements Step.
-func (s *Visit) Description() string {
-	return "resolves to the values of the given property or properties in via of the current objects. If via is a path it's resolved values will be used as properties."
-}
-
-// BuildIterator implements IteratorStep.
-func (s *Visit) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *Visit) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	viaPath, err := s.Properties.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return fromPath.Out(viaPath), nil
-}
-
-var _ IteratorStep = (*Out)(nil)
-var _ PathStep = (*Out)(nil)
-
-// Out is an alias for View.
-type Out struct {
-	Visit
-}
-
-// Type implements Step.
-func (s *Out) Type() quad.IRI {
-	return Prefix + "Out"
-}
-
-// Description implements Step.
-func (s *Out) Description() string {
-	return "aliases for View"
-}
-
-var _ IteratorStep = (*As)(nil)
-var _ PathStep = (*As)(nil)
-
-// As corresponds to .tag().
-type As struct {
-	From PathStep `json:"from"`
-	Name string   `json:"name"`
-}
-
-// Type implements Step.
-func (s *As) Type() quad.IRI {
-	return Prefix + "As"
-}
-
-// Description implements Step.
-func (s *As) Description() string {
-	return "assigns the resolved values of the from step to a given name. The name can be used with the Select and Documents steps to retrieve the values or to return to the values in further steps with the Back step. It resolves to the values of the from step."
-}
-
-// BuildIterator implements IteratorStep.
-func (s *As) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *As) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return fromPath.Tag(s.Name), nil
-}
-
-var _ IteratorStep = (*Intersect)(nil)
-var _ PathStep = (*Intersect)(nil)
-
-// Intersect represents .intersect() and .and().
-type Intersect struct {
-	From  PathStep   `json:"from"`
-	Steps []PathStep `json:"steps"`
-}
-
-// Type implements Step.
-func (s *Intersect) Type() quad.IRI {
-	return Prefix + "Intersect"
-}
-
-// Description implements Step.
-func (s *Intersect) Description() string {
-	return "resolves to all the same values resolved by the from step and the provided steps."
-}
-
-// BuildIterator implements IteratorStep.
-func (s *Intersect) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *Intersect) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	p := fromPath
-	for _, step := range s.Steps {
-		stepPath, err := step.BuildPath(qs)
-		if err != nil {
-			return nil, err
-		}
-		p = p.And(stepPath)
-	}
-	return p, nil
-}
-
-var _ IteratorStep = (*Is)(nil)
-var _ PathStep = (*Is)(nil)
-
-// Is corresponds to .back().
-type Is struct {
-	From   PathStep     `json:"from"`
-	Values []quad.Value `json:"values"`
-}
-
-// Type implements Step.
-func (s *Is) Type() quad.IRI {
-	return Prefix + "Is"
-}
-
-// Description implements Step.
-func (s *Is) Description() string {
-	return "resolves to all the values resolved by the from step which are included in provided values."
-}
-
-// BuildIterator implements IteratorStep.
-func (s *Is) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *Is) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return fromPath.Is(s.Values...), nil
-}
-
-var _ IteratorStep = (*Back)(nil)
-var _ PathStep = (*Back)(nil)
-
-// Back corresponds to .back().
-type Back struct {
-	From PathStep `json:"from"`
-	Name string   `json:"name"`
-}
-
-// Type implements Step.
-func (s *Back) Type() quad.IRI {
-	return Prefix + "Back"
-}
-
-// Description implements Step.
-func (s *Back) Description() string {
-	return "resolves to the values of the previous the step or the values assigned to name in a former step."
-}
-
-// BuildIterator implements IteratorStep.
-func (s *Back) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *Back) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return fromPath.Back(s.Name), nil
-}
-
-var _ IteratorStep = (*Both)(nil)
-var _ PathStep = (*Both)(nil)
-
-// Both corresponds to .both().
-type Both struct {
-	From       PathStep     `json:"from"`
-	Properties PropertyPath `json:"properties"`
-}
-
-// Type implements Step.
-func (s *Both) Type() quad.IRI {
-	return Prefix + "Both"
-}
-
-// Description implements Step.
-func (s *Both) Description() string {
-	return "is like View but resolves to both the object values and references to the values of the given properties in via. It is the equivalent for the Union of View and ViewReverse of the same property."
-}
-
-// BuildIterator implements IteratorStep.
-func (s *Both) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *Both) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	viaPath, err := s.Properties.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return fromPath.Both(viaPath), nil
-}
-
-var _ IteratorStep = (*Count)(nil)
-var _ PathStep = (*Count)(nil)
-
-// Count corresponds to .count().
-type Count struct {
-	From PathStep `json:"from"`
-}
-
-// Type implements Step.
-func (s *Count) Type() quad.IRI {
-	return Prefix + "Count"
-}
-
-// Description implements Step.
-func (s *Count) Description() string {
-	return "resolves to the number of the resolved values of the from step"
-}
-
-// BuildIterator implements IteratorStep.
-func (s *Count) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *Count) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return fromPath.Count(), nil
-}
-
-var _ IteratorStep = (*Difference)(nil)
-var _ PathStep = (*Difference)(nil)
-
-// Difference corresponds to .difference().
-type Difference struct {
-	From  PathStep   `json:"from"`
-	Steps []PathStep `json:"steps"`
-}
-
-// Type implements Step.
-func (s *Difference) Type() quad.IRI {
-	return Prefix + "Difference"
-}
-
-// Description implements Step.
-func (s *Difference) Description() string {
-	return "resolves to all the values resolved by the from step different then the values resolved by the provided steps. Caution: it might be slow to execute."
-}
-
-// BuildIterator implements IteratorStep.
-func (s *Difference) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *Difference) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	path := fromPath
-	for _, step := range s.Steps {
-		p, err := step.BuildPath(qs)
-		if err != nil {
-			return nil, err
-		}
-		path = path.Except(p)
-	}
-	return path, nil
-}
-
-var _ IteratorStep = (*Filter)(nil)
-var _ PathStep = (*Filter)(nil)
-
-// Filter corresponds to filter().
-type Filter struct {
-	From   PathStep `json:"from"`
-	Filter Operator `json:"filter"`
-}
-
-// Type implements Step.
-func (s *Filter) Type() quad.IRI {
-	return Prefix + "Filter"
-}
-
-// Description implements Step.
-func (s *Filter) Description() string {
-	return "applies constraints to a set of nodes. Can be used to filter values by range or match strings."
-}
-
-// BuildIterator implements IteratorStep.
-func (s *Filter) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *Filter) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromIt, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return s.Filter.Apply(fromIt)
-}
-
-var _ IteratorStep = (*Follow)(nil)
-var _ PathStep = (*Follow)(nil)
-
-// Follow corresponds to .follow().
-type Follow struct {
-	From     PathStep `json:"from"`
-	Followed PathStep `json:"followed"`
-}
-
-// Type implements Step.
-func (s *Follow) Type() quad.IRI {
-	return Prefix + "Follow"
-}
-
-// Description implements Step.
-func (s *Follow) Description() string {
-	return "is the way to use a path prepared with Morphism. Applies the path chain on the morphism object to the current path. Starts as if at the g.M() and follows through the morphism path."
-}
-
-// BuildIterator implements IteratorStep.
-func (s *Follow) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *Follow) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	p, err := s.Followed.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return fromPath.Follow(p), nil
-}
-
-var _ IteratorStep = (*FollowReverse)(nil)
-var _ PathStep = (*FollowReverse)(nil)
-
-// FollowReverse corresponds to .followR().
-type FollowReverse struct {
-	From     PathStep `json:"from"`
-	Followed PathStep `json:"followed"`
-}
-
-// Type implements Step.
-func (s *FollowReverse) Type() quad.IRI {
-	return Prefix + "FollowReverse"
-}
-
-// Description implements Step.
-func (s *FollowReverse) Description() string {
-	return "is the same as follow but follows the chain in the reverse direction. Flips View and ViewReverse where appropriate, the net result being a virtual predicate followed in the reverse direction. Starts at the end of the morphism and follows it backwards (with appropriate flipped directions) to the g.M() location."
-}
-
-// BuildIterator implements IteratorStep.
-func (s *FollowReverse) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *FollowReverse) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	p, err := s.Followed.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return fromPath.FollowReverse(p), nil
-}
-
-var _ IteratorStep = (*Has)(nil)
-var _ PathStep = (*Has)(nil)
-
-// Has corresponds to .has().
-type Has struct {
-	From     PathStep     `json:"from"`
-	Property PropertyPath `json:"property"`
-	Values   []quad.Value `json:"values"`
-}
-
-// Type implements Step.
-func (s *Has) Type() quad.IRI {
-	return Prefix + "Has"
-}
-
-// Description implements Step.
-func (s *Has) Description() string {
-	return "filters all paths which are, at this point, on the subject for the given predicate and object, but do not follow the path, merely filter the possible paths. Usually useful for starting with all nodes, or limiting to a subset depending on some predicate/value pair."
-}
-
-// BuildIterator implements IteratorStep.
-func (s *Has) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *Has) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	viaPath, err := s.Property.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return fromPath.Has(viaPath, s.Values...), nil
-}
-
-var _ IteratorStep = (*HasReverse)(nil)
-var _ PathStep = (*HasReverse)(nil)
-
-// HasReverse corresponds to .hasR().
-type HasReverse struct {
-	From     PathStep     `json:"from"`
-	Property PropertyPath `json:"property"`
-	Values   []quad.Value `json:"values"`
-}
-
-// Type implements Step.
-func (s *HasReverse) Type() quad.IRI {
-	return Prefix + "HasReverse"
-}
-
-// Description implements Step.
-func (s *HasReverse) Description() string {
-	return "is the same as Has, but sets constraint in reverse direction."
-}
-
-// BuildIterator implements IteratorStep.
-func (s *HasReverse) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *HasReverse) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	viaPath, err := s.Property.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return fromPath.HasReverse(viaPath, s.Values...), nil
-}
-
-var _ IteratorStep = (*VisitReverse)(nil)
-var _ PathStep = (*VisitReverse)(nil)
-
-// VisitReverse corresponds to .viewReverse().
-type VisitReverse struct {
-	From       PathStep     `json:"from"`
-	Properties PropertyPath `json:"properties"`
-}
-
-// Type implements Step.
-func (s *VisitReverse) Type() quad.IRI {
-	return Prefix + "VisitReverse"
-}
-
-// Description implements Step.
-func (s *VisitReverse) Description() string {
-	return "is the inverse of View. Starting with the nodes in `path` on the object, follow the quads with predicates defined by `predicatePath` to their subjects."
-}
-
-// BuildIterator implements IteratorStep.
-func (s *VisitReverse) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *VisitReverse) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	viaPath, err := s.Properties.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return fromPath.In(viaPath), nil
-}
-
-var _ IteratorStep = (*In)(nil)
-var _ PathStep = (*In)(nil)
-
-// In is an alias for ViewReverse.
-type In struct {
-	VisitReverse
-}
-
-// Type implements Step.
-func (s *In) Type() quad.IRI {
-	return Prefix + "In"
-}
-
-// Description implements Step.
-func (s *In) Description() string {
-	return "aliases for ViewReverse"
-}
-
-var _ IteratorStep = (*ReversePropertyNames)(nil)
-var _ PathStep = (*ReversePropertyNames)(nil)
-
-// ReversePropertyNames corresponds to .reversePropertyNames().
-type ReversePropertyNames struct {
-	From PathStep `json:"from"`
-}
-
-// Type implements Step.
-func (s *ReversePropertyNames) Type() quad.IRI {
-	return Prefix + "ReversePropertyNames"
-}
-
-// Description implements Step.
-func (s *ReversePropertyNames) Description() string {
-	return "gets the list of predicates that are pointing in to a node."
-}
-
-// BuildIterator implements IteratorStep.
-func (s *ReversePropertyNames) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *ReversePropertyNames) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return fromPath.InPredicates(), nil
-}
-
-var _ IteratorStep = (*Labels)(nil)
-var _ PathStep = (*Labels)(nil)
-
-// Labels corresponds to .labels().
-type Labels struct {
-	From PathStep `json:"from"`
-}
-
-// Type implements Step.
-func (s *Labels) Type() quad.IRI {
-	return Prefix + "Labels"
-}
-
-// Description implements Step.
-func (s *Labels) Description() string {
-	return "gets the list of inbound and outbound quad labels"
-}
-
-// BuildIterator implements IteratorStep.
-func (s *Labels) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *Labels) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return fromPath.Labels(), nil
-}
-
-var _ IteratorStep = (*Limit)(nil)
-var _ PathStep = (*Limit)(nil)
-
-// Limit corresponds to .limit().
-type Limit struct {
-	From  PathStep `json:"from"`
-	Limit int64    `json:"limit"`
-}
-
-// Type implements Step.
-func (s *Limit) Type() quad.IRI {
-	return Prefix + "Limit"
-}
-
-// Description implements Step.
-func (s *Limit) Description() string {
-	return "limits a number of nodes for current path."
-}
-
-// BuildIterator implements IteratorStep.
-func (s *Limit) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *Limit) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return fromPath.Limit(s.Limit), nil
-}
-
-var _ IteratorStep = (*PropertyNames)(nil)
-var _ PathStep = (*PropertyNames)(nil)
-
-// PropertyNames corresponds to .propertyNames().
-type PropertyNames struct {
-	From PathStep `json:"from"`
-}
-
-// Type implements Step.
-func (s *PropertyNames) Type() quad.IRI {
-	return Prefix + "PropertyNames"
-}
-
-// Description implements Step.
-func (s *PropertyNames) Description() string {
-	return "gets the list of predicates that are pointing out from a node."
-}
-
-// BuildIterator implements IteratorStep.
-func (s *PropertyNames) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *PropertyNames) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return fromPath.OutPredicates(), nil
-}
-
-var _ IteratorStep = (*Properties)(nil)
-var _ PathStep = (*Properties)(nil)
-
-// Properties corresponds to .properties().
-type Properties struct {
-	From PathStep `json:"from"`
-	// TODO(iddan): Use PropertyPath
-	Names []quad.IRI `json:"names"`
-}
-
-// Type implements Step.
-func (s *Properties) Type() quad.IRI {
-	return Prefix + "Properties"
-}
-
-// Description implements Step.
-func (s *Properties) Description() string {
-	return "adds tags for all properties of the current entity"
-}
-
-// BuildIterator implements IteratorStep.
-// TODO(iddan): Default tag to Via.
-func (s *Properties) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *Properties) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	p := fromPath
-	if s.Names != nil {
-		for _, name := range s.Names {
-			tag := string(name)
-			p = p.Save(name, tag)
-		}
-	} else {
-		panic("Not implemented: should tag all properties")
-	}
-	return p, nil
-}
-
-var _ IteratorStep = (*ReversePropertyNamesAs)(nil)
-var _ PathStep = (*ReversePropertyNamesAs)(nil)
-
-// ReversePropertyNamesAs corresponds to .reversePropertyNamesAs().
-type ReversePropertyNamesAs struct {
-	From PathStep `json:"from"`
-	Tag  string   `json:"tag"`
-}
-
-// Type implements Step.
-func (s *ReversePropertyNamesAs) Type() quad.IRI {
-	return Prefix + "ReversePropertyNamesAs"
-}
-
-// Description implements Step.
-func (s *ReversePropertyNamesAs) Description() string {
-	return "tags the list of predicates that are pointing in to a node."
-}
-
-// BuildIterator implements IteratorStep.
-func (s *ReversePropertyNamesAs) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *ReversePropertyNamesAs) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return fromPath.SavePredicates(true, s.Tag), nil
-}
-
-var _ IteratorStep = (*PropertyNamesAs)(nil)
-var _ PathStep = (*PropertyNamesAs)(nil)
-
-// PropertyNamesAs corresponds to .propertyNamesAs().
-type PropertyNamesAs struct {
-	From PathStep `json:"from"`
-	Tag  string   `json:"tag"`
-}
-
-// Type implements Step.
-func (s *PropertyNamesAs) Type() quad.IRI {
-	return Prefix + "PropertyNamesAs"
-}
-
-// Description implements Step.
-func (s *PropertyNamesAs) Description() string {
-	return "tags the list of predicates that are pointing out from a node."
-}
-
-// BuildIterator implements IteratorStep.
-func (s *PropertyNamesAs) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *PropertyNamesAs) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return fromPath.SavePredicates(false, s.Tag), nil
-}
-
-var _ IteratorStep = (*ReverseProperties)(nil)
-var _ PathStep = (*ReverseProperties)(nil)
-
-// ReverseProperties corresponds to .reverseProperties().
-type ReverseProperties struct {
-	From PathStep `json:"from"`
-	// TODO(iddan): Use property path
-	Names []quad.IRI `json:"names"`
-}
-
-// Type implements Step.
-func (s *ReverseProperties) Type() quad.IRI {
-	return Prefix + "ReverseProperties"
-}
-
-// Description implements Step.
-func (s *ReverseProperties) Description() string {
-	return "gets all the properties the current entity / value is referenced at"
-}
-
-// BuildIterator implements IteratorStep.
-func (s *ReverseProperties) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *ReverseProperties) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	p := fromPath
-	for _, name := range s.Names {
-		p = fromPath.SaveReverse(name, string(name))
-	}
-	return p, nil
-}
-
-var _ IteratorStep = (*Skip)(nil)
-var _ PathStep = (*Skip)(nil)
-
-// Skip corresponds to .skip().
-type Skip struct {
-	From   PathStep `json:"from"`
-	Offset int64    `json:"offset"`
-}
-
-// Type implements Step.
-func (s *Skip) Type() quad.IRI {
-	return Prefix + "Skip"
-}
-
-// Description implements Step.
-func (s *Skip) Description() string {
-	return "skips a number of nodes for current path."
-}
-
-// BuildIterator implements IteratorStep.
-func (s *Skip) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *Skip) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return fromPath.Skip(s.Offset), nil
-}
-
-var _ IteratorStep = (*Union)(nil)
-var _ PathStep = (*Union)(nil)
-
-// Union corresponds to .union() and .or().
-type Union struct {
-	From  PathStep   `json:"from"`
-	Steps []PathStep `json:"steps"`
-}
-
-// Type implements Step.
-func (s *Union) Type() quad.IRI {
-	return Prefix + "Union"
-}
-
-// Description implements Step.
-func (s *Union) Description() string {
-	return "returns the combined paths of the two queries. Notice that it's per-path, not per-node. Once again, if multiple paths reach the same destination, they might have had different ways of getting there (and different tags)."
-}
-
-// BuildIterator implements IteratorStep.
-func (s *Union) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *Union) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	p := fromPath
-	for _, step := range s.Steps {
-		valuePath, err := step.BuildPath(qs)
-		if err != nil {
-			return nil, err
-		}
-		p = p.Or(valuePath)
-	}
-	return p, nil
-}
-
-var _ IteratorStep = (*Unique)(nil)
-var _ PathStep = (*Unique)(nil)
-
-// Unique corresponds to .unique().
-type Unique struct {
-	From PathStep `json:"from"`
-}
-
-// Type implements Step.
-func (s *Unique) Type() quad.IRI {
-	return Prefix + "Unique"
-}
-
-// Description implements Step.
-func (s *Unique) Description() string {
-	return "removes duplicate values from the path."
-}
-
-// BuildIterator implements IteratorStep.
-func (s *Unique) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *Unique) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return fromPath.Unique(), nil
-}
-
-var _ IteratorStep = (*Order)(nil)
-var _ PathStep = (*Order)(nil)
-
-// Order corresponds to .order().
-type Order struct {
-	From PathStep `json:"from"`
-}
-
-// Type implements Step.
-func (s *Order) Type() quad.IRI {
-	return Prefix + "Order"
-}
-
-// Description implements Step.
-func (s *Order) Description() string {
-	return "sorts the results in ascending order according to the current entity / value"
-}
-
-// BuildIterator implements IteratorStep.
-func (s *Order) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *Order) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return fromPath.Order(), nil
-}
-
-var _ IteratorStep = (*Optional)(nil)
-var _ PathStep = (*Optional)(nil)
-
-// Optional corresponds to .optional().
-type Optional struct {
-	From PathStep `json:"from"`
-	Step PathStep `json:"step"`
-}
-
-// Type implements Step.
-func (s *Optional) Type() quad.IRI {
-	return Prefix + "Optional"
-}
-
-// Description implements Step.
-func (s *Optional) Description() string {
-	return "attempts to follow the given path from the current entity / value, if fails the entity / value will still be kept in the results"
-}
-
-// BuildIterator implements IteratorStep.
-func (s *Optional) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *Optional) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	p, err := s.Step.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return fromPath.Optional(p), nil
-}
-
-var _ IteratorStep = (*Where)(nil)
-var _ PathStep = (*Where)(nil)
-
-// Where corresponds to .where().
-type Where struct {
-	From  PathStep   `json:"from"`
-	Steps []PathStep `json:"steps"`
-}
-
-// Type implements Step.
-func (s *Where) Type() quad.IRI {
-	return Prefix + "Where"
-}
-
-// Description implements Step.
-func (s *Where) Description() string {
-	return "applies each provided step in steps in isolation on from"
-}
-
-// BuildIterator implements IteratorStep.
-func (s *Where) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements PathStep.
-func (s *Where) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	p := fromPath
-	for _, step := range s.Steps {
-		stepPath, err := step.BuildPath(qs)
-		if err != nil {
-			return nil, err
-		}
-		p = p.And(stepPath.Reverse())
-	}
-	return p, nil
-}
-
-var _ IteratorStep = (*LessThan)(nil)
-var _ PathStep = (*LessThan)(nil)
-
-// LessThan corresponds to lt().
-type LessThan struct {
-	From  PathStep   `json:"from"`
-	Value quad.Value `json:"value"`
-}
-
-// Type implements Step.
-func (s *LessThan) Type() quad.IRI {
-	return Prefix + "LessThan"
-}
-
-// Description implements Step.
-func (s *LessThan) Description() string {
-	return "Less than filters out values that are not less than given value"
-}
-
-// BuildIterator implements IteratorStep.
-func (s *LessThan) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements Step.
-func (s *LessThan) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return fromPath.Filter(iterator.CompareLT, s.Value), nil
-}
-
-var _ IteratorStep = (*LessThanEquals)(nil)
-var _ PathStep = (*LessThanEquals)(nil)
-
-// LessThanEquals corresponds to lte().
-type LessThanEquals struct {
-	From  PathStep   `json:"from"`
-	Value quad.Value `json:"value"`
-}
-
-// Type implements Step.
-func (s *LessThanEquals) Type() quad.IRI {
-	return Prefix + "LessThanEquals"
-}
-
-// Description implements Step.
-func (s *LessThanEquals) Description() string {
-	return "Less than equals filters out values that are not less than or equal given value"
-}
-
-// BuildIterator implements Step.
-func (s *LessThanEquals) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements Step.
-func (s *LessThanEquals) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return fromPath.Filter(iterator.CompareLTE, s.Value), nil
-}
-
-var _ IteratorStep = (*GreaterThan)(nil)
-var _ PathStep = (*GreaterThan)(nil)
-
-// GreaterThan corresponds to gt().
-type GreaterThan struct {
-	From  PathStep   `json:"from"`
-	Value quad.Value `json:"value"`
-}
-
-// Type implements Step.
-func (s *GreaterThan) Type() quad.IRI {
-	return Prefix + "GreaterThan"
-}
-
-// Description implements Step.
-func (s *GreaterThan) Description() string {
-	return "Greater than equals filters out values that are not greater than given value"
-}
-
-// BuildIterator implements Step.
-func (s *GreaterThan) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements Step.
-func (s *GreaterThan) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return fromPath.Filter(iterator.CompareGT, s.Value), nil
-}
-
-var _ IteratorStep = (*GreaterThanEquals)(nil)
-var _ PathStep = (*GreaterThanEquals)(nil)
-
-// GreaterThanEquals corresponds to gte().
-type GreaterThanEquals struct {
-	From  PathStep   `json:"from"`
-	Value quad.Value `json:"value"`
-}
-
-// Type implements Step.
-func (s *GreaterThanEquals) Type() quad.IRI {
-	return Prefix + "GreaterThanEquals"
-}
-
-// Description implements Step.
-func (s *GreaterThanEquals) Description() string {
-	return "Greater than equals filters out values that are not greater than or equal given value"
-}
-
-// BuildIterator implements Step.
-func (s *GreaterThanEquals) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return NewValueIteratorFromPathStep(s, qs)
-}
-
-// BuildPath implements Step.
-func (s *GreaterThanEquals) BuildPath(qs graph.QuadStore) (*path.Path, error) {
-	fromPath, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return fromPath.Filter(iterator.CompareGTE, s.Value), nil
-}
diff --git a/query/linkedql/steps/as.go b/query/linkedql/steps/as.go
new file mode 100644
index 0000000..63642cc
--- /dev/null
+++ b/query/linkedql/steps/as.go
@@ -0,0 +1,41 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&As{})
+}
+
+var _ linkedql.IteratorStep = (*As)(nil)
+var _ linkedql.PathStep = (*As)(nil)
+
+// As corresponds to .tag().
+type As struct {
+	From linkedql.PathStep `json:"from"`
+	Name string            `json:"name"`
+}
+
+// Description implements Step.
+func (s *As) Description() string {
+	return "assigns the resolved values of the from step to a given name. The name can be used with the Select and Documents steps to retrieve the values or to return to the values in further steps with the Back step. It resolves to the values of the from step."
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *As) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *As) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return fromPath.Tag(s.Name), nil
+}
diff --git a/query/linkedql/steps/back.go b/query/linkedql/steps/back.go
new file mode 100644
index 0000000..ced6360
--- /dev/null
+++ b/query/linkedql/steps/back.go
@@ -0,0 +1,41 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&Back{})
+}
+
+var _ linkedql.IteratorStep = (*Back)(nil)
+var _ linkedql.PathStep = (*Back)(nil)
+
+// Back corresponds to .back().
+type Back struct {
+	From linkedql.PathStep `json:"from"`
+	Name string            `json:"name"`
+}
+
+// Description implements Step.
+func (s *Back) Description() string {
+	return "resolves to the values of the previous the step or the values assigned to name in a former step."
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *Back) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *Back) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return fromPath.Back(s.Name), nil
+}
diff --git a/query/linkedql/steps/both.go b/query/linkedql/steps/both.go
new file mode 100644
index 0000000..2d0d33c
--- /dev/null
+++ b/query/linkedql/steps/both.go
@@ -0,0 +1,45 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&Both{})
+}
+
+var _ linkedql.IteratorStep = (*Both)(nil)
+var _ linkedql.PathStep = (*Both)(nil)
+
+// Both corresponds to .both().
+type Both struct {
+	From       linkedql.PathStep     `json:"from"`
+	Properties linkedql.PropertyPath `json:"properties"`
+}
+
+// Description implements Step.
+func (s *Both) Description() string {
+	return "is like View but resolves to both the object values and references to the values of the given properties in via. It is the equivalent for the Union of View and ViewReverse of the same property."
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *Both) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *Both) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	viaPath, err := s.Properties.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return fromPath.Both(viaPath), nil
+}
diff --git a/query/linkedql/steps/context.go b/query/linkedql/steps/context.go
new file mode 100644
index 0000000..7384d04
--- /dev/null
+++ b/query/linkedql/steps/context.go
@@ -0,0 +1,45 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&Context{})
+}
+
+var _ linkedql.IteratorStep = (*Context)(nil)
+var _ linkedql.PathStep = (*Context)(nil)
+
+// Context corresponds to context().
+type Context struct {
+	From  linkedql.PathStep `json:"from"`
+	Rules map[string]string `json:"rules"`
+}
+
+// Description implements Step.
+func (s *Context) Description() string {
+	return "A a set of rules for interpreting identifiers used in the query"
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *Context) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	for name, iri := range s.Rules {
+		namespace := voc.Namespace{Prefix: name, Full: iri}
+		ns.Register(namespace)
+	}
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return fromPath, nil
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *Context) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
diff --git a/query/linkedql/steps/count.go b/query/linkedql/steps/count.go
new file mode 100644
index 0000000..33c378e
--- /dev/null
+++ b/query/linkedql/steps/count.go
@@ -0,0 +1,40 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&Count{})
+}
+
+var _ linkedql.IteratorStep = (*Count)(nil)
+var _ linkedql.PathStep = (*Count)(nil)
+
+// Count corresponds to .count().
+type Count struct {
+	From linkedql.PathStep `json:"from"`
+}
+
+// Description implements Step.
+func (s *Count) Description() string {
+	return "resolves to the number of the resolved values of the from step"
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *Count) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *Count) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return fromPath.Count(), nil
+}
diff --git a/query/linkedql/steps/difference.go b/query/linkedql/steps/difference.go
new file mode 100644
index 0000000..e4d10c1
--- /dev/null
+++ b/query/linkedql/steps/difference.go
@@ -0,0 +1,49 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&Difference{})
+}
+
+var _ linkedql.IteratorStep = (*Difference)(nil)
+var _ linkedql.PathStep = (*Difference)(nil)
+
+// Difference corresponds to .difference().
+type Difference struct {
+	From  linkedql.PathStep   `json:"from"`
+	Steps []linkedql.PathStep `json:"steps"`
+}
+
+// Description implements Step.
+func (s *Difference) Description() string {
+	return "resolves to all the values resolved by the from step different then the values resolved by the provided steps. Caution: it might be slow to execute."
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *Difference) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *Difference) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	path := fromPath
+	for _, step := range s.Steps {
+		p, err := step.BuildPath(qs, ns)
+		if err != nil {
+			return nil, err
+		}
+		path = path.Except(p)
+	}
+	return path, nil
+}
diff --git a/query/linkedql/steps/entities.go b/query/linkedql/steps/entities.go
new file mode 100644
index 0000000..f5d0e4f
--- /dev/null
+++ b/query/linkedql/steps/entities.go
@@ -0,0 +1,46 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&Entities{})
+}
+
+var _ linkedql.IteratorStep = (*Entities)(nil)
+var _ linkedql.PathStep = (*Entities)(nil)
+
+// Entities corresponds to g.Entities().
+type Entities struct {
+	Identifiers []linkedql.EntityIdentifier `json:"identifiers"`
+}
+
+// Description implements Step.
+func (s *Entities) Description() string {
+	return "resolves to all the existing objects in the graph. If provided with identifiers resolves to a sublist of all the existing identifiers in the graph."
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *Entities) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *Entities) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	var values []quad.Value
+	for _, identifier := range s.Identifiers {
+		value, err := identifier.BuildIdentifier(ns)
+		if err != nil {
+			return nil, err
+		}
+		values = append(values, value)
+	}
+	// TODO(iddan): Construct a path that only match entities
+	return path.StartPath(qs, values...), nil
+}
diff --git a/query/linkedql/steps/entity.go b/query/linkedql/steps/entity.go
new file mode 100644
index 0000000..dd414eb
--- /dev/null
+++ b/query/linkedql/steps/entity.go
@@ -0,0 +1,40 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&Entity{})
+}
+
+var _ linkedql.IteratorStep = (*Entity)(nil)
+var _ linkedql.PathStep = (*Entity)(nil)
+
+// Entity corresponds to g.Entity().
+type Entity struct {
+	Identifier linkedql.EntityIdentifier `json:"identifier"`
+}
+
+// Description implements Step.
+func (s *Entity) Description() string {
+	return "resolves to the object matching given identifier in the graph."
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *Entity) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *Entity) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	identifier, err := s.Identifier.BuildIdentifier(ns)
+	if err != nil {
+		return nil, err
+	}
+	return path.StartPath(qs, identifier), nil
+}
diff --git a/query/linkedql/steps/filter.go b/query/linkedql/steps/filter.go
new file mode 100644
index 0000000..985094f
--- /dev/null
+++ b/query/linkedql/steps/filter.go
@@ -0,0 +1,41 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&Filter{})
+}
+
+var _ linkedql.IteratorStep = (*Filter)(nil)
+var _ linkedql.PathStep = (*Filter)(nil)
+
+// Filter corresponds to filter().
+type Filter struct {
+	From   linkedql.PathStep `json:"from"`
+	Filter linkedql.Operator `json:"filter"`
+}
+
+// Description implements Step.
+func (s *Filter) Description() string {
+	return "applies constraints to a set of nodes. Can be used to filter values by range or match strings."
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *Filter) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *Filter) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromIt, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return s.Filter.Apply(fromIt)
+}
diff --git a/query/linkedql/steps/follow.go b/query/linkedql/steps/follow.go
new file mode 100644
index 0000000..90b27a2
--- /dev/null
+++ b/query/linkedql/steps/follow.go
@@ -0,0 +1,45 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&Follow{})
+}
+
+var _ linkedql.IteratorStep = (*Follow)(nil)
+var _ linkedql.PathStep = (*Follow)(nil)
+
+// Follow corresponds to .follow().
+type Follow struct {
+	From     linkedql.PathStep `json:"from"`
+	Followed linkedql.PathStep `json:"followed"`
+}
+
+// Description implements Step.
+func (s *Follow) Description() string {
+	return "is the way to use a path prepared with Morphism. Applies the path chain on the morphism object to the current path. Starts as if at the g.M() and follows through the morphism path."
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *Follow) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *Follow) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	p, err := s.Followed.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return fromPath.Follow(p), nil
+}
diff --git a/query/linkedql/steps/follow_reverse.go b/query/linkedql/steps/follow_reverse.go
new file mode 100644
index 0000000..6e601c0
--- /dev/null
+++ b/query/linkedql/steps/follow_reverse.go
@@ -0,0 +1,45 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&FollowReverse{})
+}
+
+var _ linkedql.IteratorStep = (*FollowReverse)(nil)
+var _ linkedql.PathStep = (*FollowReverse)(nil)
+
+// FollowReverse corresponds to .followR().
+type FollowReverse struct {
+	From     linkedql.PathStep `json:"from"`
+	Followed linkedql.PathStep `json:"followed"`
+}
+
+// Description implements Step.
+func (s *FollowReverse) Description() string {
+	return "is the same as follow but follows the chain in the reverse direction. Flips View and ViewReverse where appropriate, the net result being a virtual predicate followed in the reverse direction. Starts at the end of the morphism and follows it backwards (with appropriate flipped directions) to the g.M() location."
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *FollowReverse) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *FollowReverse) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	p, err := s.Followed.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return fromPath.FollowReverse(p), nil
+}
diff --git a/query/linkedql/steps/greater_than.go b/query/linkedql/steps/greater_than.go
new file mode 100644
index 0000000..20d7e9e
--- /dev/null
+++ b/query/linkedql/steps/greater_than.go
@@ -0,0 +1,43 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/graph/iterator"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&GreaterThan{})
+}
+
+var _ linkedql.IteratorStep = (*GreaterThan)(nil)
+var _ linkedql.PathStep = (*GreaterThan)(nil)
+
+// GreaterThan corresponds to gt().
+type GreaterThan struct {
+	From  linkedql.PathStep `json:"from"`
+	Value quad.Value        `json:"value"`
+}
+
+// Description implements Step.
+func (s *GreaterThan) Description() string {
+	return "Greater than equals filters out values that are not greater than given value"
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *GreaterThan) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *GreaterThan) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return fromPath.Filter(iterator.CompareGT, linkedql.AbsoluteValue(s.Value, ns)), nil
+}
diff --git a/query/linkedql/steps/greater_than_equals.go b/query/linkedql/steps/greater_than_equals.go
new file mode 100644
index 0000000..fb81c8c
--- /dev/null
+++ b/query/linkedql/steps/greater_than_equals.go
@@ -0,0 +1,43 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/graph/iterator"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&GreaterThanEquals{})
+}
+
+var _ linkedql.IteratorStep = (*GreaterThanEquals)(nil)
+var _ linkedql.PathStep = (*GreaterThanEquals)(nil)
+
+// GreaterThanEquals corresponds to gte().
+type GreaterThanEquals struct {
+	From  linkedql.PathStep `json:"from"`
+	Value quad.Value        `json:"value"`
+}
+
+// Description implements Step.
+func (s *GreaterThanEquals) Description() string {
+	return "Greater than equals filters out values that are not greater than or equal given value"
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *GreaterThanEquals) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *GreaterThanEquals) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return fromPath.Filter(iterator.CompareGTE, linkedql.AbsoluteValue(s.Value, ns)), nil
+}
diff --git a/query/linkedql/steps/has.go b/query/linkedql/steps/has.go
new file mode 100644
index 0000000..683889c
--- /dev/null
+++ b/query/linkedql/steps/has.go
@@ -0,0 +1,47 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&Has{})
+}
+
+var _ linkedql.IteratorStep = (*Has)(nil)
+var _ linkedql.PathStep = (*Has)(nil)
+
+// Has corresponds to .has().
+type Has struct {
+	From     linkedql.PathStep     `json:"from"`
+	Property linkedql.PropertyPath `json:"property"`
+	Values   []quad.Value          `json:"values"`
+}
+
+// Description implements Step.
+func (s *Has) Description() string {
+	return "filters all paths which are, at this point, on the subject for the given predicate and object, but do not follow the path, merely filter the possible paths. Usually useful for starting with all nodes, or limiting to a subset depending on some predicate/value pair."
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *Has) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *Has) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	viaPath, err := s.Property.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return fromPath.Has(viaPath, linkedql.AbsoluteValues(s.Values, ns)...), nil
+}
diff --git a/query/linkedql/steps/has_reverse.go b/query/linkedql/steps/has_reverse.go
new file mode 100644
index 0000000..5ae1fae
--- /dev/null
+++ b/query/linkedql/steps/has_reverse.go
@@ -0,0 +1,47 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&HasReverse{})
+}
+
+var _ linkedql.IteratorStep = (*HasReverse)(nil)
+var _ linkedql.PathStep = (*HasReverse)(nil)
+
+// HasReverse corresponds to .hasR().
+type HasReverse struct {
+	From     linkedql.PathStep     `json:"from"`
+	Property linkedql.PropertyPath `json:"property"`
+	Values   []quad.Value          `json:"values"`
+}
+
+// Description implements Step.
+func (s *HasReverse) Description() string {
+	return "is the same as Has, but sets constraint in reverse direction."
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *HasReverse) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *HasReverse) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	viaPath, err := s.Property.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return fromPath.HasReverse(viaPath, linkedql.AbsoluteValues(s.Values, ns)...), nil
+}
diff --git a/query/linkedql/steps/in.go b/query/linkedql/steps/in.go
new file mode 100644
index 0000000..b9d4c26
--- /dev/null
+++ b/query/linkedql/steps/in.go
@@ -0,0 +1,22 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/query/linkedql"
+)
+
+func init() {
+	linkedql.Register(&In{})
+}
+
+var _ linkedql.IteratorStep = (*In)(nil)
+var _ linkedql.PathStep = (*In)(nil)
+
+// In is an alias for ViewReverse.
+type In struct {
+	VisitReverse
+}
+
+// Description implements Step.
+func (s *In) Description() string {
+	return "aliases for ViewReverse"
+}
diff --git a/query/linkedql/steps/intersect.go b/query/linkedql/steps/intersect.go
new file mode 100644
index 0000000..69ad752
--- /dev/null
+++ b/query/linkedql/steps/intersect.go
@@ -0,0 +1,49 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&Intersect{})
+}
+
+var _ linkedql.IteratorStep = (*Intersect)(nil)
+var _ linkedql.PathStep = (*Intersect)(nil)
+
+// Intersect represents .intersect() and .and().
+type Intersect struct {
+	From  linkedql.PathStep   `json:"from"`
+	Steps []linkedql.PathStep `json:"steps"`
+}
+
+// Description implements Step.
+func (s *Intersect) Description() string {
+	return "resolves to all the same values resolved by the from step and the provided steps."
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *Intersect) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *Intersect) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	p := fromPath
+	for _, step := range s.Steps {
+		stepPath, err := step.BuildPath(qs, ns)
+		if err != nil {
+			return nil, err
+		}
+		p = p.And(stepPath)
+	}
+	return p, nil
+}
diff --git a/query/linkedql/steps/is.go b/query/linkedql/steps/is.go
new file mode 100644
index 0000000..31ab8f2
--- /dev/null
+++ b/query/linkedql/steps/is.go
@@ -0,0 +1,42 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&Is{})
+}
+
+var _ linkedql.IteratorStep = (*Is)(nil)
+var _ linkedql.PathStep = (*Is)(nil)
+
+// Is corresponds to .back().
+type Is struct {
+	From   linkedql.PathStep `json:"from"`
+	Values []quad.Value      `json:"values"`
+}
+
+// Description implements Step.
+func (s *Is) Description() string {
+	return "resolves to all the values resolved by the from step which are included in provided values."
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *Is) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *Is) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return fromPath.Is(linkedql.AbsoluteValues(s.Values, ns)...), nil
+}
diff --git a/query/linkedql/steps/labels.go b/query/linkedql/steps/labels.go
new file mode 100644
index 0000000..51979ff
--- /dev/null
+++ b/query/linkedql/steps/labels.go
@@ -0,0 +1,40 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&Labels{})
+}
+
+var _ linkedql.IteratorStep = (*Labels)(nil)
+var _ linkedql.PathStep = (*Labels)(nil)
+
+// Labels corresponds to .labels().
+type Labels struct {
+	From linkedql.PathStep `json:"from"`
+}
+
+// Description implements Step.
+func (s *Labels) Description() string {
+	return "gets the list of inbound and outbound quad labels"
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *Labels) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *Labels) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return fromPath.Labels(), nil
+}
diff --git a/query/linkedql/steps/less_than.go b/query/linkedql/steps/less_than.go
new file mode 100644
index 0000000..3955449
--- /dev/null
+++ b/query/linkedql/steps/less_than.go
@@ -0,0 +1,48 @@
+
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/graph/iterator"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad"
+	"github.com/cayleygraph/quad/voc"
+	"github.com/cayleygraph/cayley/query/linkedql"
+)
+
+func init() {
+	linkedql.Register(&LessThan{})
+}
+
+var _ linkedql.IteratorStep = (*LessThan)(nil)
+var _ linkedql.PathStep = (*LessThan)(nil)
+
+// LessThan corresponds to lt().
+type LessThan struct {
+	From  linkedql.PathStep   `json:"from"`
+	Value quad.Value `json:"value"`
+}
+
+
+
+
+// Description implements Step.
+func (s *LessThan) Description() string {
+	return "Less than filters out values that are not less than given value"
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *LessThan) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *LessThan) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return fromPath.Filter(iterator.CompareLT, s.Value), nil
+}
+
diff --git a/query/linkedql/steps/less_than_equals.go b/query/linkedql/steps/less_than_equals.go
new file mode 100644
index 0000000..c994cc8
--- /dev/null
+++ b/query/linkedql/steps/less_than_equals.go
@@ -0,0 +1,43 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/graph/iterator"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&LessThanEquals{})
+}
+
+var _ linkedql.IteratorStep = (*LessThanEquals)(nil)
+var _ linkedql.PathStep = (*LessThanEquals)(nil)
+
+// LessThanEquals corresponds to lte().
+type LessThanEquals struct {
+	From  linkedql.PathStep `json:"from"`
+	Value quad.Value        `json:"value"`
+}
+
+// Description implements Step.
+func (s *LessThanEquals) Description() string {
+	return "Less than equals filters out values that are not less than or equal given value"
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *LessThanEquals) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *LessThanEquals) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return fromPath.Filter(iterator.CompareLTE, linkedql.AbsoluteValue(s.Value, ns)), nil
+}
diff --git a/query/linkedql/steps/limit.go b/query/linkedql/steps/limit.go
new file mode 100644
index 0000000..88b5ec6
--- /dev/null
+++ b/query/linkedql/steps/limit.go
@@ -0,0 +1,41 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&Limit{})
+}
+
+var _ linkedql.IteratorStep = (*Limit)(nil)
+var _ linkedql.PathStep = (*Limit)(nil)
+
+// Limit corresponds to .limit().
+type Limit struct {
+	From  linkedql.PathStep `json:"from"`
+	Limit int64             `json:"limit"`
+}
+
+// Description implements Step.
+func (s *Limit) Description() string {
+	return "limits a number of nodes for current path."
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *Limit) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *Limit) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return fromPath.Limit(s.Limit), nil
+}
diff --git a/query/linkedql/operators.go b/query/linkedql/steps/operators.go
similarity index 70%
rename from query/linkedql/operators.go
rename to query/linkedql/steps/operators.go
index c5e22e7..f2f54dc 100644
--- a/query/linkedql/operators.go
+++ b/query/linkedql/steps/operators.go
@@ -1,32 +1,19 @@
-package linkedql
+package steps
 
 import (
 	"regexp"
 
+	"github.com/cayleygraph/cayley/query/linkedql"
 	"github.com/cayleygraph/cayley/query/path"
 	"github.com/cayleygraph/cayley/query/shape"
-	"github.com/cayleygraph/quad"
 )
 
-// Operator represents an operator used in a query inside a step (e.g. greater than).
-type Operator interface {
-	RegistryItem
-	Apply(p *path.Path) (*path.Path, error)
-}
-
-var _ Operator = (*RegExp)(nil)
-
 // RegExp corresponds to regex().
 type RegExp struct {
 	Pattern     string `json:"pattern"`
 	IncludeIRIs bool   `json:"includeIRIs,omitempty"`
 }
 
-// Type implements Operator.
-func (s *RegExp) Type() quad.IRI {
-	return Prefix + "RegExp"
-}
-
 // Description implements Operator.
 func (s *RegExp) Description() string {
 	return "RegExp filters out values that do not match given pattern. If includeIRIs is set to true it matches IRIs in addition to literals."
@@ -44,18 +31,13 @@ func (s *RegExp) Apply(p *path.Path) (*path.Path, error) {
 	return p.RegexWithRefs(pattern), nil
 }
 
-var _ Operator = (*Like)(nil)
+var _ linkedql.Operator = (*Like)(nil)
 
 // Like corresponds to like().
 type Like struct {
 	Pattern string `json:"pattern"`
 }
 
-// Type implements Operator.
-func (s *Like) Type() quad.IRI {
-	return Prefix + "Like"
-}
-
 // Description implements Operator.
 func (s *Like) Description() string {
 	return "Like filters out values that do not match given pattern."
diff --git a/query/linkedql/steps/optional.go b/query/linkedql/steps/optional.go
new file mode 100644
index 0000000..0fe2fab
--- /dev/null
+++ b/query/linkedql/steps/optional.go
@@ -0,0 +1,45 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&Optional{})
+}
+
+var _ linkedql.IteratorStep = (*Optional)(nil)
+var _ linkedql.PathStep = (*Optional)(nil)
+
+// Optional corresponds to .optional().
+type Optional struct {
+	From linkedql.PathStep `json:"from"`
+	Step linkedql.PathStep `json:"step"`
+}
+
+// Description implements Step.
+func (s *Optional) Description() string {
+	return "attempts to follow the given path from the current entity / value, if fails the entity / value will still be kept in the results"
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *Optional) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *Optional) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	p, err := s.Step.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return fromPath.Optional(p), nil
+}
diff --git a/query/linkedql/steps/order.go b/query/linkedql/steps/order.go
new file mode 100644
index 0000000..8e88240
--- /dev/null
+++ b/query/linkedql/steps/order.go
@@ -0,0 +1,40 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&Order{})
+}
+
+var _ linkedql.IteratorStep = (*Order)(nil)
+var _ linkedql.PathStep = (*Order)(nil)
+
+// Order corresponds to .order().
+type Order struct {
+	From linkedql.PathStep `json:"from"`
+}
+
+// Description implements Step.
+func (s *Order) Description() string {
+	return "sorts the results in ascending order according to the current entity / value"
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *Order) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *Order) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return fromPath.Order(), nil
+}
diff --git a/query/linkedql/steps/out.go b/query/linkedql/steps/out.go
new file mode 100644
index 0000000..7230184
--- /dev/null
+++ b/query/linkedql/steps/out.go
@@ -0,0 +1,22 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/query/linkedql"
+)
+
+func init() {
+	linkedql.Register(&Out{})
+}
+
+var _ linkedql.IteratorStep = (*Out)(nil)
+var _ linkedql.PathStep = (*Out)(nil)
+
+// Out is an alias for View.
+type Out struct {
+	Visit
+}
+
+// Description implements Step.
+func (s *Out) Description() string {
+	return "aliases for View"
+}
diff --git a/query/linkedql/steps/placeholder.go b/query/linkedql/steps/placeholder.go
new file mode 100644
index 0000000..8a08283
--- /dev/null
+++ b/query/linkedql/steps/placeholder.go
@@ -0,0 +1,27 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&Placeholder{})
+}
+
+var _ linkedql.PathStep = (*Placeholder)(nil)
+
+// Placeholder corresponds to .Placeholder().
+type Placeholder struct{}
+
+// Description implements Step.
+func (s *Placeholder) Description() string {
+	return "is like Vertex but resolves to the values in the context it is placed in. It should only be used where a linkedql.PathStep is expected and can't be resolved on its own."
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *Placeholder) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	return path.StartMorphism(), nil
+}
diff --git a/query/linkedql/steps/properties.go b/query/linkedql/steps/properties.go
new file mode 100644
index 0000000..beb6c09
--- /dev/null
+++ b/query/linkedql/steps/properties.go
@@ -0,0 +1,54 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&Properties{})
+}
+
+var _ linkedql.IteratorStep = (*Properties)(nil)
+var _ linkedql.PathStep = (*Properties)(nil)
+
+// Properties corresponds to .properties().
+type Properties struct {
+	From linkedql.PathStep `json:"from"`
+	// TODO(iddan): Use linkedql.PropertyPath
+	Names []quad.IRI `json:"names"`
+}
+
+// Description implements Step.
+func (s *Properties) Description() string {
+	return "adds tags for all properties of the current entity"
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+// TODO(iddan): Default tag to Via.
+func (s *Properties) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *Properties) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	p := fromPath
+	if s.Names != nil {
+		for _, name := range s.Names {
+			name = name.FullWith(ns)
+			tag := string(name)
+			p = p.Save(name, tag)
+		}
+	} else {
+		panic("Not implemented: should tag all properties")
+	}
+	return p, nil
+}
diff --git a/query/linkedql/steps/property_names.go b/query/linkedql/steps/property_names.go
new file mode 100644
index 0000000..f2abce5
--- /dev/null
+++ b/query/linkedql/steps/property_names.go
@@ -0,0 +1,40 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&PropertyNames{})
+}
+
+var _ linkedql.IteratorStep = (*PropertyNames)(nil)
+var _ linkedql.PathStep = (*PropertyNames)(nil)
+
+// PropertyNames corresponds to .propertyNames().
+type PropertyNames struct {
+	From linkedql.PathStep `json:"from"`
+}
+
+// Description implements Step.
+func (s *PropertyNames) Description() string {
+	return "gets the list of predicates that are pointing out from a node."
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *PropertyNames) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *PropertyNames) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return fromPath.OutPredicates(), nil
+}
diff --git a/query/linkedql/steps/property_names_as.go b/query/linkedql/steps/property_names_as.go
new file mode 100644
index 0000000..5f30ce4
--- /dev/null
+++ b/query/linkedql/steps/property_names_as.go
@@ -0,0 +1,41 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&PropertyNamesAs{})
+}
+
+var _ linkedql.IteratorStep = (*PropertyNamesAs)(nil)
+var _ linkedql.PathStep = (*PropertyNamesAs)(nil)
+
+// PropertyNamesAs corresponds to .propertyNamesAs().
+type PropertyNamesAs struct {
+	From linkedql.PathStep `json:"from"`
+	Tag  string            `json:"tag"`
+}
+
+// Description implements Step.
+func (s *PropertyNamesAs) Description() string {
+	return "tags the list of predicates that are pointing out from a node."
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *PropertyNamesAs) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *PropertyNamesAs) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return fromPath.SavePredicates(false, s.Tag), nil
+}
diff --git a/query/linkedql/steps/reverse_properties.go b/query/linkedql/steps/reverse_properties.go
new file mode 100644
index 0000000..275b7f7
--- /dev/null
+++ b/query/linkedql/steps/reverse_properties.go
@@ -0,0 +1,49 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&ReverseProperties{})
+}
+
+var _ linkedql.IteratorStep = (*ReverseProperties)(nil)
+var _ linkedql.PathStep = (*ReverseProperties)(nil)
+
+// ReverseProperties corresponds to .reverseProperties().
+type ReverseProperties struct {
+	From linkedql.PathStep `json:"from"`
+	// TODO(iddan): Use property path
+	Names []quad.IRI `json:"names"`
+}
+
+// Description implements Step.
+func (s *ReverseProperties) Description() string {
+	return "gets all the properties the current entity / value is referenced at"
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *ReverseProperties) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *ReverseProperties) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	p := fromPath
+	for _, name := range s.Names {
+		name = name.FullWith(ns)
+		tag := string(name)
+		p = fromPath.SaveReverse(name, tag)
+	}
+	return p, nil
+}
diff --git a/query/linkedql/steps/reverse_property_names.go b/query/linkedql/steps/reverse_property_names.go
new file mode 100644
index 0000000..d107d05
--- /dev/null
+++ b/query/linkedql/steps/reverse_property_names.go
@@ -0,0 +1,40 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&ReversePropertyNames{})
+}
+
+var _ linkedql.IteratorStep = (*ReversePropertyNames)(nil)
+var _ linkedql.PathStep = (*ReversePropertyNames)(nil)
+
+// ReversePropertyNames corresponds to .reversePropertyNames().
+type ReversePropertyNames struct {
+	From linkedql.PathStep `json:"from"`
+}
+
+// Description implements Step.
+func (s *ReversePropertyNames) Description() string {
+	return "gets the list of predicates that are pointing in to a node."
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *ReversePropertyNames) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *ReversePropertyNames) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return fromPath.InPredicates(), nil
+}
diff --git a/query/linkedql/steps/reverse_property_names_as.go b/query/linkedql/steps/reverse_property_names_as.go
new file mode 100644
index 0000000..a44a568
--- /dev/null
+++ b/query/linkedql/steps/reverse_property_names_as.go
@@ -0,0 +1,41 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&ReversePropertyNamesAs{})
+}
+
+var _ linkedql.IteratorStep = (*ReversePropertyNamesAs)(nil)
+var _ linkedql.PathStep = (*ReversePropertyNamesAs)(nil)
+
+// ReversePropertyNamesAs corresponds to .reversePropertyNamesAs().
+type ReversePropertyNamesAs struct {
+	From linkedql.PathStep `json:"from"`
+	Tag  string            `json:"tag"`
+}
+
+// Description implements Step.
+func (s *ReversePropertyNamesAs) Description() string {
+	return "tags the list of predicates that are pointing in to a node."
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *ReversePropertyNamesAs) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *ReversePropertyNamesAs) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return fromPath.SavePredicates(true, s.Tag), nil
+}
diff --git a/query/linkedql/steps/skip.go b/query/linkedql/steps/skip.go
new file mode 100644
index 0000000..8c47195
--- /dev/null
+++ b/query/linkedql/steps/skip.go
@@ -0,0 +1,41 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&Skip{})
+}
+
+var _ linkedql.IteratorStep = (*Skip)(nil)
+var _ linkedql.PathStep = (*Skip)(nil)
+
+// Skip corresponds to .skip().
+type Skip struct {
+	From   linkedql.PathStep `json:"from"`
+	Offset int64             `json:"offset"`
+}
+
+// Description implements Step.
+func (s *Skip) Description() string {
+	return "skips a number of nodes for current path."
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *Skip) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *Skip) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return fromPath.Skip(s.Offset), nil
+}
diff --git a/query/linkedql/steps/steps_final.go b/query/linkedql/steps/steps_final.go
new file mode 100644
index 0000000..166600a
--- /dev/null
+++ b/query/linkedql/steps/steps_final.go
@@ -0,0 +1,109 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&Select{})
+	linkedql.Register(&SelectFirst{})
+	linkedql.Register(&Value{})
+	linkedql.Register(&Documents{})
+}
+
+var _ linkedql.IteratorStep = (*Select)(nil)
+
+// Select corresponds to .select().
+type Select struct {
+	Tags []string          `json:"tags"`
+	From linkedql.PathStep `json:"from"`
+}
+
+// Description implements Step.
+func (s *Select) Description() string {
+	return "Select returns flat records of tags matched in the query"
+}
+
+// BuildIterator implements IteratorStep
+func (s *Select) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	valueIt, err := linkedql.NewValueIteratorFromPathStep(s.From, qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return &linkedql.TagsIterator{ValueIt: valueIt, Selected: s.Tags}, nil
+}
+
+var _ linkedql.IteratorStep = (*SelectFirst)(nil)
+
+// SelectFirst corresponds to .selectFirst().
+type SelectFirst struct {
+	Tags []string          `json:"tags"`
+	From linkedql.PathStep `json:"from"`
+}
+
+// Description implements Step.
+func (s *SelectFirst) Description() string {
+	return "Like Select but only returns the first result"
+}
+
+func singleValueIteratorFromPathStep(step linkedql.PathStep, qs graph.QuadStore, ns *voc.Namespaces) (*linkedql.ValueIterator, error) {
+	p, err := step.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return linkedql.NewValueIterator(p.Limit(1), qs), nil
+}
+
+// BuildIterator implements IteratorStep
+func (s *SelectFirst) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	it, err := singleValueIteratorFromPathStep(s.From, qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return &linkedql.TagsIterator{it, s.Tags}, nil
+}
+
+var _ linkedql.IteratorStep = (*Value)(nil)
+
+// Value corresponds to .value().
+type Value struct {
+	From linkedql.PathStep `json:"from"`
+}
+
+// Description implements Step.
+func (s *Value) Description() string {
+	return "Value returns a single value matched in the query"
+}
+
+// BuildIterator implements IteratorStep
+func (s *Value) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return singleValueIteratorFromPathStep(s.From, qs, ns)
+}
+
+var _ linkedql.IteratorStep = (*Documents)(nil)
+
+// Documents corresponds to .documents().
+type Documents struct {
+	From linkedql.PathStep `json:"from"`
+}
+
+// Description implements Step.
+func (s *Documents) Description() string {
+	return "Documents return documents of the tags matched in the query associated with their entity"
+}
+
+// BuildIterator implements IteratorStep
+func (s *Documents) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	p, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	it, err := linkedql.NewValueIterator(p, qs), nil
+	if err != nil {
+		return nil, err
+	}
+	return linkedql.NewDocumentIterator(it), nil
+}
diff --git a/query/linkedql/steps/union.go b/query/linkedql/steps/union.go
new file mode 100644
index 0000000..5728608
--- /dev/null
+++ b/query/linkedql/steps/union.go
@@ -0,0 +1,49 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&Union{})
+}
+
+var _ linkedql.IteratorStep = (*Union)(nil)
+var _ linkedql.PathStep = (*Union)(nil)
+
+// Union corresponds to .union() and .or().
+type Union struct {
+	From  linkedql.PathStep   `json:"from"`
+	Steps []linkedql.PathStep `json:"steps"`
+}
+
+// Description implements Step.
+func (s *Union) Description() string {
+	return "returns the combined paths of the two queries. Notice that it's per-path, not per-node. Once again, if multiple paths reach the same destination, they might have had different ways of getting there (and different tags)."
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *Union) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *Union) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	p := fromPath
+	for _, step := range s.Steps {
+		valuePath, err := step.BuildPath(qs, ns)
+		if err != nil {
+			return nil, err
+		}
+		p = p.Or(valuePath)
+	}
+	return p, nil
+}
diff --git a/query/linkedql/steps/unique.go b/query/linkedql/steps/unique.go
new file mode 100644
index 0000000..4d21c72
--- /dev/null
+++ b/query/linkedql/steps/unique.go
@@ -0,0 +1,40 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&Unique{})
+}
+
+var _ linkedql.IteratorStep = (*Unique)(nil)
+var _ linkedql.PathStep = (*Unique)(nil)
+
+// Unique corresponds to .unique().
+type Unique struct {
+	From linkedql.PathStep `json:"from"`
+}
+
+// Description implements Step.
+func (s *Unique) Description() string {
+	return "removes duplicate values from the path."
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *Unique) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *Unique) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return fromPath.Unique(), nil
+}
diff --git a/query/linkedql/steps/vertex.go b/query/linkedql/steps/vertex.go
new file mode 100644
index 0000000..8379ae5
--- /dev/null
+++ b/query/linkedql/steps/vertex.go
@@ -0,0 +1,37 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&Vertex{})
+}
+
+var _ linkedql.IteratorStep = (*Vertex)(nil)
+var _ linkedql.PathStep = (*Vertex)(nil)
+
+// Vertex corresponds to g.Vertex() and g.V().
+type Vertex struct {
+	Values []quad.Value `json:"values"`
+}
+
+// Description implements Step.
+func (s *Vertex) Description() string {
+	return "resolves to all the existing objects and primitive values in the graph. If provided with values resolves to a sublist of all the existing values in the graph."
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *Vertex) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *Vertex) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	return path.StartPath(qs, linkedql.AbsoluteValues(s.Values, ns)...), nil
+}
diff --git a/query/linkedql/steps/visit.go b/query/linkedql/steps/visit.go
new file mode 100644
index 0000000..559213f
--- /dev/null
+++ b/query/linkedql/steps/visit.go
@@ -0,0 +1,45 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&Visit{})
+}
+
+var _ linkedql.IteratorStep = (*Visit)(nil)
+var _ linkedql.PathStep = (*Visit)(nil)
+
+// Visit corresponds to .view().
+type Visit struct {
+	From       linkedql.PathStep     `json:"from"`
+	Properties linkedql.PropertyPath `json:"properties"`
+}
+
+// Description implements Step.
+func (s *Visit) Description() string {
+	return "resolves to the values of the given property or properties in via of the current objects. If via is a path it's resolved values will be used as properties."
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *Visit) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *Visit) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	viaPath, err := s.Properties.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return fromPath.Out(viaPath), nil
+}
diff --git a/query/linkedql/steps/visit_reverse.go b/query/linkedql/steps/visit_reverse.go
new file mode 100644
index 0000000..c42cf45
--- /dev/null
+++ b/query/linkedql/steps/visit_reverse.go
@@ -0,0 +1,45 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&VisitReverse{})
+}
+
+var _ linkedql.IteratorStep = (*VisitReverse)(nil)
+var _ linkedql.PathStep = (*VisitReverse)(nil)
+
+// VisitReverse corresponds to .viewReverse().
+type VisitReverse struct {
+	From       linkedql.PathStep     `json:"from"`
+	Properties linkedql.PropertyPath `json:"properties"`
+}
+
+// Description implements Step.
+func (s *VisitReverse) Description() string {
+	return "is the inverse of View. Starting with the nodes in `path` on the object, follow the quads with predicates defined by `predicatePath` to their subjects."
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *VisitReverse) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *VisitReverse) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	viaPath, err := s.Properties.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	return fromPath.In(viaPath), nil
+}
diff --git a/query/linkedql/steps/where.go b/query/linkedql/steps/where.go
new file mode 100644
index 0000000..646be2f
--- /dev/null
+++ b/query/linkedql/steps/where.go
@@ -0,0 +1,49 @@
+package steps
+
+import (
+	"github.com/cayleygraph/cayley/graph"
+	"github.com/cayleygraph/cayley/query"
+	"github.com/cayleygraph/cayley/query/linkedql"
+	"github.com/cayleygraph/cayley/query/path"
+	"github.com/cayleygraph/quad/voc"
+)
+
+func init() {
+	linkedql.Register(&Where{})
+}
+
+var _ linkedql.IteratorStep = (*Where)(nil)
+var _ linkedql.PathStep = (*Where)(nil)
+
+// Where corresponds to .where().
+type Where struct {
+	From  linkedql.PathStep   `json:"from"`
+	Steps []linkedql.PathStep `json:"steps"`
+}
+
+// Description implements Step.
+func (s *Where) Description() string {
+	return "applies each provided step in steps in isolation on from"
+}
+
+// BuildIterator implements linkedql.IteratorStep.
+func (s *Where) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
+	return linkedql.NewValueIteratorFromPathStep(s, qs, ns)
+}
+
+// BuildPath implements linkedql.PathStep.
+func (s *Where) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
+	fromPath, err := s.From.BuildPath(qs, ns)
+	if err != nil {
+		return nil, err
+	}
+	p := fromPath
+	for _, step := range s.Steps {
+		stepPath, err := step.BuildPath(qs, ns)
+		if err != nil {
+			return nil, err
+		}
+		p = p.And(stepPath.Reverse())
+	}
+	return p, nil
+}
diff --git a/query/linkedql/steps_final.go b/query/linkedql/steps_final.go
deleted file mode 100644
index de451c7..0000000
--- a/query/linkedql/steps_final.go
+++ /dev/null
@@ -1,128 +0,0 @@
-package linkedql
-
-import (
-	"github.com/cayleygraph/cayley/graph"
-	"github.com/cayleygraph/cayley/query"
-	"github.com/cayleygraph/quad"
-)
-
-func init() {
-	Register(&Select{})
-	Register(&SelectFirst{})
-	Register(&Value{})
-	Register(&Documents{})
-}
-
-var _ IteratorStep = (*Select)(nil)
-
-// Select corresponds to .select().
-type Select struct {
-	Tags []string `json:"tags"`
-	From PathStep `json:"from"`
-}
-
-// Type implements Step.
-func (s *Select) Type() quad.IRI {
-	return Prefix + "Select"
-}
-
-// Description implements Step.
-func (s *Select) Description() string {
-	return "Select returns flat records of tags matched in the query"
-}
-
-// BuildIterator implements IteratorStep
-func (s *Select) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	valueIt, err := NewValueIteratorFromPathStep(s.From, qs)
-	if err != nil {
-		return nil, err
-	}
-	return &TagsIterator{valueIt: valueIt, selected: s.Tags}, nil
-}
-
-var _ IteratorStep = (*SelectFirst)(nil)
-
-// SelectFirst corresponds to .selectFirst().
-type SelectFirst struct {
-	Tags []string `json:"tags"`
-	From PathStep `json:"from"`
-}
-
-// Type implements Step.
-func (s *SelectFirst) Type() quad.IRI {
-	return Prefix + "SelectFirst"
-}
-
-// Description implements Step.
-func (s *SelectFirst) Description() string {
-	return "Like Select but only returns the first result"
-}
-
-func singleValueIteratorFromPathStep(step PathStep, qs graph.QuadStore) (*ValueIterator, error) {
-	p, err := step.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	return NewValueIterator(p.Limit(1), qs), nil
-}
-
-// BuildIterator implements IteratorStep
-func (s *SelectFirst) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	it, err := singleValueIteratorFromPathStep(s.From, qs)
-	if err != nil {
-		return nil, err
-	}
-	return &TagsIterator{it, s.Tags}, nil
-}
-
-var _ IteratorStep = (*Value)(nil)
-
-// Value corresponds to .value().
-type Value struct {
-	From PathStep `json:"from"`
-}
-
-// Type implements Step.
-func (s *Value) Type() quad.IRI {
-	return Prefix + "Value"
-}
-
-// Description implements Step.
-func (s *Value) Description() string {
-	return "Value returns a single value matched in the query"
-}
-
-// BuildIterator implements IteratorStep
-func (s *Value) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	return singleValueIteratorFromPathStep(s.From, qs)
-}
-
-var _ IteratorStep = (*Documents)(nil)
-
-// Documents corresponds to .documents().
-type Documents struct {
-	From PathStep `json:"from"`
-}
-
-// Type implements Step.
-func (s *Documents) Type() quad.IRI {
-	return Prefix + "Documents"
-}
-
-// Description implements Step.
-func (s *Documents) Description() string {
-	return "Documents return documents of the tags matched in the query associated with their entity"
-}
-
-// BuildIterator implements IteratorStep
-func (s *Documents) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
-	p, err := s.From.BuildPath(qs)
-	if err != nil {
-		return nil, err
-	}
-	it, err := NewValueIterator(p, qs), nil
-	if err != nil {
-		return nil, err
-	}
-	return NewDocumentIterator(it), nil
-}
diff --git a/query/linkedql/voc_util.go b/query/linkedql/voc_util.go
new file mode 100644
index 0000000..e4893da
--- /dev/null
+++ b/query/linkedql/voc_util.go
@@ -0,0 +1,27 @@
+package linkedql
+
+import (
+	"github.com/cayleygraph/quad"
+	"github.com/cayleygraph/quad/voc"
+)
+
+// AbsoluteValue uses given ns to resolve short IRIs and types in typed strings to their full form
+func AbsoluteValue(value quad.Value, ns *voc.Namespaces) quad.Value {
+	switch v := value.(type) {
+	case quad.IRI:
+		return v.FullWith(ns)
+	case quad.TypedString:
+		return quad.TypedString{Value: v.Value, Type: v.Type.FullWith(ns)}
+	default:
+		return v
+	}
+}
+
+// AbsoluteValues applies AbsoluteValue on each item in provided values using provided ns
+func AbsoluteValues(values []quad.Value, ns *voc.Namespaces) []quad.Value {
+	var absoluteValues []quad.Value
+	for _, value := range values {
+		absoluteValues = append(absoluteValues, AbsoluteValue(value, ns))
+	}
+	return absoluteValues
+}


Test patch:
diff --git a/query/linkedql/registry_test.go b/query/linkedql/registry_test.go
index d146546..eec949a 100644
--- a/query/linkedql/registry_test.go
+++ b/query/linkedql/registry_test.go
@@ -6,7 +6,7 @@ import (
 	"github.com/cayleygraph/cayley/graph"
 	"github.com/cayleygraph/cayley/query"
 	"github.com/cayleygraph/cayley/query/path"
-	"github.com/cayleygraph/quad"
+	"github.com/cayleygraph/quad/voc"
 
 	"github.com/stretchr/testify/require"
 )
@@ -23,7 +23,7 @@ var unmarshalCases = []struct {
 	{
 		name: "simple",
 		data: `{
-	"@type": "cayley:TestStep",
+	"@type": "linkedql:TestStep",
 	"linkedql:limit": 10
 }`,
 		exp: &TestStep{Limit: 10},
@@ -31,7 +31,7 @@ var unmarshalCases = []struct {
 	{
 		name: "simple",
 		data: `{
-	"@type": "cayley:TestStep",
+	"@type": "linkedql:TestStep",
 	"linkedql:tags": ["a", "b"]
 }`,
 		exp: &TestStep{Tags: []string{"a", "b"}},
@@ -39,13 +39,13 @@ var unmarshalCases = []struct {
 	{
 		name: "nested",
 		data: `{
-	"@type": "cayley:TestStep",
+	"@type": "linkedql:TestStep",
 	"linkedql:limit": 10,
 	"linkedql:from": {
-		"@type": "cayley:TestStep",
+		"@type": "linkedql:TestStep",
 		"linkedql:limit": 15,
 		"linkedql:from": {
-			"@type": "cayley:TestStep",
+			"@type": "linkedql:TestStep",
 			"linkedql:limit": 20
 		}
 	}
@@ -63,15 +63,15 @@ var unmarshalCases = []struct {
 	{
 		name: "nested slice",
 		data: `{
-	"@type": "cayley:TestStep",
+	"@type": "linkedql:TestStep",
 	"linkedql:limit": 10,
 	"linkedql:sub": [
 		{
-			"@type": "cayley:TestStep",
+			"@type": "linkedql:TestStep",
 			"linkedql:limit": 15
 		},
 		{
-			"@type": "cayley:TestStep",
+			"@type": "linkedql:TestStep",
 			"linkedql:limit": 20
 		}
 	]
@@ -97,19 +97,15 @@ type TestStep struct {
 	Sub   []PathStep `json:"sub"`
 }
 
-func (s *TestStep) Type() quad.IRI {
-	return "cayley:TestStep"
-}
-
 func (s *TestStep) Description() string {
 	return "A TestStep for checking the registry"
 }
 
-func (s *TestStep) BuildIterator(qs graph.QuadStore) (query.Iterator, error) {
+func (s *TestStep) BuildIterator(qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
 	panic("Can't build iterator for TestStep")
 }
 
-func (s *TestStep) BuildPath(qs graph.QuadStore) (*path.Path, error) {
+func (s *TestStep) BuildPath(qs graph.QuadStore, ns *voc.Namespaces) (*path.Path, error) {
 	panic("Can't build path for TestStep")
 }
 
diff --git a/query/linkedql/steps_test.go b/query/linkedql/steps/steps_test.go
similarity index 85%
rename from query/linkedql/steps_test.go
rename to query/linkedql/steps/steps_test.go
index a20db41..629e658 100644
--- a/query/linkedql/steps_test.go
+++ b/query/linkedql/steps/steps_test.go
@@ -1,11 +1,13 @@
-package linkedql
+package steps
 
 import (
 	"context"
 	"testing"
 
 	"github.com/cayleygraph/cayley/graph/memstore"
+	"github.com/cayleygraph/cayley/query/linkedql"
 	"github.com/cayleygraph/quad"
+	"github.com/cayleygraph/quad/voc"
 	"github.com/stretchr/testify/require"
 )
 
@@ -16,13 +18,13 @@ var singleQuadData = []quad.Quad{
 var testCases = []struct {
 	name    string
 	data    []quad.Quad
-	query   IteratorStep
+	query   linkedql.IteratorStep
 	results []interface{}
 }{
 	{
 		name:  "All Entities",
 		data:  singleQuadData,
-		query: &Entities{Identifiers: []EntityIdentifier{EntityIdentifierString("alice")}},
+		query: &Entities{Identifiers: []linkedql.EntityIdentifier{linkedql.EntityIdentifierString("alice")}},
 		results: []interface{}{
 			map[string]string{"@id": "alice"},
 		},
@@ -47,7 +49,7 @@ var testCases = []struct {
 						From: &Vertex{},
 						Name: "liker",
 					},
-					Properties: PropertyPath{&Vertex{Values: []quad.Value{quad.IRI("likes")}}},
+					Properties: linkedql.PropertyPath{&Vertex{Values: []quad.Value{quad.IRI("likes")}}},
 				},
 				Name: "liked",
 			},
@@ -70,7 +72,7 @@ var testCases = []struct {
 						From: &Vertex{},
 						Name: "liker",
 					},
-					Properties: PropertyPath{&Vertex{Values: []quad.Value{quad.IRI("likes")}}},
+					Properties: linkedql.PropertyPath{&Vertex{Values: []quad.Value{quad.IRI("likes")}}},
 				},
 				Name: "liked",
 			},
@@ -89,7 +91,7 @@ var testCases = []struct {
 				From: &Vertex{
 					Values: []quad.Value{quad.IRI("alice")},
 				},
-				Properties: PropertyPath{&Vertex{
+				Properties: linkedql.PropertyPath{&Vertex{
 					Values: []quad.Value{
 						quad.IRI("likes"),
 					},
@@ -110,7 +112,7 @@ var testCases = []struct {
 			From: &Vertex{
 				Values: []quad.Value{quad.IRI("bob")},
 			},
-			Properties: PropertyPath{&Vertex{Values: []quad.Value{quad.IRI("likes")}}},
+			Properties: linkedql.PropertyPath{&Vertex{Values: []quad.Value{quad.IRI("likes")}}},
 		},
 		results: []interface{}{
 			map[string]string{"@id": "alice"},
@@ -134,7 +136,7 @@ var testCases = []struct {
 			From: &Vertex{
 				Values: []quad.Value{quad.IRI("alice"), quad.IRI("likes")},
 			},
-			Steps: []PathStep{
+			Steps: []linkedql.PathStep{
 				&Vertex{
 					Values: []quad.Value{quad.IRI("likes")},
 				},
@@ -237,7 +239,7 @@ var testCases = []struct {
 			From: &Vertex{
 				Values: []quad.Value{},
 			},
-			Property: PropertyPath{&Vertex{
+			Property: linkedql.PropertyPath{&Vertex{
 				Values: []quad.Value{quad.IRI("likes")},
 			}},
 			Values: []quad.Value{quad.IRI("bob")},
@@ -253,7 +255,7 @@ var testCases = []struct {
 			From: &Vertex{
 				Values: []quad.Value{},
 			},
-			Property: PropertyPath{&Vertex{
+			Property: linkedql.PropertyPath{&Vertex{
 				Values: []quad.Value{quad.IRI("likes")},
 			}},
 			Values: []quad.Value{quad.IRI("alice")},
@@ -267,7 +269,7 @@ var testCases = []struct {
 		data: singleQuadData,
 		query: &VisitReverse{
 			From:       &Vertex{Values: []quad.Value{}},
-			Properties: PropertyPath{&Vertex{Values: []quad.Value{quad.IRI("likes")}}},
+			Properties: linkedql.PropertyPath{&Vertex{Values: []quad.Value{quad.IRI("likes")}}},
 		},
 		results: []interface{}{
 			map[string]string{"@id": "alice"},
@@ -292,14 +294,14 @@ var testCases = []struct {
 		query: &Intersect{
 			From: &Visit{
 				From: &Vertex{Values: []quad.Value{quad.IRI("bob")}},
-				Properties: PropertyPath{&Vertex{
+				Properties: linkedql.PropertyPath{&Vertex{
 					Values: []quad.Value{quad.IRI("likes")},
 				}},
 			},
-			Steps: []PathStep{
+			Steps: []linkedql.PathStep{
 				&Visit{
 					From:       &Vertex{Values: []quad.Value{quad.IRI("bob")}},
-					Properties: PropertyPath{&Vertex{Values: []quad.Value{quad.IRI("likes")}}},
+					Properties: linkedql.PropertyPath{&Vertex{Values: []quad.Value{quad.IRI("likes")}}},
 				},
 			},
 		},
@@ -314,7 +316,7 @@ var testCases = []struct {
 			Values: []quad.Value{quad.IRI("bob")},
 			From: &Visit{
 				From: &Vertex{Values: []quad.Value{quad.IRI("alice")}},
-				Properties: PropertyPath{&Vertex{
+				Properties: linkedql.PropertyPath{&Vertex{
 					Values: []quad.Value{quad.IRI("likes")},
 				}},
 			},
@@ -342,7 +344,7 @@ var testCases = []struct {
 		data: singleQuadData,
 		query: &Visit{
 			From:       &Vertex{Values: []quad.Value{}},
-			Properties: PropertyPath{&Vertex{Values: []quad.Value{quad.IRI("likes")}}},
+			Properties: linkedql.PropertyPath{&Vertex{Values: []quad.Value{quad.IRI("likes")}}},
 		},
 		results: []interface{}{
 			map[string]string{"@id": "bob"},
@@ -422,7 +424,7 @@ var testCases = []struct {
 			From: &Vertex{
 				Values: []quad.Value{quad.IRI("alice")},
 			},
-			Steps: []PathStep{
+			Steps: []linkedql.PathStep{
 				&Vertex{
 					Values: []quad.Value{quad.IRI("bob")},
 				},
@@ -443,7 +445,7 @@ var testCases = []struct {
 						Name: "liker",
 						From: &Vertex{},
 					},
-					Properties: PropertyPath{&Vertex{Values: []quad.Value{quad.IRI("likes")}}},
+					Properties: linkedql.PropertyPath{&Vertex{Values: []quad.Value{quad.IRI("likes")}}},
 				},
 				Name: "liked",
 			},
@@ -515,21 +517,21 @@ var testCases = []struct {
 			From: &As{
 				From: &Where{
 					From: &Vertex{},
-					Steps: []PathStep{
+					Steps: []linkedql.PathStep{
 						&As{
 							From: &Visit{
 								From: &Visit{
 									From:       &Placeholder{},
-									Properties: PropertyPath{&Vertex{Values: []quad.Value{quad.IRI("likes")}}},
+									Properties: linkedql.PropertyPath{&Vertex{Values: []quad.Value{quad.IRI("likes")}}},
 								},
-								Properties: PropertyPath{&Vertex{Values: []quad.Value{quad.IRI("name")}}},
+								Properties: linkedql.PropertyPath{&Vertex{Values: []quad.Value{quad.IRI("name")}}},
 							},
 							Name: "likesName",
 						},
 						&As{
 							From: &Visit{
 								From:       &Placeholder{},
-								Properties: PropertyPath{&Vertex{Values: []quad.Value{quad.IRI("name")}}},
+								Properties: linkedql.PropertyPath{&Vertex{Values: []quad.Value{quad.IRI("name")}}},
 							},
 							Name: "name",
 						},
@@ -573,14 +575,36 @@ var testCases = []struct {
 			},
 		},
 	},
+	{
+		name: "Context",
+		data: []quad.Quad{
+			quad.MakeIRI("http://example.org/alice", "http://example.org/likes", "http://example.org/bob", ""),
+			quad.MakeIRI("http://example.org/bob", "http://example.org/likes", "http://example.org/alice", ""),
+		},
+		query: &Context{
+			From: &Has{
+				From:     &Vertex{},
+				Property: linkedql.PropertyPath{linkedql.PropertyIRI("likes")},
+				Values:   []quad.Value{quad.IRI("bob")},
+			},
+			Rules: map[string]string{
+				"bob":   "http://example.org/bob",
+				"likes": "http://example.org/likes",
+			},
+		},
+		results: []interface{}{
+			map[string]string{"@id": "http://example.org/alice"},
+		},
+	},
 }
 
 func TestLinkedQL(t *testing.T) {
 	for _, c := range testCases {
 		t.Run(c.name, func(t *testing.T) {
 			store := memstore.New(c.data...)
+			voc := voc.Namespaces{}
 			ctx := context.TODO()
-			iterator, err := c.query.BuildIterator(store)
+			iterator, err := c.query.BuildIterator(store, &voc)
 			require.NoError(t, err)
 			var results []interface{}
 			for iterator.Next(ctx) {