Skip to content

Commit 0a1ea64

Browse files
committedSep 8, 2018
distinct support for Ruby and Node.js
1 parent c0f58c9 commit 0a1ea64

File tree

10 files changed

+119
-31
lines changed

10 files changed

+119
-31
lines changed
 

‎durable_rules.gemspec

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Gem::Specification.new do |s|
22
s.name = 'durable_rules'
3-
s.version = '0.34.51'
3+
s.version = '0.34.52'
44
s.summary = "for real time analytics (a Ruby Rules Engine)"
55
s.description = "A lightweight library for real-time, consistent and scalable coordination of events."
66
s.authors = ["Jesus Ruiz"]

‎libjs/durable.js

+25-4
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,8 @@ exports = module.exports = durableEngine = function () {
512512
});
513513
} else if ((statement.label.name === 'pri') ||
514514
(statement.label.name === 'count') ||
515-
(statement.label.name === 'cap')) {
515+
(statement.label.name === 'cap') ||
516+
(statement.label.name === 'distinct')) {
516517
currentRule.properties.push({
517518
type: 'Property',
518519
key: { type: 'Identifier', name: statement.label.name },
@@ -601,7 +602,8 @@ exports = module.exports = durableEngine = function () {
601602
});
602603
} else if ((statement.label.name === 'pri') ||
603604
(statement.label.name === 'count') ||
604-
(statement.label.name === 'cap')) {
605+
(statement.label.name === 'cap') ||
606+
(statement.label.name === 'distinct')) {
605607
currentTrigger.properties.push({
606608
type: 'Property',
607609
key: { type: 'Identifier', name: statement.label.name },
@@ -717,14 +719,15 @@ exports = module.exports = durableEngine = function () {
717719
});
718720
} else if ((statement.label.name === 'pri') ||
719721
(statement.label.name === 'count') ||
720-
(statement.label.name === 'cap')) {
722+
(statement.label.name === 'cap') ||
723+
(statement.label.name === 'distinct')) {
721724
currentCondition.properties.push({
722725
type: 'Property',
723726
key: { type: 'Identifier', name: statement.label.name },
724727
value: statement.body.expression
725728
});
726729
} else {
727-
throw 'syntax error: whenAll, pri, count or cap labels expected';
730+
throw 'syntax error: whenAll, pri, count, distinct, or cap labels expected';
728731
}
729732
}
730733
});
@@ -1240,6 +1243,12 @@ exports = module.exports = durableEngine = function () {
12401243
if (argRule.run) {
12411244
newDefinition['run'] = argRule.run;
12421245
}
1246+
if (argRule.distinct === true) {
1247+
newDefinition['dist'] = 1;
1248+
}
1249+
if (argRule.distinct === false) {
1250+
newDefinition['dist'] = 0;
1251+
}
12431252
}
12441253
var expDefinition;
12451254
var func;
@@ -1267,6 +1276,10 @@ exports = module.exports = durableEngine = function () {
12671276
newDefinition['pri'] = expDefinition['pri'];
12681277
} else if (expDefinition['cap']) {
12691278
newDefinition['cap'] = expDefinition['cap'];
1279+
} else if (expDefinition['dist'] === true) {
1280+
newDefinition['dist'] = 1;
1281+
} else if (expDefinition['dist'] === false) {
1282+
newDefinition['dist'] = 0;
12701283
} else {
12711284
newArray.push(lexp[i]);
12721285
}
@@ -1456,6 +1469,14 @@ exports = module.exports = durableEngine = function () {
14561469
}
14571470
return that;
14581471
};
1472+
1473+
obj.distinct = function(dist) {
1474+
var that = {};
1475+
that.define = function () {
1476+
return {dist: dist};
1477+
}
1478+
return that;
1479+
};
14591480
};
14601481

