Macros

A macro gives a title to reusable expression syntax. Expansion replaces a call with its template before compilation. The expanded expression follows the expression type and cost rules.

dust192B
#_ada {name Ada
       role engineer
       age  36}
#_bob {name   Bob
       role   engineer
       age    41
       mentor {#link #_ada}}
#_cy  {name Cy
       role designer
       age  29}

Define a macro

A macro document has ordered params and an expands template. An optional description explains its purpose. A stored definition has a title. The native macro builder also accepts an authored definition without saving it.

dust114B
description Multiply an amount by a rate.
params      [amount rate]
expands     [* {insert amount} {insert rate}]

Parameter names are plain text. Each name must differ from the other names. A name cannot be empty or contain whitespace. A macro cannot have a built-in operator's title. Definition validation rejects unknown fields, missing required fields and invalid markers.

Call a macro

A call has the title first, then one argument for each declared parameter.

dust35B
[pricing/apply-rate ?subtotal 0.2]
Result / 4B
subtotal
100.0
20.0

Expansion produces [* ?subtotal 0.2]. The variable remains a caller input. Expansion rejects an invalid argument count.

dust27B
[pricing/apply-rate 100.0]

Error

Invalid_Call

Insert and spread

An insertion marker is a map with one member. {insert name} replaces the marker with one argument tree. {spread name} inserts each item of a list argument into the surrounding list.

dust45B
params  [values]
expands [+ {spread values}]
dust20B
[sum-all [1 2 3 4]]
Result / 2B
10

The expansion is [+ 1 2 3 4]. A spread marker needs a surrounding list and a list argument. An insertion preserves a list or map as one argument tree.

Compose macros

A template can call another macro. Expansion resolves nested calls before the compiler validates operators and types. Expansion rejects direct and indirect cycles.

dust65B
params  [value floor]
expands [>= {insert value} {insert floor}]
dust81B
params  [value]
expands [and [at-least {insert value} 18] [< {insert value} 65]]
dust17B
[working-age 36]
Result / 4B
true

quote stops macro expansion inside its values. The expression evaluator still rejects quote. Syntax preserved during expansion is not necessarily executable.

Use macros in queries

A query expands macros in expression positions, including predicates, derivations, computed columns, grouping filters, ordering and projection. Ordinary fact values remain data.

dust119B
find    [?name]
where   [[?person age ?age]
         [?person name ?name]
         [working-age ?age]]
orderBy [?name]
Result / 33B
[{name Ada} {name Bob} {name Cy}]

A mutation uses the same expansion rules in its selection query.

Current and pinned definitions

An unpinned call uses the current title mapping. Each accepted update records a mapping revision. A pin names that mapping revision, rather than the macro entity or its definition revision.

This update changes working-age to require an age of at least 40.

dust75B
params  [value]
expands [and [>= {insert value} 40] [< {insert value} 65]]
dust17B
[working-age 36]
Result / 5B
false

The first recorded mapping revision of working-age is 13 in this fresh fixture. Read the actual revision from the saved definition in your database. A pinned call keeps that earlier rule.

dust62B
[
  {title           working-age
   mappingRevision 13}
  36]
Result / 4B
true

A query can pin all calls of a title with its definitions member. Expansion consumes that metadata before query compilation.

dust168B
definitions {working-age 13}
find        [?name]
where       [[?person age ?age]
             [?person name ?name]
             [working-age ?age]]
orderBy     [?name]
Result / 33B
[{name Ada} {name Bob} {name Cy}]

Expansion rejects an unknown mapping revision. It does not select the current rule.

Run it

build macro · expand macro.