|
| 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. |
0 commit comments