Skip to main content

Que: SQL for Sneks 🐍

image image image image image codecov

Que allows you to get generate your SQL queries on the fly, without the overhead of a fully-fledged ORM.

Motivations

Que was born out of a need for dynamically generated SQL for an ASGI web service. I found my self wishing for the convenience of dynamic querying with an ORM such as SQLAlchemy, but the performance of a fully asynchronous database client. Que attempts to fill this void. Choose the connection client you prefer and let Que worry about the SQL.

What Is It?

Que looks to solve a single purpose: generate SQL-compliant queries in pure-Python. Que has absolutely no hard dependendencies and does not enforce the use of a specific database client or dialect.

Still want to use SQLAlchemy for your connection? Go for it. Want to use PyMySQL or psycopg2? Que won't stop you. Want to use an asyncio framework such as aiopg? You have excellent taste! This library was written just for you.

Design

The focus of Que is simplicity, just look at what it takes for a simple SELECT:

>>> import que
>>> select = que.Select(table='foo')
>>> select
Select(table='foo', schema=None, filters=FilterList([]), fields=FieldList([]))
>>> sql, args = select.to_sql()
>>> print(sql)
SELECT
  *
FROM
  foo

Que works with the DBAPI client of your choice by parametrizing your sql and formatting your arguments for you:

>>> import que
>>> fields = [que.Field('bar')]
>>> filters = [que.Filter(que.Field('id', 1))]
>>> select = que.Select(table='foo', filters=filters, fields=fields)
>>> sql, args = select.to_sql()
>>> print(sql)
SELECT
  bar
FROM
  foo
WHERE
  id = :1

>>> args
[1]
>>> sql, args = select.to_sql(style=que.NameParamStyle.NAME)
>>> print(sql)
SELECT
  bar
FROM
  foo
WHERE
  id = :id

>>> args
{'id': 1}

Que works to normalize the API for your SQL operations, so that initializing an INSERT or UPDATE is functionally the same as initializing a SELECT:

>>> import que
>>> import dataclasses
>>> import datetime
>>>
>>> @dataclasses.dataclass
... class Foo:
...     bar: str
...     id: int = None
...     created: datetime.datetime = None
... 
>>> new_foo = Foo('blah')
>>> fields = que.data_to_fields(new_foo, exclude=None)
>>> insert = que.Insert(table='foo', fields=fields)
>>> sql, args = insert.to_sql(que.NameParamStyle.NAME)
>>> print(sql)
INSERT INTO
  foo (:colbar)
VALUES
  (:valbar)

>>> args
{'colbar': 'bar', 'valbar': 'blah'}

QuickStart

Que has no dependencies and is exceptionally light-weight (currently only ~30Kb!), comprising of only a few hundred lines of code. Installation is as simple as pip3 install que-py.

Then you're good to go! import que and rock on 🤘

Examples

A simple client for generating your SQL and inserting new entries:

import dataclasses
import sqlite3

import que

@dataclasses.dataclass
class Spam:
    flavor: str
    id: int = None
    created_on: int = None


class SpamClient:
    """A database client for tracking spam flavors."""

    def __init__(self):
        self.conn = sqlite3.connect('sqlite://spam.db')

    def insert_spam(self, spam: Spam):
        fields = que.data_to_fields(spam, exclude=None)
        insert = que.Insert('spam', fields=fields)
        sql, args = insert.to_sql()
        return self.conn.execute(sql, args)

    def get_spam(self, **kwargs):
        fields = que.data_to_fields(kwargs)
        filters = [que.Filter(x) for x in fields]
        select = que.Select('spam', filters=filters)
        return self.conn.execute(*select.to_sql())

    def update_spam(self, spam: Spam):
        fields = [que.Field('flavor', spam.flavor)]
        filters = [que.Filter(que.Field('id', spam.id))]
        update = que.Update('spam', filters=filters, fields=fields)
        return self.conn.execute(*update.to_sql())

    def delete_spam(self, spam: Spam):
        filters = [que.Filter(que.Field('id', spam.id))]
        delete = que.Delete('spam', filters=filters)
        return self.conn.execute(*delete.to_sql())

Documentation

Full documentation coming soon!

Happy Querying 🐍

How to Contribute

  1. Check for open issues or open a fresh issue to start a discussion around a feature idea or a bug.
  2. Create a branch on Github for your issue or fork the repository on GitHub to start making your changes to the master branch.
  3. Write a test which shows that the bug was fixed or that the feature works as expected.
  4. Send a pull request and bug the maintainer until it gets merged and published. :)

Metadata

Release files for que-py 1.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for que-py 1.1.1
File Size Uploaded Provenance
que-py-1.1.1.tar.gz 12.9 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for que-py 1.1.1
File Interpreter ABI Platform
que_py-1.1.1-py2.py3-none-any.whl Python 3, Python 2 none any Details

Total release size: 23.6 kB

Release files / que-py-1.1.1.tar.gz

Download URL que-py-1.1.1.tar.gz
Size 12.9 kB
Tags Source
SHA-256 checksum
How to use checksums
939c0c218e6f752f44b0eceec42b3f389151927501eeff99bb4d17c714943494
BLAKE2b-256 checksum
How to use checksums
7b900b2784e269eac964b6809ce3cca94980022fb2fe89747251d71f341d398d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/39.1.0 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.7.3

Release files / que_py-1.1.1-py2.py3-none-any.whl

Download URL que_py-1.1.1-py2.py3-none-any.whl
Size 10.7 kB
Tags Python 2 Python 3
SHA-256 checksum
How to use checksums
b062be82c0c1f759980fc0c5cbc2ee57ac9ac51240a538407e0ba9bb0628032e
BLAKE2b-256 checksum
How to use checksums
7b0319dd8d38a4f49462f550dfe45c7dec0bf91b664d1ebb03f1fe02c72cf9fd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/39.1.0 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.7.3

Security for que-py 1.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page