14611482
var ruleset = function () {

‎libpy/durable/lang.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ def __init__(self, operator, multi, *args):
243243
self.count = None
244244
self.pri = None
245245
self.cap = None
246-
self.dist = True
246+
self.dist = None
247247
self.func = []
248248
new_args = []
249249
for arg in args:
@@ -330,9 +330,10 @@ def define(self, parent_name = None):
330330
if self.cap:
331331
defined_expression['cap'] = self.cap
332332

333-
if self.dist:
333+
if self.dist == True:
334334
defined_expression['dist'] = 1
335-
else:
335+
336+
if self.dist == False:
336337
defined_expression['dist'] = 0
337338

338339
return defined_expression

‎librb/durable.rb

+12
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,10 @@ def cap(value)
449449
{:cap => value}
450450
end
451451

452+
def distinct(value)
453+
{:dist => value}
454+
end
455+
452456
def timeout(name)
453457
expression = Expression.new(:$m, :$t)
454458
expression == name
@@ -507,6 +511,14 @@ def define_rule(operator, expression_definition, options, &block)
507511
rule["cap"] = options[:cap]
508512
end
509513

514+
if options.key? :dist
515+
if (options[:dist])
516+
rule["dist"] = 1
517+
else
518+
rule["dist"] = 0
519+
end
520+
end
521+
510522
@rules[rule_name] = rule
511523
rule
512524
end

‎package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "durable",
3-
"version": "0.36.86",
3+
"version": "0.36.87",
44
"description": "A lightweight rules engine for real-time, consistent and scalable coordination of events.",
55
"keywords": ["business rules", "rules engine", "rete", "forward chaining", "streaming analytics", "complex event processing", "state machine", "workflow"],
66
"dependencies": { "express": "3.4.x" , "node-static": "0.7.x", "body-parser": "1.12.x", "bindings": "*", "nan": "~1.1.0", "esprima": "3.1.x", "escodegen": "1.8.x"},

‎setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def build(self):
4747

4848
setup (
4949
name = 'durable_rules',
50-
version = '0.33.127',
50+
version = '0.33.128',
5151
description = 'for real time analytics (a Python Rules Engine)',
5252
long_description=long_description,
5353
url='https://github.com/jruizgit/rules',

‎src/rules/rete.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1863,7 +1863,7 @@ static unsigned int createTree(ruleset *tree, char *rules) {
18631863
ruleAction->value.c.count = 1;
18641864
}
18651865

1866-
unsigned short distinct = 0;
1866+
unsigned short distinct = 1;
18671867
getSetting(HASH_DIST, first, &distinct);
18681868
result = readNextName(first, &first, &last, &hash);
18691869
while (result == PARSE_OK) {

‎testjs/testsamples.js

+27-7
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,42 @@ d.ruleset('risk0', function() {
2222
}
2323
});
2424

25-
d.ruleset('risk1', function() {
25+
d.ruleset('indistinct', function() {
2626
whenAll: {
27-
first = m.amount > 100
27+
first = m.amount > 10
2828
second = m.amount > first.amount * 2
29-
third = m.amount > first.amount + second.amount
29+
third = m.amount > (first.amount + second.amount) / 2
3030
}
31+
distinct: false
3132
run: {
32-
console.log('fraud detected -> ' + first.amount);
33+
console.log('indistinct detected -> ' + first.amount);
34+
console.log(' -> ' + second.amount);
35+
console.log(' -> ' + third.amount);
36+
}
37+
38+
whenStart: {
39+
host.post('indistinct', {amount: 50});
40+
host.post('indistinct', {amount: 200});
41+
host.post('indistinct', {amount: 251});
42+
}
43+
});
44+
45+
d.ruleset('distinct', function() {
46+
whenAll: {
47+
first = m.amount > 10
48+
second = m.amount > first.amount * 2
49+
third = m.amount > (first.amount + second.amount) / 2
50+
}
51+
run: {
52+
console.log('distinct detected -> ' + first.amount);
3353
console.log(' -> ' + second.amount);
3454
console.log(' -> ' + third.amount);
3555
}
3656

3757
whenStart: {
38-
host.post('risk1', {amount: 200});
39-
host.post('risk1', {amount: 500});
40-
host.post('risk1', {amount: 1000});
58+
host.post('distinct', {amount: 50});
59+
host.post('distinct', {amount: 200});
60+
host.post('distinct', {amount: 251});
4161
}
4262
});
4363

‎testpy/testsamples.py

+23-6
Original file line numberDiff line numberDiff line change
@@ -196,22 +196,39 @@ def start(host):
196196
host.assert_fact('strings', { 'subject': 'hello hi' })
197197
host.assert_fact('strings', { 'subject': 'has Hello string' })
198198
host.assert_fact('strings', { 'subject': 'does not match' })
199+
200+
201+
with ruleset('indistinct'):
202+
@when_all(distinct(False),
203+
c.first << m.amount > 10,
204+
c.second << m.amount > c.first.amount * 2,
205+
c.third << m.amount > (c.first.amount + c.second.amount) / 2)
206+
def detected(c):
207+
print('indistinct detected -> {0}'.format(c.first.amount))
208+
print(' -> {0}'.format(c.second.amount))
209+
print(' -> {0}'.format(c.third.amount))
210+
211+
@when_start
212+
def start(host):
213+
host.post('indistinct', { 'amount': 50 })
214+
host.post('indistinct', { 'amount': 200 })
215+
host.post('indistinct', { 'amount': 251 })
199216

200217

201-
with ruleset('risk0'):
218+
with ruleset('distinct'):
202219
@when_all(c.first << m.amount > 10,
203220
c.second << m.amount > c.first.amount * 2,
204-
c.third << m.amount > c.first.amount + c.second.amount)
221+
c.third << m.amount > (c.first.amount + c.second.amount) / 2)
205222
def detected(c):
206-
print('fraud detected -> {0}'.format(c.first.amount))
223+
print('distinct detected -> {0}'.format(c.first.amount))
207224
print(' -> {0}'.format(c.second.amount))
208225
print(' -> {0}'.format(c.third.amount))
209226

210227
@when_start
211228
def start(host):
212-
host.post('risk0', { 'amount': 50 })
213-
host.post('risk0', { 'amount': 200 })
214-
host.post('risk0', { 'amount': 300 })
229+
host.post('distinct', { 'amount': 50 })
230+
host.post('distinct', { 'amount': 200 })
231+
host.post('distinct', { 'amount': 251 })
215232

216233

217234
with ruleset('expense1'):

‎testrb/testsamples.rb

+24-7
Original file line numberDiff line numberDiff line change
@@ -196,19 +196,36 @@
196196
end
197197
end
198198

199-
Durable.ruleset :risk2 do
200-
when_all c.first = m.t == "purchase",
199+
Durable.ruleset :indistinct do
200+
when_all distinct(false),
201+
c.first = m.amount > 10,
202+
c.second = m.amount > first.amount * 2,
203+
c.third = m.amount > (first.amount + second.amount) / 2 do
204+
puts "indistinct detected -> #{first.amount}"
205+
puts " -> #{second.amount}"
206+
puts " -> #{third.amount}"
207+
end
208+
209+
when_start do
210+
post :indistinct, { :t => "purchase", :amount => 50 }
211+
post :indistinct, { :t => "purchase", :amount => 200 }
212+
post :indistinct, { :t => "purchase", :amount => 251 }
213+
end
214+
end
215+
216+
Durable.ruleset :distinct do
217+
when_all c.first = m.amount > 10,
201218
c.second = m.amount > first.amount * 2,
202-
c.third = m.amount > first.amount + second.amount do
203-
puts "fraud detected -> #{first.amount}"
219+
c.third = m.amount > (first.amount + second.amount) / 2 do
220+
puts "distinct detected -> #{first.amount}"
204221
puts " -> #{second.amount}"
205222
puts " -> #{third.amount}"
206223
end
207224

208225
when_start do
209-
post :risk2, { :t => "purchase", :amount => 50 }
210-
post :risk2, { :t => "purchase", :amount => 200 }
211-
post :risk2, { :t => "purchase", :amount => 300 }
226+
post :distinct, { :t => "purchase", :amount => 50 }
227+
post :distinct, { :t => "purchase", :amount => 200 }
228+
post :distinct, { :t => "purchase", :amount => 251 }
212229
end
213230
end
214231

0 commit comments

Comments
 (0)
Please sign in to comment.