Last active
March 30, 2022 09:58
-
-
Save DmitryevichD/9f0d26d84f1a1da809e1c35f04e2bc8c to your computer and use it in GitHub Desktop.
Revisions
-
DmitryevichD revised this gist
Mar 30, 2022 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,4 @@ # Abstract expression language v2.0.1 ## Innovations: -
DmitryevichD revised this gist
Mar 29, 2022 . 1 changed file with 74 additions and 60 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -5,43 +5,43 @@ * Expressions can return result as simple types (**date**, **boolean**, **number**, **version**, **string**) * Expressions can use names functions with predefined logic and signature such as (**some**, **every**, **count**, **min**, **max**, **if** etc) * Expression can use new type (**dictionary**) * Backward compatibility with contract v1.0.0 ## [2.0.1] - 2022-03-29 ### Added - #### type: `dictionary` * **Group:** Complex type * **Description:** Type is used for define variables that store **key-value** variables. * **Available operations:** **`dictionary_1` ** **`(in | nin | eq | neq)`** **`dictionary_2`** * **Attributes:** - type - value type => **`dictionary`** - element_type - type of values in the dictionary => **`(string | number | version | date | boolean)`** - value - contains object with key-values. Required if user_property is not present - user_property - name of user property that contains object with key-values. Required if value is not present * **Restrictions:** - Keys in the dictionary must be present as **`string`**. - Values in the one dictionary must have the same type that defined in the attribute **`element_type`** - Values must be represented as a simple type **`(string | number | version | date | boolean)`** - **Example:** ```json { "type": "dictionary", "element_type": "string", "value": { "map_key1": "mav_value_1", "map_key2": "mav_value_2" } }, { "type": "dictionary", "element_type": "string", "user_property": "name_of_user_param_with_map_type" } @@ -53,9 +53,9 @@ * **Group:** Complex type * **Available operations:** operations depends on simple type **`(string | number | version | date | boolean)`** that return function * **Description:** The rule-engine has some named function with a specific signature. This type is used to define the name of this functions to be used in the expression * **Attributes:** @@ -87,13 +87,13 @@ }, { "type": "string", "argument": "key_user_param" } ] } }, { "type": "dictionary", "user_property": "experiment" } ] @@ -140,7 +140,7 @@ * **Name:** **`count`** * **Signature:** **`count(inner_rule as predicate, dictionary)`** * **Return type:** **`number`** @@ -149,7 +149,7 @@ * **Description:** returns true if some element of the map match the provided predicate * **Name:** **`some`** * **Signature:** **`some(inner_rule as predicate, dictionary)`** * **Return type:** **`boolean`** @@ -158,7 +158,7 @@ * **Description:** returns true if every element of the map match the provided predicate * **Name:** **`every`** * **Signature:** **`every(inner_rule as predicate, dictionary)`** * **Return type:** **`boolean`** @@ -205,9 +205,9 @@ ## Examples ### Checking that the `dictionary` contains 1 or more key values corresponding to the predicate #### RabbitMQ message that contains user param `experiments` with type `dictionary` and element type `string` ```json { @@ -240,7 +240,7 @@ #### Rule expression that counts the number of values in a dictionary using a predicate ```json { @@ -267,7 +267,7 @@ } }, { "type": "dictionary", "user_property": "experiment" } ] @@ -285,37 +285,42 @@ #### Execution steps (as of date 2022-03-22) ##### Step 0 - Receive from database user_param `experiment` ##### Step 1 - Extract valid key-values that will be used in expression This step uses the message attributes such as **`startDate`**, **`endDate`**, **`enabled`** to define available attributes - `experiment_key2` is skipped because it is disabled, - `experement_key1` is skipped because it is deprecated The user_property **`experiment`** that should use in the ```json { "type": "dictionary", "user_property": "experiment" } ``` will have the following value ```json { "experiment_key3": "1", "experiment_key4": "4" } ``` ##### Step 2 - Execute `count` function - predicate attribute `"argument": "experement_key3"` will be changed to `"argument": "1"` because key with name `experiment_key3` has value `"1"` - For each key-value will be execute next steps: - if the predicate doesn't contain the key name in any `agrument` attribute the key-value is skipped - else the predicate is executed and it result is true count is incremented - Returns the count @@ -341,9 +346,9 @@ The map will be contained only two key-values ### Checks that `dictionary` contains some key-values #### RabbitMQ message that contains user param `experiments` with type `dictionary` and element type `string` ```json { @@ -376,7 +381,7 @@ The map will be contained only two key-values #### Rule expression that detects one or more of values in a dictionary using a predicate ```json { @@ -393,7 +398,7 @@ The map will be contained only two key-values "values": [ { "type": "string", "value": "1" }, { "type": "string", @@ -403,7 +408,7 @@ The map will be contained only two key-values } }, { "type": "dictionary", "user_property": "experiment" } ] @@ -417,34 +422,43 @@ The map will be contained only two key-values #### Execution steps (as of date 2022-03-22) ##### Step 0 - Receive from database user_param `experiment` ##### Step 1 - Extract valid key-values that will be used in expression This step uses the message attributes such as **`startDate`**, **`endDate`**, **`enabled`** to define available attributes - `experiment_key2` is skipped because it is disabled, - `experement_key1` is skipped because it is deprecated The user_property **`experiment`** that should use in the ```json { "type": "dictionary", "user_property": "experiment" } ``` will have the following value ```json { "experiment_key3": "1", "experiment_key4": "4" } ``` ##### Step 2 - Execute `some` function - predicate attribute `"argument": "experement_key3"` will be changed to `"argument": "1"` because key with name `experiment_key3` has value `"1"` - For each key-value will be execute next steps: - if the predicate doesn't contain the key name in any `agrument` attribute the key-value is skipped - else the predicate is executed and it result is true the function returns true -
DmitryevichD revised this gist
Mar 28, 2022 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -257,11 +257,11 @@ "values": [ { "type": "string", "value": "1" }, { "type": "string", "argument": "experement_key3" } ] } -
DmitryevichD revised this gist
Mar 27, 2022 . 1 changed file with 357 additions and 106 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,108 +1,213 @@ # Abstract expression language v2.0.0 ## Innovations: * Expressions can return result as simple types (**date**, **boolean**, **number**, **version**, **string**) * Expressions can use names functions with predefined logic and signature such as (**some**, **every**, **count**, **min**, **max**, **if** etc) * Expression can use new type (**map**) * Backward compatibility with contract v1.0.0 ## [2.0.0] - 2022-03-25 ### Added - #### type: `map` * **Group:** Complex type * **Description:** Type is used for define variables that store **key-value of simple types** * **Available operations:** **`map_1` ** **`(in | nin | eq | neq)`** **`map_2`** * **Attributes:** - type - value type => **`map`** - element_type - type of values into the map => **`(string | number | version | date | boolean)`** - value - contains object with key-values. Required if user_property is not present - user_property - name of user property that contains object with key-values. Required if value is not present * **Restrictions:** - Keys in the map must be present as **`string`**. - Values in the one map must have the same type - Values must be represented as a simple type **`(string | number | version | date | boolean)`** - **Example:** ```json { "type": "map", "element_type": "string", "value": { "map_key1": "mav_value_1", "map_key2": "mav_value_2" } }, { "type": "map", "element_type": "string", "user_property": "name_of_user_param_with_map_type" } ``` - #### type: `func` * **Group:** Complex type * **Available operations:** operations depends of simple type **`(string | number | version | date | boolean)`** that return function * **Description:** Type is used to define the name of the function that is implemented in the rule service * **Attributes:** - type - value type => **`func`** - name - function name => **`(some | every | count | min | max | if)`** - values - list of function arguments * **Restrictions:** * function result must be only simple type **`(string | number | version | date | boolean)`** * **Example:** ```json { "type": "func", "name": "count", "values": [ { "type": "inner_rule", "value": { "operation": "eq", "values": [ { "type": "string", "value": "key_value" }, { "type": "string", "user_property": "key_user_param" } ] } }, { "type": "map", "user_property": "experiment" } ] } ``` - #### operation: `call` * **Description:** This operation execute function and return result * **Example:** ```json { "operation": "call", "values": [ { "type": "func", "name": "min", "values": [ { "type": "number", "value": "20" }, { "type": "number", "value": "100" }, { "type": "number", "value": "10" } ] } ] } ``` - #### function: `count` * **Description:** returns count of elements of the map match the provided predicate * **Name:** **`count`** * **Signature:** **`count(inner_rule as predicate, map)`** * **Return type:** **`number`** - #### function: `some` * **Description:** returns true if some element of the map match the provided predicate * **Name:** **`some`** * **Signature:** **`some(inner_rule as predicate, map)`** * **Return type:** **`boolean`** - #### function: `every` * **Description:** returns true if every element of the map match the provided predicate * **Name:** **`every`** * **Signature:** **`every(inner_rule as predicate, map)`** * **Return type:** **`boolean`** - #### function: `min` - **Description:** returns the minimal number from list of numbers - **Name:** **`min`** - **Signature:** **`min(number, number, ...)`** - **Return type:** **`number`** - #### function: `max` * **Description:** returns the maximal number from list of numbers * **Name:** **`max`** * **Signature:** **`max(number, number, ...)`** * **Return type:** **`number`** - #### function: `if` * **Description:** if the predicate is true returns branch 1 else branch 2 * **Name:** **`if`** * **Signature:** **`if(inner_rule as predicate, number as branch1, number as branch2)`** * **Return type:** **`number`** ### Changed - #### `inner_rule` * can return simple types **`(string | number | version | date | boolean)`** - #### `rule_expression` * can return simple types **`(string | number | version | date | boolean)`** ## Examples ### Checks that `map` contains 1 or more key-values #### User param `type` with name `experiments` ```json { @@ -133,14 +238,63 @@ } ``` #### Rule expression ```json { "operation": "gte", "values": [ { "type": "func", "name": "count", "values": [ { "type": "inner_rule", "value": { "operation": "eq", "values": [ { "type": "string", "value": "key_value" }, { "type": "string", "user_property": "experement_key3" } ] } }, { "type": "map", "user_property": "experiment" } ] }, { "type": "number", "value": "1" } ] } ``` #### Execution steps (as of date 2022-03-22) ##### Step 1 - Getting user param `experiment` from the database - `experiment_key2` is skipped because it is disabled, - `experement_key1` is skipped because it is deprecated The map will be contained only two key-values ```json { "experiment_key3": { "value": "1", "startDate": "2022-01-12", "endDate": "2022-09-12", @@ -155,45 +309,142 @@ From the database will get only two user params **experiment_key3** and **experi } ``` ##### Step 2 - Execute `count` function - Each key-value from user_param **`experiment`** add to expression context - If predicate contains **`experement_key3`** and inner_rule returns true count is incremented - Returns the number of elements found ##### Step 3 - Execute expression in which the function `count` changes to number elements that to match to predicate ``` { "operation": "gte", "values": [ { "type": "number", "value": "1" }, { "type": "number", "value": "1" } ] } ``` ##### Result `true` ### Checks that `map` contains some key-values #### User param `type` with name `experiments` ```json { "experiment_key1": { "value": "1", "startDate": "2022-01-12", "endDate": "2022-02-12", "enabled": true }, "experiment_key2": { "value": "3", "startDate": "2022-01-12", "endDate": "2022-04-12", "enabled": false }, "experiment_key3": { "value": "1", "startDate": "2022-01-12", "endDate": "2022-09-12", "enabled": true }, "experiment_key4": { "value": "4", "startDate": "2022-01-12", "endDate": "2022-04-12", "enabled": true } } ``` #### Rule expression ```json { "operation": "call", "values": [ { "type": "func", "name": "some", "values": [ { "type": "inner_rule", "value": { "operation": "eq", "values": [ { "type": "string", "value": "key_value" }, { "type": "string", "user_property": "experement_key3" } ] } }, { "type": "map", "user_property": "experiment" } ] } ] } ``` #### Execution steps (as of date 2022-03-22) ##### Step 1 - Getting user param `experiment` from the database - `experiment_key2` is skipped because it is disabled, - `experement_key1` is skipped because it is deprecated The map will be contained only two key-values ```json { "experiment_key3": { "value": "1", "startDate": "2022-01-12", "endDate": "2022-09-12", "enabled": true }, "experiment_key4": { "value": "4", "startDate": "2022-01-12", "endDate": "2022-04-12", "enabled": true } } ``` ##### Step 2 - Execute `some` function - Each key-value from user_param **`experiment`** add to expression context - If predicate contains at least one name **`experement_key3`** and inner_rule returns true function must return true else false -
DmitryevichD revised this gist
Mar 24, 2022 . 1 changed file with 7 additions and 12 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,4 @@ # v.0.2.1 # Rule service. Add-ons for the rule expressions contract: @@ -18,9 +18,8 @@ { ... "func": { "name": "some | every | count_by", "content": { "count": { "min": 0, "max": 1 @@ -48,12 +47,10 @@ - **func:** field contains body of function - **func.name:** functions name - **every** - result map size must be equals source map - **some** - result map must contain one or more elements - **count_by:** - size of result map. Value should be set by count element (see **func.content.count**) - **func.content:** functions details - **func.content.count:** setting the number of elements that should contain the resulting map - **func.content.predicate:** Rule expression that uses the map keys as params. Before evaluate the expression all map keys will be changed to map values. @@ -73,9 +70,8 @@ { "operation": "func", "func": { "name": "some", "content": { "count": { "min": 0, "max": 1 @@ -165,9 +161,8 @@ Function ```json "func": { "name": "some", "content": { "predicate": { "operation": "gt", "values": [ -
DmitryevichD revised this gist
Mar 24, 2022 . 1 changed file with 79 additions and 189 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,5 @@ # v.0.2.0 # Rule service. Add-ons for the rule expressions contract: ### New type: @@ -9,126 +10,77 @@ - **Description:** Type is used for define variables that store **key-value of simple types** - **Restrictions:** Key must be present as **string**. All values must be represented as a simple type (**string**, **number**, **version**, **date**) and have the same type ### New expression attribute: ### **`func`** ```json { ... "func": { "name": "filter", "content": { "match": "all | any | none | count", "count": { "min": 0, "max": 1 }, "predicate": { "operation": "gt", "values": [ { "type": "number", "value": "2" }, { "type": "number", "arg": "key_from_map" } ] } } }, ... } ``` - **func:** field contains body of function - **func.name:** functions name - **func.content:** functions details - **func.content.match:** matching the results map after applying the predicate - **all** - result map size must be equals source map - **any** - result map must contain one or more elements - **none** - result map must be empty - **count** - size of result map. Value should be set by count element (see **func.content.count**) - **func.content.count:** setting the number of elements that should contain the resulting map - **func.content.predicate:** Rule expression that uses the map keys as params. Before evaluate the expression all map keys will be changed to map values. ### New operations: ### `func` - **Description:** Specifies that the expression should use the function defined in the attribute `func` ## Example ### Expression ```json { "operation": "func", "func": { "type": "filter", "content": { "match": "all | any | count | none", "count": { "min": 0, "max": 1 }, "predicate": { "operation": "gt", "values": [ { @@ -137,94 +89,21 @@ Filter }, { "type": "number", "arg": "key_from_user_params" } ] } } }, "values": [ { "type": "map", "element_type": "number", "user_property": "experiments" } ] } ``` ### User params @@ -280,12 +159,16 @@ From the database will get only two user params **experiment_key3** and **experi } ``` #### Step 2. - Using predicate Function ```json "func": { "type": "filter", "content": { "match": "any", "predicate": { "operation": "gt", "values": [ { @@ -294,21 +177,28 @@ Filter }, { "type": "number", "arg": "experiment_key3" } ] } } }, ``` for each map element will be call predicate. if predicate expression has the arg with key name and predicate return true -> map element will be add to result map map element `"expression_key3": "1"` will be added to result map because key name be found in predicate and the predicate expression `2 > 1` == true map element `"expression_key4": "4"` will be missed because key name `"expression_key4"` doesn't use in the predicate expression after using the function result map will contain one element ```json "experiment_key3": "1" ``` #### Step 3. - Match result Returns true because `"match": "any"` and the result map has one key-value -
DmitryevichD revised this gist
Mar 23, 2022 . 1 changed file with 1 addition and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,7 +1,6 @@ # v.0.1.0 # Rule service. Add-ons for the rule expressions contract: ### New type: ### `map` -
DmitryevichD created this gist
Mar 21, 2022 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,315 @@ # Rule service. Add-ons for the rule expressions contract: ### New type: ### `map` - **Group:** Complex type - **Description:** Type is used for define variables that store **key-value of simple types** - **Restrictions:** Key must be present as **string**. All values must be represented as a simple type (**string**, **number**, **version**, **date**) and have the same type ### New expression value attribute: ### `filter` - **Description**: Optional element that contains predicate in the form of an rule expression. This predicate will use for each value of map and if it return true key-value will be used in the expression else key--value will be ignored. - **Restrictions:** If filter is null or not present all map values will be used in expression ### New operations: ### `exist` It is used for cases when it is necessary to check that map is **not empty** after using the filter ### `not_exist` It is used for cases when it is necessary to check that map is **empty** after using the filter ## Example with `in` operation ### Expression ```json { "operation": "in", "values": [ { "type": "map", "element_type": "number", "value": { "experiment_key1": "1", "experiment_key2": "2", "experiment_key3": "3" } }, { "type": "map", "element_type": "number", "filter": { "operation": "gt", "values": [ { "type": "number", "value": "2" }, { "type": "number", "user_param": "experement" } ] }, "user_param": "experement" } ] } ``` ### User params ```json { "experiment_key1": { "value": "1", "startDate": "2022-01-12", "endDate": "2022-02-12", "enabled": true }, "experiment_key2": { "value": "3", "startDate": "2022-01-12", "endDate": "2022-04-12", "enabled": false }, "experiment_key3": { "value": "1", "startDate": "2022-01-12", "endDate": "2022-09-12", "enabled": true }, "experiment_key4": { "value": "4", "startDate": "2022-01-12", "endDate": "2022-04-12", "enabled": true } } ``` ### Execution steps (as of date 2022-03-22) #### Step 1. - Getting user params from the database From the database will get only two user params **experiment_key3** and **experiment_key4** because they have a valid date and they are enabled ```json { "experiment_key3": { "value": "1", "startDate": "2022-01-12", "endDate": "2022-09-12", "enabled": true }, "experiment_key4": { "value": "4", "startDate": "2022-01-12", "endDate": "2022-04-12", "enabled": true } } ``` #### Step 2. - Apply filter to map Filter ```json "filter": { "operation": "gt", "values": [ { "type": "number", "value": "2" }, { "type": "number", "user_param": "experement" } ] } ``` will be apply for each value. (`"user_param": "experement"` will be replaced by values `1` and `4` and evaluated.) After that the user param map should contains only one key-value ```json "experiment_key3": "1" ``` #### Step 3. - Evaluate expression Add user param map to expression and evaluate it ```json { "operation": "in", "values": [ { "type": "map", "element_type": "number", "value": { "experiment_key1": "1", "experiment_key2": "2", "experiment_key3": "3" } }, { "type": "map", "element_type": "number", "value": { "experiment_key3": "1" } } ] } ``` Result of expression must be false because map ```json "experiment_key1": "1", "experiment_key2": "2", "experiment_key3": "3" ``` doesn't contains ```json "experiment_key3": "1" ``` ## Example with `exist` operation ### Expression ```json { "operation": "exist", "values": [ { "type": "map", "element_type": "number", "filter": { "operation": "gt", "values": [ { "type": "number", "value": "2" }, { "type": "number", "user_param": "experement" } ] }, "user_param": "experement" } ] } ``` ### User params ```json { "experiment_key1": { "value": "1", "startDate": "2022-01-12", "endDate": "2022-02-12", "enabled": true }, "experiment_key2": { "value": "3", "startDate": "2022-01-12", "endDate": "2022-04-12", "enabled": false }, "experiment_key3": { "value": "1", "startDate": "2022-01-12", "endDate": "2022-09-12", "enabled": true }, "experiment_key4": { "value": "4", "startDate": "2022-01-12", "endDate": "2022-04-12", "enabled": true } } ``` ### Execution steps (as of date 2022-03-22) #### Step 1. - Getting user params from the database From the database will get only two user params **experiment_key3** and **experiment_key4** because they have a valid date and they are enabled ```json { "experiment_key3": { "value": "1", "startDate": "2022-01-12", "endDate": "2022-09-12", "enabled": true }, "experiment_key4": { "value": "4", "startDate": "2022-01-12", "endDate": "2022-04-12", "enabled": true } } ``` #### Step 2. - Apply filter to map Filter ```json "filter": { "operation": "gt", "values": [ { "type": "number", "value": "2" }, { "type": "number", "user_param": "experement" } ] } ``` will be apply for each value. (`"user_param": "experement"` will be replaced by values `1` and `4` and evaluated.) After that the user param map should contains only one key-value ```json "experiment_key3": "1" ``` #### Step 3. - Evaluate expression Returns true, since the map contains one element and is not empty