Query a blaze expression in a given time range properly forward filling
    from values that fall before the lower date.

    Parameters
    ----------
    expr : Expr
        Bound blaze expression.
    lower : datetime
        The lower date to query for.
    upper : datetime
        The upper date to query for.
    checkpoints : Expr, optional
        Bound blaze expression for a checkpoints table from which to get a
        computed lower bound.
    odo_kwargs : dict, optional
        The extra keyword arguments to pass to ``odo``.
    ts_field : str, optional
        The name of the timestamp field in the given blaze expression.

    Returns
    -------
    raw : pd.DataFrame
        A strict dataframe for the data in the given date range. This may
        start before the requested start date if a value is needed to ffill.

def ffill_query_in_range(expr,
                         lower,
                         upper,
                         checkpoints=None,
                         odo_kwargs=None,
                         ts_field=TS_FIELD_NAME):
    """Query a blaze expression in a given time range properly forward filling
    from values that fall before the lower date.

    Parameters
    ----------
    expr : Expr
        Bound blaze expression.
    lower : datetime
        The lower date to query for.
    upper : datetime
        The upper date to query for.
    checkpoints : Expr, optional
        Bound blaze expression for a checkpoints table from which to get a
        computed lower bound.
    odo_kwargs : dict, optional
        The extra keyword arguments to pass to ``odo``.
    ts_field : str, optional
        The name of the timestamp field in the given blaze expression.

    Returns
    -------
    raw : pd.DataFrame
        A strict dataframe for the data in the given date range. This may
        start before the requested start date if a value is needed to ffill.
    """
    odo_kwargs = odo_kwargs or {}
    computed_lower, materialized_checkpoints = get_materialized_checkpoints(
        checkpoints,
        expr.fields,
        lower,
        odo_kwargs,
    )

    pred = expr[ts_field] <= upper

    if computed_lower is not None:
        # only constrain the lower date if we computed a new lower date
        pred &= expr[ts_field] >= computed_lower

    raw = pd.concat(
        (
            materialized_checkpoints,
            odo(
                expr[pred],
                pd.DataFrame,
                **odo_kwargs
            ),
        ),
        ignore_index=True,
    )
    raw.loc[:, ts_field] = raw.loc[:, ts_field].astype('datetime64[ns]')
    return raw