Skip to main content

A simple Python Library for building relational database queries using objects

Project description

Overview

Supported Versions

This is pysqlscribe, the Python library intended to make building SQL queries in your code a bit easier!

Motivation

Other query building libraries, such as pypika are fantastic but not actively maintained. Some ORM libraries such as sqlalchemy offer similar (and awesome) capabilities using the core API, but if you're not already using the library in your application, it's a bit of a large dependency to introduce for the purposes of query building.

API

pysqlscribe currently offers several APIs for building queries.

Query

A Query object can be constructed using the QueryRegistry's get_builder if you supply a valid dialect (e.g; "mysql", "postgres", "oracle). For example, "mysql" would be:

from pysqlscribe.query import QueryRegistry

query_builder = QueryRegistry.get_builder("mysql")
query = query_builder.select("test_column", "another_test_column").from_("test_table").build()

Alternatively, you can create the corresponding Query class associated with the dialect directly:

from pysqlscribe.query import MySQLQuery

query_builder = MySQLQuery()
query = query_builder.select("test_column", "another_test_column").from_("test_table").build()

In both cases, the output is:

SELECT `test_column`,`another_test_column` FROM `test_table`

Furthermore, if there are any dialects that we currently don't support, you can create your own by subclassing Query and registering it with the QueryRegistry:

from pysqlscribe.query import QueryRegistry, Query


@QueryRegistry.register("custom")
class CustomQuery(Query):
    ...

Table

An alternative method for building queries is through the Table object:

from pysqlscribe.table import MySQLTable

table = MySQLTable("test_table", "test_column", "another_test_column")
query = table.select("test_column").build()

Output:

SELECT `test_column` FROM `test_table`

A schema for the table can also be provided as a keyword argument, after the columns:

from pysqlscribe.table import MySQLTable

table = MySQLTable("test_table", "test_column", "another_test_column", schema="test_schema")
query = table.select("test_column").build()

Output:

SELECT `test_column` FROM `test_schema.test_table`

Additionally, in the event an invalid field is provided in the select call, we will raise an exception:

from pysqlscribe.table import MySQLTable

table = MySQLTable("test_table", "test_column", "another_test_column")
table.select("some_nonexistent_field")  # will raise InvalidColumnException

Table also offers a create method in the event you've added a new dialect which doesn't have an associated Table implementation, or if you need to change it for different environments (e.g; sqlite for local development, mysql/postgres/oracle/etc. for deployment):

from pysqlscribe.table import Table

new_dialect_table_class = Table.create(
    "new-dialect")  # assuming you've registered "new-dialect" with the `QueryRegistry`
table = new_dialect_table_class("test_table", "test_column", "another_test_column")

You can overwrite the original columns supplied to a Table as well, which will delete the old attributes and set new ones:

from pysqlscribe.table import MySQLTable

table = MySQLTable("test_table", "test_column", "another_test_column")
table.test_column  # valid
table.fields = ['new_test_column']
table.select("new_test_column")
table.new_test_column  # now valid - but `table.test_column` is not anymore

Additionally, you can reference the column attributes Table object when constructing queries. For example, in a WHERE clause:

from pysqlscribe.table import PostgresTable

table = PostgresTable("employee", "first_name", "last_name", "salary", "location")
table.select("first_name", "last_name", "location").where(table.salary > 1000).build()

Output:

SELECT "first_name","last_name","location" FROM "employee" WHERE salary > 1000

Schema

For associating multiple Tables with a single schema, you can use the Schema:

from pysqlscribe.schema import Schema

schema = Schema("test_schema", tables=["test_table", "another_test_table"], dialect="postgres")
schema.tables  # a list of two `Table` objects

This is functionally equivalent to:

from pysqlscribe.table import PostgresTable

table = PostgresTable("test_table", schema="test_schema")
another_table = PostgresTable("another_test_table", schema="test_schema")

Instead of supplying a dialect directly to Schema, you can also set the environment variable PYQUERY_BUILDER_DIALECT:

export PYQUERY_BUILDER_DIALECT = 'postgres'
from pysqlscribe.schema import Schema

schema = Schema("test_schema", tables=["test_table", "another_test_table"])
schema.tables  # a list of two `PostgresTable` objects

Alternatively, if you already have existing Table objects you want to associate with the schema, you can supply them directly (in this case, dialect is not needed):

from pysqlscribe.schema import Schema
from pysqlscribe.table import PostgresTable

table = PostgresTable("test_table")
another_table = PostgresTable("another_test_table")
schema = Schema("test_schema", [table, another_table])

Schema also has each table set as an attribute, so in the example above, you can do the following:

schema.test_table # will return the supplied table object with the name `"test_table"`

Contributions

Contributions are always welcome, as this is a new and active project.

Local Environment Setup

This project currently uses uv for convenience, although we currently only have dev dependencies. To create your environment:

uv sync

Unit Testing

pytest is used for all unit testing. To run the unit tests locally (assuming a local environment is set up):

uv run pytest

Unit tests are executed as part of CI, and the behavior should be consistent with what is observed in local development.

Supported Dialects

This is anticipated to grow, also there are certainly operations that are missing within dialects.

  • MySQL
  • Oracle
  • Postgres
  • Sqlite

TODO

  • Support JOINs
  • Add more dialects
  • Support OFFSET for Oracle and SQLServer
  • Incorporate aggregations in a cleaner way e.g; an aggregates or functions module which can be applied to Column objects - potentially wrappers
  • Support for aliases for tables and columns

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

pysqlscribe-0.0.2.tar.gz (19.5 kB view details)

Uploaded Source

Built Distribution

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

pysqlscribe-0.0.2-py3-none-any.whl (9.2 kB view details)

Uploaded Python 3

File details

Details for the file pysqlscribe-0.0.2.tar.gz.

File metadata

  • Download URL: pysqlscribe-0.0.2.tar.gz
  • Upload date:
  • Size: 19.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.5.21

File hashes

Hashes for pysqlscribe-0.0.2.tar.gz
Algorithm Hash digest
SHA256 478558ff4f67e7ee2167e4bcc58e754d8bd1a0649bdfec8d9ce431945ace5e3f
MD5 810ff244effc244eee4269551ae35daa
BLAKE2b-256 bfdc08bf5057980b37787ff2423540f4ebf6b340944e85e134d46dacd34d6d57

See more details on using hashes here.

File details

Details for the file pysqlscribe-0.0.2-py3-none-any.whl.

File metadata

File hashes

Hashes for pysqlscribe-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 0e5aa417665a70ff6d119d3d2ae351b1db1c2901f62a4048f9ab23305d8e8c9b
MD5 10c1a0d9d3e136185409a4dcece99ca2
BLAKE2b-256 748da8dff95a45e1715e4565ce6bfaa286177090401219afb789b3459853300f

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