Skip to content

Commit 7685be4

Browse files
committed
Fixing not operation
1 parent 0ca291a commit 7685be4

9 files changed

+592
-144
lines changed

README.md

+170-40
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ let rules = [{
3737
event: {
3838
type: "remove",
3939
params: {
40-
fields: [ "password" ]
40+
field: "password"
4141
},
4242
}
4343
}];
@@ -60,11 +60,42 @@ engine
6060

6161
```
6262

63-
## Schema and rules validation on construction
63+
Rules engine expects to know all the rules in advance, it effectively drops builder pattern, but keeps the interface.
64+
65+
## Validation
6466

6567
In order to prevent most common errors, `Engine` does initial validation on the schema, during construction.
66-
If no `schema` is provided to the constructor
68+
Validation is done automatically if you specify `schema` during construction.
69+
70+
```js
71+
let rules = [{
72+
conditions: {
73+
firstName: "empty"
74+
},
75+
event: {
76+
type: "remove",
77+
params: { field: "password" },
78+
}
79+
}];
80+
81+
let schema = {
82+
properties: {
83+
firstName: { type: "string" },
84+
lastName: { type: "string" }
85+
}
86+
}
87+
88+
let engine = new Engine(rules, schema);
89+
```
90+
### Types of errors
91+
92+
- Conditions field validation (conditions use fields that are not part of the schema)
93+
- Predicate validation (used predicates are not part of the
94+
[predicates](https://github.com/landau/predicate) library and most likely wrong)
95+
96+
Validation is done only during development, validation is disabled by default in `production`.
6797

98+
WARNING!!! Currently validation does not support nested structures, so be extra careful, when using those.
6899

69100
## Conditional logic
70101

@@ -73,44 +104,119 @@ with boolean logic extension.
73104

74105
[Predicate](https://github.com/landau/predicate) library has a lot of predicates that we found more, than sufficient for our use cases.
75106

107+
To showcase conditional logic, we'll be using simple `registration` schema
108+
109+
```js
110+
let schema = {
111+
definitions: {
112+
hobby: {
113+
type: "object",
114+
properties: {
115+
name: { type: "string" },
116+
durationInMonth: { type: "integer" },
117+
}
118+
}
119+
},
120+
title: "A registration form",
121+
description: "A simple form example.",
122+
type: "object",
123+
required: [
124+
"firstName",
125+
"lastName"
126+
],
127+
properties: {
128+
firstName: {
129+
type: "string",
130+
title: "First name"
131+
},
132+
lastName: {
133+
type: "string",
134+
title: "Last name"
135+
},
136+
age: {
137+
type: "integer",
138+
title: "Age",
139+
},
140+
bio: {
141+
type: "string",
142+
title: "Bio",
143+
},
144+
country: {
145+
type: "string",
146+
title: "Country"
147+
},
148+
state: {
149+
type: "string",
150+
title: "State"
151+
},
152+
zip: {
153+
type: "string",
154+
title: "ZIP"
155+
},
156+
password: {
157+
type: "string",
158+
title: "Password",
159+
minLength: 3
160+
},
161+
telephone: {
162+
type: "string",
163+
title: "Telephone",
164+
minLength: 10
165+
},
166+
work: { "$ref": "#/definitions/hobby" },
167+
hobbies: {
168+
type: "array",
169+
items: { "$ref": "#/definitions/hobby" }
170+
}
171+
}
172+
}
173+
```
174+
Assuming action part is taken from [react-jsonschema-form-conditionals](https://github.com/RxNT/react-jsonschema-form-conditionals)
175+
76176
### Single line conditionals
77177

78-
Let's say we need to `remove` `password`, when `firstName` is missing, this can be expressed like this:
178+
Let's say we want to `remove` `password` , when `firstName` is missing, we can expressed it like this:
79179

80180
```js
81181
let rules = [{
82182
conditions: {
83183
firstName: "empty"
84184
},
85185
event: {
86-
type: "remove",
87-
params: { fields: [ "password" ] },
186+
type: "remove",
187+
params: {
188+
field: "password"
189+
}
88190
}
89191
}]
90192
```
91193

92194
This translates into -
93-
when `firstName` is `empty`, perform `remove` of `password`, pretty straightforward.
195+
when `firstName` is `empty`, trigger `remove` `event`.
94196

95197
`Empty` keyword is [equal in predicate library](https://landau.github.io/predicate/#equal) and required
96-
action will be performed only when `predicate.empty(registration.firstName)` is `true`.
198+
event will be performed only when `predicate.empty(registration.firstName)` is `true`.
97199

98200
### Conditionals with arguments
99201

100-
Let's say we need to `remove` `telephone`, when `age` is `less` than `5`
202+
Let's say we need to `require` `zip`, when `age` is `less` than `16`,
203+
because the service we are using is legal only after `16` in some countries
101204

102205
```js
103206
let rules = [{
104-
conditions: { age: { less : 5 } },
207+
conditions: {
208+
age: { less : 16 }
209+
},
105210
event: {
106-
type: "remove",
107-
params: { fields: [ "telephone" ] }
211+
type: "require",
212+
params: {
213+
field: "zip"
214+
}
108215
}
109216
}]
110217
```
111218

112-
This translates into -
113-
when `age` is `less` than 5, `remove` `telephone` field from the schema.
219+
This translates into - when `age` is `less` than `16`, `require` zip.
114220

115221
[Less](https://landau.github.io/predicate/#less) keyword is [less in predicate](https://landau.github.io/predicate/#less) and required
116222
event will be returned only when `predicate.empty(registration.age, 5)` is `true`.
@@ -121,73 +227,80 @@ event will be returned only when `predicate.empty(registration.age, 5)` is `true
121227

