I've followed the Gremlin pagination receipe and find it works fine in all scenarios, except when you ask for 1 item against an empty traversal, then it fails with an error:
The provided start does not map to a value: []->[NeptuneMemoryTrackerStep, RangeLocalStep(0,1)]
Asking for one item from a non-empty traversal works fine. Asking for 0 items, 2 items or 10,000 items from an empty traversal is also fine!
Behaviour is as-expected with no errors except when asking for exactly 1 item from an empty traversal.
How can I make pagination resilient and work against queries that find no data when consumers are asking for exactly one item?
g.inject([])
.as('items','count')
.select('items','count')
.by(range(local, 0, 1))
.by(count(local))
.project('count', 'items')
.by(select('count'))
.by(select('items'))
BTW this is running on AWS Neptune.
Running the query just in the Gremlin Console perhaps further illustrates why this happens with values of 2 in the first case and 1 in the second.
gremlin> g.inject([]).
......1> as('items','count').
......2> select('items','count').
......3> by(range(local, 0, 2)).
......4> by(count(local)).
......5> project('count', 'items').
......6> by(select('count')).
......7> by(select('items'))
==>[count:0,items:[]]
gremlin> g.inject([]).
......1> as('items','count').
......2> select('items','count').
......3> by(range(local, 0, 1)).
......4> by(count(local)).
......5> project('count', 'items').
......6> by(select('count')).
......7> by(select('items'))
The provided start does not map to a value: []->[RangeLocalStep(0,1)]
The reason this happens is that any call to range
with a length greater than 1 will return a list. However, when at most 1 item can be returned a single value gets returned, which in this case is essentially "nothing" and hence there is no value to put into the final project
result. You will have to change the query to allow for this if an empty result and a range of length 1 is something you expect to encounter.
To further illustrate the difference, see the example below:
gremlin> g.inject([1,2,3]).range(local,0,2)
==>[1,2]
gremlin> g.inject([1,2,3]).range(local,0,1)
==>1
Here is one way to adjust your query so that all of these cases still yield a result.
gremlin> g.inject([]).
......1> as('items','count').
......2> select('items','count').
......3> by(coalesce(range(local, 0, 1),constant([]))).
......4> by(count(local)).
......5> project('count', 'items').
......6> by(select('count')).
......7> by(select('items'))
==>[count:0,items:[]]