Table and column metadata
Identity
Section titled “Identity”SapportaMeta, SapportaTableInputMeta, ColumnMeta, ChildMeta,
TreeMetaInput, TreeMeta, columnBySqlName(), and columnPropertyName()
from @sapporta/server; serialized TableSchema, ColumnSchema,
ChildSchema, ComputedFieldSchema, and TableTree from
@sapporta/shared/contracts.
Contract
Section titled “Contract”SapportaTableInputMetais the sparse authoring shape accepted bysapportaTable().SapportaMetais its normalized server form.- Authoring metadata includes
label, requiredrowLabelColumns,rowScope,immutable,references,defaultSort,children,columns,search,tree, androwCaption. rowLabelColumnsmust contain at least one real SQL column name from the current table. Labels concatenate those stored values; they do not resolve referenced-row labels.rowScopedefaults toworkspaceUserScoped, which requiresworkspace_idandscoped_to_user_id.workspaceGlobalrequiresworkspace_id;systemGlobalrequires neither scope column.- Child metadata includes
table,foreignKey,label,columns,defaultSort, andwidth. Child display metadata does not configure search. treedeclares that the rows form a tree through a self-referencing column, such as an account’sparent_id. It takesparentColumn(required),column(the column that shows the hierarchy, default the firstrowLabelColumnsentry),defaultExpanded(defaulttrue), andmatchContext("ancestors-and-descendants"by default, or"ancestors"), which sets what a search or filter keeps besides the matching rows. Two optional fields have no default:rootOrder: { column, values }orders the top-level rows bycolumn, in the order ofvalues; rows whose value is not listed come last. Siblings otherwise followdefaultSort. A tree read with nosort, such as the table page’s tree, and a tree lookup use this order.pathnames a computed field made withtreePath(). The table’s tree pickers draw a chosen row and each search match with that path. The resolvedTableSchema.treecarriespathandpathSeparator, the separator given totreePath().
parentColumnmust be a nullable, single-column foreign key to the same table’s primary key, declared with Drizzle.references()or ameta.referencesrule.columnmust be a visible column, and the table cannot also list itself inmeta.children.rootOrder.columnmust be a column of the table with at least one value listed, andpathmust name atreePath()field. A violation fails the boot with the table and column in the message.- The stock table page shows a tree table as one list with the hierarchy in the
tree column, loads all its rows at once (up to 1,000), and shows each search
or filter match under its ancestors. The
meta.childrenentries of a tree table become row links, and a row expands into its child rows of the same table. See Show a table as a tree. searchisfalse,"allColumns", or an object with optionalselfandchildren. Search defaults to"allColumns". Aselfvalue isfalse,"allColumns", or an array of SQL column names;childrenis a recursive record keyed by SQL child table names already declared inmeta.children.- An empty
self: []is invalid; useself: falseto search descendants without searching values from the current table. "allColumns"includes visible application columns at the current node. Foreign keys search the target row label, not the stored ID. Has-many traversal is explicit, and expanded child grids do not inherit the root search term.- Column metadata includes semantic kind, formatting, label, visibility, width
bounds, additive behavior, color/zero/strong hints, notes,
apiWritable, andgridEditable. - Select options belong to the Drizzle column. Use Sapporta
select()or raw Drizzletext(name, { enum: options }); schema extraction serializes the same option list for browser controls. columnBySqlName(table, sqlName)returns the table’sSQLiteColumnornull.columnPropertyName(table, column)performs the reverse lookup and returns the Drizzle property name ornull. SQL column names remain the public query vocabulary even when a Drizzle property uses a different name.- Application validation belongs to the top-level
validate()callback onsapportaTable(). It composes with structural column validation. apiWritable: falseremoves a column from generated write schemas and forms, and generated table APIs reject callers that submit it. Reference-levelapiSettable: falseapplies the same policy to a server-authored foreign key.gridEditable: falsekeeps a column out of grid cell editing and out of a record’s detail field, while the table API still accepts the column and a create form still asks for it. It suits text an import wrote that a person should not change. A generated grid also keeps anapiWritable: falsecolumn read-only, as the detail field and the create form already did.- A table declaring
meta.childrendeclares the child’s foreign key non-writable, through eitherreferences: { fk: { apiSettable: false } }on the child orcolumns: { fk: { apiWritable: false } }. Either removes the key from the child insert shape, which is what the master-with-$detailscreate branch is built on. Without one of them a$detailsrow carrying that key is accepted and the value is silently replaced by the created master’s key. - Browser
TableSchemacontainsname,label,immutable,columns,children, optionalrowLinks,rowLabelColumns, optionalrowCount,searchable, optionaltreewith every field resolved, optionalcomputed, and optionalrowCaption.computedlists the table’s computed fields as{ name, label, kind, notes? }(ComputedFieldSchema) and is absent when the table declares none.rowCaptionis the caption’s column or field name. It does not serialize row scope, abilities, request authority, authoring references, validation callbacks, the table-level DrizzledefaultSort, or the recursive search plan. - Visual metadata, hidden fields, and a protected frontend route do not replace server authorization or row scope.
Row caption
Section titled “Row caption”meta.rowCaption names one column or
computed field of
the table. The default row display draws its text under the row’s label, such as
an account’s parent path under its name:
meta: { rowLabelColumns: ["name"], tree: { parentColumn: "parent_id" }, rowCaption: "parentPath",},computed: { parentPath: treePath() },sapportaTable()throws whenrowCaptionnames neither a column nor a computed field.- A column caption is the row’s value as text. A computed caption is formatted
by its field’s
kind: a number with digit grouping, a boolean as “Yes” or “No”, a"json"value as JSON text, and any other kind as text.nulland""show no caption. - The caption is drawn on the
"option","selected", and"field"surfaces: picker and editor options, beside a picker’s chosen value, and record sheet references. Grid cells, report cells, and filter chips draw the label alone; a filter chip uses the caption as its tooltip. A view that already shows the row’s place in its tree draws no caption. - Every lookup of the table carries a computed caption, so references arrive with it.
See Show rows with their captions and display slots.