DRAFTThis page is not published. Only visible in development mode.

Procedures

A procedure is named, callable logic stored in the catalog next to the data it operates on. In an architecture where frontends query the database directly, procedures are where multi-step business operations live - invoked with call, executed transactionally, governed by policies like any other object.

Creating and calling

The body is a block of statements; calling the procedure returns the result of its last statement. Run the snippets on this page in order:

$ Create and Call a Procedure
$ ctrl+enter to run

Parameters

Parameters are declared as a typed record and referenced in the body with a $ prefix. Calls pass arguments positionally:

$ Typed Parameters
$ ctrl+enter to run

The body is a full script

Procedure bodies are ReifyDB Scripting, not just single queries: variables with let, conditionals, loops, and any number of reads and writes. See Parameters & Control Flow for the scripting constructs in depth.

$ The Body Is a Full Script
$ ctrl+enter to run

Procedures compose - a procedure can call another:

$ Procedures Call Procedures
$ ctrl+enter to run

Test procedures

ReifyDB's testing framework runs inside the database. create test procedure declares a helper callable only from test context - fixtures like seeding rows - and create test plus run tests execute assertions against real data:

$ Test Procedures and In-Database Tests
$ ctrl+enter to run

Each test runs in a transaction that is rolled back, so tests never leak state into your data - the seeded row does not survive the run:

$ Tests Roll Back - the Seed Row Is Gone
$ ctrl+enter to run

Beyond RQL bodies

RQL is one of several procedure kinds the catalog manages. Procedures can also be backed by built-in native implementations, by functions loaded from FFI libraries, or by WASM modules - all invoked through the same call statement with the same typed parameters. Event-driven logic, by contrast, is not a procedure kind: declare an event and attach handlers, which run automatically on dispatch instead of being called.

Access control

Who may invoke a procedure is governed by a policy with the call operation: create procedure policy on ns::proc { call: { filter { ... } } }. Like all policies, procedure policies apply to non-root identities.

Procedure or view?
If the logic computes state from other state, you usually want a view - it stays correct by itself. Reach for a procedure when the operation is an action: multiple writes that belong together, validation with branching, or an API-like entry point you want to expose to clients.