private NonSegmentedIncludeCharPredicate buildExclusiveToPredicate(final DataRange dataRange,
                                                                       final boolean limitChars) {
        // TO (exclusive)

        long maxChars = limitChars
                ? sourceConfig.getMaxCharactersPerFetch()
                : Long.MAX_VALUE;

        final NonSegmentedIncludeCharPredicate exclusiveToPredicate;
        if (dataRange == null || !dataRange.hasBoundedEnd()) {
            // No end bound
            LOGGER.debug("Unbounded to predicate");
            exclusiveToPredicate = tracker ->
                    tracker.charsInRangeCount >= maxChars;
        } else if (dataRange.getOptLength().isPresent()) {
            final long dataLength = dataRange.getOptLength().get();
            LOGGER.debug("Length (inc.) to predicate [{}]", dataLength);
            exclusiveToPredicate = tracker ->
                    tracker.charsInRangeCount > dataLength || tracker.charsInRangeCount >= maxChars;
        } else if (dataRange.getOptByteOffsetTo().isPresent()) {
            final long byteOffsetTo = dataRange.getOptByteOffsetTo().get();
            LOGGER.debug("Byte offset (inc.) to predicate [{}]", byteOffsetTo);
            exclusiveToPredicate = tracker ->
                    tracker.currByteOffset > byteOffsetTo || tracker.charsInRangeCount >= maxChars;
        } else if (dataRange.getOptCharOffsetTo().isPresent()) {
            final long charOffsetTo = dataRange.getOptCharOffsetTo().get();
            LOGGER.debug("Char offset (inc.) to predicate [{}]", charOffsetTo);
            exclusiveToPredicate = tracker ->
                    tracker.currCharOffset > charOffsetTo || tracker.charsInRangeCount >= maxChars;
        } else if (dataRange.getOptLocationTo().isPresent()) {
            final int lineNoTo = dataRange.getOptLocationTo().get().getLineNo();
            final int colNoTo = dataRange.getOptLocationTo().get().getColNo();
            LOGGER.debug("Line/col (inc.) to predicate [{}, {}]", lineNoTo, colNoTo);
            exclusiveToPredicate = tracker ->
                    tracker.currLineNo > lineNoTo
                    || (tracker.currLineNo == lineNoTo && tracker.currColNo > colNoTo)
                    || tracker.charsInRangeCount >= maxChars;
        } else {
            throw new RuntimeException("No start point specified");
        }
        return exclusiveToPredicate;
    }
@return True if we have gone past our desired range
stroom-data/stroom-data-store-impl/src/main/java/stroom/data/store/impl/DataFetcher.java