Move conditional logic out of source code and database triggers and into a reusable package, where explicit rules can be independently defined and managed.
archetypes-rules
models Boolean logic. Instead of writing conditionals like
if / else if / else, you can instead create Rules that describe and
evaluate Facts (aka, RuleContexts).
Figure 1: Class diagram for the archetypes.rules
namespace.
Rules are explicit constraints that govern actions. Rules evaluate Facts, or RuleContexts.
Rules are defined with⏤and stored as⏤JSON.
Rules contain one or more RuleElements. There are three types of RuleElements
:
Propositions
, Operators
, and Variables
.
Propositions are statements that are either, true
, false
, or null
(unknown).
Learn more...
Variables are symbols that represent the value of something. Learn more...
Operators: Boolean and quantifier operators.
RuleContexts
are facts, stored as JSON in files, databases, etc.
Rules
evaluate RuleContexts
. During evaluation, we determine whether a
RuleContext
/Fact
complies with a Rule
.
returning a Proposition
that tells us whether a given set of facts conform to
the defined Rule
.
RuleElements
are evaluated using
Reverse Polish Notation (RPN).
See the examples below for details.
npm install archetypes-rules
Suppose we have a very simple rule that checks whether a customer is eligible for a discount. In order to be eligible, the customer simply needs to be a Gold Card holder.
const { Rule, RuleContext } = require('archetypes-rules')
// Create the rule
const rule = new Rule('eligibleForDiscount')
// Add a Proposition, i.e., a statement that has a value of true or false
rule.addProposition('customerIsGoldCardHolder', true)
// Create a RuleContext, i.e., a "Fact"
const ruleContext = RuleContext('eligibleForDiscountContext')
// Provide the truth statement as to whether the actual customer
// has a Gold Card
ruleContext.addProposition('customerIsGoldCardHolder', true)
// Evaluate
const result = rule.evaluate(ruleContext)
// Log the resulting Proposition
// Outputs
// Proposition statement = customerIsGoldCardHolder, value = true
Say you provide a discount to a group of six or more people:
// Create the rule
const rule = Rule('eligible-for-group-discount')
// Declare a "placeholder" variable for the actual number of people
// (This value will be retrieved from the RuleContext)
rule.addVariable('actual-num-people', null)
// Declare the minimum number of people required for discount
rule.addVariable('min-num-people', 6)
// Compare the two, i.e.,
// actual-num-people >= min-num-people
rule.addOperator(Operator.GREATER_THAN_OR_EQUAL_TO)
// Create a RuleContext, i.e., a "Fact"
const ruleContext = RuleContext('eligible-for-group-discount-fact')
// How many people are there?
ruleContext.addVariable('actual-num-people', 5)
// Declare the "placeholder" minimun number of people required for discount
// (This value will be retrieved from the Rule)
ruleContext.addVariable('min-num-people', 'NULL_NUMBER_VARIABLE')
// Evaluate
const result = rule.evaluate(ruleContext)
// Log the resulting Proposition
// OUTPUT:
// Proposition statement =
// (actualNumPeople >= minNumPeople), value = false
In this example, we’re determining whether a given airline passenger is eligible to have their coach seat upgraded to a first-class seat. In order to be eligible, a passenger must:
- Be in economy class now and either
- Hold a Gold member card or
- Hold a Silver member card and
- Their carry-on luggage must be less than or equal to 15.0 pounds.
In order to determine this, we must compare a passenger’s facts with our rule.
const { Rule, RuleContext, RuleElement } = require('archetypes-rules')
// Create the rule
const rule = Rule('eligible-for-upgrade')
// Populate the rule using method chaining
rule
.addProposition('passenger-is-economy', true)
.addProposition('passenger-is-gold-card-holder', true)
.addProposition('passenger-is-silver-card-holder', true)
.addOperator('OR')
.addOperator('AND')
.addVariable('passenger-carry-on-baggage-weight', 'NULL_NUMBER_VARIABLE')
.addVariable('passenger-carry-on-baggage-allowance', 15.0)
.addOperator('LESS_THAN_OR_EQUAL_TO')
.addOperator('AND')
// Create the RuleContext
const fact = RuleContext('eligibleForUpgradeFact')
// Load it with the facts about the passenger
fact
.addProposition('passengerIsEconomy', true)
.addProposition('passengerIsGoldCardHolder', true)
.addProposition('passengerIsSilverCardHolder', false)
.addVariable('passenger-carry-on-baggage-weight', 10.0)
.addVariable('passenger-carry-on-baggage-allowance', 'NULL_NUMBER_VARIABLE')
// Log the resulting Proposition
// =>
// Proposition statement = (
// (passengerIsEconomy AND
// (passengerIsGoldCardHolder OR passengerIsSilverCardHolder)
// ) AND (
// passenger-carry-on-baggage-weight <= passenger-carry-on-baggage-allowance
// )
// ), value = true
The Maintainer Guide describes how we develop and release archetype-rules (and has useful information for Maintainers and Trusted Committers).
We gratefully accept Pull Requests. Here's what you need to know to get started.
Before submitting a Pull Request, please read our:
- Code of Conduct
- Contributing Aggreement
- Developer Guide
- Maintainer/Trusted Committer Guide
- Architecture Decision Records
MIT © 2019 Greg Swindle