Table schema reference#
Tables define persisted records and configuration rows. Use them for business data, tenant-owned policy, workflow configuration, and lookup data that can vary by company, country, process, or time.
Declaration shape#
@audited
public table PostingPolicy inherits AuditedRecord {
field company_code: CompanyCode key;
field document_type: DocumentType key;
field valid_from: date key;
field valid_to: date optional;
field active: bool required default(true);
}A table can have annotations, an access modifier, a name, optional inheritance, and a body of table members.
| Part | Shape |
|---|---|
| Annotation | @audited |
| Access | public, private, protected, or internal |
| Declaration | table Name { ... } |
| Inheritance | inherits BaseRecord or a comma-separated type list |
| Members | Fields, functions, events, computed fields, getter fields, UI, constraints, indexes, and validation |
The table grammar also accepts entity in table-declaration position for persisted entity-shaped schemas.
Fields#
Table fields use field name: Type or the shorter name: Type form.
table InvoiceLine {
field invoice_id: uuid key;
company_code: CompanyCode required indexed;
amount: decimal required min(0) max(999999999);
description: string optional max_length(240);
}Field modifiers can appear before or after a reference.
field vendor_id: VendorId key -> Vendor.vendor_id cascade indexed;Field modifiers#
| Modifier | Use |
|---|---|
required, optional | Presence intent |
key, primary, unique, indexed | Identity and lookup behavior |
default, default(...), default = expr | Default value |
pattern expr, pattern = expr | Pattern constraint |
max_length(...), min(...), max(...), range(...) | Scalar constraints |
searchable, immutable | Storage and update semantics |
upper, lower, capitalize | Case transforms |
associated(a, b) | Field association group |
modifier(...), modifier = expr, modifier expr, modifier | Custom modifier forms |
Custom modifiers are syntax extensions. Use them for compiler/runtime metadata, not for hiding configurable ERP policy.
References#
References use arrow syntax and may include cascade.
table CategoryAssignment {
field vendor_id: VendorId -> Vendor.vendor_id;
field parent_id: uuid optional -> Category.category_id cascade;
}For explicit relational behavior, prefer a foreign-key constraint with a referential action.
table VendorCategoryLink {
field vendor_id: VendorId;
field parent_id: uuid optional;
foreign key (vendor_id) references Vendor (vendor_id) on delete restrict;
foreign key (parent_id) references Category (category_id) on update cascade;
}Supported referential actions are cascade, restrict, set null / set_null, set default, and no action / no_action.
Computed and getter fields#
Computed fields can be expression-based or use a block with named get entries.
computed gross_amount: decimal = net_amount + tax_amount;
computed labels: Json {
get en: invoice_id;
get ar: invoice_id;
}Getter fields are lightweight computed values.
get display_name => invoice_id;
get lookup_key = company_code + ":" + document_type indexed;Use computed and getter fields for derived values. Do not use them to replace explicit configuration resolution when the value is policy-owned.
Constraints#
Constraints can be written with or without the constraint keyword.
constraint primary key (company_code, document_type, valid_from);
unique (company_code, document_type, valid_from);
check (valid_to is null || valid_to >= valid_from);
foreign key (company_code) references Company (company_code) on delete restrict;| Constraint | Shape |
|---|---|
| Primary key | primary key (field_a, field_b) |
| Unique | unique (field_a, field_b) |
| Check | check (expression) |
| Foreign key | foreign key (local_field) references Target (target_field) |
Use constraints for structural guarantees. Process policy still belongs in configuration tables plus resolver functions when it can vary.
Indexes#
Indexes have a name, a field list, and optional key-value options.
index posting_policy_lookup on (company_code, document_type) {
unique: false;
}
index by_status on status, company_code;The field list can be parenthesized or written as a comma-separated identifier list.
Events#
Tables can declare named event collections for runtime fixtures and generated integrations.
events PostingPolicyEvents {
PostingPolicyActivated activated(policy_id: uuid);
PostingPolicyExpired expired(policy_id: uuid, expired_on: date);
}Use table events to describe event shapes. Use lifecycle subscriptions to attach handlers to insert, update, or delete operations.
Table UI#
The ui: table member accepts either an expression or a source UI layout block.
For a complete reference to groups, rows, row operations, and field operations, see Source UI layouts.
table PostingPolicy {
field company_code: CompanyCode key;
field document_type: DocumentType key;
field valid_from: date key;
field valid_to: date optional;
field active: bool required default(true);
ui: {
group "Posting policy" {
columns: 2;
row {
field company_code;
field document_type;
}
row {
field valid_from;
field valid_to;
}
readonly field active;
}
}
}Source UI groups can contain group properties, rows, row operations, and field operations.
Validation#
Table validation sections contain named expressions or reusable validation rule references.
validation {
valid_range: valid_to is null || valid_to >= valid_from;
active_policy: rule ActivePolicy(company_code, document_type);
}Keep validation deterministic. Missing required configuration should raise a declared message-backed failure in the resolver or command layer, not silently pass validation with a default.