from sqlalchemy import func

from babbage.model.concept import Concept


class Aggregate(Concept):
    """ An aggregates describes the application of an aggregate function (such
    as summing, averages, counts etc.) to a measure or the primary key of the
    cube. """

    def __init__(self, model, label, function, measure=None):
        super(Aggregate, self).__init__(model, None, {'label': label})
        self.function = function
        self.measure = measure

    @property
    def ref(self):
        if self.measure is not None:
            return '%s.%s' % (self.measure.ref, self.function)
        return '_%s' % self.function

    def bind(self, cube):
        """ When one column needs to match, use the key. """
        if self.measure:
            table, column = self.measure.bind(cube)
        else:
            table, column = cube.fact_table, cube.fact_pk
        # apply the SQL aggregation function:
        column = getattr(func, self.function)(column)
        column = column.label(self.ref)
        column.quote = True
        return table, column

    def __repr__(self):
        return "<Aggregate(%s)>" % self.ref

    def to_dict(self):
        data = self.spec.copy()
        data['ref'] = self.ref
        data['function'] = self.function
        if self.measure is not None:
            data['measure'] = self.measure.ref
        return data