{ "info": { "author": "Robert Lechte", "author_email": "robertlechte@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha" ], "description": "sqlakeyset: offset-free paging for sqlalchemy\n=============================================\n\n.. image:: https://travis-ci.org/djrobstep/sqlakeyset.svg?branch=master\n :target: https://travis-ci.org/djrobstep/sqlakeyset\n\nThis library implements keyset-based paging for SQLAlchemy (both ORM and core).\n\nThis library has been tested with PostgreSQL and MariaDB/MySQL. It should work with other SQLAlchemy-supported databases too provided they support ``row(`` syntax (see below).\n\nBackground\n----------\n\nA lot of people use SQL's ``OFFSET`` syntax to implement paging of query results. The trouble with that is, the more pages you get through, the slower your query gets. Also, if the results you're paging through change frequently, it's possible to skip over or repeat results between pages. Keyset paging avoids these problems: Selecting even the millionth page is as fast as selecting the first.\n\n**sqlakeyset seems to work well so far, but is in its early stages of development, and as such, is alpha software. Treat it accordingly.**\n\n\nGetting Started\n---------------\n\nHere's how it works with a typical ORM query:\n\n.. code-block:: python\n\n from sqlakeyset import get_page\n from sqlbag import S\n\n from models import Book\n\n with S('postgresql:///books') as s: # create a session\n q = s.query(Book).order_by(Book.author, Book.title, Book.id) #\n\n # gets the first page\n page1 = get_page(q, per_page=20)\n\n # gets the key for the next page\n next_page = page1.paging.next\n\n # gets the second page\n page2 = get_page(q, per_page=20, page=next_page)\n\n # returning to the first page, getting the key\n previous_page = page2.paging.previous\n\n # the first page again, backwards from the previous page\n page1 = get_page(q, per_page=20, page=previous_page)\n\n # what if new items were added at the start?\n if page1.paging.has_previous:\n\n # go back even further\n previous_page = page1.paging.previous\n page1 = get_page(q, per_page=20, page=previous_page)\n\n\nUnder the Hood\n--------------\n\nsqlakeyset does the following to your query in order to get the paged contents:\n\n- adds a where clause, to get only rows after the specified row key.\n- if getting the previous page, reverses the order by direction in order the get the rows *before* the specified bookmark.\n- adds a limit clause, to fetch only enough items to fill the page, plus one additional (this additional row is used only to test for the existence of further pages after the current one, and is discarded from the results).\n- returns the page contents as an ordinary list that has an attached ``.paging`` attribute with the paging information for this and related pages.\n\n\nPage objects\n------------\n\nPaged items/rows are returned in a Page object, which is a vanilla python list, except with an attached ``Paging`` object with the paging information.\n\nProperties such as `next` and `previous` return a 2-tuple containing the ordering key for the row, and a boolean to specify if the direction is forwards or backwards.\n\nIn our above example, the 2-tuple specifying the second page might look like:\n\n.. code-block:: python\n\n ('Joseph Heller', 'Catch 22', 123), False\n\nThe `False` means the query will fetch the page *after* the row containing Catch 22. This tuple contains two elements, title and id, to match the order by clause of the query.\n\nThe page before this row would be specified as:\n\n.. code-block:: python\n\n ('Joseph Heller', 'Catch 22', 123), True\n\nThe first and last pages are fetched with `None` instead of a tuple, so for the first page (this is also the default if the page parameter is not specified):\n\n.. code-block:: python\n\n None, False\n\nAnd the last page:\n\n.. code-block:: python\n\n None, True\n\nKeyset Serialization\n--------------------\n\nYou will probably want to turn these keysets/bookmarks for passing around. ``sqlakeyset`` includes code to do this. To get a serialized bookmark, just add ``bookmark_`` to the name of the property that holds the keyset you want.\n\nMost commonly you'll want ``next`` and ``previous``, so:\n\n.. code-block:: python\n\n >>> page.paging.bookmark_previous\n >> page.paging.bookmark_next\n >i:1~i:2014~s:Shake It Off~i:31\n\n``sqlakeyset`` uses the python csv row serializer to serialize the bookmark values (using ``~`` instead of a ``,`` as the separator). Direction is indicated by ``>`` (forwards/next), or ``<`` (backwards/previous) at the start of the string.\n\nLimitations\n-----------\n\n- **Golden Rule:** Always ensure your keysets are unique per row. If you violate this condition you risk skipped rows and other nasty problems. The simplest way to do this is to always include your primary key column(s) at the end of your ordering columns.\n\n- If you're using the in-built keyset serialization, this only handles basic data/column types so far (strings, ints, floats, datetimes, dates, booleans, and a few others). The serialization can be extended to serialize more advanced types as necessary (documentation on this is forthcoming).\n\n- **Known MariaDB/MySQL issue:** For performing comparisons, sqlakeyset generates row-value syntax similar to the following:\n\n.. code-block:: sql\n\n where row('a', 1) > row(name, id)\n\nIndexing support for this syntax in MariaDB/MySQL is apparently faulty. So performance on paging large tables may be poor (Meanwhile, PostgreSQL correctly supports indexing for this syntax).\n\n- **sqlakeyset is alpha software** Please be aware that ``sqlakeyset`` is in its early stage of development. That said, please use it! Your feedback is most welcome (good or bad).\n\n\nDocumentation\n-------------\n\n``sqlakeyset`` is in early alpha and documentation other than this README is scarce so far. We are working on remedying this. Watch this space.\n\n\nInstallation\n------------\n\nAssuming you have `pip `_ installed, all you need to do is install as follows:\n\n.. code-block:: shell\n\n $ pip install sqlakeyset\n\nThis will install sqlakeyset and also sqlalchemy if not already installed. Obviously you'll need the necessary database driver for your chosen database to be installed also.\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/djrobstep/sqlakeyset", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "sqlakeyset", "package_url": "https://pypi.org/project/sqlakeyset/", "platform": "", "project_url": "https://pypi.org/project/sqlakeyset/", "project_urls": { "Homepage": "https://github.com/djrobstep/sqlakeyset" }, "release_url": "https://pypi.org/project/sqlakeyset/0.1.1559103842/", "requires_dist": [ "sqlalchemy", "python-dateutil" ], "requires_python": "", "summary": "offset-free paging for sqlalchemy", "version": "0.1.1559103842" }, "last_serial": 5330990, "releases": { "0.1.1472125695": [ { "comment_text": "", "digests": { "md5": "01908472fd94573cba65d220a9ef2578", "sha256": "02f44cdda986d200c9d1d079a5c106a6fbc2d1646b117c7e644e6516a22877da" }, "downloads": -1, "filename": "sqlakeyset-0.1.1472125695-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "01908472fd94573cba65d220a9ef2578", "packagetype": "bdist_wheel", "python_version": "3.5", "requires_python": null, "size": 13467, "upload_time": "2016-08-25T12:06:46", "url": "https://files.pythonhosted.org/packages/9c/bb/286e639f2040fe7973750a5c247fdd2571e1ba3c368f5f24bafb4f4c8184/sqlakeyset-0.1.1472125695-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7191b5d91bdc1cdf287cfd29315ac71d", "sha256": "b2d8f67e069d717c5a4068c1580b7e49f04944d145af0e770bd0681b50dc9265" }, "downloads": -1, "filename": "sqlakeyset-0.1.1472125695.tar.gz", "has_sig": false, "md5_digest": "7191b5d91bdc1cdf287cfd29315ac71d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11051, "upload_time": "2016-08-25T12:06:44", "url": "https://files.pythonhosted.org/packages/71/be/cfd3cdf27c77e98ce2249e6ed980a93e5a533eb11dcdb78dbbe5552a25bd/sqlakeyset-0.1.1472125695.tar.gz" } ], "0.1.1485813522": [ { "comment_text": "", "digests": { "md5": "df87e059f28485b4644ad1f4c9d9bace", "sha256": "f34f7b00dd66491815b050b6f1725d0836a51749bbff342afaa10aee5715e65b" }, "downloads": -1, "filename": "sqlakeyset-0.1.1485813522-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "df87e059f28485b4644ad1f4c9d9bace", "packagetype": "bdist_wheel", "python_version": "3.5", "requires_python": null, "size": 13717, "upload_time": "2017-01-30T22:06:10", "url": "https://files.pythonhosted.org/packages/f0/91/f15a15373bed6b76a29d037d89990ea0a2bbb530eeefb219c38a43f93632/sqlakeyset-0.1.1485813522-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "60d33b8f0180e96f515ad6abf4c59875", "sha256": "252452e27ac67438f0e5ccaad214830130f186b3dbba86478ce2ed8a16c8c72a" }, "downloads": -1, "filename": "sqlakeyset-0.1.1485813522.tar.gz", "has_sig": false, "md5_digest": "60d33b8f0180e96f515ad6abf4c59875", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8856, "upload_time": "2017-01-30T22:06:05", "url": "https://files.pythonhosted.org/packages/93/c0/c9d11265cb94de44597ebd6916e8dd3eb53a52b24d217489c7717427d47f/sqlakeyset-0.1.1485813522.tar.gz" } ], "0.1.1558438465": [ { "comment_text": "", "digests": { "md5": "979e556133dec9ddd014ec2062892f89", "sha256": "b526e048d571f0b6b5006320109fb6bbc48b005e74ecea1cab7f24f78e882a10" }, "downloads": -1, "filename": "sqlakeyset-0.1.1558438465-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "979e556133dec9ddd014ec2062892f89", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 11347, "upload_time": "2019-05-21T11:36:47", "url": "https://files.pythonhosted.org/packages/fe/b2/10e4cad7e80deb904c2cfad233a1c668b1ca76c87facf708206065d8e08d/sqlakeyset-0.1.1558438465-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "2ef6539ea10c5d9656c8581758b8cc75", "sha256": "38fd6e0982bc3c33c92b86ded0b471b8fcb29d8f2014967499a2e133e70455f4" }, "downloads": -1, "filename": "sqlakeyset-0.1.1558438465.tar.gz", "has_sig": false, "md5_digest": "2ef6539ea10c5d9656c8581758b8cc75", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11424, "upload_time": "2019-05-21T11:36:49", "url": "https://files.pythonhosted.org/packages/89/9e/b5bd6c86ba9dbb7b06922de5c0676cc1d8c78a8d4508f92bf4899aff9dc5/sqlakeyset-0.1.1558438465.tar.gz" } ], "0.1.1559103842": [ { "comment_text": "", "digests": { "md5": "8f44d66c9e33caf3131f10e54b3e526f", "sha256": "7f5ec3f66794618d8364743a41a09d75691475a8fcd2b3b0c6d81209d4e12e0a" }, "downloads": -1, "filename": "sqlakeyset-0.1.1559103842-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "8f44d66c9e33caf3131f10e54b3e526f", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 11377, "upload_time": "2019-05-29T07:54:05", "url": "https://files.pythonhosted.org/packages/30/5a/d997e6cb3b4deee47fc1f14f162f1175b837752cb8c71d1e9b5d28f71e3d/sqlakeyset-0.1.1559103842-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "82036822d242e91b6c7bd7f643db1ccd", "sha256": "6644d3a6df7fe69d6f3b356befac156c19b1641c5a520cccc82e1d5c9aef0103" }, "downloads": -1, "filename": "sqlakeyset-0.1.1559103842.tar.gz", "has_sig": false, "md5_digest": "82036822d242e91b6c7bd7f643db1ccd", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11463, "upload_time": "2019-05-29T07:54:08", "url": "https://files.pythonhosted.org/packages/68/f6/96568d405dc6eada6cfea8d69d19d9a16b2968555c04e7db73e8b7a86983/sqlakeyset-0.1.1559103842.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "8f44d66c9e33caf3131f10e54b3e526f", "sha256": "7f5ec3f66794618d8364743a41a09d75691475a8fcd2b3b0c6d81209d4e12e0a" }, "downloads": -1, "filename": "sqlakeyset-0.1.1559103842-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "8f44d66c9e33caf3131f10e54b3e526f", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 11377, "upload_time": "2019-05-29T07:54:05", "url": "https://files.pythonhosted.org/packages/30/5a/d997e6cb3b4deee47fc1f14f162f1175b837752cb8c71d1e9b5d28f71e3d/sqlakeyset-0.1.1559103842-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "82036822d242e91b6c7bd7f643db1ccd", "sha256": "6644d3a6df7fe69d6f3b356befac156c19b1641c5a520cccc82e1d5c9aef0103" }, "downloads": -1, "filename": "sqlakeyset-0.1.1559103842.tar.gz", "has_sig": false, "md5_digest": "82036822d242e91b6c7bd7f643db1ccd", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11463, "upload_time": "2019-05-29T07:54:08", "url": "https://files.pythonhosted.org/packages/68/f6/96568d405dc6eada6cfea8d69d19d9a16b2968555c04e7db73e8b7a86983/sqlakeyset-0.1.1559103842.tar.gz" } ] }