rqlalchemy


Namerqlalchemy JSON
Version 0.5.0 PyPI version JSON
download
home_pagehttps://github.com/pjwerneck/rqlalchemy
Summary"Resource Query Language for SQLAlchemy"
upload_time2023-12-09 18:31:04
maintainer
docs_urlNone
authorPedro Werneck
requires_python>=3.8,<4.0
licenseMIT
keywords sqlachemy sql rql querying httpapi
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI
coveralls test coverage No coveralls.
            # RQLAlchemy

[![Build Status](https://github.com/pjwerneck/rqlalchemy/actions/workflows/pytest.yml/badge.svg?branch=develop)](https://github.com/pjwerneck/rqlalchemy/actions/workflows/pytest.yml)

## Resource Query Language extension for SQLAlchemy

**Overview**

Resource Query Language (RQL) is a query language designed for use in URIs, with object-style data structures.

`rqlalchemy` is an RQL extension for SQLAlchemy, making it easy to expose SQLAlchemy tables or models as an HTTP API endpoint and perform complex queries using only query string parameters.

**Installing**

```bash
pip install rqlalchemy
```

**Usage**

Support RQL queries in your application by using the `select()` construct provided by RQLAlchemy. After creating the selectable, use the `rql()` method to apply the RQL query string, and then use the `execute()` method with the session to retrieve the results.

For example, in a Flask HTTP API with a users collection endpoint querying the `User` model:

```python
from urllib.parse import unquote
from flask import request

from rqlalchemy import select

@app.route('/users')
def get_users_collection():
    qs = unquote(request.query_string.decode(request.charset))
    users = select(User).rql(qs).execute(session)

    return render_response(users)
```

The `.execute()` method handles the session and adjusts the results accordingly, returning scalars, lists of dicts, or a single scalar result when appropriate. There's no need to use `session.execute()` or `session.scalars()` directly unless you want to handle the results yourself.

**Pagination**

RQLAlchemy offers limit/offset pagination with the `rql_paginate()` method, returning the requested page, RQL expressions for previous and next pages if available, and the total number of items.

```python
from urllib.parse import unquote
from flask import request

from rqlalchemy import select

@app.route('/users')
def get_users_collection():
    qs = unquote(request.query_string.decode(request.charset))
    res = select(User).rql(qs).rql_paginate(session)

    response = {
        "data": res.page,
        "total": res.total,
    }

    if res.previous_page:
        response["previous"] = '/users?' + res.previous_page

    if res.next_page:
        response["next"] = '/users?' + res.next_page

    return render_response(response)
```

Pagination requires a limit, as a `RQLSelect._rql_default_limit` value, a query string `limit(x)`, or the `limit` parameter to the `rql()` method. Calling `rql_paginate()` without a limit will raise `RQLQueryError`.

**Reference Table**

| RQL                     | SQLAlchemy equivalent                              | Observation                                                                                                                     |
|-------------------------|----------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------|
| QUERYING                |                                                    |                                                                                                                                 |
| select(a,b,c,...)       | select(Model.a, Model.b, Model.c,...)              |                                                                                                                                 |
| values(a)               | [o.a for o in query.from_self(a)]                  |                                                                                                                                 |
| limit(count,start?)     | .limit(count).offset(start)                        |                                                                                                                                 |
| sort(attr1)             | .order_by(attr)                                    |                                                                                                                                 |
| sort(-attr1)            | .order_by(attr.desc())                             |                                                                                                                                 |
| distinct()              | .distinct()                                        |                                                                                                                                 |
| first()                 | .limit(1)                                          |                                                                                                                                 |
| one()                   | [query.one()]                                      |                                                                                                                                 |
| FILTERING               |                                                    |                                                                                                                                 |
| eq(attr,value)          | .where(Model.attr == value)                        |                                                                                                                                 |
| ne(attr,value)          | .where(Model.attr != value)                        |                                                                                                                                 |
| lt(attr,value)          | .where(Model.attr < value)                         |                                                                                                                                 |
| le(attr,value)          | .where(Model.attr <= value)                        |                                                                                                                                 |
| gt(attr,value)          | .where(Model.attr > value)                         |                                                                                                                                 |
| ge(attr,value)          | .where(Model.attr >= value)                        |                                                                                                                                 |
| in(attr,value)          | .where(Model.attr.in_(value)                       |                                                                                                                                 |
| out(attr,value)         | .where(not_(Model.attr.in_(value)))                |                                                                                                                                 |
| contains(attr,value)    | .where(Model.contains(value))                      | Produces a LIKE expression when querying against a string, or an IN expression when querying against an iterable relationship   |
| excludes(attr,value)    | .where(not_(Model.contains(value)))                | See above.                                                                                                                      |
| and(expr1,expr2,...)    | .where(and_(expr1, expr2, ...))                    |                                                                                                                                 |
| or(expr1,expr2,...)     | .where(or_(expr1, expr2, ...))                     |                                                                                                                                 |
| AGGREGATING             |                                                    | All aggregation functions return scalar results.                                                                                |
| aggregate(a,b\(c\),...) | select(Model.a, func.b(Model.c)).group_by(Model.a) |                                                                                                                                 |
| sum(attr)               | select(func.sum(Model.attr))                       |                                                                                                                                 |
| mean(attr)              | select(func.avg(Model.attr))                       |                                                                                                                                 |
| max(attr)               | select(func.max(Model.attr))                       |                                                                                                                                 |
| min(attr)               | select(func.min(Model.attr))                       |                                                                                                                                 |
| count()                 | select(func.count())                               |                                                                                                                                 |


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/pjwerneck/rqlalchemy",
    "name": "rqlalchemy",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8,<4.0",
    "maintainer_email": "",
    "keywords": "sqlachemy,sql,rql,querying,httpapi",
    "author": "Pedro Werneck",
    "author_email": "pjwerneck@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/59/c5/ac566b53f835898c3219e1f1bd610ddbd66e444ec24231dd3c1676c9388d/rqlalchemy-0.5.0.tar.gz",
    "platform": null,
    "description": "# RQLAlchemy\n\n[![Build Status](https://github.com/pjwerneck/rqlalchemy/actions/workflows/pytest.yml/badge.svg?branch=develop)](https://github.com/pjwerneck/rqlalchemy/actions/workflows/pytest.yml)\n\n## Resource Query Language extension for SQLAlchemy\n\n**Overview**\n\nResource Query Language (RQL) is a query language designed for use in URIs, with object-style data structures.\n\n`rqlalchemy` is an RQL extension for SQLAlchemy, making it easy to expose SQLAlchemy tables or models as an HTTP API endpoint and perform complex queries using only query string parameters.\n\n**Installing**\n\n```bash\npip install rqlalchemy\n```\n\n**Usage**\n\nSupport RQL queries in your application by using the `select()` construct provided by RQLAlchemy. After creating the selectable, use the `rql()` method to apply the RQL query string, and then use the `execute()` method with the session to retrieve the results.\n\nFor example, in a Flask HTTP API with a users collection endpoint querying the `User` model:\n\n```python\nfrom urllib.parse import unquote\nfrom flask import request\n\nfrom rqlalchemy import select\n\n@app.route('/users')\ndef get_users_collection():\n    qs = unquote(request.query_string.decode(request.charset))\n    users = select(User).rql(qs).execute(session)\n\n    return render_response(users)\n```\n\nThe `.execute()` method handles the session and adjusts the results accordingly, returning scalars, lists of dicts, or a single scalar result when appropriate. There's no need to use `session.execute()` or `session.scalars()` directly unless you want to handle the results yourself.\n\n**Pagination**\n\nRQLAlchemy offers limit/offset pagination with the `rql_paginate()` method, returning the requested page, RQL expressions for previous and next pages if available, and the total number of items.\n\n```python\nfrom urllib.parse import unquote\nfrom flask import request\n\nfrom rqlalchemy import select\n\n@app.route('/users')\ndef get_users_collection():\n    qs = unquote(request.query_string.decode(request.charset))\n    res = select(User).rql(qs).rql_paginate(session)\n\n    response = {\n        \"data\": res.page,\n        \"total\": res.total,\n    }\n\n    if res.previous_page:\n        response[\"previous\"] = '/users?' + res.previous_page\n\n    if res.next_page:\n        response[\"next\"] = '/users?' + res.next_page\n\n    return render_response(response)\n```\n\nPagination requires a limit, as a `RQLSelect._rql_default_limit` value, a query string `limit(x)`, or the `limit` parameter to the `rql()` method. Calling `rql_paginate()` without a limit will raise `RQLQueryError`.\n\n**Reference Table**\n\n| RQL                     | SQLAlchemy equivalent                              | Observation                                                                                                                     |\n|-------------------------|----------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------|\n| QUERYING                |                                                    |                                                                                                                                 |\n| select(a,b,c,...)       | select(Model.a, Model.b, Model.c,...)              |                                                                                                                                 |\n| values(a)               | [o.a for o in query.from_self(a)]                  |                                                                                                                                 |\n| limit(count,start?)     | .limit(count).offset(start)                        |                                                                                                                                 |\n| sort(attr1)             | .order_by(attr)                                    |                                                                                                                                 |\n| sort(-attr1)            | .order_by(attr.desc())                             |                                                                                                                                 |\n| distinct()              | .distinct()                                        |                                                                                                                                 |\n| first()                 | .limit(1)                                          |                                                                                                                                 |\n| one()                   | [query.one()]                                      |                                                                                                                                 |\n| FILTERING               |                                                    |                                                                                                                                 |\n| eq(attr,value)          | .where(Model.attr == value)                        |                                                                                                                                 |\n| ne(attr,value)          | .where(Model.attr != value)                        |                                                                                                                                 |\n| lt(attr,value)          | .where(Model.attr < value)                         |                                                                                                                                 |\n| le(attr,value)          | .where(Model.attr <= value)                        |                                                                                                                                 |\n| gt(attr,value)          | .where(Model.attr > value)                         |                                                                                                                                 |\n| ge(attr,value)          | .where(Model.attr >= value)                        |                                                                                                                                 |\n| in(attr,value)          | .where(Model.attr.in_(value)                       |                                                                                                                                 |\n| out(attr,value)         | .where(not_(Model.attr.in_(value)))                |                                                                                                                                 |\n| contains(attr,value)    | .where(Model.contains(value))                      | Produces a LIKE expression when querying against a string, or an IN expression when querying against an iterable relationship   |\n| excludes(attr,value)    | .where(not_(Model.contains(value)))                | See above.                                                                                                                      |\n| and(expr1,expr2,...)    | .where(and_(expr1, expr2, ...))                    |                                                                                                                                 |\n| or(expr1,expr2,...)     | .where(or_(expr1, expr2, ...))                     |                                                                                                                                 |\n| AGGREGATING             |                                                    | All aggregation functions return scalar results.                                                                                |\n| aggregate(a,b\\(c\\),...) | select(Model.a, func.b(Model.c)).group_by(Model.a) |                                                                                                                                 |\n| sum(attr)               | select(func.sum(Model.attr))                       |                                                                                                                                 |\n| mean(attr)              | select(func.avg(Model.attr))                       |                                                                                                                                 |\n| max(attr)               | select(func.max(Model.attr))                       |                                                                                                                                 |\n| min(attr)               | select(func.min(Model.attr))                       |                                                                                                                                 |\n| count()                 | select(func.count())                               |                                                                                                                                 |\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "\"Resource Query Language for SQLAlchemy\"",
    "version": "0.5.0",
    "project_urls": {
        "Homepage": "https://github.com/pjwerneck/rqlalchemy",
        "Repository": "https://github.com/pjwerneck/rqlalchemy"
    },
    "split_keywords": [
        "sqlachemy",
        "sql",
        "rql",
        "querying",
        "httpapi"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "e935d158e7c66431db200b5cf635996982aba331262e863877b5b05102c6da35",
                "md5": "12ecd1bf094e6cd15c567e10f8cfb5d6",
                "sha256": "d9d215eb02ca7fc6c2c911235ac2f5111d6d406728e18be923bc685835decb59"
            },
            "downloads": -1,
            "filename": "rqlalchemy-0.5.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "12ecd1bf094e6cd15c567e10f8cfb5d6",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8,<4.0",
            "size": 7328,
            "upload_time": "2023-12-09T18:31:02",
            "upload_time_iso_8601": "2023-12-09T18:31:02.368258Z",
            "url": "https://files.pythonhosted.org/packages/e9/35/d158e7c66431db200b5cf635996982aba331262e863877b5b05102c6da35/rqlalchemy-0.5.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "59c5ac566b53f835898c3219e1f1bd610ddbd66e444ec24231dd3c1676c9388d",
                "md5": "5e1ab1807cd8011c2a85a868bc5e39c2",
                "sha256": "9870eda54b585eb6abf0d994949a349457bd64541838584d2eb245194caa423d"
            },
            "downloads": -1,
            "filename": "rqlalchemy-0.5.0.tar.gz",
            "has_sig": false,
            "md5_digest": "5e1ab1807cd8011c2a85a868bc5e39c2",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8,<4.0",
            "size": 7654,
            "upload_time": "2023-12-09T18:31:04",
            "upload_time_iso_8601": "2023-12-09T18:31:04.492260Z",
            "url": "https://files.pythonhosted.org/packages/59/c5/ac566b53f835898c3219e1f1bd610ddbd66e444ec24231dd3c1676c9388d/rqlalchemy-0.5.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-12-09 18:31:04",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "pjwerneck",
    "github_project": "rqlalchemy",
    "travis_ci": true,
    "coveralls": false,
    "github_actions": true,
    "lcname": "rqlalchemy"
}
        
Elapsed time: 0.15228s