Skip to content

Instantly share code, notes, and snippets.

@DmitryevichD
Last active March 30, 2022 09:58
Show Gist options
  • Save DmitryevichD/9f0d26d84f1a1da809e1c35f04e2bc8c to your computer and use it in GitHub Desktop.
Save DmitryevichD/9f0d26d84f1a1da809e1c35f04e2bc8c to your computer and use it in GitHub Desktop.

Revisions

  1. DmitryevichD revised this gist Mar 30, 2022. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion ruleServiceMapValue.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    # Abstract expression language v2.0.0
    # Abstract expression language v2.0.1

    ## Innovations:

  2. DmitryevichD revised this gist Mar 29, 2022. 1 changed file with 74 additions and 60 deletions.
    134 changes: 74 additions & 60 deletions ruleServiceMapValue.md
    Original 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 (**map**)
    * Expression can use new type (**dictionary**)
    * Backward compatibility with contract v1.0.0



    ## [2.0.0] - 2022-03-25
    ## [2.0.1] - 2022-03-29

    ### Added

    - #### type: `map`
    - #### type: `dictionary`

    * **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`**
    * **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 => **`map`**
    - element_type - type of values into the map => **`(string | number | version | date | boolean)`**
    - 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 map must be present as **`string`**.
    - Values in the one map must have the same type
    - 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": "map",
    "type": "dictionary",
    "element_type": "string",
    "value": {
    "map_key1": "mav_value_1",
    "map_key2": "mav_value_2"
    }
    },
    {
    "type": "map",
    "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 of simple type **`(string | number | version | date | boolean)`** that return function
    * **Available operations:** operations depends on 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
    * **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",
    "user_property": "key_user_param"
    "argument": "key_user_param"
    }
    ]
    }
    },
    {
    "type": "map",
    "type": "dictionary",
    "user_property": "experiment"
    }
    ]
    @@ -140,7 +140,7 @@

    * **Name:** **`count`**

    * **Signature:** **`count(inner_rule as predicate, map)`**
    * **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, map)`**
    * **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, map)`**
    * **Signature:** **`every(inner_rule as predicate, dictionary)`**

    * **Return type:** **`boolean`**

    @@ -205,9 +205,9 @@

    ## Examples

    ### Checks that `map` contains 1 or more key-values
    ### Checking that the `dictionary` contains 1 or more key values corresponding to the predicate

    #### User param `type` with name `experiments`
    #### RabbitMQ message that contains user param `experiments` with type `dictionary` and element type `string`

    ```json
    {
    @@ -240,7 +240,7 @@



    #### Rule expression
    #### Rule expression that counts the number of values in a dictionary using a predicate

    ```json
    {
    @@ -267,7 +267,7 @@
    }
    },
    {
    "type": "map",
    "type": "dictionary",
    "user_property": "experiment"
    }
    ]
    @@ -285,37 +285,42 @@

    #### Execution steps (as of date 2022-03-22)

    ##### Step 1 - Getting user param `experiment` from the database
    ##### 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 map will be contained only two key-values
    The user_property **`experiment`** that should use in the

    ```json
    {
    "type": "dictionary",
    "user_property": "experiment"
    }
    ```

    will have the following value

    ```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
    }
    "experiment_key3": "1",
    "experiment_key4": "4"
    }
    ```



    ##### 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
    - 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 `map` contains some key-values
    ### Checks that `dictionary` contains some key-values

    #### User param `type` with name `experiments`
    #### 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
    #### 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": "key_value"
    "value": "1"
    },
    {
    "type": "string",
    @@ -403,7 +408,7 @@ The map will be contained only two key-values
    }
    },
    {
    "type": "map",
    "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 1 - Getting user param `experiment` from the database
    ##### 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 map will be contained only two key-values
    The user_property **`experiment`** that should use in the

    ```json
    {
    "type": "dictionary",
    "user_property": "experiment"
    }
    ```

    will have the following value

    ```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
    }
    "experiment_key3": "1",
    "experiment_key4": "4"
    }
    ```



    ##### Step 2 - Execute `some` function

    - Each key-value from user_param **`experiment`** add to expression context
    - 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



    - If predicate contains at least one name **`experement_key3`** and inner_rule returns true function must return true else false
  3. DmitryevichD revised this gist Mar 28, 2022. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions ruleServiceMapValue.md
    Original file line number Diff line number Diff line change
    @@ -257,11 +257,11 @@
    "values": [
    {
    "type": "string",
    "value": "key_value"
    "value": "1"
    },
    {
    "type": "string",
    "user_property": "experement_key3"
    "argument": "experement_key3"
    }
    ]
    }
  4. DmitryevichD revised this gist Mar 27, 2022. 1 changed file with 357 additions and 106 deletions.
    463 changes: 357 additions & 106 deletions ruleServiceMapValue.md
    Original file line number Diff line number Diff line change
    @@ -1,108 +1,213 @@
    # v.0.2.1
    # Abstract expression language v2.0.0

    # Rule service. Add-ons for the rule expressions contract:
    ## Innovations:

    ### New type:
    * 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)

    ### `map`
    * Expression can use new type (**map**)
    * Backward compatibility with contract v1.0.0

    - **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 attribute:

    ### **`func`**
    ## [2.0.0] - 2022-03-25

    ```json
    {
    ...
    "func": {
    "name": "some | every | count_by",
    "content": {
    "count": {
    "min": 0,
    "max": 1
    },
    "predicate": {
    "operation": "gt",
    ### 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": "2"
    "value": "100"
    },
    {
    "type": "number",
    "arg": "key_from_map"
    "value": "10"
    }
    ]
    }
    }
    },
    ...
    }
    ```
    ]
    }
    ```

    - #### function: `count`

    * **Description:** returns count of elements of the map match the provided predicate

    - **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.
    * **Name:** **`count`**

    ### New operations:
    * **Signature:** **`count(inner_rule as predicate, map)`**

    ### `func`
    * **Return type:** **`number`**

    - **Description:** Specifies that the expression should use the function defined in the attribute `func`
    - #### function: `some`

    * **Description:** returns true if some element of the map match the provided predicate
    * **Name:** **`some`**

    * **Signature:** **`some(inner_rule as predicate, map)`**

    ## Example
    * **Return type:** **`boolean`**

    ### Expression
    - #### function: `every`

    ```json
    {
    "operation": "func",
    "func": {
    "name": "some",
    "content": {
    "count": {
    "min": 0,
    "max": 1
    },
    "predicate": {
    "operation": "gt",
    "values": [
    {
    "type": "number",
    "value": "2"
    },
    {
    "type": "number",
    "arg": "key_from_user_params"
    }
    ]
    }
    }
    },
    "values": [
    {
    "type": "map",
    "element_type": "number",
    "user_property": "experiments"
    }
    ]
    }
    * **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`**

    ### User params


    ### 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 @@
    }
    ```

    ### 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
    #### Rule expression

    ```json
    { "experiment_key3": {
    {
    "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. - Using predicate

    Function

    ##### 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
    "func": {
    "name": "some",
    "content": {
    "predicate": {
    "operation": "gt",
    "values": [
    {
    "type": "number",
    "value": "2"
    },
    {
    "type": "number",
    "arg": "experiment_key3"
    {
    "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"
    }
    ]
    }
    },
    ]
    }

    ```

    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
    #### Execution steps (as of date 2022-03-22)

    ##### Step 1 - Getting user param `experiment` from the database

    map element `"expression_key4": "4"` will be missed because key name `"expression_key4"` doesn't use in the predicate expression
    - `experiment_key2` is skipped because it is disabled,
    - `experement_key1` is skipped because it is deprecated

    after using the function result map will contain one element
    The map will be contained only two key-values

    ```json
    "experiment_key3": "1"
    {
    "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 3. - Match result

    Returns true because `"match": "any"` and the result map has one key-value

    ##### 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
  5. DmitryevichD revised this gist Mar 24, 2022. 1 changed file with 7 additions and 12 deletions.
    19 changes: 7 additions & 12 deletions ruleServiceMapValue.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    # v.0.2.0
    # v.0.2.1

    # Rule service. Add-ons for the rule expressions contract:

    @@ -18,9 +18,8 @@
    {
    ...
    "func": {
    "name": "filter",
    "name": "some | every | count_by",
    "content": {
    "match": "all | any | none | count",
    "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.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.

    @@ -73,9 +70,8 @@
    {
    "operation": "func",
    "func": {
    "type": "filter",
    "name": "some",
    "content": {
    "match": "all | any | count | none",
    "count": {
    "min": 0,
    "max": 1
    @@ -165,9 +161,8 @@ Function

    ```json
    "func": {
    "type": "filter",
    "name": "some",
    "content": {
    "match": "any",
    "predicate": {
    "operation": "gt",
    "values": [
  6. DmitryevichD revised this gist Mar 24, 2022. 1 changed file with 79 additions and 189 deletions.
    268 changes: 79 additions & 189 deletions ruleServiceMapValue.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,5 @@
    # v.0.1.0
    # 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 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
    ### New expression attribute:



    ## Example with `in` operation

    ### Expression
    ### **`func`**

    ```json
    {
    "operation": "in",
    "values": [
    {
    "type": "map",
    "element_type": "number",
    "value": {
    "experiment_key1": "1",
    "experiment_key2": "2",
    "experiment_key3": "3"
    ...
    "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"
    }
    ]
    }
    }
    },
    {
    "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
    }
    }

    ```
    - **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.

    ### Execution steps (as of date 2022-03-22)
    ### New operations:

    #### Step 1. - Getting user params from the database
    ### `func`

    From the database will get only two user params **experiment_key3** and **experiment_key4** because they have a valid date and they are enabled
    - **Description:** Specifies that the expression should use the function defined in the attribute `func`

    ```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
    ## Example

    ### Expression

    ```json
    "filter": {
    {
    "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",
    "user_param": "experement"
    "arg": "key_from_user_params"
    }
    ]
    }
    ```

    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"
    "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. - Apply filter to map
    #### Step 2. - Using predicate

    Filter
    Function

    ```json
    "filter": {
    "func": {
    "type": "filter",
    "content": {
    "match": "any",
    "predicate": {
    "operation": "gt",
    "values": [
    {
    @@ -294,21 +177,28 @@ Filter
    },
    {
    "type": "number",
    "user_param": "experement"
    "arg": "experiment_key3"
    }
    ]
    }
    }
    },
    ```

    will be apply for each value. (`"user_param": "experement"` will be replaced by values `1` and `4` and evaluated.)
    for each map element will be call predicate.

    After that the user param map should contains only one key-value
    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. - Evaluate expression

    Returns true, since the map contains one element and is not empty
    #### Step 3. - Match result

    Returns true because `"match": "any"` and the result map has one key-value
  7. DmitryevichD revised this gist Mar 23, 2022. 1 changed file with 1 addition and 2 deletions.
    3 changes: 1 addition & 2 deletions ruleServiceMapValue.md
    Original 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`
  8. DmitryevichD created this gist Mar 21, 2022.
    315 changes: 315 additions & 0 deletions ruleServiceMapValue.md
    Original 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