Fields

Field type markers

These are Python 3.12 generic classes that serve as type annotations for entity fields. Sphinx autodoc cannot fully process Python 3.12 class Cls[T]: syntax, so they are described here manually. See Defining Entities for usage examples.

class nextorm.fields.PK[T]

Primary-key field — auto-generated integer by default.

On the class: returns a ColumnExpr for use in query predicates. On an instance: returns the T value.

Example:

class User(Entity):
    id: PK[int]         # auto-increment integer PK
    id: PK[uuid7]       # time-ordered UUID PK
class nextorm.fields.Req[T]

Required (non-nullable) field. Maps to a NOT NULL column.

Example:

class Product(Entity):
    name: Req[str]
class nextorm.fields.Opt[T]

Optional (nullable) field — value may be None. Maps to a nullable column.

Example:

class Product(Entity):
    description: Opt[str]
class nextorm.fields.Local[T]

Local (transient) field — never written to or read from the database. Use it to attach computed or cached state to an entity instance.

Example:

class User(Entity):
    _full_name: Local[str]
class nextorm.fields.Set[T]

Collection relation attribute — used for both one-to-many and many-to-many.

Declare Set[Child] on the one side and Single[Parent] on the many side for one-to-many; declare Set[Other] on both entities for many-to-many.

class nextorm.fields.Single[T]

Single-entity relation attribute (FK).

Use Single[Other] for a required FK (NOT NULL, CASCADE). Use Single[Other | None] for an optional FK (NULLABLE, SET NULL). When both sides use Single, a UNIQUE constraint is added (one-to-one).

Special column types

class nextorm.fields.LongStr[source]

Bases: object

Sentinel type for large text columns.

Maps to LONGTEXT on MariaDB and TEXT on PostgreSQL / SQLite. Use when the content may exceed the ~65 KB limit of MariaDB TEXT (which is limited to 65,535 bytes):

class Article(Entity):
    body: Req[LongStr]

By default LongStr fields are lazy — they are omitted from the main SELECT and loaded on first access. Override with body: Req[LongStr] = FieldSpec(lazy=False) to load eagerly.

class nextorm.fields.Json[source]

Bases: object

Sentinel type for JSON columns.

Maps to JSONB (PostgreSQL), JSON (MariaDB), TEXT (SQLite). Values are stored as Python dict / list objects and serialised/deserialised automatically:

class Config(Entity):
    data: Req[Json]
class nextorm.fields.DateTimeTz[source]

Bases: object

Sentinel type for timezone-aware datetime columns.

Maps to TIMESTAMPTZ (PostgreSQL), DATETIME (MariaDB, assumes UTC session), TEXT ISO 8601 (SQLite).

PostgreSQL: psycopg / asyncpg automatically return a timezone-aware datetime object. For MariaDB and SQLite the application is responsible for serialising to/from UTC:

class Event(Entity):
    start_at: Req[DateTimeTz]
class nextorm.fields.Vec[source]

Bases: object

Parameterized sentinel type for fixed-dimension vector columns.

Maps to vector(n) (PostgreSQL with pgvector extension), TEXT (MariaDB / SQLite — JSON-serialised list).

Specify the dimension by subscripting:

class Article(Entity):
    embedding: Req[Vec[384]]

Alternatively use FieldSpec(dimensions=n) explicitly:

class Article(Entity):
    embedding: Req[Vec] = FieldSpec(dimensions=384)

UUID / ULID types

class nextorm.fields.uuid7[source]

Bases: object

Sentinel type for UUID v7 auto-generated primary keys.

Use in entity annotations to declare a time-ordered, sortable UUID PK:

class Event(Entity):
    id: PK[uuid7]

The field is stored as uuid.UUID in Python and mapped to UUID (PostgreSQL), CHAR(36) (MariaDB), or TEXT (SQLite). A UUID v7 value is auto-generated before every INSERT if the field is not already set.

class nextorm.fields.uuid4[source]

Bases: object

Sentinel type for UUID v4 auto-generated primary keys.

Use like PK[uuid4]. Same storage as uuid7 but uses random UUID v4 generation (not time-ordered).

class nextorm.fields.ulid[source]

Bases: object

Sentinel type for ULID auto-generated primary keys.

Use like PK[ulid]. The field is stored as a ULID string (26-character Crockford base32) mapped to CHAR(26) in DDL.

class nextorm.fields.ULID[source]

Bases: str

26-character Crockford base32 ULID value type.

Used as the Python type for PK[ulid] fields. ULID values are stored as CHAR(26) (MariaDB), TEXT (SQLite), or the native UUID column cast to base32 (not supported — stored as TEXT on all backends).

A ULID instance is an ordinary string and sorts lexicographically in creation order (time-order), which is the key property of ULIDs.

Metadata classes

class nextorm.fields.FieldSpec[source]

Bases: object

Metadata that describes a persistent field.

Created internally by EntityMeta based on which type alias was used in the annotation (PK, Req, Opt, …). Direct construction is only needed when customising field behaviour:

from nextorm.fields import FieldSpec


class MyEntity(Entity):
    slug: Req[str]  # EntityMeta creates FieldSpec() automatically


