Skip to main content
Loss of provenance

A previous release had provenance metadata, but this release does not. View details.

🧩 recordsql

Build Status PyPI version Python Version PyPI Downloads License: MIT

recordsql is a Python-based SQL query builder that offers a fluent and composable interface for generating complex SQL statements — safely and efficiently.

📦 Installation

Install the required dependency and the pip package

pip install expressql
pip install recordsql

🚀 Features

  • Fluent, chainable API for building SQL queries
  • Support for SELECT, INSERT, UPDATE, DELETE, WITH, JOIN, COUNT, and EXISTS
  • Parameterized placeholders for SQL injection safety
  • Full support for multiple JOIN types (INNER, LEFT, RIGHT, FULL)
  • Modular, composable components for query reuse

🛠️ Usage

Here are some examples of how to use recordsql to build SQL queries.

1. SELECT Query

from recordsql import SELECT, cols, text, col

# Define columns
name, age, email, total_purchases, signup_date, infractions = cols(
    "name", "age", "email", "total_purchases", "signup_date", "infractions"
)

# Build a SELECT query
select_query = SELECT(name, age, email, total_purchases).FROM("customers").WHERE(
    ((signup_date - col("CURRENT_TIMESTAMP")) > (text("1 year").DATETIME())) &
    (total_purchases > 1000) &
    (infractions == 0)
).ORDER_BY(total_purchases, "DESC", (signup_date - col("CURRENT_TIMESTAMP"), "ASC")).LIMIT(10).OFFSET(1)

print(*select_query.placeholder_pair(), sep="\n")

2. WITH Query and JOINs

from recordsql import WITH, JoinQuery, cols, num, col

# Define columns and values
name, age, email, total_purchases = cols("name", "age", "email", "total_purchases")
current_store_id = num(1275682)

# Build a WITH query
with_query = WITH(select_query.AS("customer_data")).SELECT(
    name, age, email, total_purchases
).FROM("customer_data").WHERE(
    (total_purchases > 1000) & (infractions == 0)
).ORDER_BY(total_purchases, "DESC").LIMIT(10).OFFSET(1)

# Add JOINs
with_query.INNER_JOIN(
    table_name="prices",
    on=(current_store_id == col("store_id"))
).LEFT_JOIN(
    table_name="orders",
    on=(current_store_id == col("store_id"))
)

print(*with_query.placeholder_pair(), sep="\n")
Click to reveal output

WITH customer_data AS (SELECT name, age, email, total_purchases FROM "customers" WHERE ((signup_date-CURRENT_TIMESTAMP) > DATETIME(?)) AND (total_purchases > ?) AND (infractions = ?) ORDER BY total_purchases DESC, (signup_date-CURRENT_TIMESTAMP) ASC LIMIT 10 OFFSET 1) SELECT name, age, email, total_purchases FROM "customer_data" INNER JOIN "prices" ON ? = store_id LEFT JOIN "orders" ON ? = store_id WHERE (total_purchases > ?) AND (infractions = ?) ORDER BY total_purchases DESC LIMIT 10 OFFSET 1

['1 year', 1000, 0, 1000, 0, 1275682, 1275682]

3. UPDATE Query

from recordsql import UPDATE, col

# Build an UPDATE query
update_query = UPDATE("customers").SET(
    name="John Doe",
    age=30,
    email="johndoe@gmail.com"
).WHERE(col("customer_id") == 12345).RETURNING("name", "age", "email")

print(*update_query.placeholder_pair(), sep="\n")

4. INSERT Query

from recordsql import INSERT

# Build an INSERT query
insert_query = INSERT("col1", "col2").INTO("table_name").VALUES(
    (1, 2),
    (3, 4),
    (5, 6)
).ON_CONFLICT(
    do="UPDATE",
    conflict_cols=["col1"],
    set={"col2": 10},
    where=col("col1") == 1
).RETURNING("col1", "col2")

print(*insert_query.placeholder_pair(), sep="\n")

5. COUNT and EXISTS Queries

from recordsql import COUNT, EXISTS, col, text

