Skip to content

SQL functions

SQL functions are python functions with only a docstring containing an SQL statement. To declare an SQL function, use the sqlfunc decorator. Unless bound to an engine using the engine argument, sql functions require a session context to be used.

from sqlorm import sqlfunc

@sqlfunc
def fetch_todos():
    "SELECT * FROM tasks WHERE not done"

with engine:
    todos = fetch_todos()

The type of fetching being done can be controlled using @sqlorm.fetchSTYLE() instead:

from sqlorm import sqlfunc

@sqlfunc.fetchscalar
def count_todos():
    "SELECT COUNT(*) FROM tasks WHERE not done"

with engine:
    nb_todos = count_todos()

The same arguments as fetch can be provided to the decorator.

If you do not expect any return from your statement, use @sqlfunc.execute.

The content of the docstring behaves similarly to f-strings:

  • code in curly braces will be evaluated and be inserted in the final statement as is
  • code in python format markers will be evaluated and inserted as parameters

The function arguments are available in the evaluation context. The SQL utility as well as datetime and uuid are also available in the evaluation context.

from sqlorm import sqlfunc

@sqlfunc.fetchscalar
def count_since(table, created_after, date_column="created_at"):
    "SELECT COUNT(*) FROM {table} WHERE {date_column} >= %(created_after)s"

with engine:
    tasks2024 = count_since("tasks", "2024-01-01")

To get the sql statement of a function, use the sql() method on the function itself. It takes the same arguments as the decorated function. It returns an SQLTemplate object, itself a subclass of SQL.

print(count_since.sql("tasks", "2024-01-01"))

Tip

You can also create "sql functions" without using sql statements as docstrings using query decorators. Your function should then return a statement to execute (possibly parameterized using ParametrizedStmt or SQL).

Available decorators are: fetchall, fetchone, fetchscalar, fetchscalars, fetchcomposite, execute

from sqlorm import fetchall, execute

@fetchall
def count_since(table, created_after, date_column="created_at"):
   return SQL.select("COUNT(*)").from_(table).where(SQL(date_column) >= SQL.Param(created_after)) # same as previous example

@execute
def insert_task(title):
   return SQL.insert("tasks", {"title": title})

with engine:
   tasks2024 = count_since("tasks", "2024-01-01")
   insert_task("my todo")

Under the hood, @sqlfunc converts the docstring-only function to a function returning an SQLTemplate and wraps it in a query decorator