@@ -0,0 +1,2961 @@
+import graphene%0Afrom graphene.utils.str_converters import to_camel_case%0Afrom django.utils import six%0Afrom django.utils.functional import cached_property%0A%0A__all__ = %5B'Pager'%5D%0A%0A%0Aclass BasePager(object):%0A    def __init__(self, data, queryset, default_size=20):%0A        # process data%0A        self.qs = self._process_data(data or %7B%7D, queryset, default_size)%0A%0A    def _process_data(self, data, queryset, default_size):%0A        # we may have to handle sorting fields%0A        if self._sort_fields:%0A            # check if we've some%0A            sort_fields = data.get('sort', None)%0A%0A            if sort_fields:%0A                # so order the queryset%0A                queryset = queryset.order_by(*sort_fields)%0A%0A        # we maye have to get all items%0A        if data.get('all', False):%0A            # no need to paginate it%0A            return queryset%0A%0A        # get the offset (0 by default)%0A        offset = data.get('offset', 0)%0A        # final queryset%0A        return queryset%5Boffset:offset + data.get('size', default_size)%5D%0A%0A    @classmethod%0A    def to_input(cls, input_name, graphql_type=graphene.InputObjectType, enum_name=None):%0A        # start with basic attributes%0A        attrs = %7B%0A            'offset': graphene.Int(),%0A            'size': graphene.Int(),%0A            'all': graphene.Boolean()%0A        %7D%0A%0A        # we might have to support sorting%0A        if cls._sort_fields:%0A            # first ensure we have a name%0A            if enum_name is None:%0A                # made it from the input name%0A                enum_name = '%25SortField' %25 input_name%0A%0A            # then build the enum for this input%0A            sort_enum = graphene.Enum(enum_name, list(cls._sort_fields.items()))%0A            # and the field%0A            attrs%5B'sort'%5D = graphene.List(sort_enum)%0A%0A        # build the final type%0A        return type(input_name, (graphql_type,), attrs)%0A%0A%0Aclass PagerMeta(type):%0A    def __new__(mcs, name, bases, attrs):%0A        # build the new class%0A        new_method = super(PagerMeta, mcs).__new__%0A%0A        if bases == (BasePager,):%0A            return new_method(mcs, name, bases, attrs)%0A%0A        # start with an empty list of fields%0A        fields = %7B%7D%0A%0A        # loop on attributes%0A        for key, field in list(attrs.items()):%0A            # only attributes with an upper name and a string as value%0A            # will be considered as sorting field%0A            if key.isupper() and isinstance(field, str):%0A                # remove it from attribute%0A                attrs.pop(key)%0A                # turn the key into camel case%0A                key = to_camel_case(key.lower())%0A                # push it into valid fields%0A                fields%5Bkey%5D = field%0A                fields%5B'%25s_Desc' %25 key%5D = '-%25s' %25 field%0A%0A        # create the new class%0A        new_cls = new_method(mcs, name, bases, attrs)%0A%0A        # then add fields%0A        new_cls._sort_fields = fields%0A%0A        return new_cls%0A%0A%0Aclass Pager(six.with_metaclass(PagerMeta, BasePager)):%0A    pass%0A

Add a way to handle sorts & pagination