Macros
Declarative macros are exported from riverbase_core (and its prelude). The two procedural macros
live in riverbase_proc. When a macro produces a confusing error, run cargo expand on the crate to
see the generated code.
domain!
riverbase_core::domain! {
domain <Name> {
meta { namespace: "<ns>", title: "<title>", description: "<text>" }
command: <CommandEngine>, // optional (query-only domains)
query: <QueryEngine>,
service: <ServiceEngine>, // optional
routes(<api_base>) { <axum::Router expr> } // optional; needs `http`
spawn(runtime: &DomainRuntime) { <body returning RiverbaseResult<Self>> }
}
}
The generated <Name><S> has NAMESPACE, spawn, engine_context, from_engines, from_query,
into_arc, command(), query(), service(), execute_command, execute_query, and implements
Domain. See Domains.
command_engine! / command!
riverbase_core::command_engine! {
engine <Name> {
domain_trait: generate | manual, // optional
meta { command_pool_size: <n> }, // optional; actor_pool_size alias
aggregate: <Aggregate>,
component: { <field>: <Type>, … },
}
commands {
command <PascalName> {
meta {
key: "<cmdkey>", title: "<title>", kind: collection | object, resources: [<expr>, …],
// optional: scope: required, link: true, hook: true, tenant_scope: exempt,
// engine_method: false, response_type: "…", openapi_tag: "…", …
}
payload { <field>: <Type>, … }
target collection(<resource>) | object(<resource>); // optional
handle (<payload>, <aggregate>) { <body> }
}
}
methods ( // optional
<name>(<arg>: [<Type>]; …) for <PascalName> {
payload <PayloadType> { … },
target none | some(<CommandTarget expr>)
}
)
}
The commands-only form, command_engine! { commands <Aggregate> { … } }, generates handlers and a
register_<aggregate>_handlers(&mut args) function. See Commands.
impl_domain_command_engine!(<Engine>) writes a forwarding DomainCommandEngine impl for engines
declared with domain_trait: manual that need no custom behavior.
query_resource!
riverbase_core::query_resource! {
<Name> name "<resource>" {
meta {
title: "<title>", description: "<text>",
default_order: [<field>.asc | <field>.desc, …],
scope: none | required,
// optional: order_fields: [<field>, …]
}
fields {
field <name> { preset: <Preset>, label: "<label>" [, identifier] [, sortable | no_sort] }
}
binding source "<table>" { <field> => "<column>", … }
errors { list: ("<CODE>", "<message>"), item: ("<CODE>", "<message>") }
policy: required | optional | public("<reason>", "<sign-off>"),
scope_policy(<ctx>, <url_scope>) { <RiverbaseResult<Option<Expr>>> } // optional
tenant_scope: exempt("<reason>", "<sign-off>"), // optional
}
}
Presets: Uuid, String, Integer, Number, Boolean, Datetime, Date, Enum, Array,
Json, Textsearch, None. It also generates <Name>Key, a typed resource key.
report_resource!
Same shape as query_resource!, with filters { field … } instead of fields, plus:
params { param <name> { type: <Date|…>, label: "<label>" [, required] } }
errors { report: ("<CODE>", "<message>") }
handler (<self>, <ctx>, <session>, <request>, <query>) { <RiverbaseResult<ReportOutput>> }
query_engine!
riverbase_core::query_engine! {
engine <Name> {
meta { query_pool_size: <n> }, // actor_pool_size alias
component: { … },
}
resources { <Resource>, … }
reports { <Report>, … } // optional
}
Persistence macros
| Macro | Purpose |
|---|---|
diesel_table_with_domain_fields! { schema.table (_id) { col -> Type, … } } | Diesel table! plus the domain columns |
domain_row! { #[derive(…)] pub struct Row { … } } | A row struct with domain fields prepended |
pg_domain_entity! { Name { schema, row, resources, source, row_to_json, upsert_from_json, order } } | A writable Postgres entity |
pg_readonly_entity! { … } | A read-only entity, for views and reports |
domain_insert_values!(table, domain, col.eq(v), …) | Insert values including the domain columns |
domain_json_converters! | Row-to-JSON helpers |
Other declarative macros
| Macro | Purpose |
|---|---|
declare_errors! { type_base: "…", CODE { status, title, code, message, hint } … } | A crate error catalogue. See Errors. |
aggregate_core_deref!(Aggregate) | Deref/DerefMut to AggregateCore |
resource_name!(…) | A ResourceName from a literal |
Procedural macros (riverbase_proc)
| Macro | Purpose |
|---|---|
#[domain_action(event = "…", resources = ["…"])] | Mark an aggregate method as a state-changing action. See riverbase_proc. |
riverbase_namespace!("…") | A Namespace from a literal |