Documentation
¶
Overview ¶
Package ntable is a general, Redis-backed table built from one primitive: the ordered set. A table is a series of ordered sets, one per cell, and the value a cell prints is by default that set's cardinality, |s|. It knows nothing about sprints: the nova-table tool is its face.
A table has three kinds of cell:
- HEADER cells: the top row is the column labels (Column.Label, default the column name); the left column is the row labels (Row.Label, default the row key), in front of every declared column. Labels, not sets.
- BODY cells: every body cell is an ordered set, a Redis ZSET, rendered by its column's projection: count (the cardinality, |s|), members (the members in score order, comma-joined), first, last (the lowest and highest scored member), text (a value per row, set by row set, blank when none; no set).
- FOOTER cells: one per column, the column's fold over the body: sum or max of the counts, union of the members, none (blank). The footer row carries the table's footer label (default total). A table whose columns all fold none prints no footer row.
A cell's set is either OWNED by the table, at table:<t>:cell:<row>:<col>, and written by the cell verbs, or BOUND to a set another tool owns (the stream block's ws:<s>:<state>): a bound cell is a view, read freely and never written here (ErrBound). A row may name one member its counts and members leave out (Row.Exclude: the stream's sentinel is the stream's stop, not work).
Keys, all under one prefix so an ACL row can grant them (~table:*), plus the registry set tables:
tables SET every table name (List)
table:<t> HASH order (the column names, comma-joined),
footer (the footer label), created_at,
col:<name> = <projection>:<fold>:<width>:<label>
table:<t>:rows ZSET row key -> rank (the render order)
table:<t>:row:<r> HASH label, exclude, owner, key:<col> (a bound
cell's set; absent: the owned cell)
table:<t>:cell:<r>:<c> ZSET an owned cell
Each table operation is one Redis function call. Read-only snapshots include the definition, current rows, bindings and cells even on a cold read. QueueCells remains available to callers already holding a shape, so they can include cell reads in their own larger pipeline. Writes validate bindings and permissions before changing any key.
Index ¶
- Constants
- Variables
- func Bind(ctx context.Context, c redis.Cmdable, t Table, now time.Time, ...) error
- func CellAdd(ctx context.Context, c redis.Cmdable, name, row, col, member string, ...) (int64, error)
- func CellKey(table, row, col string) string
- func CellKeyAt(table, row, col string, epoch uint64) string
- func CellMove(ctx context.Context, c redis.Cmdable, name, row, from, to, member string, ...) (int64, error)
- func CellRemove(ctx context.Context, c redis.Cmdable, name, row, col, member string, ...) (int64, error)
- func CellText(cols []Column, r Row, j int) string
- func CellsAdd(ctx context.Context, c redis.Cmdable, name, row, col string, score float64, ...) (int64, error)
- func CellsMove(ctx context.Context, c redis.Cmdable, name, row, from, to string, ...) (int64, error)
- func CellsRemove(ctx context.Context, c redis.Cmdable, name, row, col string, members []string, ...) (int64, error)
- func ChangesKey(table string) string
- func CheckBatchBounds(m *BatchManifest) error
- func Clear(ctx context.Context, c redis.Cmdable, name string, opts ...WriteOptions) (int64, error)
- func Create(ctx context.Context, c redis.Cmdable, t Table, now time.Time, ...) error
- func DefKey(table string) string
- func Drop(ctx context.Context, c redis.Cmdable, name string, opts ...WriteOptions) (int, error)
- func DropDefinition(ctx context.Context, c redis.Cmdable, name string, opts ...WriteOptions) (int, error)
- func EpochPrefix(table string, epoch uint64) string
- func FormulaArg(projection string) string
- func IdentityKey(table string) string
- func IsFormula(projection string) bool
- func IsPct(projection string) bool
- func IsRefusal(err error) bool
- func IsSum(projection string) bool
- func List(ctx context.Context, c redis.Cmdable) ([]string, error)
- func MemberCreate(ctx context.Context, c redis.Cmdable, name, id string, opts ...WriteOptions) error
- func MemberKey(id string) string
- func ParseWidths(spec string) (map[string]int, error)
- func PropsKeyAt(table string, epoch uint64) string
- func QueueViewState(ctx context.Context, p redis.Pipeliner, name, text string) *redis.Cmd
- func Render(t Table, opts RenderOpts) string
- func RenderTables(title string, tables []Table, opts RenderOpts) string
- func RevisionKey(table string) string
- func RowDel(ctx context.Context, c redis.Cmdable, name, key string, opts ...WriteOptions) (bool, error)
- func RowKey(table, row string) string
- func RowKeyAt(table, row string, epoch uint64) string
- func RowSet(ctx context.Context, c redis.Cmdable, name, key string, ...) (int, error)
- func RowSetMany(ctx context.Context, c redis.Cmdable, name string, ...) error
- func RowsAdd(ctx context.Context, c redis.Cmdable, name string, keys []string, ...) (int, error)
- func RowsAddWithSpec(ctx context.Context, c redis.Cmdable, name string, keys []string, spec RowSpec, ...) (int, error)
- func RowsHide(ctx context.Context, c redis.Cmdable, name string, hide bool, keys []string, ...) (int, error)
- func RowsKey(table string) string
- func RowsKeyAt(table string, epoch uint64) string
- func SameDefinition(a, b Table) bool
- func SameShape(a, b Table) bool
- func Set(ctx context.Context, c redis.Cmdable, name string, change SetOpts, ...) (int, error)
- func SummaryLine(v View, first Table) string
- func ValidName(s string) bool
- func ValidRowKey(s string) bool
- func ValidViewState(text string) bool
- func ValidateColumns(cols []Column) error
- func ViewDelete(ctx context.Context, c redis.Cmdable, name string) (int64, error)
- func ViewList(ctx context.Context, c redis.Cmdable) ([]string, error)
- func ViewSet(ctx context.Context, c redis.Cmdable, v View) error
- func ViewState(ctx context.Context, c redis.Cmdable, name, text string) error
- func ViewStateResult(name string, cmd *redis.Cmd) error
- type BatchDelta
- type BatchManifest
- type BatchMemberDelta
- type BatchMemberEntry
- type BoundError
- type Cell
- type CellSelection
- type CellsCmd
- type CheckReport
- type Column
- type CountCmd
- type FieldChange
- type FieldGuard
- type Formula
- type LimitError
- type ManifestError
- type Member
- type MemberCreateOp
- type MemberExpect
- type MemberLocation
- type MemberMoveOp
- type Place
- type PlaceExpect
- type ReadCmd
- type ReadSetCmd
- type ReadSetMember
- type ReadSetResult
- type ReadSetScope
- type Reader
- type Receipt
- type Refusal
- type RenderOpts
- type Reorder
- type Row
- type RowSpec
- type RuleError
- type SetOpts
- type Sort
- type Summary
- type Table
- type View
- type WriteOptions
Constants ¶
const ( LimitManifestBytes = 1 << 20 // canonical encoded request LimitChangedEntries = 128 // entries with changes LimitGuardEntries = 1024 // guard-only entries LimitMemberIDBytes = 256 LimitFieldValueBytes = 64 << 10 LimitSetFields = 128 // set fields per member LimitUnsetFields = 1000 // unset fields per member LimitFieldGuards = 1000 // guards per member LimitOneOfOptions = 1000 // options in one guard LimitReadSetMembers = 1024 LimitColumns = 1000 // columns per table LimitRows = 100000 // rows per table LimitManifestProps = 64 // properties a manifest sets, expects or expects absent (each) LimitTableProps = 64 // properties a table holds at an epoch LimitReceiptBytes = LimitManifestBytes // the encoded batch delta of one receipt LimitBatchValueBytes = 16 << 20 // bytes of the field values a batch's entries name, before and after )
The bounds of a batch manifest and of a read set. table.lua holds the same numbers (T.limits) and docs/SPEC-NOVA-TABLE.md states them; a test compares the three. A refusal names the bound and the count found, never the input.
const ( Count = "count" Members = "members" First = "first" Last = "last" Text = "text" )
The projections: what a body cell prints.
const ( Sum = "sum" Max = "max" Union = "union" Avg = "avg" // the mean of a count column over the rows Pooled = "pooled" // a pct column's footer: the named counts summed over every row's counts summed (never the mean of percentages) None = "none" )
The folds: what a footer cell prints over its column.
const ( FnClear = "ns_table_clear" FnCreate = "ns_table_create" FnSet = "ns_table_set" FnRowSet = "ns_table_row_set" FnRowsAdd = "ns_table_rows_add" FnRowsHide = "ns_table_rows_hide" FnDrop = "ns_table_drop" FnDropDefinition = "ns_table_drop_definition" FnMemberCreate = "ns_table_member_create" FnMemberFind = "ns_table_member_find" FnRowAdd = "ns_table_row_add" FnRowDel = "ns_table_row_del" FnCellAdd = "ns_table_cell_add" FnCellRemove = "ns_table_cell_remove" FnCellMove = "ns_table_cell_move" FnBind = "ns_table_bind" FnRead = "ns_table_read" FnCheck = "ns_table_check" FnList = "ns_table_list" FnMembers = "ns_table_members" FnApply = "ns_table_apply" FnReadSet = "ns_table_read_set" )
const CheckedBeforeSending = "checked before sending, so this call changed nothing; it says nothing about an earlier call with the same operation id"
CheckedBeforeSending is what a refusal made before anything is sent says of itself; the library and the command both say it. The store looks an operation up before it judges the request, so a manifest that the current rules refuse can still have been applied earlier, under looser rules: this refusal is about this call only.
DefaultFooter is the footer label a table has when none is set: none; the footer row still prints the folds, with a blank label cell, and `create --footer <label>` names it.
const FnMove = "ns_oset_move"
FnMove is the ordered-set move library function: ZREM from, ZADD to, in one call, refused NOTMEMBER when the member is not in from (pkg/nsprint/fn/lua/table.lua).
const MaxViewState = 64
MaxViewState bounds a view's state text, in bytes.
const ReceiptValueBytes = 64
ReceiptValueBytes is the longest field value a receipt, the change event and the operation record's result hold in full; a longer one is recorded as its length and SHA-1 (FieldChange.BeforeBytes, BeforeSHA1). The record's request is the manifest as sent, in full, because replay compares bytes. table.lua holds the same number (T.receipt_value_bytes); a test compares them.
const Registry = "tables"
Registry is the SET of every table name.
Variables ¶
var ( ErrExists = errors.New("exists with another definition") ErrOccupied = errors.New("shape would delete or hide placed members") ErrOwnedAlias = errors.New("binding target is table-owned storage") ErrStale = errors.New("requested epoch is stale, not the active epoch") ErrEpochAhead = errors.New("requested epoch is ahead of the active epoch") ErrMemberEpoch = errors.New("member belongs to another epoch") ErrPlaced = errors.New("member already has a place in this table") ErrDrift = errors.New("member record and owned set disagree") ErrMemberExists = errors.New("member identity already exists") ErrRevisionMismatch = errors.New("table revision mismatch") ErrMemberRevision = errors.New("member revision mismatch") ErrFieldGuard = errors.New("failed field guard") ErrPlaceGuard = errors.New("failed place guard") ErrPropGuard = errors.New("failed property guard") ErrOpConflict = errors.New("operation ID conflict") ErrLimit = errors.New("limit exceeded") ErrReservedField = errors.New("reserved field write") ErrDuplicateMember = errors.New("duplicate manifest member") ErrInvalidScore = errors.New("invalid score") ErrCounterOverflow = errors.New("counter overflow") ErrMutation = errors.New("incompatible mutation") ErrWrongType = errors.New("WRONGTYPE") ErrMalformedManifest = errors.New("malformed manifest") // ErrOrphan is a table that is gone while its identity record is left: a // verb on it refuses, and drop --definition removes the record. ErrOrphan = errors.New("orphan table identity") // ErrResidue is a create refused because rows of an earlier table of the // name are left at the epoch it would open at. ErrResidue = errors.New("rows of an earlier table are left") // ErrUnknownOutcome is a transport failure: the store did not answer, so the // batch may or may not have been applied (changed=unknown). Send the same // manifest again with the same operation id. ErrUnknownOutcome = errors.New("the store did not confirm the batch") )
var ErrNoTable = errors.New("no such table")
var ErrNoView = errors.New("no such view")
ErrNoView is a view that is not there.
var ErrNotMember = errors.New("NOTMEMBER")
ErrNotMember is the refusal of a move whose set does not hold the member it would leave.
Functions ¶
func Bind ¶
Bind replaces the caller-owned table shape in one atomic call. Existing owned cells of retained rows survive; removed rows leave bound sets alone. Omitting a row holding owned members or nonempty text is refused until the caller explicitly clears that content (or deletes the row).
func CellAdd ¶
func CellAdd(ctx context.Context, c redis.Cmdable, name, row, col, member string, score float64, opts ...WriteOptions) (int64, error)
Single-member helpers use the same list operation and wire protocol.
func CellRemove ¶
func CellText ¶
CellText returns a full, unpadded projected cell. Render and machine-readable show use the same value, including text, percentages and unread dependencies.
func CellsAdd ¶
func CellsAdd(ctx context.Context, c redis.Cmdable, name, row, col string, score float64, members []string, opts ...WriteOptions) (int64, error)
CellsAdd atomically adds every member at one score and returns the cell count.
func CellsMove ¶
func CellsMove(ctx context.Context, c redis.Cmdable, name, row, from, to string, members []string, opts ...WriteOptions) (int64, error)
CellsMove keeps scores and refuses the complete list if any member is absent or inconsistent.
func CellsRemove ¶
func CellsRemove(ctx context.Context, c redis.Cmdable, name, row, col string, members []string, opts ...WriteOptions) (int64, error)
CellsRemove removes a list; absent members are accepted no-ops.
func ChangesKey ¶
func CheckBatchBounds ¶
func CheckBatchBounds(m *BatchManifest) error
CheckBatchBounds applies every bound to a decoded manifest, in the order the server applies them: per entry (id, set, unset, guards, one_of), then the entry counts.
func Create ¶
func Create(ctx context.Context, c redis.Cmdable, t Table, now time.Time, opts ...WriteOptions) error
Create checks the definition and writes it atomically in one round trip.
func Drop ¶
Drop removes the active epoch and its owned cells. The template and older epochs survive; a later epoch starts with the same definition and no rows.
func DropDefinition ¶
func DropDefinition(ctx context.Context, c redis.Cmdable, name string, opts ...WriteOptions) (int, error)
DropDefinition also removes the stable template. Materialised epoch snapshots and immutable member identities remain available for inspection.
func EpochPrefix ¶
EpochPrefix is the storage namespace for one table generation.
func FormulaArg ¶
FormulaArg is the text between a formula's parentheses.
func IdentityKey ¶
IdentityKey is the table's identity hash: its epoch_key, epoch_field and member_prefix, written with the table and removed by drop --definition.
func MemberCreate ¶
func MemberCreate(ctx context.Context, c redis.Cmdable, name, id string, opts ...WriteOptions) error
MemberCreate allocates an unplaced identity in the table's record namespace. Existing IDs, including removed members and older epochs, are refused.
func ParseWidths ¶
ParseWidths reads col=n,col=n.
func PropsKeyAt ¶
PropsKeyAt is the table's properties at the epoch (L1 contract amendment, table properties): a hash of name -> value beside the rows key.
func QueueViewState ¶
QueueViewState queues ViewState on a pipeline or a transaction, so a caller writes a view's state in the same MULTI/EXEC as a record of its own (the state it shows); ViewStateResult reads the queued call's answer after Exec.
func Render ¶
func Render(t Table, opts RenderOpts) string
Render prints the table as fixed-width text: the header row of column labels, a rule, one line per row (its label, then its cells), and, when any column folds, a rule and the footer row. Text, members, first and last cells are left-aligned; count cells right-aligned; a column's cells are separated by " | " and the rule joins dashes with "-+-". A cell whose set did not come back prints "?", and so does a fold over it. The last column is padded only when it is right-aligned, so no line ends in a blank. A table always renders, with its header and its footer, and with no body line when it has no row (the owner 2026-09-30, the owner's ruling: tables and rows always show, empty or not); with no body line the footer sits under the header's one rule, and the rule above the footer is not drawn (the owner, 2026-10-02: "when the work stream table is empty, please just show the summary row" / "not the extra --------------------+-----------+----------- etc.").
The row's label is always the first column (the owner 2026-09-27, the live session: eight benches rendered as eight anonymous rows of numbers), put in front of every declared column, and the footer label prints under it instead of eating the first count column's fold. Its header is the table's name when the caller gives one (opts.Title), else "row". A text column is a column like any other: it prints the row's value (row set), blank when the row has none; it never stands in for the label (a reviewer's read of #4456: a value in a leading text column made the row's key vanish; "the row identity must still have its own visible cell"). Display values are escaped before measuring widths: stored text cannot add terminal controls or line breaks, and rendering never changes the snapshot.
func RenderTables ¶
func RenderTables(title string, tables []Table, opts RenderOpts) string
RenderTables is the title line, then every table's render, one blank line between two; a table kept and read but not drawn (HiddenTable) prints nothing and leaves no gap. An empty table prints its header and footer.
func RevisionKey ¶
func RowSet ¶
func RowSet(ctx context.Context, c redis.Cmdable, name, key string, texts map[string]string, opts ...WriteOptions) (int, error)
RowSet writes text values as one validated mutation, with a single receipt.
func RowSetMany ¶
func RowSetMany(ctx context.Context, c redis.Cmdable, name string, rows map[string]map[string]string, opts ...WriteOptions) error
RowSetMany sets the text cells of several rows of one table in one round trip: one ns_table_row_set per row, all in one pipeline, each its own write (its own revision and change event), as RowSet writes it. An error names the first row the store refused, or the exchange that failed.
func RowsAdd ¶
func RowsAdd(ctx context.Context, c redis.Cmdable, name string, keys []string, opts ...WriteOptions) (int, error)
RowsAdd adds a list of rows using the same staged writer as RowAdd.
func RowsAddWithSpec ¶
func RowsAddWithSpec(ctx context.Context, c redis.Cmdable, name string, keys []string, spec RowSpec, opts ...WriteOptions) (int, error)
RowsAddWithSpec applies one metadata specification to every named row.
func RowsHide ¶
func RowsHide(ctx context.Context, c redis.Cmdable, name string, hide bool, keys []string, opts ...WriteOptions) (int, error)
RowsHide hides rows from the render while retaining their contribution to folds.
func SameDefinition ¶
SameDefinition says two tables declare the same columns and footer.
func SameShape ¶
SameShape says two tables have the same definition and the same rows with the same bindings, labels, excludes and owners (the cells' values aside): what a writer compares before binding again.
func Set ¶
func Set(ctx context.Context, c redis.Cmdable, name string, change SetOpts, opts ...WriteOptions) (int, error)
Set validates and commits a complete definition edit in one call. The return value counts physical keys moved when renaming, otherwise zero.
func SummaryLine ¶
SummaryLine is a stored view's summary line over its first table's snapshot, "" for no line: the view's state alone while it has one ("STOPPED", nothing more: no counts, no percent, no ETA), else "x/y z% -> ETA" when the view names a done column. The counts pool the first table's count columns; unread input, hidden rows and columns included, leaves them unknown. ETA has no value until change-stream rate sampling is available.
func ValidName ¶
ValidName says a table or column name is one word of letters, digits, '_', '.' and '-', starting with a letter, digit or '_'.
func ValidRowKey ¶
ValidRowKey says a row key is non-empty, valid UTF-8 and holds no ASCII control character.
func ValidViewState ¶
ValidViewState says a state text is one a view takes: empty (none), or one line of at most MaxViewState bytes with no control characters.
func ValidateColumns ¶
ValidateColumns refuses a column list a table cannot carry: a bad name, a repeated name, an unknown projection or fold, or a fold that does not fit its projection (sum and max fold counts; union folds members, first and last; none folds anything; a text column folds none).
func ViewDelete ¶
ViewDelete removes only presentation configuration; tables are untouched.
Types ¶
type BatchDelta ¶
type BatchDelta struct {
OperationID string `json:"operation_id"`
Digest string `json:"digest"`
Actor string `json:"actor"`
SelectedCount int `json:"selected_count"`
GuardCount int `json:"guard_count"`
ChangedCount int `json:"changed_count"`
Members []BatchMemberDelta `json:"members"`
// Props are the table's properties the batch changed, name -> new value
// (L1 contract amendment, table properties).
Props map[string]string `json:"props,omitempty"`
}
BatchDelta records the applied batch outcome for change stream and receipts.
func (*BatchDelta) UnmarshalJSON ¶
func (b *BatchDelta) UnmarshalJSON(data []byte) error
type BatchManifest ¶
type BatchManifest struct {
Schema int `json:"schema"`
Table string `json:"table"`
Epoch string `json:"epoch"`
ExpectedTableRevision string `json:"expected_table_revision"`
OperationID string `json:"operation_id"`
Actor string `json:"actor,omitempty"`
Members []BatchMemberEntry `json:"members"`
// Props are the table's properties the batch sets, PropExpect the ones it
// expects present with a value and PropAbsent the ones it expects absent,
// checked before any write and applied in the same atomic call as the
// members (L1 contract amendment, table properties, section 4).
Props map[string]string `json:"props,omitempty"`
PropExpect map[string]string `json:"prop_expect,omitempty"`
PropAbsent []string `json:"prop_absent,omitempty"`
}
BatchManifest specifies an atomic set of preconditions and mutations across members in a table.
func ValidateBatchManifestRaw ¶
func ValidateBatchManifestRaw(raw []byte) (*BatchManifest, error)
ValidateBatchManifestRaw reads raw manifest bytes as a batch manifest and applies every rule the server applies that needs no store: the manifest's size, UTF-8, exact-case keys, no key twice, each value's type, the bounds, and the combinations of changes. Nothing is coerced. The errors are of two kinds: a *ManifestError, a manifest that cannot be read as one (it names the place, members[0].create.score, in the manifest's words), and a *RuleError or a *LimitError, a manifest that reads as one and that a rule refuses; each is what the store would answer, with the same code.
type BatchMemberDelta ¶
type BatchMemberDelta struct {
ID string `json:"id"`
BeforePlace string `json:"before_place"`
AfterPlace string `json:"after_place"`
// BeforeScore and AfterScore are the scores parsed; BeforeScoreText and
// AfterScoreText are the exact decimal strings the store holds, which two
// different scores never share. Nil is no score (unplaced).
BeforeScore *float64 `json:"-"`
AfterScore *float64 `json:"-"`
BeforeScoreText *string `json:"before_score"`
AfterScoreText *string `json:"after_score"`
BeforeRev string `json:"before_rev"`
AfterRev string `json:"after_rev"`
FieldsSet map[string]string `json:"fields_set"`
FieldsUnset []string `json:"fields_unset"`
Fields map[string]FieldChange `json:"fields"`
}
BatchMemberDelta records before and after state for a member affected by a batch.
func (*BatchMemberDelta) UnmarshalJSON ¶
func (b *BatchMemberDelta) UnmarshalJSON(data []byte) error
type BatchMemberEntry ¶
type BatchMemberEntry struct {
ID string `json:"id"`
Expect *MemberExpect `json:"expect,omitempty"`
Create *MemberCreateOp `json:"create,omitempty"`
Move *MemberMoveOp `json:"move,omitempty"`
Remove bool `json:"remove,omitempty"`
Set map[string]string `json:"set,omitempty"`
Unset []string `json:"unset,omitempty"`
}
BatchMemberEntry defines expectations and mutations for one member.
type BoundError ¶
type BoundError struct{ Table, Row, Col, Key, Owner string }
BoundError names the other writer. The table may read the binding but cannot acquire write ownership merely by displaying it.
func (*BoundError) Error ¶
func (e *BoundError) Error() string
type Cell ¶
type Cell struct {
Key string
Bound bool
Count int64
Members []Member
Unread bool
// UnreadWhy says why the set did not come back: the key and the type found
// ("key K is string, expected zset"), or the store's error.
UnreadWhy string
}
Cell is one body cell: its set's key ("" for a text column), whether the set is bound (owned elsewhere), and what the last read found: the count, the members (for members, first and last), and Unread when the set did not come back (it prints "?", never a false 0).
type CellSelection ¶
CellSelection specifies a row and column for ReadSet.
type CellsCmd ¶
type CellsCmd struct {
// contains filtered or unexported fields
}
CellsCmd is one queued read of every body cell of a table the caller holds in memory: the ZCARD (and the excluded member's ZSCORE) of every count cell, the ZRANGE of every members, first and last cell. Result fills the table's cells in place.
func QueueCells ¶
QueueCells queues the cells of t on pipe: one command per count cell (two with a row exclude), one per members, first or last cell, none for a text column. It is how a caller that already knows a table's shape (the sprint tick, whose stream rows are ws:order) reads every cell in its own one pipeline.
type CheckReport ¶
type CheckReport = typedrec.TableCheck
CheckReport covers both directions of record/set membership in one instant.
type Column ¶
Column is one column: its name (the key its cells and definition use), its header label, the projection its body cells print, the fold its footer cell prints, and a fixed width (0: as wide as its widest cell).
func ParseColumn ¶
ParseColumn reads one column declaration, name[:projection[:fold[:label]]] (defaults: count, sum for a count or sum(...) column, pooled for a pct column and none otherwise, the name).
func ParseColumns ¶
ParseColumns reads a comma-separated list of column declarations.
type CountCmd ¶
type CountCmd struct {
// contains filtered or unexported fields
}
CountCmd is one queued count of an ordered set: its ZCARD, less one when the excluded member is in it (its ZSCORE rides the same pipeline). It is the one count every reader of a set counts through: the sprint's card count leaves the stream's sentinel out this way.
func QueueCount ¶
QueueCount queues the count of the set at key on pipe, leaving exclude out when it is a member ("" excludes nothing).
type FieldChange ¶
type FieldChange struct {
Before *string `json:"before"`
After *string `json:"after"`
BeforeBytes int `json:"before_bytes,omitempty"`
BeforeSHA1 string `json:"before_sha1,omitempty"`
AfterBytes int `json:"after_bytes,omitempty"`
AfterSHA1 string `json:"after_sha1,omitempty"`
}
FieldChange records before and after values for an application field. Absence is represented by nil, distinguished from a present empty string.
A value longer than ReceiptValueBytes is not recorded: its side is nil and carries the value's length and SHA-1 (BeforeBytes, BeforeSHA1), so a nil side with no length is an absent field and a nil side with a length is a long one.
type FieldGuard ¶
type FieldGuard struct {
Equals *string `json:"equals,omitempty"`
Absent *bool `json:"absent,omitempty"`
OneOf []string `json:"one_of,omitempty"`
}
FieldGuard checks a member application field's exact value, absence, or inclusion.
type Formula ¶
Formula is a formula projection read: for pct, Part is the numerator and Over the named denominator (nil: every count column of the row); for sum, Over is the columns added and Part is empty.
func ParseFormula ¶
ParseFormula reads a formula projection: pct(<col>), pct(<col>/<a>+<b>+...) or sum(<a>+<b>+...). The error says what is wrong with the text; that the named columns exist and are counts is the table's check (ValidateColumns).
type LimitError ¶
type LimitError struct {
Name string
Bound, Observed int
Member string
// AtLeast says the call stopped counting when it passed the bound: the true
// size is at least Observed.
AtLeast bool
}
LimitError is a named LIMIT refusal: the bound and the count found, and the member at fault when one is. It wraps ErrLimit.
func (*LimitError) Advice ¶
func (e *LimitError) Advice() string
Advice says how to get under the bound: what to narrow. A request that is narrowed is a different transaction, with its own operation id.
func (*LimitError) Error ¶
func (e *LimitError) Error() string
func (*LimitError) Unwrap ¶
func (e *LimitError) Unwrap() error
type ManifestError ¶
type ManifestError struct {
Where, Msg string
}
ManifestError is a manifest that cannot be read as a manifest: it is not JSON, names a key it may not, or holds a value of the wrong type. It says where, in the manifest's own words (members[0].create.score), and never in the parser's.
func (*ManifestError) Error ¶
func (e *ManifestError) Error() string
func (*ManifestError) Is ¶
func (e *ManifestError) Is(target error) bool
type MemberCreateOp ¶
type MemberCreateOp struct {
Row string `json:"row"`
Col string `json:"col"`
Score float64 `json:"score"`
}
MemberCreateOp places a new member at row, column, and score.
type MemberExpect ¶
type MemberExpect struct {
Absent bool `json:"absent,omitempty"`
Revision string `json:"revision,omitempty"`
Place *PlaceExpect `json:"place,omitempty"`
Fields map[string]FieldGuard `json:"fields,omitempty"`
}
MemberExpect guards an existing or absent member record before mutation.
type MemberLocation ¶
type MemberLocation = typedrec.TableMember
MemberLocation is an indexed placement in this table, or missing/unplaced.
func MemberFind ¶
MemberFind reads and verifies one member's owned placement atomically. It does not search external bindings; Check audits the complete namespace.
type MemberMoveOp ¶
type MemberMoveOp struct {
Row string `json:"row"`
Col string `json:"col"`
Score *float64 `json:"score,omitempty"`
}
MemberMoveOp moves an existing member to row, column, with optional new score.
type Place ¶
type Place struct {
Where string // first, last, before, after
Ref string // the neighbour, for before and after
}
Place is a position in an order: first, last, or before or after Ref.
type PlaceExpect ¶
PlaceExpect checks the expected row and column of a placed member.
type ReadSetCmd ¶
type ReadSetCmd struct {
// contains filtered or unexported fields
}
ReadSet reads members in one round trip from one consistent snapshot of one table (ns_table_read_set, a read-only function): each member's place, score, revision and fields, the members that are missing, and the table's epoch and revision, which a manifest's expected_table_revision is prepared from.
The scope is one of two shapes, each nonempty: Members (ids) or Selection (row and column pairs, every member of each cell). An empty scope, both lists together, or more than LimitReadSetMembers members is refused. epoch is optional (at most one value): it reads a materialised epoch of the table instead of the active one, and an epoch ahead of the active one is refused (ErrEpochAhead). Errors are refusals (IsRefusal) that wrote nothing, or a transport error from the client. ReadSetCmd holds a queued ns_table_read_set command.
func QueueReadSet ¶
func QueueReadSet(ctx context.Context, c redis.Cmdable, table string, scope ReadSetScope, epoch ...uint64) (*ReadSetCmd, error)
QueueReadSet queues ns_table_read_set on c (a redis.Pipeliner or Cmdable).
func QueueReadSetMembers ¶
func QueueReadSetMembers(ctx context.Context, c redis.Cmdable, table string, members []string, epoch ...uint64) (*ReadSetCmd, error)
QueueReadSetMembers queues ns_table_read_set for a list of member IDs.
func (*ReadSetCmd) Result ¶
func (q *ReadSetCmd) Result() (ReadSetResult, error)
Result decodes the result of a queued ReadSet.
type ReadSetMember ¶
type ReadSetMember struct {
ID string
Revision uint64
Placed bool
Row string
Col string
Score float64
// ScoreText is the score exactly as the store holds it.
ScoreText string
Fields map[string]string
}
ReadSetMember represents one member returned by ReadSet.
type ReadSetResult ¶
type ReadSetResult struct {
Table string
Epoch uint64
Revision uint64
Members []ReadSetMember
Missing []string
}
ReadSetResult contains the verified atomic snapshot of members and table revision.
func ReadSet ¶
func ReadSet(ctx context.Context, c redis.Cmdable, table string, scope ReadSetScope, epoch ...uint64) (ReadSetResult, error)
func ReadSetMembers ¶
func ReadSetMembers(ctx context.Context, c redis.Cmdable, table string, members []string, epoch ...uint64) (ReadSetResult, error)
ReadSetMembers is ReadSet for member ids: one round trip, one snapshot. The optional epoch is the epoch to read, as in ReadSet.
func (ReadSetResult) IsMissing ¶
func (r ReadSetResult) IsMissing(id string) bool
IsMissing says the id was asked for and does not exist as a member of the table. A missing member is an answer, not an error: it is listed in Missing.
func (ReadSetResult) Member ¶
func (r ReadSetResult) Member(id string) (ReadSetMember, bool)
Member returns the member with the id from the members that were found; ok is false for an id that is missing (see IsMissing) or was not asked for.
type ReadSetScope ¶
type ReadSetScope struct {
Members []string `json:"members,omitempty"`
Selection []CellSelection `json:"selection,omitempty"`
}
ReadSetScope specifies members or row/col selections to read atomically.
type Reader ¶
type Reader struct{ Name string }
Reader queues a read-only server snapshot, even on the first tick or a changed shape. QueueCells remains available for callers holding a shape.
type Receipt ¶
type Receipt struct {
ID string
Epoch, Before, After uint64
Outcome string
BatchDelta *BatchDelta
// Replay is true when ApplyBatch returned the receipt recorded for an
// operation it had already applied, and wrote nothing.
Replay bool
}
Receipt identifies the durable table change. Idem is recorded as caller metadata; this primitive does not deduplicate attempts.
func ApplyBatch ¶
ApplyBatch commits an atomic batch of member mutations and preconditions against one table in one round trip (ns_table_apply): every guard is read against one pre-state, and either every change is written with one receipt or nothing is.
It runs the manifest through the Go validator (ValidateBatchManifestRaw) before it sends anything, so a manifest that a rule refuses never reaches the store. Its errors are of three kinds, told apart with errors.Is and errors.As:
- a refusal (IsRefusal): the store or a rule said no, nothing changed, and the error says the code, the operation, the member, what was expected against what was found, changed=no and a next command. It wraps the sentinel of its code (ErrNotMember, ErrMemberRevision, ErrLimit, ErrStale, ErrEpochAhead, ErrOpConflict, ...).
- a manifest that cannot be read as one (ErrMalformedManifest, a *ManifestError): not JSON, an unknown key, a value of the wrong type. It names the place in the manifest.
- a transport failure (ErrUnknownOutcome): the store did not answer, so the batch may or may not have been applied. Send the same manifest again with the same operation id: it returns the original receipt if the batch was applied and applies it if it was not.
Operation identity is the table, the epoch and the operation id. Sending the same request again returns the receipt recorded for it (Receipt.Replay is true) and writes nothing, even after the table has moved on; a different request under the same id is refused (ErrOpConflict). manifest.Epoch is the epoch the caller observed: an epoch behind the active one is ErrStale, one ahead of it ErrEpochAhead. Operation records do not expire, but a drop of the table ends them.
func ApplyBatches ¶
func ApplyBatches(ctx context.Context, c redis.Cmdable, manifests []BatchManifest) ([]Receipt, []error)
ApplyBatches applies manifests of one table in one round trip, in one MULTI/EXEC: each is its own batch, applied or refused as ApplyBatch applies it, and none runs between them, so a refused one leaves every one after it refused on the table revision it expected. The receipts and errors are each manifest's; a manifest refused before sending (a rule or a bound this process checks) is its error, and none after it is sent.
type Refusal ¶
type Refusal struct {
Code string // the store's refusal code: NOTMEMBER, LIMIT, MEMBERREVISION, ...
Location string // the operation: table "demo" batch "op-1" member "a"
Sentence string // what was expected against what was found
Next string // a command that runs when pasted
Guarded bool // a batch or a read set: it wrote nothing, and says so
// contains filtered or unexported fields
}
Refusal is the store's no, or a rule's, with its code and its sentence: the operation, what was expected against what was found, whether anything changed, and the next command. A refusal is not a transport failure (ErrUnknownOutcome) and not a manifest that cannot be read (ErrMalformedManifest); a caller tells them apart with errors.Is, or IsRefusal.
type RenderOpts ¶
type RenderOpts struct {
// Widths fixes a column's width by name (a minimum: a longer cell is
// not cut), over the column's own Width; 0 leaves it as wide as its
// widest cell.
Widths map[string]int
// LabelWidth fixes the row-label column's width the same way (the
// sprint's stream block keeps its names 25 wide); 0 fits the labels.
LabelWidth int
// Title is the table's name, printed in the top-left cell, the header
// of the row-label column (the owner 2026-09-27: "tables need a title";
// "the title goes where 'row' is currently").
Title string
}
RenderOpts is what Render is told beyond the table.
type Row ¶
type Row struct {
Key string
Label string
Exclude string
Owner string
Cells []Cell
Texts map[string]string // a text column's value for this row (row set <col>=<value>), else blank
Hidden bool // kept and counted in the folds, not drawn (row hide)
}
Row is one row: its key, its label (the row header; "" prints the key), the member its counts leave out ("" for none), the verb that owns its bound sets (for the refusal that names it), and one cell per column.
type RuleError ¶
type RuleError struct {
Code string // the store's refusal code for the same rule
Member string // the member at fault, if one is
Msg string // the sentence, naming the member
Detail string // the sentence without the member
// contains filtered or unexported fields
}
RuleError is a manifest that reads as a manifest and that a rule refuses: a repeated member, a set and an unset of one field, a reserved field, a create with a move, an empty members array. It is a refusal, as the store's are, and says what the store would: a code and a sentence.
type SetOpts ¶
type SetOpts struct {
Rename string
Columns []Column
Hidden *[]string
Hide, Show []string // atomic deltas to the hidden column list
Visible *bool
// One column added (at the end, or where At says), removed (refused
// while it holds members or text) or moved; the other columns stand.
ColAdd *Column
ColAt *Place // where ColAdd enters; nil is last
ColDel string
ColMove *Reorder
// The rows' order: all sorted, then the named rows first, then one row
// moved, in that order when several are given. A standing sort refuses
// RowOrder and RowMove unless RowSort clears it in the same call.
RowSort *Sort
RowOrder []string
RowMove *Reorder
}
SetOpts changes the active definition while retaining rows and members. A removed or hidden occupied owned cell is refused. Rename moves the table identity, all retained epochs and its change stream to the new name.
type Sort ¶
Sort orders the rows once by name, label, or a column's value (a count, or a text value). Keep makes it standing (name and label only): every row added or rebound later takes its place. Manual ends a standing sort and leaves the rows where they are.
type Table ¶
type Table struct {
// EpochKey/Field bind this table to a shared epoch domain. An empty key
// means epoch zero permanently; the default field for a key is "n".
EpochKey string
EpochField string
MemberPrefix string
// Epoch and Revision describe the snapshot returned by the store.
Epoch uint64
Revision uint64
Name string
Columns []Column
Hidden []string // columns kept, read and used by formulas, but not drawn (set --hide)
HiddenTable bool // the whole table kept and read, not drawn by watch (set --hidden / --visible)
Sort string // the standing row sort (row sort --keep): name, -name, label, -label; empty is by hand
Rows []Row
// Props are the table's properties at the snapshot's epoch, name -> value
// (nil when it has none): values a batch writes with its members, such as
// a rolling index (L1 contract amendment, table properties).
Props map[string]string
}
Table is a table as read, or as a caller declares it before binding.
type View ¶
type View struct {
Name string
Tables []string
Title string
Summary string // the count column of the first table the summary line counts as done ("" for no line)
// State, when set, is the summary line, alone, in place of the counts:
// the state of whatever fills the view ("STOPPED"). ViewState writes it;
// ViewSet leaves it as it is.
State string
}
A view: a named list of tables with a title, read by watch every frame.
type WriteOptions ¶
type WriteOptions struct {
Epoch uint64
Actor string
Fence string
Idem string
// Receipt receives the committed event without another store exchange.
Receipt *Receipt
}
WriteOptions binds a mutation to the epoch its caller observed. Omitting options means epoch zero; a stale call is never retried into a new epoch. Actor, Fence and Idem accompany the change event; authorization and the coordinator lease are separate from this table primitive.