Skip to content

Fetching records

In nORM, reads start as ordinary SQL. Add a query annotation, run code generation, and nORM turns the result shape into typed code.

Start with normal SQL

Without parameters:

sql
-- name: list_authors :many
SELECT * FROM authors;

With a parameter:

sql
-- name: get_author_by_id :one
SELECT * FROM authors
WHERE id = :id;

Return mode: :one, :many, :exec

Choose the return mode from the behavior the generated method should expose:

  • :one: return at most one row
  • :many: return multiple rows
  • :exec: run query without returning rows

See Query annotations for :execrows and :execlastid.

For a typical Postgres target, nORM generates the following shape:

authors_repo.sql
sql
-- name: list_authors :many
SELECT * FROM authors;

-- name: get_author_by_id :one
SELECT * FROM authors
WHERE id = :id;
python
async def list_authors(
    self,
) -> list[Author]:
    query = """
        SELECT
          authors.id AS id,
          authors.name AS name,
          authors.rating AS rating
        FROM authors
    """

    async with self.db.cursor() as cur:
        await cur.execute(query)
        result = [
            Author(
                id=item[0],
                name=item[1],
                rating=item[2],
            )
            async for item in cur
        ]

    return result

async def get_author_by_id(
    self,
    id: int,
) -> Author | None:
    query = """
        SELECT
          authors.id AS id,
          authors.name AS name,
          authors.rating AS rating
        FROM authors
        WHERE
          authors.id = %(id)s
    """

    params = {
        "id": id,
    }

    async with self.db.cursor() as cur:
        await cur.execute(query, params)
        result = await cur.fetchone()
        if result is None:
            return None

        result = Author(
            id=result[0],
            name=result[1],
            rating=result[2],
        )

    return result
go
// coming soon
rust
// coming soon
typescript
// coming soon

Wildcard expansion (SELECT *)

Using * is fine while writing repository SQL. nORM expands wildcards during generation, so the generated SQL still maps explicit columns into typed models.

How nORM chooses return schema

For row results, nORM chooses one of two schemas:

  • If the query returns every column from exactly one table, and nothing else, nORM reuses that table model.
  • Otherwise, nORM generates a query-specific row model.

Generated row schema names use the query name:

  • <QueryName>Row in PascalCase.
  • Example: list_author_summaries becomes ListAuthorSummariesRow.

Parameter syntax

Use named parameters in repository SQL:

  • :id
  • :limit
  • :offset

nORM rewrites those placeholders for the target driver. For Postgres-generated Python, the final SQL string uses %(name)s.

max_params and generated function signatures

max_params controls when nORM groups parameters into a single input model instead of many separate function arguments.

python
# max_params: 1 with two query params -> grouped params model
class CreateUserParams(BaseModel):
    name: str
    blocked: bool | None

async def create_user(self, arg: CreateUserParams) -> None: ...
go
// coming soon
rust
// coming soon
typescript
// coming soon

Type inference and casts

nORM infers parameter types, nullability, and result types from the schema and query context. When SQL leaves a type ambiguous, cast explicitly:

sql
-- name: list_authors_min_rating :many
SELECT * FROM authors
WHERE rating >= :min_rating::int;

Nullable arguments with n.narg()

nORM infers nullable parameters in many cases. Use n.narg() when the query itself should mark a parameter as nullable.

sql
-- name: get_author :one
SELECT * FROM authors a
WHERE a.id = n.narg(:id);

List arguments with n.list()

Use n.list() when one logical parameter represents multiple values, such as an IN filter. This is especially useful for dialects that do not support array-style bindings like id IN (:ids::int[]).

sql
-- name: get_authors :many
SELECT authors.name AS name
FROM authors
WHERE authors.id IN (n.list(:ids));

Released under the MIT License.