######################################################################## # File name: xso.py # This file is part of: aioxmpp # # LICENSE # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program. If not, see # . # ######################################################################## import copy import aioxmpp.xso as xso from aioxmpp.utils import namespaces, magicmethod namespaces.xep0059_rsm = "http://jabber.org/protocol/rsm" class _RangeLimitBase(xso.XSO): value = xso.Text(default=None) def __init__(self, value=None): super().__init__() self.value = value class After(_RangeLimitBase): """ .. attribute:: value Identifier of the element which serves as a range limit for the query. """ TAG = namespaces.xep0059_rsm, "after" class Before(_RangeLimitBase): """ .. attribute:: value Identifier of the element which serves as a range limit for the query. """ TAG = namespaces.xep0059_rsm, "before" class First(_RangeLimitBase): """ .. attribute:: value Identifier of the first element in the result set. .. attribute:: index Approximate index of the first element in the result set. Can be used with :attr:`ResultSetMetadata.index` and :meth:`ResultSetMetadata.fetch_page` to approximately re-retrieve the page. .. seealso:: :meth:`~ResultSetMetadata.fetch_page` for hints on caveats and inaccuracies """ TAG = namespaces.xep0059_rsm, "first" index = xso.Attr( "index", type_=xso.Integer(), default=None, ) class Last(_RangeLimitBase): """ .. attribute:: value Identifier of the last element in the result set. """ TAG = namespaces.xep0059_rsm, "last" class ResultSetMetadata(xso.XSO): """ Represent the result set or query metadata. For requests, the following attributes are relevant: .. attribute:: after Either :data:`None` or a :class:`After` object. Generally mutually exclusive with :attr:`index`. .. attribute:: before Either :data:`None` or a :class:`Before` object. Generally mutually exclusive with :attr:`index`. .. attribute:: index The index of the first result to return, or :data:`None`. Generally mutually exclusive with :attr:`after` and :attr:`before`. .. attribute:: max The maximum number of items to return or :data:`None`. Setting :attr:`max` to zero will make the peer return a :class:`ResultSetMetadata` with the total number of items in the :attr:`count` field. These methods are useful when constructing queries: .. automethod:: fetch_page .. automethod:: limit .. automethod:: last_page For responses, the following attributes are relevant: .. attribute:: first Either :data:`None` or a :class:`First` object. .. attribute:: last Either :data:`None` or a :class:`Last` object. .. attribute:: count Either :data:`None` or the number of elements in the result set. If this is a response to a query with :attr:`max` set to zero, this is the total number of elements in the queried data. These methods are useful to construct a new request from a previous response: .. automethod:: next_page .. automethod:: previous_page """ TAG = namespaces.xep0059_rsm, "set" after = xso.Child([After]) before = xso.Child([Before]) first = xso.Child([First]) last = xso.Child([Last]) count = xso.ChildText( (namespaces.xep0059_rsm, "count"), type_=xso.Integer(), default=None, ) max_ = xso.ChildText( (namespaces.xep0059_rsm, "max"), type_=xso.Integer(), default=None, ) index = xso.ChildText( (namespaces.xep0059_rsm, "index"), type_=xso.Integer(), default=None, ) @classmethod def fetch_page(cls, index, max_=None): """ Return a query set which requests a specific page. :param index: Index of the first element of the page to fetch. :type index: :class:`int` :param max_: Maximum number of elements to fetch :type max_: :class:`int` or :data:`None` :rtype: :class:`ResultSetMetadata` :return: A new request set up to request a page starting with the element indexed by `index`. .. note:: This way of retrieving items may be approximate. See :xep:`59` and the embedding protocol for which RSM is used for specifics. """ result = cls() result.index = index result.max_ = max_ return result @magicmethod def limit(self, max_): """ Limit the result set to a given number of items. :param max_: Maximum number of items to return. :type max_: :class:`int` or :data:`None` :rtype: :class:`ResultSetMetadata` :return: A new request set up to request at most `max_` items. This method can be called on the class and on objects. When called on objects, it returns a copy of the object with :attr:`max_` set accordingly. When called on the class, it creates a fresh object with :attr:`max_` set accordingly. """ if isinstance(self, type): result = self() else: result = copy.deepcopy(self) result.max_ = max_ return result def next_page(self, max_=None): """ Return a query set which requests the page after this response. :param max_: Maximum number of items to return. :type max_: :class:`int` or :data:`None` :rtype: :class:`ResultSetMetadata` :return: A new request set up to request the next page. Must be called on a result set which has :attr:`last` set. """ result = type(self)() result.after = After(self.last.value) result.max_ = max_ return result def previous_page(self, max_=None): """ Return a query set which requests the page before this response. :param max_: Maximum number of items to return. :type max_: :class:`int` or :data:`None` :rtype: :class:`ResultSetMetadata` :return: A new request set up to request the previous page. Must be called on a result set which has :attr:`first` set. """ result = type(self)() result.before = Before(self.first.value) result.max_ = max_ return result @classmethod def last_page(self_or_cls, max_=None): """ Return a query set which requests the last page. :param max_: Maximum number of items to return. :type max_: :class:`int` or :data:`None` :rtype: :class:`ResultSetMetadata` :return: A new request set up to request the last page. """ result = self_or_cls() result.before = Before() result.max_ = max_ return result