SELSimple Expression Language
GitHub

SEL — Simple Expression Language

Write a business rule once. Run it in five languages — or in your database — and get the same answer.

Python · JavaScript · PHP · C++23 · Common Lisp  |  MariaDB · MySQL · PostgreSQL · SQLite


SEL is a small expression language for the rules applications live by — validation, pricing, eligibility, routing, reporting. A rule is text:

sel
TOTAL = SUM(ITEMS, _["qty"] * _["price"]);
COND(IS_BLANK(CUSTOMER),                   ABORT("customer is required"),
     NOT RMATCH('^\d{2}-\d{3}$', POSTCODE), ABORT("postcode {POSTCODE} is not 00-000"),
     TOTAL > CREDIT_LIMIT,                  ABORT("total {TOTAL} exceeds {CREDIT_LIMIT}"),
     "ok")

Five independent implementations run it, held to one written specification, and they agree to the byte — on the value, and on the error code and position when a rule fails. The browser and the server, the batch job and the API, give one verdict.

Why SEL

  • Parity is the product. Exact decimal arithmetic — no floating point — no truthiness, strict UTF-8, a portable regex subset, and NULL that never turns into zero. Every host is held to a shared conformance suite, a differential fuzzer, a decimal oracle and documentation whose every example is executed. How parity is guaranteed →
  • Rules that reach the database. The same rule compiles to a SQL condition — knowing nothing about the schema, or with a description of it that makes the SQL tight and reaches related tables. A pipeline of FILTER, LINK, BUCKET, MAP and sorts compiles to a whole SELECT, and the hybrid planner pushes the longest exact prefix into the database and finishes the rest in memory — refusing, never guessing, wherever SQL would mean something else. SQL conditions → · SQL pipelines →
  • Easy to embed and to extend. Python, PHP and JavaScript have no dependencies; C++ is three files and a vendored regex engine; Lisp is an ASDF system. An application adds its own functions with one call, and its own SQL dialects and spellings the same way. Extending SEL →
  • Small on purpose. One expression per program. No loops, no user-defined functions, no dynamic names — so every rule terminates, and the inputs it reads are known before it runs. Overview →

A taste, in each language

Compile once, run per row:

python
rule = compile('IF(QTY * PRICE > LIMIT, "over budget", "ok")')
for row in [{'QTY': '3', 'PRICE': '19.99'}, {'QTY': '1', 'PRICE': '5.00'}]:
    ctx = Value.from_native({**row, 'LIMIT': '50.00'})
    print(f"   QTY={row['QTY']} PRICE={row['PRICE']} =>", rule.run(ctx).as_text())

Each of these is part of examples/plain, and the five print byte-identical output — which the test suite checks, on the code shown here.

Documentation

Overview what SEL is, its principles, where it fits, what it leaves out
Parity how five hosts are made to agree, and how that is checked
Syntax · Operators · Functions the language
Using SEL the host API; a REPL, validation, scripting with host functions
SEL and SQL conditions; pipelines over star, EAV, 3NF, flat and complex data; reference
Extending · Contributing host functions, dialects, builtins; the order of work and the traps
Specification the normative text, with grammar and error codes

All of it is also a styled site with language tabs — see the documentation home to build or serve it, or to run it as a Docker image.

Install

The package is sel-lang everywhere:

sh
pip install sel-lang
npm install sel-lang
composer require nathanjel/sel-lang
vcpkg install sel-lang            # or: conan install --requires sel-lang/0.8.1
(ql:quickload :sel-lang)          # Quicklisp / Ultralisp

Or copy python/sel/, js/src/ or php/src/ into a project — no package manager, no build step. Using SEL has the imports for each host, and PACKAGING.md the registries.

Checking it

sh
tools/check.sh          # every layer, every host; prints ALL GREEN or it isn't done

Parity describes each layer, and Contributing the order of work.

Licence

MIT. Two third-party components keep their own BSD 2-Clause licences: SRELL, vendored into the C++ implementation, and cl-ppcre, which the Common Lisp system depends on; both are listed in LICENSE. The Python, PHP and JavaScript implementations have no dependencies at all.

View this page's Markdown on GitHub