Maya Workflow Kit
The whole Maya workflow in Blender, in one install. Free and open source, Blender 4.5 – 5.2.
翻译准备中
尚未收集仓库信息。
尚未检测到更新。GitHub 发布版本后会显示在这里。
PostgreSQL extension bringing DMN (Decision Model and Notation) support to Postgres
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗PostgreSQL extension that brings DMN (Decision Model and Notation) support to Postgres. Built with Rust, pgrx, and dsntk.
-- Install the extension
CREATE EXTENSION pgdmn;
-- Evaluate a FEEL expression directly
SELECT feel_eval('1 + 2');
-- Returns: 3
-- Load a DMN model and evaluate a decision
SELECT dmn_eval(
dmn_load('<your DMN XML here>'),
'Decision Name',
'{"input": "value"}'::jsonb
);
Parse DMN XML into a dmnmodel value. This is the entry point for all DMN operations.
SELECT dmn_load('<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="https://www.omg.org/spec/DMN/20191111/MODEL/"
namespace="https://example.com/greeting"
name="greeting-model">
<decision id="greeting" name="Greeting">
<literalExpression>
<text>"Hello, " + name</text>
</literalExpression>
</decision>
</definitions>');
-- https://example.com/greeting::greeting-model
The display format is namespace::name. The model can be stored in a column for reuse:
CREATE TABLE models (model dmnmodel);
INSERT INTO models VALUES (dmn_load('<your DMN XML>'));
Evaluate a named invocable (decision, BKM, or decision service) from a DMN model.
-- Simple decision with no inputs
SELECT dmn_eval(dmn_load('...'), 'Greeting');
-- Decision table with JSONB inputs
SELECT dmn_eval(
dmn_load('...'),
'Eligibility',
'{"Age": 30, "Income": 75000}'::jsonb
);
-- "Approved"
-- Chained decisions (dependencies resolved automatically)
SELECT dmn_eval(
dmn_load('...'),
'Total Price',
'{"Base Price": 100, "Tax Rate": 0.1}'::jsonb
);
-- 110
Same as dmn_eval, but accepts a composite-type record instead of JSONB for the input.
CREATE TYPE loan_input AS ("Age" int, "Income" numeric);
SELECT dmn_record_eval(
dmn_load('...'),
'Eligibility',
ROW(30, 75000)::loan_input
);
-- "Approved"
dmn_eval returns JSONB, so a decision that produces the string Approved comes back as "Approved"—quoted. Unwrapping that by hand means dmn_eval(...) #>> '{}', and a numeric decision means (dmn_eval(...) #>> '{}')::numeric.
The typed variants take the same arguments and return a native PostgreSQL type instead. Each raises an error if the decision returns something else—asking for a number and getting a string is a mistake worth hearing about.
SELECT dmn_eval_text(
dmn_load('...'),
'Eligibility',
'{"Age": 34, "Income": 82000, "Bankrupt": false}'::jsonb
);
-- Approved
Drops straight into arithmetic, with no unwrap and no cast.
SELECT round(dmn_eval_numeric(
dmn_load('...'),
'Total Price',
'{"Base Price": 2499.99, "Tax Rate": 0.0825}'::jsonb
), 2);
-- 2706.24
Usable directly in a WHERE clause or a CHECK constraint.
SELECT dmn_eval_bool(dmn_load('...'), 'Eligible', '{"Age": 30}'::jsonb);
-- true
SELECT dmn_eval_date(dmn_load('...'), 'Due Date');
-- 2024-03-15
SELECT dmn_eval_timestamp(dmn_load('...'), 'Effective From');
-- 2024-03-15 10:30:00
Both FEEL durations convert: years and months, and days and time.
SELECT dmn_eval_interval(dmn_load('...'), 'Term');
-- 2 years 3 mons
List all invocable elements in a DMN model as a table.
SELECT * FROM dmn_invocables(dmn_load('...'));
-- name | kind
-- -------------+----------
-- Tax Amount | decision
-- Total Price | decision
Return model metadata as JSONB, including counts of each element type and invocable names.
SELECT dmn_info(dmn_load('...'));
-- {"name": "greeting-model", "namespace": "https://example.com/greeting",
-- "decisions": 1, "business_knowledge_models": 0,
-- "decision_services": 0, "invocables": ["Greeting"]}
Extract the raw XML source from a DMN model.
SELECT dmn_xml(dmn_load('<definitions ...>...</definitions>'));
-- Returns the original XML
Get the model name.
SELECT dmn_name(dmn_load('...'));
-- greeting-model
Get the model namespace.
SELECT dmn_namespace(dmn_load('...'));
-- https://example.com/greeting
Evaluate a FEEL expression. Optionally pass a JSONB context for variable bindings.
-- Simple arithmetic
SELECT feel_eval('1 + 2');
-- 3
-- With context variables
SELECT feel_eval('x * 2', '{"x": 21}'::jsonb);
-- 42
-- List comprehension
SELECT feel_eval('for i in [1,2,3] return i * i');
-- [1, 4, 9]
-- String operations
SELECT feel_eval('"Hello " + name', '{"name": "World"}'::jsonb);
-- "Hello World"
Same as feel_eval, but accepts a composite-type record instead of JSONB for the context. Columns map directly to FEEL variables.
CREATE TYPE calc_input AS (x numeric, y numeric);
SELECT feel_record_eval('x + y', ROW(3, 4)::calc_input);
-- 7
Evaluate a FEEL expression that returns a number. Returns a native PG numeric.
SELECT feel_eval_numeric('x * 2', '{"x": 21}'::jsonb);
-- 42
Evaluate a FEEL expression that returns a boolean.
SELECT feel_eval_bool('5 > 3');
-- true
SELECT feel_eval_bool('x > 100', '{"x": 50}'::jsonb);
-- false
Evaluate a FEEL expression that returns a string.
SELECT feel_eval_text('"Hello " + name', '{"name": "World"}'::jsonb);
-- Hello World
Evaluate a FEEL expression that returns a date.
SELECT feel_eval_date('date("2024-03-15")');
-- 2024-03-15
Evaluate a FEEL expression that returns a date-time.
SELECT feel_eval_timestamp('date and time("2024-03-15T10:30:00")');
-- 2024-03-15 10:30:00
Evaluate a FEEL expression that returns a duration.
SELECT feel_eval_interval('duration("P2Y3M")');
-- 2 years 3 mons
SELECT feel_eval_interval('duration("PT4H30M")');
-- 04:30:00
Evaluate a FEEL expression that returns a range of numbers, as a native PG
numrange. Open/closed endpoints are preserved, and an unbounded FEEL endpoint
becomes an infinite range bound.
SELECT feel_eval_numrange('range("[18..65)")');
-- [18,65)
SELECT feel_eval_numrange('range("[1..)")');
-- [1,)
-- Compose with native PG range operators
SELECT feel_eval_numrange('[low..high)', '{"low": 18, "high": 65}'::jsonb) @> 42::numeric;
-- true
feel_eval, dmn_eval, …)
appear as FEEL-syntax strings, e.g. "[18..65)"; an unbounded end renders
with nothing after the .. ("[1..)"). Use feel_eval_numrange for a
structured value.in works with unary-test lists (5 in (=4, =5)), variables may share names
with temporal builtins (a context key or column named date or duration is
fine), and multi-word range properties parse ([1..10].end included).\u escapes in FEEL string literals are parse errors.external function definitions (Java/PMML) are not supported: the
machinery that would evaluate them (a blocking HTTP client) is compiled out
of the extension entirely, so any external invocation yields an explained
null—and definitions detectable at load time are rejected with a clear
error before evaluation.pgdmn vendors the dsntk DMN/FEEL
engine (by Dariusz Depta / Engos Software) under vendor/: verbatim,
checksum-verified crates.io releases plus a minimal, deliberately upstreamable
patch layer (performance work, one bug fix, and an off-by-default feature gate
that keeps an HTTP/TLS stack out of the PostgreSQL backend). Each change is
its own commit with PGDMN: markers. See vendor/README.md
for provenance and conventions, and vendor/PATCHES.md for
what each patch does; make vendor-status shows the carried layer at any time.
All builds run in Docker and go through make. See CLAUDE.md for the full target list and conventions.
make test-image # build the Docker image (first time, and after dependency changes)
make check # fast compilation check
make test # run the pgrx test suite against PG17
make verify # fmt + lint + check
pgdmn runs inside your database, so a few properties are worth stating plainly:
dmn_load parses caller-supplied XML, and does not resolve external entities—DMN XML is not an XXE vector. A test asserts this so it stays true.IMMUTABLE and PARALLEL SAFE and touch no external state.A DMN model and a FEEL expression are code: treat one from an untrusted source as you would any SQL you did not write. To report a vulnerability, see SECURITY.md—please do not open a public issue.
Licensed under either of
at your option.
website/posts/ (Leptos, prerendered to static HTML; make website-build, deployed to GitHub Pages at www.pgdmn.com on push to main)There is no docs/ directory: explanation aimed at users lives on the website, decisions live in CLAUDE.md, and findings and future work live in TODO.md.
vendor/—the dsntk engine, copyright Dariusz Depta / Engos Software,
licensed MIT OR Apache-2.0 at your option; the upstream license texts and
NOTICE are included in that directory. The sources carry local
modifications, each marked with a PGDMN: comment.examples/—DMN example models from the DMN TCK (DMN TCK Contributors)
and Camunda Services GmbH, licensed Apache-2.0 (see file headers).pgdmn's own license applies to everything else in the repository.