data.query

Page actions AI-ready formats and sharing
Open LLM text
Share with AI
Ask Claude Ask ChatGPT Ask Gemini Ask Copilot

Immutable query builder for chirp.data.

Accumulates SQL clauses through chaining methods, compiles to a SQL string

  • parameters tuple, and executes via the existingDatabasemethods.

Each method returns a new frozenQuery…

Immutable query builder for chirp.data.

Accumulates SQL clauses through chaining methods, compiles to a SQL string

  • parameters tuple, and executes via the existingDatabasemethods.

Each method returns a new frozenQuery— the original is never mutated. Same pattern asResponse.with_*()but for SELECT queries.

Usage::

from chirp.data import Database, Query

@dataclass(frozen=True, slots=True)
class Todo:
    id: int
    text: str
    done: bool

todos = await (
    Query(Todo, "todos")
    .where("done = ?", False)
    .where_if(search, "text LIKE ?", f"%{search}%")
    .order_by("id DESC")
    .take(20)
    .fetch(db)
)

Transparency:.sql and .paramsshow exactly what will run. No hidden queries, no magic.

Free-threading safety:

  • Frozen dataclass — immutable after creation
  • Tuple accumulators — no shared mutable state
  • No locks needed

data.query

Name Type Default Description
type
qualified_name
element_type
description
source_file
line_number
is_autodoc
autodoc_element
_autodoc_template
_autodoc_url_path
_autodoc_page_type
title
doc_content_hash

Symbols on this page

json_path
function
def json_path(column: str, /, *keys: str, dialect: str) -> str

Build a dialect-correct JSON-extraction SQL expression fragment.

Emits the right syntax for the active driver so the sqlite-vs-postgres branch stops leaking into every call site::

json_path("oauth", "sub", dialect="sqlite")      # json_extract(oauth, '$.sub')
json_path("oauth", "sub", dialect="postgresql")  # oauth->>'sub'
json_path("data", "a", "b", dialect="sqlite")    # json_extract(data, '$.a.b')
json_path("data", "a", "b", dialect="postgresql")# data->'a'->>'b'

Drop the result straight into aWHERE/SELECTstring and keep the actual filter value as a separate bound parameter::

Query(Row, "users").where(
    json_path("oauth", "sub", dialect="sqlite") + " = ?", sub_id
)

The expression contains no bound-parameter placeholder of its own — the JSON pathkeysare static, author-supplied identifiers concatenated into the SQL text. Never pass request/user-controlled values ascolumnor keys: they are not parameterized and would be an injection vector. Keep real filter values in the separate bound params ofQuery.where(clause, *params) / db.fetch(sql, *params).

Parameters

Name Type Default Description
column str The JSON column name.
*keys str
dialect str The driver dialect — ``"sqlite"`` or ``"postgresql"`` (any non-``"sqlite"`` value is treated as PostgreSQL, matching the driver-dispatch convention in ``chirp.data.shapes``).
Query
class

Immutable SELECT query builder.

Construct with a target dataclass and table name, chain methods to add clauses, then execute viafetch(), fetch_one(), etc.

Every method returns a newQuery— the original is unchanged.

View source · /home/runner/work/chirp/chirp/site/../src/chirp/data/query.py:1