# Build a COUNT query
count_query = COUNT().FROM("customers").WHERE(
    ((signup_date - col("CURRENT_TIMESTAMP")) > (text("1 year").DATETIME())) &
    (total_purchases > 1000) &
    (infractions == 0)
).GROUP_BY(name).HAVING(total_purchases > 1000)

print(*count_query.placeholder_pair(), sep="\n")

# Build an EXISTS query
exists_query = EXISTS().FROM("customers").WHERE(
    ((signup_date - col("CURRENT_TIMESTAMP")) > (text("1 year").DATETIME())) &
    (total_purchases > 1000) &
    (infractions == 0)
)

print(*exists_query.placeholder_pair(), sep="\n")

6. DELETE Query

from recordsql import DELETE, col, text

# Build a DELETE query
delete_query = DELETE().FROM("customers").WHERE(
    ((signup_date - col("CURRENT_TIMESTAMP")) > (text("1 year").DATETIME())) &
    (total_purchases > 1000) &
    (infractions == 0)
)

print(*delete_query.placeholder_pair(), sep="\n")

📝 Output

The queries generated by recordsql are parameterized and safe for execution. Here’s an example output:

WITH customer_data AS (
    SELECT * FROM "customers"
    WHERE ((signup_date - CURRENT_TIMESTAMP) > DATETIME(?))
    AND (total_purchases > ?)
    AND (infractions = ?)
    ORDER BY total_purchases DESC, (signup_date - CURRENT_TIMESTAMP) ASC
    LIMIT 10 OFFSET 1
)
SELECT * FROM "customer_data"
WHERE (total_purchases > ?)
AND (infractions = ?)
ORDER BY total_purchases DESC, (signup_date - CURRENT_TIMESTAMP) ASC
LIMIT 10 OFFSET 1

Placeholders:

['1 year', 1000, 0, 1000, 0]

📖 Documentation

Full documentation is available and includes:

  • Installation Guide: Detailed installation instructions
  • Quick Start: Get started with recordsql in minutes
  • Advanced Examples: Complex query patterns and best practices
  • API Reference: Complete API documentation with type hints

Building Documentation Locally

To build the documentation locally:

cd docs
poetry run sphinx-build -b html . _build/html

Or using make:

cd docs
make html  # On Unix/Linux/macOS
make.bat html  # On Windows

The generated documentation will be in docs/_build/html/. Open index.html in your browser to view it.

For more details on contributing to documentation, see docs/README.md.

Metadata

Release files for recordsql 0.2.3

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

Loss of provenance

These files do not have provenance metadata, despite files in a prior release including this data.

We recommend further investigation before installing these files. View details.

Source distribution (sdist)

Source distribution for recordsql 0.2.3
File Size Uploaded Provenance
recordsql-0.2.3.tar.gz 29.9 kB Without provenance Details

Built distribution (wheel)

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

Total release size: 72.8 kB

Release files / recordsql-0.2.3.tar.gz

Loss of provenance

This file belongs to a release without provenance metadata, despite a prior release including this data.

We recommend further investigation before installing this file. View details.

Download URL recordsql-0.2.3.tar.gz
Size 29.9 kB
Tags Source
SHA-256 checksum
How to use checksums
e486f13ed16acaeb6bd13cd8008e35a340754ada0a002e559055e6d8382a64fe
BLAKE2b-256 checksum
How to use checksums
d83c801ff789a8a023ee468f0c7d6cad3011476eedec29bd35824bb80ababcb8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.10

Release files / recordsql-0.2.3-py3-none-any.whl

Loss of provenance

This file belongs to a release without provenance metadata, despite a prior release including this data.

We recommend further investigation before installing this file. View details.

Download URL recordsql-0.2.3-py3-none-any.whl
Size 42.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
03efd9c134cb519339d1cd7034bfa28cd345a4fa36ce9eae961fb0b327444b71
BLAKE2b-256 checksum
How to use checksums
b67d872b1a6590f37a8ea2d600149b64210bf6cbdad442bc004817fa897e32e7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.10

Security for recordsql 0.2.3

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.

Loss of provenance

A previous release of these files had provenance metadata, but this release does not.

While this could reflect a routine change by the project maintainers, it may also indicate that the release files have been compromised.

Release comparison

  • Removed 0.2.2 2 files With provenance
  • Added 0.2.3 2 files Without provenance

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