Skip to main content

Lightweight Python query builder for asyncpg. Use ? placeholders and querymark handles the $1, $2, $3 conversion.

Project description

querymark

Lightweight Python query builder for asyncpg. Use ? placeholders and querymark handles the $1, $2, $3 conversion. Compose queries with + operator while keeping parameters tracked automatically.

The Problem

When managing indexed parameters in SQL queries to use for asyncpg for example you can easily get into problems when conditionally constructing queries.

For example if the number of conditions needed in the query is based on some logic you could end up with something like this

if role and extended_role:
    check = "(role <= $1 AND extended_role <= $2)"
    params = [role, extended_role]
elif role:
    check = "role <= $1"
    params = [role]
elif extended_role:
    check = "extended_role <= $1"
    params = [extended_role]
else:
    raise Exception("Must specify either role, extended_role or both")
if project:
    query = f"""
        SELECT 1 FROM user_project_roles
        WHERE user_id = ${len(params) + 1} AND {check}
        AND (project_id = ${len(params) + 2} OR project_id IS NULL)
        LIMIT 1
    """
    result = await db.fetchrow(query, *params, user.id, project.id)
    return result is not None
else:
    query = f"""
        SELECT 1 FROM user_project_roles
        WHERE user_id = ${len(params) + 1} AND {check}
        AND project_id IS NULL
        LIMIT 1
    """
    result = await db.fetchrow(query, *params, user.id)
    return result is not None

The Solution

With querymark, you write queries using ? placeholders and let the library handle parameter indexing:

from querymark import q

# Build conditions naturally
if role and extended_role:
    check = q("(role <= ? AND extended_role <= ?)", role, extended_role)
elif role:
    check = q("role <= ?", role)
elif extended_role:
    check = q("extended_role <= ?", extended_role)
else:
    raise Exception("Must specify either role, extended_role or both")

# Compose the full query
query = q("SELECT 1 FROM user_project_roles")
query += q("WHERE user_id = ?", user.id) + " AND " + check
if project:
    query += q("AND (project_id = ? OR project_id IS NULL)", project.id)
result = await db.fetchrow(*query.to_sql())
return result is not None

Installation

pip install querymark
(Note: Package will be available on PyPI soon. For now, install from source.)

Basic Usage

from querymark import q

# Simple query with parameters
query = q("SELECT * FROM users WHERE id = ?", user_id)
result = await db.fetch(*query.to_sql())

# Compose queries dynamically
base = q("SELECT id, name, email FROM users")
if filter_active:
    base += q("WHERE active = ?", True)
if sort_by:
    base += f"ORDER BY {sort_by}"
    
results = await db.fetch(*base.to_sql())

# Functions can return query fragments
def group_filter(self) -> q:
    return q("group_id = ?", self.group_id)

@staticmethod
def to_query() -> q:
    return q("SELECT id, group_id, text, published FROM article")

# And then combined when needed
rows = await db.fetch(
    Article.to_query()
    + q("WHERE") + article.group_filter()
    + "ORDER BY published"
)

For more examples and detailed documentation, see USAGE.md.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

querymark-1.1.0.tar.gz (5.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

querymark-1.1.0-py3-none-any.whl (5.2 kB view details)

Uploaded Python 3

File details

Details for the file querymark-1.1.0.tar.gz.

File metadata

  • Download URL: querymark-1.1.0.tar.gz
  • Upload date:
  • Size: 5.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for querymark-1.1.0.tar.gz
Algorithm Hash digest
SHA256 7f56c89b03ce104dc7a18202a5e8e3fe1ce8aa075896b3a5fc23ff50d20e8d1a
MD5 f9b1a691fac6bd583b8e70778407ffff
BLAKE2b-256 cc8a6fdd85a32f5f9a7d1ee824b8402d77b75c475b5cbc060e201c04942b183b

See more details on using hashes here.

File details

Details for the file querymark-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: querymark-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 5.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for querymark-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 27e3ea1b25559fa330e1981c3572bb1a3dfbfa7ad19465795dbef18bef92c54a
MD5 89c5e031daa39f2798590aa481594129
BLAKE2b-256 a5ba90f6ecd4af7ee7c853d5e8ba59e765bfbcfc475cc5695c33d7ed3f4938a2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page