Skip to content

Changing Query Types

Gremlinq's query interfaces form a hierarchy — IVertexGremlinQuery<T> is more specific than IElementGremlinQuery<T>, which is more specific than IGremlinQuery<T>. Three families of methods let you move through that hierarchy at compile time, without emitting any Gremlin step.

Purpose Gremlin emitted
Lower() Steps down to the next less-specific interface (nothing)
Force*() Changes the interface type and projection hint (nothing)
AsAdmin().ChangeQueryType<T>() Direct switch to any built-in Gremlinq interface (nothing)

Lower()

Lower() returns the next less-specific interface in the hierarchy. The exact return type depends on the starting point:

Starting type Result of Lower()
IVertexGremlinQuery<T> IElementGremlinQuery<T>
IEdgeGremlinQuery<T> IEdgeOrVertexGremlinQuery<T>
IArrayGremlinQuery<…> IGremlinQuery<T[]>
IGremlinQuery<T> IGremlinQuery<T> (no-op)

The most common use is obtaining a shared base type when two branches of a Union() have different specific types, or when a DSL extension method requires a less-specific interface.

Lower on a vertex query
C#
// IVertexGremlinQuery<Airport> steps down to IElementGremlinQuery<Airport>.
_g.V<Airport>()
    .Lower();
Lower on an edge query
C#
// IEdgeGremlinQuery<Route> steps down to IEdgeOrVertexGremlinQuery<Route>.
_g.E<Route>()
    .Lower();

Force*()

The Force*() family changes both the C# interface type and the projection metadata that controls how Gremlinq deserializes results. They are available on any IGremlinQueryBase<TElement> and do not emit a Gremlin step.

Method Return type
ForceBase() IGremlinQuery<TElement>
ForceVertex() IVertexGremlinQuery<TElement>
ForceEdge() IEdgeGremlinQuery<TElement>
ForceElement() IElementGremlinQuery<TElement>
ForceValue() IGremlinQuery<TElement> (value projection)
ForceProperty() IPropertyGremlinQuery<TElement>
ForceValueTuple() IMapGremlinQuery<TElement>
ForceArray() IArrayGremlinQuery<TElement[], TElement, …>
ForceInEdge<TIn>() IInEdgeGremlinQuery<TElement, TIn>
ForceOutEdge<TOut>() IOutEdgeGremlinQuery<TElement, TOut>
ForceEdge<TOut, TIn>() IEdgeGremlinQuery<TElement, TOut, TIn>
ForceVertexProperty<TValue>() IVertexPropertyGremlinQuery<TElement, TValue>
ForceVertexProperty<TValue, TMeta>() IVertexPropertyGremlinQuery<TElement, TValue, TMeta>

A typical use case is re-establishing the correct interface type after an operation that strips specialisation — for example ForceBase(), or after constructing steps via AsAdmin(). ForceEdge<TOut, TIn>() is also the right tool when you need the three-parameter edge variant that records both incident vertex types.

Stripping and restoring vertex semantics
C#
// ForceBase() strips vertex projection semantics entirely.
// ForceVertex() re-establishes them.
// The Gremlin traversal is unchanged; only the C# interface type changes.
_g.V<Airport>()
    .ForceBase()     // → IGremlinQuery<Airport>
    .ForceVertex();  // → IVertexGremlinQuery<Airport>
Fully parameterizing an edge query with vertex types
C#
// ForceEdge<TOut, TIn>() produces the three-parameter variant that
// records both incident vertex types on the query object.
_g.E<Route>()
    .ForceEdge<Airport, Airport>();

Warning

Force*() only changes the C# type and the deserialization hint — it does not filter the graph. Use OfType<T>() when you need a server-side hasLabel(…) filter.

AsAdmin().ChangeQueryType<T>()

AsAdmin() is available on every query object and exposes IGremlinQueryAdmin, which provides ChangeQueryType<TTargetQuery>(). The only constraint is where TTargetQuery : IStartGremlinQuery, making it the broadest possible type change.

Force*() and Lower() cover most situations. Use ChangeQueryType<T>() when you need a specific Gremlinq query interface that neither produces — for example, switching between two well-known Gremlinq interfaces that have no direct coercion path. The target type must be one of the interfaces already implemented by Gremlinq's internal query type; arbitrary user-defined interfaces are not supported.

Direct type change via ChangeQueryType
C#
// ChangeQueryType<T> is the unrestricted escape hatch.
// Force*() and Lower() cover common cases; use this when you need to
// reach a custom DSL interface or a parameterized type they cannot produce.
_g.V<Airport>()
    .AsAdmin()
    .ChangeQueryType<IElementGremlinQuery<Airport>>();

IGremlinQueryAdmin also exposes AddStep<TTargetQuery>(), ConfigureSteps<TTargetQuery>(), ConfigureMetadata<TTargetQuery>(), and GetSource() for advanced step-level query construction in DSL extension methods.