# 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
        """Constructor.

        :param time_field: name of the timestamp field.
        :param copy_fields: list of fields to copy from the top hit document
            into the resulting aggregation.
        :param query_modifiers: List of functions accepting a ``query`` and
            ``**kwargs`` (same as provided to the ``run`` method), that will
            be applied to the aggregation query.
        :param required_filters: Dict of "mandatory query parameter" ->
            "filtered field".
        :param metric_fields: Dict of "destination field" ->
            tuple("metric type", "source field", "metric_options").
        """
        super(ESDateHistogramQuery, self).__init__(*args, **kwargs)
        self.time_field = time_field
        self.copy_fields = copy_fields or {}
        self.query_modifiers = query_modifiers or []
        self.required_filters = required_filters or {}
        self.metric_fields = metric_fields or {'value': ('sum', 'count', {})}
        self.allowed_metrics = {
            'cardinality', 'min', 'max', 'avg', 'sum', 'extended_stats',
            'geo_centroid', 'percentiles', 'stats'}
        if any(v not in self.allowed_metrics
               for k, (v, _, _) in (self.metric_fields or {}).items()):
            raise(ValueError('Metric type should be one of [{}]'
                             .format(', '.join(self.allowed_metrics))))

    def validate_arguments(self, interval, start_date, end_date, **kwargs):
        """Validate query arguments."""
        if interval not in self.allowed_intervals:

# 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

        """Constructor.

        :param time_field: name of the timestamp field.
        :param copy_fields: list of fields to copy from the top hit document
            into the resulting aggregation.
        :param query_modifiers: List of functions accepting a ``query`` and
            ``**kwargs`` (same as provided to the ``run`` method), that will
            be applied to the aggregation query.
        :param required_filters: Dict of "mandatory query parameter" ->
            "filtered field".
        :param metric_fields: Dict of "destination field" ->
            tuple("metric type", "source field", "metric_options").
        """
        super(ESDateHistogramQuery, self).__init__(*args, **kwargs)
        self.time_field = time_field
        self.copy_fields = copy_fields or {}
        self.query_modifiers = query_modifiers or []
        self.required_filters = required_filters or {}
        self.metric_fields = metric_fields or {'value': ('sum', 'count', {})}
        self.allowed_metrics = {
            'cardinality', 'min', 'max', 'avg', 'sum', 'extended_stats',
            'geo_centroid', 'percentiles', 'stats'}
        if any(v not in self.allowed_metrics
               for k, (v, _, _) in (self.metric_fields or {}).items()):
            raise(ValueError('Metric type should be one of [{}]'
                             .format(', '.join(self.allowed_metrics))))

    def validate_arguments(self, interval, start_date, end_date, **kwargs):
        """Validate query arguments."""
        if interval not in self.allowed_intervals:

            raise InvalidRequestInputError(