aster.Web Data / Docs Aster UI ↗

Aster Web Data / Connect your data

TigerBeetlePreview

How Aster Web Data publishes TigerBeetle accounts and transfers, and which reads and writes the ledger can answer.

If you keep balances in a TigerBeetle ledger, Aster Web Data publishes its accounts and transfers as two OData sets, so a screen can list an account's transfers or create a transfer with an ordinary request. The service runs no SQL here: each read or write becomes a request to the cluster, and the cluster's own rules apply. Records are immutable once created, so they can be read and created, but not changed or deleted.

TigerBeetle has no table scan, which shapes every read you design. A read must name an ID, an account, or a field the cluster can query by; a broad list, a count and offset paging are refused with a message that names the alternatives.

Connecting

The catalog is fixed, so a service stored on the ledger declares no data sources:

services:
  ledger:
    datasources: []
databases:
  ledger:
    kind: tigerbeetle
    options:
      cluster_id: '0'             # your cluster's ID
      addresses: 127.0.0.1:3000   # the replica addresses, comma-separated
Key Meaning
options.cluster_id Required. The cluster ID as unsigned decimal text, with no sign and no leading zero, up to 128 bits.
options.addresses Required. The replica addresses, separated by commas.
options.timeout_ms The longest a call waits for the cluster, 5,000 ms by default. The request's statement timeout applies when it is shorter.

A URL, the parts form, schema, TLS settings and read_only are refused, and setup takes only existing, because there are no tables to create and both sets accept inserts. pool is accepted and not used: one client serves every call. A service on the ledger also refuses transactional server rules and request-context rules that need a check after the write. The configuration reference lists the shared keys, such as required and retry.

The service uses the official TigerBeetle client, version 0.17.9, and the tests run against a cluster of the same version.

Start-up check

There are no tables to check, and opening the client makes no call to the cluster. The first health check, a lookup of account ID 0 bounded by timeout_ms, is the first call that reaches it. A failed check makes Accounts and Transfers answer 503 ConnectionLost until the ledger is back, while the service's other sets keep serving; A database goes down describes the rest. $metadata is the same whether or not the cluster is reachable.

Accounts and transfers

The two sets use TigerBeetle's own field names.

Field Storage in TigerBeetle OData type
id, the debit and credit account IDs, amount, pending_id, user_data_128 128-bit unsigned Edm.String holding decimal text
The four balance counters of an account (debits_pending, debits_posted, credits_pending, credits_posted) 128-bit unsigned Decimal text
user_data_64 64-bit unsigned Decimal text, because a signed 64-bit type cannot hold every value
user_data_32, ledger, timeout 32-bit Edm.Int64
code 16-bit Edm.Int32
timestamp 64-bit, in nanoseconds Edm.Int64
Each flag (linked, pending, closed, and the others) A bit Edm.Boolean

Identifiers and amounts travel as decimal text, so no value passes through floating point. Every property is required, so there are no nulls. When a record is created, an omitted writable value is zero or false, and id must be supplied. The balance counters, timestamp and linked are set by the cluster. Accounts have no navigations, so $expand does not apply.

Where each operation runs

The service answers these request shapes with a native query to the cluster:

Request shape Native request
id eq or in, up to 8,189 distinct IDs A lookup of accounts or transfers by ID. The result is complete, so any further filter is exact.
A transfer filtered by debit_account_id eq or credit_account_id eq A query for the transfers of an account, with the debit or credit flag.
The debit and credit filters for the same account, joined with or One query for the transfers of that account, with both flags.
A non-zero eq on ledger, code, user_data_128, user_data_64 or user_data_32 A query of accounts or transfers by that field.
timestamp with eq, gt, ge, lt or le, beside one of the filters above A query with inclusive bounds on the timestamp.
$orderby=timestamp, ascending or descending The native reversed flag. Timestamps are unique, so no ID tie-breaker is needed.
Server-driven paging A bounded native limit, plus one record to check for a next page. The cursor in @odata.nextLink is a timestamp.

The default page is 1,000 records, and a response holds at most 8,189. On a bounded result such as an ID lookup, the service evaluates any other filter itself, and sums 128-bit values and orders them numerically. String functions on these fields are refused.

These are refused with a 400 that names the alternatives: a read with no ID, account ID or query filter, or filtered only by timestamp; $count=true and /$count; $skip above 0; ordering by a field other than timestamp; and a query that would fill the 8,189-record batch without paging, which is refused rather than returned cut short.

Errors

Case Response
A record the cluster rejects as malformed, such as a zero value that must be non-zero, a reserved field, or mutually exclusive flags 400, with the native name in error.code
A conflict with ledger state, such as a missing account, an exceeded balance, a closed account, or an overflow of a balance counter 409, with the native name in error.code
A repeated create with an ID that exists 409, with exists
An amount or identifier outside its native width 400, before anything is sent
A request larger than the cluster's negotiated limit 400
An unknown result code from a newer cluster 500 unknown_native_result. It is never read as success.
The client was evicted or closed 503 ConnectionLost
A call that ran out of time 503 ConnectionLost, with Retry-After

Writes and transactions

Scaffold

There is nothing to scaffold. The scaffold command stops with a message on a TigerBeetle database, because the service publishes Accounts and Transfers itself, for each service whose database: names the ledger. A configuration can declare the ledger beside other databases, as Several databases in one service describes.