Docs

Data

A service that declares a database gets its own SQLite file, migrated at deploy, and every call to it runs as one transaction.

The database

  • A deployed service has one database and keyspace shared by every caller. --caller, caller() and user() do not create separate stores. For private per-user data, include the authenticated caller or the user's issuer and subject in every key and SQL ownership condition; see Callers and users. client() rotates daily and is not a durable user identifier. Local caller identities are unchecked.
  • A service declares its database with [database] migrations = "migrations" in its crab.toml, a directory of .sql files applied in name order at deploy.
  • A deploy whose migrations do not begin with the ones already applied is refused. A migration that fails refuses the deploy, and the running version keeps serving.
  • Tables named _berm_* are reserved.

Statements

let titles = berm_lang::rows::<(String,)>("SELECT title FROM items WHERE id = ?", &(42,))?;
let found = berm_lang::sql("SELECT title FROM items WHERE id = ?", "[42]")?;
  • rows::<T>(statement, params) runs one statement, params a tuple bound to its ?s in order, and answers its rows, each a tuple of its columns in order.

  • sql(statement, params) takes the parameters as a JSON array and answers {"columns": [..], "rows": [[..]], "read": n, "written": n}. For per-call usage and estimates, see Cost of a call.

  • Every statement of one call runs in one transaction, committed when the tool returns Ok.

  • BEGIN, COMMIT and other transaction statements are refused.

  • A #[tool(query)] tool cannot write.

  • One statement answers at most 4 MiB.

Use the counters from representative queries and writes when evaluating an index. The worked index-cost example separates assumed counters, marginal row rates, and remaining plan allowances.

Values by key

let seen = berm_lang::get("last-run")?.unwrap_or_default();
berm_lang::set("last-run", &now.to_le_bytes())?;
let config: Config = berm_lang::get_json("config")?.unwrap_or_default();
berm_lang::set_json("config", &config)?;
  • Any service keeps values by key with get, set, get_json and set_json, database or not. A service with a database keeps them in it.
  • They read and write the service's own keys. Another service's keys cannot be named.
  • get answers None for a key never written.
  • Writes are committed when the call returns Ok. set is refused in a query tool.

Storage

A service's database holds at most the size set in [database] of its crab.toml: 1 GiB unless set, at most 10 GiB. A write past it fails. Your services reserve at most your plan's storage together, and a deploy past it is refused; see Plans.

Seeds

A service can start from a database you filled locally: name it as seed in [database] of its crab.toml, relative to the file. On the service's first source deployment, the CLI uploads a copy and the service's database starts as it. Use crab deploy --build when its manifest declares image.

  • The seed is held to the image's migrations: those it records applied must be the image's first, unchanged. The rest are applied on top.
  • A seed holds at most 5 GiB, and no more than the service's size.
  • A service that has a database takes no seed. Later deploys leave it out.