Yeah, unfortunately, there’s not a single function for that. In theory, it’s logically equivalent to something like:
Query.or(
Query.and(Query.field("a").equalsValue(1), Query.field("b").equalsValue(2), Query.field("c").greaterThan(3)),
Query.and(Query.field("a").equalsValue(1), Query.field("b").greaterThan(2)),
Query.field("a").greaterThan(1)
)
But, (1) that’s a bit unwieldy and (2) the planner isn’t quite smart to notice that if you have an index on concatenateFields("a", "b", "c")
, the given ranges can be used to turn that into a single scan.
If you did introduce a tupleize
function and made it a QueryableKeyExpression
, then you certainly could index the result of that function. Assuming the index exists, the planner should chose it for you with something like the expression you suggested.
It’s a bit unsatsifying, but I think the most straightforward way to get this to work is actually to forego the planner and just issue an index scan directly. Something like:
recordStore.scanIndexRecords(
indexName,
IndexScanType.BY_VALUE,
new TupleRange(Tuple.from(1, 2, 3), null, EndpointType.RANGE_EXCLUSIVE, EndpointType.TREE_END),
continuation // null if starting from the beginning; previous run's continuation if resuming a scan
scanProperties // specifies forward/reverse as well as limits
);
If you know you have the index you want, this can be simpler than trying to get the planner to produce the thing you want.