# With custom options:
# slug = FieldSpec(unique=True, max_len=64)
primary_key: bool = False
auto: bool = False
nullable: bool = False
unique: bool = False
index: bool = False
max_len: int | None = None
column: str | None = None
default: Any
sql_default: str | None = None
sql_type: str | None = None
volatile: bool = False
uuid_auto: str | None = None
precision: int | None = None
scale: int | None = None
unsigned: bool = False
size: int | None = None
dimensions: int | None = None
lazy: bool = False
py_check: Any = None
autostrip: bool = False
min: Any = None
max: Any = None
property has_default: bool

Return True when a default value or factory has been set.

__init__(primary_key=False, auto=False, nullable=False, unique=False, index=False, max_len=None, column=None, default=<factory>, sql_default=None, sql_type=None, volatile=False, uuid_auto=None, precision=None, scale=None, unsigned=False, size=None, dimensions=None, lazy=False, py_check=None, autostrip=False, min=None, max=None)
Parameters:
  • primary_key (bool)

  • auto (bool)

  • nullable (bool)

  • unique (bool)

  • index (bool)

  • max_len (int | None)

  • column (str | None)

  • default (Any)

  • sql_default (str | None)

  • sql_type (str | None)

  • volatile (bool)

  • uuid_auto (str | None)

  • precision (int | None)

  • scale (int | None)

  • unsigned (bool)

  • size (int | None)

  • dimensions (int | None)

  • lazy (bool)

  • py_check (Any)

  • autostrip (bool)

  • min (Any)

  • max (Any)

Return type:

None

class nextorm.fields.RelationSpec[source]

Bases: object

Metadata that describes a relation field.

For Single relations:

  • nullable=False (default): NOT NULL column, ON DELETE CASCADE

  • nullable=True: NULLABLE column, ON DELETE SET NULL

  • cascade_delete=True: override to CASCADE regardless of nullable

  • cascade_delete=False: override to RESTRICT regardless of nullable

  • cascade_delete=None (default): auto-derive from nullable

  • owner=True: explicitly mark this Single as the owning side in a one-to-one pair (creates FK + UNIQUE here).

  • owner=False: explicitly mark this Single as the non-owning back-reference (no FK column generated here).

  • owner=None (default): auto-detect from nullable / alphabetical order.

  • column=None: override the FK column name (defaults to reverse_column or {relation_name}_id).

  • columns=None: for composite FK, override the list of FK column names (defaults to [reverse_column + "_id"] or [{relation_name}_id]).

kind: str = ''
target: type[Any] | str | None = None
reverse: str | None = None
nullable: bool = False
cascade_delete: bool | None = None
table: str | None = None
owner: bool | None = None
column: str | None = None
columns: list[str] | None = None
__init__(kind='', target=None, reverse=None, nullable=False, cascade_delete=None, table=None, owner=None, column=None, columns=None)
Parameters:
Return type:

None

class nextorm.fields.LocalSpec[source]

Bases: object

Marker for local (transient) fields that are never persisted.

Local fields are stored in instance.__dict__ only. They are never included in SQL, schema DDL, or migrations, and accessing them never triggers a database query — making them safe to initialise inside lifecycle hooks such as after_load.

__init__()
Return type:

None

Composite constraints

nextorm.fields.composite_key(*field_names)[source]

Declare a multi-column unique constraint (equivalent to UNIQUE (a, b)).

Place this inside the entity body as a class attribute:

class Booking(Entity):
    slot: Req[int]
    room: Req[int]
    _ck_slot_room_ = composite_key("slot", "room")
Parameters:

field_names (str)

Return type:

CompositeConstraint

nextorm.fields.composite_index(*field_names)[source]

Declare a multi-column non-unique index (equivalent to INDEX (a, b)).

Place this inside the entity body as a class attribute:

class LogEntry(Entity):
    source: Req[str]
    level: Req[str]
    _idx_source_level_ = composite_index("source", "level")
Parameters:

field_names (str)

Return type:

CompositeConstraint

nextorm.fields.PrimaryKey(*field_names)[source]

Declare a composite primary key spanning two or more fields.

field_names may be scalar field names or relation names (Single relations whose FK column then becomes part of the PK). All referenced relations must be required (non-nullable).

Place this inside the entity body as a class attribute:

class OrderLine(Entity):
    order: Single[Order]
    product: Single[Product]
    quantity: Req[int]
    _pk_ = PrimaryKey("order", "product")


class Enrollment(Entity):
    student_id: Req[int]
    course_id: Req[int]
    grade: Opt[str]
    _pk_ = PrimaryKey("student_id", "course_id")
Parameters:

field_names (str)

Return type:

CompositeConstraint

class nextorm.fields.CompositeConstraint[source]

Bases: object

Multi-column index, unique constraint, or primary key declared at class level.

Do not instantiate directly — use composite_key(), composite_index(), or PrimaryKey() instead.

fields: tuple[str, ...]
unique: bool = False
primary_key: bool = False
__init__(fields, unique=False, primary_key=False)
Parameters:
Return type:

None