Events and types

The data model of the logs: what writers append and what handlers receive. See Logs.

Events

class cairndb.Event(event_type: ~cairndb.core.types.EventType, timestamp: ~cairndb.core.types.Timestamp, payload: dict[str, ~typing.Any], schema_version: ~cairndb.core.types.SchemaVersion, metadata: dict[str, ~typing.Any] = <factory>)[source]

A single immutable event.

Events carry no sequence number of their own — their global order is given by their position in a committed Commit object.

class cairndb.SequencedEvent(sequence: SequenceNumber, event: Event)[source]

An event paired with its global sequence number.

This is what event handlers receive. Event fields are exposed directly (entry.payload, entry.event_type, …) for handler ergonomics.

class cairndb.Commit(number: int, created_at: Timestamp, events: tuple[Event, ...])[source]

An immutable commit object: an ordered batch of events.

Stored as log/{number:012d}.msgpack. The commit number is dense — commit N exists only if a writer won the put-if-absent race for it, so the log never has gaps.

sequences() → list[SequenceNumber][source]

Sequence numbers of this commit’s events, in order.

sequenced_events() → Iterator[SequencedEvent][source]

Yield each event paired with its global sequence number.

property last_sequence: SequenceNumber

Sequence number of the last event in this commit.

Types

class cairndb.SequenceNumber(commit: int, index: int)[source]

Global sequence number: position of an event in the commit log.

An event is totally ordered by (commit, index):

  • commit: the dense, monotonically increasing commit object number, assigned by the bucket via put-if-absent

  • index: the event’s position within its commit

Ordering never depends on clocks or process identity.

classmethod from_string(s: str) → SequenceNumber[source]

Parse from the canonical ‘{commit:012d}:{index:06d}’ form.

class cairndb.Timestamp(value: datetime)[source]

Immutable UTC timestamp value type.

Every construction path normalizes to UTC: naive datetimes are assumed UTC, aware ones are converted. Instances order among themselves, subtract to a timedelta, and shift by a timedelta — so deadline arithmetic never has to unwrap value.

Timestamps are informational (effective/valid-from time); record ordering in the log never depends on them — use identifiers for that.

classmethod now() → Timestamp[source]

Get current UTC timestamp.

classmethod from_datetime(dt: datetime) → Timestamp[source]

Create from datetime; the constructor normalizes to UTC.

classmethod from_iso(iso_string: str) → Timestamp[source]

Parse from ISO 8601 format string.

classmethod from_uuid7(u: UUID) → Timestamp[source]

Extract the embedded millisecond timestamp from a UUIDv7.

to_iso() → str[source]

Canonical RFC 3339 form: fixed-width microseconds, ‘Z’ suffix.

Fixed-width so the form sorts lexicographically as it sorts chronologically. Parsing (from_iso) stays lenient: any ISO 8601 offset, ‘Z’, or a naive string (assumed UTC) is accepted.

to_uuid7() → UUID[source]

Encode as a standard UUIDv7 (RFC 9562, ascending lexicographic order).

The 80 non-timestamp bits are random, so each call yields a distinct UUID; only the millisecond timestamp round-trips via from_uuid7.

Layout (128 bits):
127..80 unix_ts_ms 48-bit millisecond timestamp

79..76 0x7 version 75..64 rand_a 12 random bits 63..62 0b10 RFC 4122 variant 61..0 rand_b 62 random bits

cairndb.EventType

NewType("EventType", str): an event’s type name, for example EventType("order.placed"). It selects the projection handler.

cairndb.SchemaVersion

NewType("SchemaVersion", str): the version of an event payload’s shape, for example SchemaVersion("1").