literal (persisted)
A real column. Stored on the backend. Validated on write against fieldType (string, number, boolean, date, json) and optional fieldEnum.
Xuda Developer Studio
A Xuda table is a record type: a list of typed fields and a list of indexes. The actual storage is
provided by a dbs plugin you pick per table. The native Xuda backend gives you live
subscriptions, the CouchDB and MySQL adapters give you classic CRUD, and you can write your own adapter
for anything that speaks JSON.
project.tables[id].Each table is keyed by its id. Properties hold the display name and the backend choice. Fields define the row shape. Indexes define which queries are cheap. Records themselves do not live in this document; they live in whichever backend the table points to.
{
_id: 'tbl_invoices',
properties: {
menuType: 'table',
menuName: 'Invoices',
databaseSocket: '@xuda.io/xuda-dbs-plugin-xuda',
accountId: 'acc_default'
},
tableFields: [
{ data: { field_id: '_id', type: 'literal', serverField: true } },
{ data: { field_id: 'customer_id', type: 'literal', serverField: true } },
{ data: { field_id: 'amount', type: 'literal', serverField: true },
props: { fieldType: 'number' } },
{ data: { field_id: 'status', type: 'literal', serverField: true },
props: { fieldType: 'string', fieldEnum: ['draft','open','paid','void'] } },
{ data: { field_id: 'created_at', type: 'literal', serverField: true },
props: { fieldType: 'date' } },
{ data: { field_id: 'total_with_tax', type: 'virtual', serverField: false },
props: { propExpressions: { fieldComputed: '@amount * 1.17' } } }
],
tableIndexes: [
{ id: 'idx_status_created', data: { keys: ['status', 'created_at'] } },
{ id: 'idx_customer', data: { keys: ['customer_id'] } }
]
}
The same field data.type taxonomy you saw in globals shows up here. The difference is
serverField: true means the field is persisted, false means it is
computed on read. That single flag is the line between schema and projection.
A real column. Stored on the backend. Validated on write against fieldType (string, number, boolean, date, json) and optional fieldEnum.
Not stored. Evaluated on every read. Use for derivations like a tax-inclusive total or a full name.
Pulls from another table. Configured with a fieldDataSource and a fieldQuery. The runtime resolves the join when the row is read.
Computed by calling a library plugin method on read. Useful for fields that come from external services (geocoded addresses, exchange-rate conversions).
Marks the field as mandatory at write time. The studio renders the editor as a required input; the server rejects writes missing the field.
An array of allowed values. Renders as a select in the studio and as a constraint on write.
Indexes live in tableIndexes as { id, data: { keys } }. The order of the keys
matters: it defines the sort order and the prefix the runtime can use to short-circuit queries. The
native Xuda backend uses indexes for both querying and live subscriptions; SQL adapters translate them
to CREATE INDEX; CouchDB translates them to view definitions.
// Schema:
tableIndexes: [
{ id: 'idx_status_created', data: { keys: ['status', 'created_at'] } }
]
// Query against it (in a progDataSource on a list program):
{
dataSourceType: 'table',
dataSourceTableId: 'tbl_invoices',
dataSourceQuery: '({ status: \"open\" })',
dataSourceOrderBy: 'created_at',
dataSourceOrderDir: 'desc',
dataSourceLimit: 50
}
progDataSource. Writes happen through workflow actions.
A program that lists invoices points its progDataSource at the table. A program that edits
a single invoice fetches one record by id. Writes never go through the field directly: they go through a
workflow step (upsert, delete, or a plugin method) that the runtime dispatches
to the backend.
progDataSource: {
dataSourceType: 'table',
dataSourceTableId: 'tbl_invoices',
dataSourceQuery: '({ customer_id: @route.params.id })',
dataSourceOrderBy: 'created_at',
dataSourceLimit: 100,
realtime: true
}
<button xu-on:click='[{"workflow":[
{"data":{"action":"upsert",
"table":"tbl_invoices",
"fields":{"_id":"@_id",
"customer_id":"@customer_id",
"amount":"@amount",
"status":"\"open\""}}},
{"data":{"action":"toast",
"name":{"value":"\"Saved\""}}}
]}]'>Save</button>
Set realtime: true on a datasource and the runtime opens a subscription on the chosen
backend. The native Xuda store wires it up over the broker chain so you get push updates with
sub-second latency. CouchDB falls back to _changes long-polling. SQL adapters fall back to
a polling interval. The reading code does not change either way.
If you see a runtime warning about a table being typed without a
dataSourceTableId, double-check that the datasource bound to the program actually has that
key set. The runtime treats the missing id as a configuration bug rather than guessing the target.
The Tables panel splits into three tabs: schema (the field list), data (a paginated record viewer with filters and inline editing), and indexes (composite key builder). Switching the backend is a one-click change in properties; the studio re-runs validation and warns about features the new backend cannot support.