node package manager
Painless code sharing. npm Orgs help your team discover, share, and reuse code. Create a free org »

sift-rule

sift-rule

Define rules using MongoDB/sift queries

Build Status

Terminology

  • Rules have a head and a tail.
  • Rules are applied to values. If the value matches the head, the tail is implied.
  • Rules can have an optional name.
  • Rulesets are list of rules.
  • Rules are applied to values. Depending on the logic (which method is used, see RuleSet API below):
    • Return all matching rules
    • Return all an array of the tail of all matching rules
    • Return whether ever rule in the set matched
    • Return whether some rules in the set matched

Example

const {RuleSet} = require('sift-rule')
colorRules = new RuleSet()
colorRules.add({filename: {$regex: '\.js$'}}, 'red')
colorRules.add({filename: {$regex: '^foo'}}, 'green')
 
colorRules.filterApply({filename: 'foo.js'})
// => ['red', 'green'] 
colorRules.filterApply({filename: 'foo.css'})
// => ['green'] 

String notation

  • head and tail are separated by -->
  • Rule and rule name are separated by #--
  • head and tail are parsed as HJSON, JSON with some extensions:
    • Object keys can be unquoted
    • Escaped backslashes are doubled, to make it easier to write regexes
    • Unquoted values of the form YYYY-MM-DD are parsed as Date
    • Unquoted values of the form 0x... are parsed as hexadecimal numbers

{topic: "Universe"} --> 42 #== answer to everything parses as

{
  head: { topic: "Universe" },
  tail: 42,
  name: 'answer to everything',
}

Extensions

References

You can add clauses to a rule head that reference data in the object to sift using an object with a single $ref key and a JSON Pointer as the value.

For example, to define a rule that users may only edit their own posts:

var rule = new Rule({"post.user": {$ref: '/user/id'}}, true)
 
rule.apply({post: {title: 'title', user: 'john'}, user: {id: 'john'}})
// => true 
rule.apply({post: {title: 'title', user: 'john'}, user: {id: 'mike'}}) // true 
// => false 

NOTE: references to non-existing values are set to NaN (not-a-number) because NaN !== NaN so this clause will always fail.

API

Rule

Rule.new()

new Rule(stringRule)
new Rule(head[, tail][, name])

Constructor takes either a rule in String notation or head, tail (optional) and name (optional)

Rule.match()

rule.match(value)

Return true if the head matches val, false otherwise.

Rule.apply()

rule.match(value)

Return the tail if the head matches val, undefined otherwise.

RuleSet

RuleSet.new()

new RuleSet{[rule1, rule2...]}
new RuleSet({name: 'ruleset1', rules: [rule1, rule2...]})

Create a new Ruleset.

RuleSet.size

Return the number of rules in the RuleSet.

RuleSet.add()

ruleset.add(rule)
ruleset.add(ruleString)
ruleset.add(head, tail, name)

Adds a single rule to the RuleSet. If rule is not an instance of a Rule, passes arguments to the Rule.new.

Returns the rule.

RuleSet.addAll()

ruleset.addAll(otherRuleset)
ruleset.addAll(arrayOfRules)

RuleSet.delete()

RuleSet.deleteAll()

RuleSet.clear()

Delete all rules in this RuleSet.

RuleSet.every()

ruleset.every(value)

Return true if the head of every rule matches value, false otherwise.

RuleSet.some()

ruleset.some(value)

Return true if the head of any rule matches value, false if none match.

RuleSet.filter()

ruleset.filter(value)

Return the rules whose head matches value.

RuleSet.filterApply()

ruleset.filter(value)

Return the tail of any rule whose head matches value.

RuleSet.first()

ruleset.first(value)

Return the first rule whose head matches value.

RuleSet.firstApply()

ruleset.firstApply(value)

Return the tail of the first rule whose head matches value.

RuleSet.toString()