class RangeStream extends BaseVisitor implements CloseableIterable<QueryPlan> {

    public CloseableIterable<QueryPlan> streamPlans(JexlNode script) {
        JexlNode node = TreeFlatteningRebuildingVisitor.flatten(script);
        
        tree = node;
        
        if (!collapseUids && config.getParseTldUids()) {
            collapseUids = !(EvaluationRendering.canDisableEvaluation(script, config, metadataHelper, true));
            
            if (log.isTraceEnabled()) {
                log.trace("New query is " + JexlStringBuildingVisitor.buildQuery(tree));
                log.trace("Collapse UIDs is now " + collapseUids + " because we have a TLD Query with an ivarator");
            }
        }
        
        // check the query depth (up to config.getMaxDepthThreshold() + 1)
        int depth = DepthVisitor.getDepth(node, config.getMaxDepthThreshold());
        if (depth > config.getMaxDepthThreshold()) {
            PreConditionFailedQueryException qe = new PreConditionFailedQueryException(DatawaveErrorCode.QUERY_DEPTH_THRESHOLD_EXCEEDED, MessageFormat.format(
                            "{0} > {1}, last operation: {2}", depth, config.getMaxDepthThreshold(), "RangeStreamLookup"));
            throw new DatawaveFatalQueryException(qe);
        }
        
        if (log.isTraceEnabled()) {
            log.trace(JexlStringBuildingVisitor.buildQuery(node));
        }
        
        IndexStream ranges = (IndexStream) node.jjtAccept(this, null);
        
        // Guards against the case of a very oddly formed JEXL query, e.g. ("foo")
        if (null == ranges) {
            this.context = StreamContext.UNINDEXED;
            this.itr = Collections.<QueryPlan> emptySet().iterator();
        } else {
            // we can build the iterator at a later point, grabbing the top most
            // context. This will usually provide us a hint about the context
            // within our stream.
            context = ranges.context();
            this.itr = null;
        }
        if (log.isDebugEnabled()) {
            log.debug("Query returned a stream with a context of " + this.context);
            if (queryStream != null) {
                for (String line : StringUtils.split(queryStream.getContextDebug(), '\n')) {
                    log.debug(line);
                }
            }
        }
        
        this.queryStream = ranges;
        
        return this;
    }

    public  RangeStream(ShardQueryConfiguration config, ScannerFactory scanners, MetadataHelper metadataHelper);

}