Skip to content

Commit fab4b2b

Browse files
authored
Documentation for new JSON as Fact feature (#151)
* Added documentation on JSON as Fact feature
1 parent 7497e4b commit fab4b2b

File tree

3 files changed

+318
-1
lines changed

3 files changed

+318
-1
lines changed

CHANGELOG.md

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,4 +103,46 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
103103

104104
#### Removed
105105

106-
- Grule Event Bus is removed from Grule as it seems too complicated and no one use them. They just expect grule to just works.
106+
- Grule Event Bus is removed from Grule as it seems too complicated and no one use them. They just expect grule to just works.
107+
108+
### [1.7.0] - 2020-11-06
109+
110+
#### Changes
111+
112+
- Change the Grule ANTLR4 grammar for better structure, tested with ANTLR4 hierarchy and AST Tree.
113+
- FunctionCall AST graph is now under ExpressionAtom instead of Variable
114+
115+
#### Fix
116+
117+
- Proper Integer and Float literals both support exponent format
118+
119+
#### Added
120+
121+
- Integer literal support Octal and Hexadecimal, Float literal support Hexadecimal.
122+
- Added more documentation about the new numbering literals and also re-arrange the menu in the documentation.
123+
- Support negation.
124+
125+
### [1.7.1] - 2020-12-02
126+
127+
##### Fix
128+
129+
- Fixed ANTLR4 grammar to enable function chaining in the THEN scope
130+
- Fixed ANTLR4 grammar error that makes array/slice/map cannot be chained with function
131+
132+
#### Change
133+
134+
- Built-in function `Changed` is renamed to `Forget` to clearly tell the engine to forget about variable values or function invocation to make sure the engine look again into the underlying data context on the next cycle.
135+
136+
### [1.7.2] - 2020-12-09
137+
138+
##### Fix
139+
140+
- Fixes the cloning problem where Expression do not clone the negation attribute
141+
- Added mutex for unique.NewID() to make sure that this function is thread/concurrent safe.
142+
143+
### [1.8.0] - 2020-12-19
144+
145+
#### Added
146+
147+
- Support for JSON as Fact
148+
- Support native type variable to be added straight into `DataContext` not only `struct`

docs/JSON_Fact_en.md

Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
# JSON Fact
2+
3+
[Tutorial](Tutorial_en.md) | [Rule Engine](RuleEngine_en.md) | [GRL](GRL_en.md) | [GRL JSON](GRL_JSON_en.md) | [RETE Algorithm](RETE_en.md) | [Functions](Function_en.md) | [FAQ](FAQ_en.md) | [Benchmark](Benchmarking_en.md)
4+
5+
---
6+
7+
Using JSON straight away as fact in Grule is available starting on version 1.8.0. It enable user to treat JSON string as fact
8+
and add it into `DataContext` just like how you previously add fact data into it. The loaded JSON fact are now "visible" the
9+
the Grule scripts (the GRLs).
10+
11+
## Adding JSON as fact
12+
13+
Assuming you have a JSON as follow:
14+
15+
```json
16+
{
17+
"name" : "John Doe",
18+
"age" : 24,
19+
"gender" : "M",
20+
"height" : 74.8,
21+
"married" : false,
22+
"address" : {
23+
"street" : "9886 2nd St.",
24+
"city" : "Carpentersville",
25+
"state" : "Illinois",
26+
"postal" : 60110
27+
},
28+
"friends" : [ "Roth", "Jane", "Jake" ]
29+
}
30+
```
31+
32+
You put your JSON into a byte array.
33+
34+
```go
35+
myJSON := []byte (...your JSON here...)
36+
```
37+
38+
You simply add you JSON variable into `DataContext`
39+
40+
```go
41+
// create new instance of DataContext
42+
dataContext := ast.NewDataContext()
43+
44+
// add your JSON Fact into data cotnxt using AddJSON() function.
45+
err := dataContext.AddJSON("MyJSON", myJSON)
46+
```
47+
48+
Yes, you can add as many _facts_ as you wish into the context and you can mix between JSON facts
49+
(using `AddJSON`) and normal Go fact (using `Add`)
50+
51+
## Evaluating (Reading) JSON Fact Values in GRL
52+
53+
Inside GRL script, the fact is always visible through their label as you provide them
54+
when adding to the `DataContext`. For example, the code bellow add your JSON and it will be
55+
using label `MyJSON`.
56+
57+
```go
58+
err := dataContext.AddJSON("MyJSON", myJSON)
59+
```
60+
61+
Yes, you can use any label as long as its a single word.
62+
63+
### Traversing member variable like a normal object
64+
65+
Now. Using the JSON shown at the beginning, your GRL `when` scope can evaluate your json
66+
like the following.
67+
68+
```text
69+
when
70+
MyJSON.name == "John Doe"
71+
```
72+
73+
or
74+
75+
```text
76+
when
77+
MyJSON.address.city.StrContains("ville")
78+
```
79+
80+
or
81+
82+
```text
83+
when
84+
MyJSON.age > 30 && MyJSON.height < 60
85+
```
86+
87+
### Traversing member variable like a map
88+
89+
You can access JSON object's fields using `Map` like selector or like normal object.
90+
91+
```text
92+
when
93+
MyJSON["name"] == "John Doe"
94+
```
95+
96+
or
97+
98+
```text
99+
when
100+
MyJSON["address"].city.StrContains("ville")
101+
```
102+
103+
or
104+
105+
```text
106+
when
107+
MyJSON.age > 30 && MyJSON["HEIGHT".ToLower()] < 60
108+
```
109+
110+
### Traversing array member variable
111+
112+
You can inspect JSON Array element just like a normal array
113+
114+
```text
115+
when
116+
MyJSON.friends[3] == "Jake"
117+
```
118+
119+
## Writing values into JSON Facts in GRL
120+
121+
Yes, you can write new values into you JSON facts in the `then` scope of your rules. Changing those values will
122+
certainly evaluated on the following rule evaluation cycles. BUT, there are some caveat (read "Things you should know" bellow.)
123+
124+
### Writing member variable like a normal object
125+
126+
Now. Using the JSON shown at the beginning, your GRL `then` scope can modify your json
127+
**fact** like the following.
128+
129+
```text
130+
then
131+
MyJSON.name = "Robert Woo";
132+
```
133+
134+
or
135+
136+
```text
137+
then
138+
MyJSON.address.city = "Corruscant";
139+
```
140+
141+
or
142+
143+
```text
144+
then
145+
MyJSON.age = 30;
146+
```
147+
148+
That's pretty straight forward. But there are some twist to this.
149+
150+
1. You can modify not only the value of member variable of your JSON object, you can also change the `type`.
151+
Assuming your rule can handle the next evaluation chain for the new type you can do this, otherwise we very strongly not recommended this.
152+
153+
Example:
154+
155+
You modify the `MyJSON.age` into string.
156+
157+
```text
158+
then
159+
MyJSON.age = "Thirty";
160+
```
161+
162+
This make the engine to panic when evaluating rule like.
163+
164+
```text
165+
when
166+
myJSON.age > 25
167+
```
168+
169+
2. You can assign a value to non-existent member variable
170+
171+
Example:
172+
173+
```text
174+
then
175+
MyJSON.category = "FAT";
176+
```
177+
178+
Where the `category` member is not existed in the original JSON.
179+
180+
### Writing member variable like a normal map
181+
182+
Now. Using the JSON shown at the beginning, your GRL `then` scope can modify your json
183+
**fact** like the following.
184+
185+
```text
186+
then
187+
MyJSON["name"] = "Robert Woo";
188+
```
189+
190+
or
191+
192+
```text
193+
then
194+
MyJSON["address"]["city"] = "Corruscant";
195+
```
196+
197+
or
198+
199+
```text
200+
then
201+
MyJSON["age"] = 30;
202+
```
203+
204+
Like the object style, there are same exact twist to this.
205+
206+
1. You can modify not only the value of member variable of your JSON map, you can also change the `type`.
207+
Assuming your rule can handle the next evaluation chain for the new type you can do this, otherwise we very strongly not recommended this.
208+
209+
Example:
210+
211+
You modify the `MyJSON.age` into string.
212+
213+
```text
214+
then
215+
MyJSON["age"] = "Thirty";
216+
```
217+
218+
This make the engine to panic when evaluating rule like.
219+
220+
```text
221+
when
222+
myJSON.age > 25
223+
```
224+
225+
2. You can assign a value to non-existent member variable
226+
227+
Example:
228+
229+
```text
230+
then
231+
MyJSON["category"] = "FAT";
232+
```
233+
234+
Where the `category` member is not existed in the original JSON.
235+
236+
### Writing member array
237+
238+
In array you can simple replace array element by it's indices.
239+
240+
```text
241+
then
242+
MyJSON.friends[3] == "Jake";
243+
```
244+
245+
As long as that indice is a valid one. Grule will panic if the indices is out of bound.
246+
Just like normal JSON, you can replace the value of any element with different type.
247+
You can always inspect the array length. Like ...
248+
249+
```text
250+
when
251+
MyJSON.friends.Length() > 4;
252+
```
253+
254+
Yes, you can always append into Array using `Append` function. Append list of argument value of different types.
255+
256+
```text
257+
then
258+
MyJSON.friends.Append("Rubby", "Anderson", "Smith", 12.3);
259+
```
260+
261+
**Known Issue**
262+
263+
As of now, there are no built-in function to help user to inspect array element easily, such as `Contains(value) bool`
264+
265+
## Things you should know
266+
267+
1. After you add JSON fact into `DataContext`, the change to this string variable will not reflect the facts already in the `DataContext`. This is also
268+
applied in vice-versa, where changes in the fact within `DataContext` will not change the JSON string.
269+
2. You can modify your JSON fact in the `then` scope, but unlike normal `Go` facts, these changes will not reflect to your original JSON string. If you want this to happen,
270+
you should parse your JSON into a `struct` before hand, and add your `struct` into `DataContext` normally.

docs/Tutorial_en.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ if err != nil {
8888
}
8989
```
9090

91+
### Add JSON as Fact
92+
93+
JSON string as a fact in Grule is a feature introduced at version 1.8.0.
94+
You can read [JSON as a Fact](JSON_Fact_en.md) to know how to add JSON into `DataContext`.
95+
9196
## Creating KnowledgeLibrary and Add Rules Into It
9297

9398
A `KnowledgeLibrary` is basically collection of `KnowledgeBase` blue prints.

0 commit comments

Comments
 (0)