# Path: invenio_stats/errors.py
# class InvalidRequestInputError(RESTException):
#     """Error raised when the request input is invalid."""
# 
#     code = 400
# 
#     def __init__(self, description, **kwargs):
#         """Initialize exception."""
#         super(RESTException, self).__init__(**kwargs)
#         self.description = description
# 
# Path: invenio_stats/utils.py
# def get_bucket_size(client, index, agg_field, start_date=None, end_date=None):
#     """Function to help us define the size for our search query.
# 
#     :param client: search client
#     :param str index: prefixed search index
#     :param str agg_field: aggregation field
#     :param str start_date: string containing a formatted start date
#     :param str end_date: string containing a formatted end date
# 
#     """
#     time_range = {}
#     if start_date is not None:
#         time_range['gte'] = start_date
#     if end_date is not None:
#         time_range['lte'] = end_date
# 
#     search = Search(using=client, index=index)
#     if time_range:
#         search = search.filter('range', timestamp=time_range)
#     search.aggs.metric('unique_values', 'cardinality', field=agg_field)
# 
#     result = search.execute()
#     unique_values = result.aggregations.unique_values.value
# 
#     # NOTE: we increase the count by 10% in order to be safe
#     return int(ceil(unique_values + unique_values * 0.1))


from datetime import datetime
from elasticsearch_dsl import Search
from invenio_search import current_search_client
from invenio_search.utils import build_alias_name
from .errors import InvalidRequestInputError
from .utils import get_bucket_size
import dateutil.parser
import six
            )

    def build_query(self, start_date, end_date, **kwargs):
        """Build the elasticsearch query."""
        agg_query = Search(using=self.client, index=self.index)[0:0]

        if start_date is not None or end_date is not None:
            time_range = {}
            if start_date is not None:
                time_range['gte'] = start_date.isoformat()
            if end_date is not None:
                time_range['lte'] = end_date.isoformat()
            agg_query = agg_query.filter(
                'range',
                **{self.time_field: time_range})

        for modifier in self.query_modifiers:
            agg_query = modifier(agg_query, **kwargs)

        base_agg = agg_query.aggs

        def _apply_metric_aggs(agg):
            for dst, (metric, field, opts) in self.metric_fields.items():
                agg.metric(dst, metric, field=field, **opts)

        _apply_metric_aggs(base_agg)
        if self.aggregated_fields:
            cur_agg = base_agg
            for term in self.aggregated_fields:
                cur_agg = cur_agg.bucket(

# Path: invenio_stats/errors.py
# class InvalidRequestInputError(RESTException):
#     """Error raised when the request input is invalid."""
# 
#     code = 400
# 
#     def __init__(self, description, **kwargs):
#         """Initialize exception."""
#         super(RESTException, self).__init__(**kwargs)
#         self.description = description
# 
# Path: invenio_stats/utils.py
# def get_bucket_size(client, index, agg_field, start_date=None, end_date=None):
#     """Function to help us define the size for our search query.
# 
#     :param client: search client
#     :param str index: prefixed search index
#     :param str agg_field: aggregation field
#     :param str start_date: string containing a formatted start date
#     :param str end_date: string containing a formatted end date
# 
#     """
#     time_range = {}
#     if start_date is not None:
#         time_range['gte'] = start_date
#     if end_date is not None:
#         time_range['lte'] = end_date
# 
#     search = Search(using=client, index=index)
#     if time_range:
#         search = search.filter('range', timestamp=time_range)
#     search.aggs.metric('unique_values', 'cardinality', field=agg_field)
# 
#     result = search.execute()
#     unique_values = result.aggregations.unique_values.value
# 
#     # NOTE: we increase the count by 10% in order to be safe
#     return int(ceil(unique_values + unique_values * 0.1))


# Path: invenio_stats/queries.py
from datetime import datetime
from elasticsearch_dsl import Search
from invenio_search import current_search_client
from invenio_search.utils import build_alias_name
from .errors import InvalidRequestInputError
from .utils import get_bucket_size
import dateutil.parser
import six

            )

    def build_query(self, start_date, end_date, **kwargs):
        """Build the elasticsearch query."""
        agg_query = Search(using=self.client, index=self.index)[0:0]

        if start_date is not None or end_date is not None:
            time_range = {}
            if start_date is not None:
                time_range['gte'] = start_date.isoformat()
            if end_date is not None:
                time_range['lte'] = end_date.isoformat()
            agg_query = agg_query.filter(
                'range',
                **{self.time_field: time_range})

        for modifier in self.query_modifiers:
            agg_query = modifier(agg_query, **kwargs)

        base_agg = agg_query.aggs

        def _apply_metric_aggs(agg):
            for dst, (metric, field, opts) in self.metric_fields.items():
                agg.metric(dst, metric, field=field, **opts)

        _apply_metric_aggs(base_agg)
        if self.aggregated_fields:
            cur_agg = base_agg
            for term in self.aggregated_fields:
                cur_agg = cur_agg.bucket(

                    term, 'terms', field=term, size=get_bucket_size(