122228
For the field AND is a default behavior.
123229

124-
Looking at previous rule, we decide that we want to change the rule and `remove` a `telephone`,
125-
when `age` is between `5` and `70`, so it would be available only to people older, than `70` and younger than `5`.
230+
Looking at previous rule, we decide that we want to change the rule and `require` `zip`,
231+
when `age` is between `16` and `70`, so it would be available
232+
only to people older, than `16` and younger than `70`.
126233

127234
```js
128235
let rules = [{
129236
conditions: {
130237
age: {
131-
greater: 5,
238+
greater: 16,
132239
less : 70,
133240
}
134241
},
135242
event: {
136-
type: "remove",
137-
params: { fields: [ "telephone" ] }
243+
type: "require",
244+
params: {
245+
field: "zip"
246+
}
138247
}
139248
}]
140249
```
141250

142251
By default action will be applied only when both field conditions are true.
143-
In this case, when age is `greater` than 5 and `less` than 70.
252+
In this case, when age is `greater` than `16` and `less` than `70`.
144253

145254
#### NOT
146255

147-
Let's say we want to change the logic to opposite, and remove telephone when
148-
age is greater, `less`er then `5` or `greater` than `70`,
256+
Let's say we want to change the logic to opposite, and trigger event only when
257+
`age` is `less`er then `16` or `greater` than `70`,
149258

150259
```js
151260
let rules = [{
152261
conditions: {
153262
age: {
154263
not: {
155-
greater: 5,
264+
greater: 16,
156265
less : 70,
157266
}
158267
}
159268
},
160269
event: {
161-
type: "remove",
162-
params: { fields: "telephone"}
270+
type: "require",
271+
params: {
272+
field: "zip"
273+
}
163274
}
164275
}]
165276
```
166277

167-
This does it, since the final result will be opposite of the previous result.
278+
This does it, since the final result will be opposite of the previous condition.
168279

169280
#### OR
170281

171-
The previous example works, but it's a bit hard to understand, luckily we can express it in more natural way
282+
The previous example works, but it's a bit hard to understand, luckily we can express it differently
172283
with `or` conditional.
173284

174285
```js
175286
let rules = [{
176287
conditions: { age: {
177288
or: [
178-
{ less : 5 },
179-
{ greater: 70 }
289+
{ lessEq : 5 },
290+
{ greaterEq: 70 }
180291
]
181292
}
182293
},
183294
event: {
184-
type: "remove",
185-
params: { fields: "telephone" }
295+
type: "require",
296+
params: {
297+
field: "zip"
298+
}
186299
}
187300
}]
188301
```
189302

190-
This is the same as `NOT`, but easier to grasp.
303+
The result is the same as `NOT`, but easier to grasp.
191304

192305
### Boolean operations on multi fields
193306

@@ -196,7 +309,7 @@ multi fields boolean operations.
196309

197310
#### Default AND operation
198311

199-
Let's say we want to `require` `bio`, when `age` is less than 70 and `country` is `USA`
312+
Let's say, when `age` is less than 70 and `country` is `USA` we want to `require` `bio`.
200313

201314
```js
202315
let rules = [{
@@ -266,9 +379,30 @@ let rules = [{
266379

267380
### Nested object queries
268381

382+
Rules engine supports querying inside nested objects, with [selectn](https://github.com/wilmoore/selectn.js),
383+
any data query that works in [selectn](https://github.com/wilmoore/selectn.js), will work in here
384+
385+
Let's say we need to require `state`, when `work` has a `name` `congressman`, this is how we can do this:
386+
387+
```js
388+
let rules = [{
389+
conditions: {
390+
"work.name": {
391+
name: { equals: "congressman" },
392+
}
393+
},
394+
event: {
395+
type: "require",
396+
params: { fields: [ "state" ]}
397+
}
398+
}]
399+
```
400+
401+
### Nested arrays object queries
402+
269403
Sometimes we need to make changes to the form if some nested condition is true.
270404

271-
For example if one of the `hobbies` is "baseball", make `state` `required`.
405+
For example if one of the `hobbies` is `baseball`, we need to make `state` `required`.
272406
This can be expressed like this:
273407

274408
```js
@@ -285,10 +419,7 @@ let rules = [{
285419
}]
286420
```
287421

288-
## Contribute
289-
290-
- Issue Tracker: github.com/RxNT/json-rules-engine-simplified/issues
291-
- Source Code: github.com/RxNT/json-rules-engine-simplified
422+
Rules engine will go through all the elements in the array and trigger `require` if `any` of the elements meet the criteria
292423

293424
## Support
294425

@@ -297,5 +428,4 @@ We have a mailing list located at: ...
297428

298429
## License
299430

300-
The project is licensed under the ... license.
301-
431+
The project is licensed under the Apache Licence 2.0.

src/Engine.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ class Engine {
1010
if (schema !== undefined && schema !== null) {
1111
if (isObject(schema)) {
1212
validatePredicates(conditions, schema);
13-
validateConditionFields(conditions, schema)
13+
validateConditionFields(conditions, schema);
1414
} else {
15-
toError(`Expected valid schema object, but got - ${schema}`)
15+
toError(`Expected valid schema object, but got - ${schema}`);
1616
}
1717
}
1818
}
1919
}
20-
run = (formData) => Promise.resolve(applicableActions(this.rules, formData));
20+
run = formData => Promise.resolve(applicableActions(this.rules, formData));
2121
}
2222

2323
export default Engine;

0 commit comments

Comments
 (0)