Skip to main content

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

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.

Metadata

Release files for querymark 1.2.0

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

Source distribution (sdist)

Source distribution for querymark 1.2.0
File Size Uploaded Provenance
querymark-1.2.0.tar.gz 5.6 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for querymark 1.2.0
File Interpreter ABI Platform
querymark-1.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 10.7 kB

Release files / querymark-1.2.0.tar.gz

Download URL querymark-1.2.0.tar.gz
Size 5.6 kB
Tags Source
SHA-256 checksum
How to use checksums
54a12cf5b84fbf8c1ad40c73ee88125f513ebf7ba5750d9bf27430f1cabe47ae
BLAKE2b-256 checksum
How to use checksums
d15f8d7b244e35eb8cc8510d8bdbff716050792af8ab4a52e307e957ca7fd01c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.15

Release files / querymark-1.2.0-py3-none-any.whl

Download URL querymark-1.2.0-py3-none-any.whl
Size 5.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
81462972100d040797807e5d02d8b034dc2b3c2c283c0df1ebcc4da1dcff2a49
BLAKE2b-256 checksum
How to use checksums
24f22ea49e8733cf30c2f08cbe67d313a50f0a0045ee6d76c53d45dbe711738f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.15

Security for querymark 1.2.0

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.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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