Skip to main content

A modern, type-safe, and extensible SQL query builder for Python.

Project description

sqlo

CI PyPI Documentation License

A lightweight and powerful SQL query builder for Python. Build SQL queries with a clean, intuitive API while staying safe from SQL injection. Support for JSON fields, CTEs, batch updates, and more!

Why sqlo?

  • 🪶 Lightweight: Zero dependencies, minimal footprint
  • Simple: Intuitive fluent API, easy to learn
  • 🛡️ Secure by Default: Built-in SQL injection protection
  • 🐍 Pythonic: Fluent API design that feels natural to Python developers
  • 🧩 Composable: Build complex queries from reusable parts
  • 🚀 Extensible: Support for custom dialects and functions
  • 🔍 Type-Safe: Designed with type hints for better IDE support
  • Well-Tested: 99% code coverage with comprehensive security tests

Installation

pip install sqlo

Documentation

https://sqlo.readthedocs.io/en/stable/

Quick Start

from sqlo import Q

# SELECT query
query = Q.select("id", "name").from_("users").where("active", True)
sql, params = query.build()
# SQL: SELECT `id`, `name` FROM `users` WHERE `active` = %s
# Params: (True,)

# INSERT query
query = Q.insert_into("users").values([
    {"name": "Alice", "email": "alice@example.com"}
])
sql, params = query.build()

Debug Mode

Global Debug Mode

Enable debug mode to automatically print all queries:

from sqlo import Q
# Enable debug mode globally
Q.set_debug(True)
query = Q.select("*").from_("users").where("id", 1)
sql, params = query.build()
# Automatically prints:
# [sqlo DEBUG] SELECT * FROM `users` WHERE `id` = %s
# [sqlo DEBUG] Params: (1,)
# Disable debug mode
Q.set_debug(False)

Query Debug Mode

You can also enable debug mode for a specific query:

from sqlo import Q
query = Q.select("*").from_("users").where("id", 1).debug()
sql, params = query.build(
# Prints debug output for this query only
# [sqlo DEBUG] SELECT * FROM `users` WHERE `id` = %s
# [sqlo DEBUG] Params: (1,)

JSON Field Support

Query JSON columns with ease:

from sqlo import Q, JSON

# Extract JSON fields in SELECT
query = Q.select("id", JSON("data").extract("name").as_("name")).from_("users")
# SQL: SELECT `id`, `data`->>'$.name' AS `name` FROM `users`

# Filter by JSON fields
query = Q.select("*").from_("users").where(JSON("data").extract("age"), 18, ">")
# SQL: SELECT * FROM `users` WHERE `data`->>'$.age' > %s

Batch Updates

Efficiently update multiple rows with different values:

values = [
    {"id": 1, "name": "Alice", "status": "active"},
    {"id": 2, "name": "Bob", "status": "inactive"},
]
query = Q.update("users").batch_update(values, key="id")
# Generates optimized CASE WHEN SQL

Common Table Expressions (CTE)

Build complex queries with CTEs:

from sqlo import Q, func

# Define a CTE
cte = Q.select("user_id", func.count("*").as_("order_count")) \
    .from_("orders") \
    .group_by("user_id") \
    .as_("user_orders")

# Use it in main query
query = Q.select("u.name", "uo.order_count") \
    .with_(cte) \
    .from_("users", alias="u") \
    .join("user_orders uo", "u.id = uo.user_id")

Window Functions

Perform advanced analytics with window functions:

from sqlo import Q, Window, func

# Ranking within partitions
query = Q.select(
    "name",
    "department",
    "salary",
    func.row_number().over(
        Window.partition_by("department").and_order_by("-salary")
    ).as_("rank")
).from_("employees")
# SQL: SELECT `name`, `department`, `salary`,
#   ROW_NUMBER() OVER (PARTITION BY `department` ORDER BY `salary` DESC) AS `rank`
# FROM `employees`

# Running totals
query = Q.select(
    "date",
    "amount",
    func.sum("amount").over(
        Window.order_by("date").rows_between("UNBOUNDED PRECEDING", "CURRENT ROW")
    ).as_("running_total")
).from_("transactions")

# LAG and LEAD for time series
query = Q.select(
    "date",
    "value",
    func.lag("value", 1).over(Window.order_by("date")).as_("prev_value"),
    func.lead("value", 1).over(Window.order_by("date")).as_("next_value")
).from_("metrics")

Documentation

Full documentation is available at https://sqlo.readthedocs.io/en/stable/.

You can also browse the markdown files on GitHub:

License

MIT License

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

sqlo-0.2.1.tar.gz (8.8 MB view details)

Uploaded Source

Built Distribution

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

sqlo-0.2.1-py3-none-any.whl (24.8 kB view details)

Uploaded Python 3

File details

Details for the file sqlo-0.2.1.tar.gz.

File metadata

  • Download URL: sqlo-0.2.1.tar.gz
  • Upload date:
  • Size: 8.8 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.15 {"installer":{"name":"uv","version":"0.9.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for sqlo-0.2.1.tar.gz
Algorithm Hash digest
SHA256 d16bb3c10ea7daff9d01f80f91730cd468daf4d168c85ab82c53ed95753d2744
MD5 6a9a785d67195211a05ce7b07547e7f5
BLAKE2b-256 7ba86da3b75b174a44d3addc906543360fcf185cfdda12c1a964f9efd75ef998

See more details on using hashes here.

File details

Details for the file sqlo-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: sqlo-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 24.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.15 {"installer":{"name":"uv","version":"0.9.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for sqlo-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 4dfa89abce04769917bde5d52ded156bc1eb84046be3e72ec7e023095a7284c4
MD5 910463cf88996a3e2c0b2c3476bbc848
BLAKE2b-256 407d4ee7721e0dc7f1bb903218762d571322cf7b1c268e4e971b4e7df99bbd00

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