Documentation

Install instructions, and every function pgdmn installs, with its arguments.

Worked examples, with models and datasets you can download and run, are on the Examples page.

Install

pgdmn is a PostgreSQL extension. To install it, you build it from source, then copy the compiled extension into place. Both are done with pgrx, the framework pgdmn is built on.

Step one: set up pgrx for your database

Install the pgrx command-line tool. It needs a C compiler and a few build libraries; the pgrx system requirements list them for each platform.

cargo install --locked cargo-pgrx

Note: to run pgrx you need Cargo, the Rust package manager. If you do not have Cargo, you will need to install Rust.

Then initialise pgrx. Here you choose whether pgrx manages a PostgreSQL for you, or uses one you already run.

If you want pgrx to manage PostgreSQL, it downloads and builds its own—the quickest way to try pgdmn end to end. cargo pgrx run builds pgdmn, installs it into that instance, and drops you into a psql shell:

# Download and build a PostgreSQL 17 that pgrx manages.
cargo pgrx init --pg17 download

# Build pgdmn, install it into that PostgreSQL, and open psql.
cargo pgrx run pg17

To use a PostgreSQL you already run, point pgrx at its pg_config, then build and copy the extension into the directories that pg_config reports (you may need write permission there):

# Point pgrx at your server's pg_config.
cargo pgrx init --pg17 $(which pg_config)

# Build pgdmn and copy it into that PostgreSQL's install.
cargo pgrx install --release

Step two: enable and verify

In a database on that server, enable the extension and check it works:

CREATE EXTENSION pgdmn;

-- Execute a simple function from the extension.
SELECT feel_eval('1 + 2');
--  3

DMN functions

dmn_load(xml text) RETURNS dmnmodel
Parse DMN XML into a dmnmodel value. This is the entry point for everything else. The result is an ordinary PostgreSQL value: store it in a column, pass it around, join against it. It displays as namespace::name.
dmn_eval(model dmnmodel, invocable text, input jsonb DEFAULT NULL) RETURNS jsonb
Evaluate a named decision, business knowledge model, or decision service. Decisions that depend on other decisions are resolved for you—ask for the one you want, and pgdmn works out what it needs first.
dmn_record_eval(model dmnmodel, invocable text, input record DEFAULT NULL) RETURNS jsonb
The same, but the input is a composite-type record rather than JSONB, so table columns map straight onto model inputs with no JSON in between.

Typed variants

dmn_eval returns JSONB, so a decision that produces the string Approved comes back as "Approved", a quoted JSONB string. Unwrapping that by hand means dmn_eval(…) #>> '{}', and a numeric decision means (dmn_eval(…) #>> '{}')::numeric.

These take the same arguments and hand back a native PostgreSQL type instead. Each errors if the decision returns something else.

dmn_eval_text(model dmnmodel, invocable text, input jsonb DEFAULT NULL) RETURNS text
A decision that returns a string, unquoted.
dmn_eval_numeric(model dmnmodel, invocable text, input jsonb DEFAULT NULL) RETURNS numeric
A decision that returns a number, ready for arithmetic without a cast: round(dmn_eval_numeric(…), 2).
dmn_eval_bool(model dmnmodel, invocable text, input jsonb DEFAULT NULL) RETURNS boolean
A decision that returns a boolean—usable directly in a WHERE clause or a CHECK constraint.
dmn_eval_date(model dmnmodel, invocable text, input jsonb DEFAULT NULL) RETURNS date
A decision that returns a date.
dmn_eval_timestamp(model dmnmodel, invocable text, input jsonb DEFAULT NULL) RETURNS timestamp
A decision that returns a date and time.
dmn_eval_interval(model dmnmodel, invocable text, input jsonb DEFAULT NULL) RETURNS interval
A decision that returns a duration. Both flavours convert: years and months, and days and time.

Introspection functions

dmn_invocables(model dmnmodel) RETURNS setof (name text, kind text)
Every invocable element in the model, as rows. kind is decision, business_knowledge_model, or decision_service. Useful for discovering what a model you were handed can actually answer.
dmn_info(model dmnmodel) RETURNS jsonb
Model metadata: name, namespace, a count of each element type, and the list of invocable names.
dmn_xml(model dmnmodel) RETURNS text
The original XML source, byte for byte.
dmn_name(model dmnmodel) RETURNS text
The model's name.
dmn_namespace(model dmnmodel) RETURNS text
The model's namespace.

FEEL functions

FEEL is the expression language DMN is built on. These evaluate it directly, with no model involved. These utility functions aren't usually what you should use, but are here in case you want to cross check how something evaluates.

feel_eval(expression text, context jsonb DEFAULT NULL) RETURNS jsonb
Evaluate a FEEL expression. Keys of the context become variables in scope.
feel_record_eval(expression text, context record DEFAULT NULL) RETURNS jsonb
The same, with a composite-type record as the context. Columns become variables.

Typed variants

Each returns a native PostgreSQL type instead of JSONB, so the result drops into a typed column or a comparison without a cast. Each raises an error if the expression returns something else.

feel_eval_numeric(expression text, context jsonb DEFAULT NULL) RETURNS numeric
A FEEL number, as numeric.
feel_eval_bool(expression text, context jsonb DEFAULT NULL) RETURNS boolean
A FEEL boolean—usable directly in a WHERE clause or a CHECK constraint.
feel_eval_text(expression text, context jsonb DEFAULT NULL) RETURNS text
A FEEL string, unquoted.
feel_eval_date(expression text, context jsonb DEFAULT NULL) RETURNS date
A FEEL date, as date.
feel_eval_timestamp(expression text, context jsonb DEFAULT NULL) RETURNS timestamp
A FEEL date and time, as timestamp.
feel_eval_numrange(expression text, context jsonb DEFAULT NULL) RETURNS numrange
A FEEL range of numbers, as numrange.
feel_eval_interval(expression text, context jsonb DEFAULT NULL) RETURNS interval
A FEEL duration, as interval. Both flavours convert: years and months, and days and time.

Performance

Every function above is IMMUTABLE and PARALLEL SAFE. PostgreSQL is free to spread a decision table across as many parallel workers as it likes, and to skip repeated calls with identical arguments.

A model is not re-parsed per row. Parsed models are cached, keyed by the XML itself, so evaluating one model against a whole table parses it once.